tools: ffs-aio-example: convert to new descriptor format
[firefly-linux-kernel-4.4.55.git] / tools / usb / ffs-aio-example / multibuff / device_app / aio_multibuff.c
1 #define _BSD_SOURCE /* for endian.h */
2
3 #include <endian.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <sys/poll.h>
14 #include <unistd.h>
15 #include <stdbool.h>
16 #include <sys/eventfd.h>
17
18 #include "libaio.h"
19 #define IOCB_FLAG_RESFD         (1 << 0)
20
21 #include <linux/usb/functionfs.h>
22
23 #define BUF_LEN         8192
24 #define BUFS_MAX        128
25 #define AIO_MAX         (BUFS_MAX*2)
26
27 /******************** Descriptors and Strings *******************************/
28
29 static const struct {
30         struct usb_functionfs_descs_head_v2 header;
31         __le32 fs_count;
32         __le32 hs_count;
33         struct {
34                 struct usb_interface_descriptor intf;
35                 struct usb_endpoint_descriptor_no_audio bulk_sink;
36                 struct usb_endpoint_descriptor_no_audio bulk_source;
37         } __attribute__ ((__packed__)) fs_descs, hs_descs;
38 } __attribute__ ((__packed__)) descriptors = {
39         .header = {
40                 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
41                 .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
42                                      FUNCTIONFS_HAS_HS_DESC),
43                 .length = htole32(sizeof(descriptors)),
44         },
45         .fs_count = htole32(3),
46         .fs_descs = {
47                 .intf = {
48                         .bLength = sizeof(descriptors.fs_descs.intf),
49                         .bDescriptorType = USB_DT_INTERFACE,
50                         .bNumEndpoints = 2,
51                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
52                         .iInterface = 1,
53                 },
54                 .bulk_sink = {
55                         .bLength = sizeof(descriptors.fs_descs.bulk_sink),
56                         .bDescriptorType = USB_DT_ENDPOINT,
57                         .bEndpointAddress = 1 | USB_DIR_IN,
58                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
59                 },
60                 .bulk_source = {
61                         .bLength = sizeof(descriptors.fs_descs.bulk_source),
62                         .bDescriptorType = USB_DT_ENDPOINT,
63                         .bEndpointAddress = 2 | USB_DIR_OUT,
64                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
65                 },
66         },
67         .hs_count = htole32(3),
68         .hs_descs = {
69                 .intf = {
70                         .bLength = sizeof(descriptors.hs_descs.intf),
71                         .bDescriptorType = USB_DT_INTERFACE,
72                         .bNumEndpoints = 2,
73                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
74                         .iInterface = 1,
75                 },
76                 .bulk_sink = {
77                         .bLength = sizeof(descriptors.hs_descs.bulk_sink),
78                         .bDescriptorType = USB_DT_ENDPOINT,
79                         .bEndpointAddress = 1 | USB_DIR_IN,
80                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
81                         .wMaxPacketSize = htole16(512),
82                 },
83                 .bulk_source = {
84                         .bLength = sizeof(descriptors.hs_descs.bulk_source),
85                         .bDescriptorType = USB_DT_ENDPOINT,
86                         .bEndpointAddress = 2 | USB_DIR_OUT,
87                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
88                         .wMaxPacketSize = htole16(512),
89                 },
90         },
91 };
92
93 #define STR_INTERFACE "AIO Test"
94
95 static const struct {
96         struct usb_functionfs_strings_head header;
97         struct {
98                 __le16 code;
99                 const char str1[sizeof(STR_INTERFACE)];
100         } __attribute__ ((__packed__)) lang0;
101 } __attribute__ ((__packed__)) strings = {
102         .header = {
103                 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
104                 .length = htole32(sizeof(strings)),
105                 .str_count = htole32(1),
106                 .lang_count = htole32(1),
107         },
108         .lang0 = {
109                 htole16(0x0409), /* en-us */
110                 STR_INTERFACE,
111         },
112 };
113
114 /********************** Buffer structure *******************************/
115
116 struct io_buffer {
117         struct iocb **iocb;
118         unsigned char **buf;
119         unsigned cnt;
120         unsigned len;
121         unsigned requested;
122 };
123
124 /******************** Endpoints handling *******************************/
125
126 static void display_event(struct usb_functionfs_event *event)
127 {
128         static const char *const names[] = {
129                 [FUNCTIONFS_BIND] = "BIND",
130                 [FUNCTIONFS_UNBIND] = "UNBIND",
131                 [FUNCTIONFS_ENABLE] = "ENABLE",
132                 [FUNCTIONFS_DISABLE] = "DISABLE",
133                 [FUNCTIONFS_SETUP] = "SETUP",
134                 [FUNCTIONFS_SUSPEND] = "SUSPEND",
135                 [FUNCTIONFS_RESUME] = "RESUME",
136         };
137         switch (event->type) {
138         case FUNCTIONFS_BIND:
139         case FUNCTIONFS_UNBIND:
140         case FUNCTIONFS_ENABLE:
141         case FUNCTIONFS_DISABLE:
142         case FUNCTIONFS_SETUP:
143         case FUNCTIONFS_SUSPEND:
144         case FUNCTIONFS_RESUME:
145                 printf("Event %s\n", names[event->type]);
146         }
147 }
148
149 static void handle_ep0(int ep0, bool *ready)
150 {
151         int ret;
152         struct usb_functionfs_event event;
153
154         ret = read(ep0, &event, sizeof(event));
155         if (!ret) {
156                 perror("unable to read event from ep0");
157                 return;
158         }
159         display_event(&event);
160         switch (event.type) {
161         case FUNCTIONFS_SETUP:
162                 if (event.u.setup.bRequestType & USB_DIR_IN)
163                         write(ep0, NULL, 0);
164                 else
165                         read(ep0, NULL, 0);
166                 break;
167
168         case FUNCTIONFS_ENABLE:
169                 *ready = true;
170                 break;
171
172         case FUNCTIONFS_DISABLE:
173                 *ready = false;
174                 break;
175
176         default:
177                 break;
178         }
179 }
180
181 void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
182 {
183         unsigned i;
184         iobuf->buf = malloc(n*sizeof(*iobuf->buf));
185         iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
186         iobuf->cnt = n;
187         iobuf->len = len;
188         iobuf->requested = 0;
189         for (i = 0; i < n; ++i) {
190                 iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
191                 iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
192         }
193         iobuf->cnt = n;
194 }
195
196 void delete_bufs(struct io_buffer *iobuf)
197 {
198         unsigned i;
199         for (i = 0; i < iobuf->cnt; ++i) {
200                 free(iobuf->buf[i]);
201                 free(iobuf->iocb[i]);
202         }
203         free(iobuf->buf);
204         free(iobuf->iocb);
205 }
206
207 int main(int argc, char *argv[])
208 {
209         int ret;
210         unsigned i, j;
211         char *ep_path;
212
213         int ep0, ep1;
214
215         io_context_t ctx;
216
217         int evfd;
218         fd_set rfds;
219
220         struct io_buffer iobuf[2];
221         int actual = 0;
222         bool ready;
223
224         if (argc != 2) {
225                 printf("ffs directory not specified!\n");
226                 return 1;
227         }
228
229         ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
230         if (!ep_path) {
231                 perror("malloc");
232                 return 1;
233         }
234
235         /* open endpoint files */
236         sprintf(ep_path, "%s/ep0", argv[1]);
237         ep0 = open(ep_path, O_RDWR);
238         if (ep0 < 0) {
239                 perror("unable to open ep0");
240                 return 1;
241         }
242         if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
243                 perror("unable do write descriptors");
244                 return 1;
245         }
246         if (write(ep0, &strings, sizeof(strings)) < 0) {
247                 perror("unable to write strings");
248                 return 1;
249         }
250         sprintf(ep_path, "%s/ep1", argv[1]);
251         ep1 = open(ep_path, O_RDWR);
252         if (ep1 < 0) {
253                 perror("unable to open ep1");
254                 return 1;
255         }
256
257         free(ep_path);
258
259         memset(&ctx, 0, sizeof(ctx));
260         /* setup aio context to handle up to AIO_MAX requests */
261         if (io_setup(AIO_MAX, &ctx) < 0) {
262                 perror("unable to setup aio");
263                 return 1;
264         }
265
266         evfd = eventfd(0, 0);
267         if (evfd < 0) {
268                 perror("unable to open eventfd");
269                 return 1;
270         }
271
272         for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
273                 init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
274
275         while (1) {
276                 FD_ZERO(&rfds);
277                 FD_SET(ep0, &rfds);
278                 FD_SET(evfd, &rfds);
279
280                 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
281                              &rfds, NULL, NULL, NULL);
282                 if (ret < 0) {
283                         if (errno == EINTR)
284                                 continue;
285                         perror("select");
286                         break;
287                 }
288
289                 if (FD_ISSET(ep0, &rfds))
290                         handle_ep0(ep0, &ready);
291
292                 /* we are waiting for function ENABLE */
293                 if (!ready)
294                         continue;
295
296                 /*
297                  * when we're preparing new data to submit,
298                  * second buffer being transmitted
299                  */
300                 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
301                         if (iobuf[i].requested)
302                                 continue;
303                         /* prepare requests */
304                         for (j = 0; j < iobuf[i].cnt; ++j) {
305                                 io_prep_pwrite(iobuf[i].iocb[j], ep1,
306                                                iobuf[i].buf[j],
307                                                iobuf[i].len, 0);
308                                 /* enable eventfd notification */
309                                 iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
310                                 iobuf[i].iocb[j]->u.c.resfd = evfd;
311                         }
312                         /* submit table of requests */
313                         ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
314                         if (ret >= 0) {
315                                 iobuf[i].requested = ret;
316                                 printf("submit: %d requests buf: %d\n", ret, i);
317                         } else
318                                 perror("unable to submit reqests");
319                 }
320
321                 /* if event is ready to read */
322                 if (!FD_ISSET(evfd, &rfds))
323                         continue;
324
325                 uint64_t ev_cnt;
326                 ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
327                 if (ret < 0) {
328                         perror("unable to read eventfd");
329                         break;
330                 }
331
332                 struct io_event e[BUFS_MAX];
333                 /* we read aio events */
334                 ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
335                 if (ret > 0) /* if we got events */
336                         iobuf[actual].requested -= ret;
337
338                 /* if all req's from iocb completed */
339                 if (!iobuf[actual].requested)
340                         actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
341         }
342
343         /* free resources */
344
345         for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
346                 delete_bufs(&iobuf[i]);
347         io_destroy(ctx);
348
349         close(ep1);
350         close(ep0);
351
352         return 0;
353 }