adc310a6d48991072ae0081318ac3d60a00a480d
[sfrench/cifs-2.6.git] / tools / usb / ffs-aio-example / simple / device_app / aio_simple.c
1 /*
2  * This is free and unencumbered software released into the public domain.
3  *
4  * Anyone is free to copy, modify, publish, use, compile, sell, or
5  * distribute this software, either in source code form or as a compiled
6  * binary, for any purpose, commercial or non-commercial, and by any
7  * means.
8  *
9  * In jurisdictions that recognize copyright laws, the author or authors
10  * of this software dedicate any and all copyright interest in the
11  * software to the public domain. We make this dedication for the benefit
12  * of the public at large and to the detriment of our heirs and
13  * successors. We intend this dedication to be an overt act of
14  * relinquishment in perpetuity of all present and future rights to this
15  * software under copyright law.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * For more information, please refer to <http://unlicense.org/>
26  */
27
28 #define _BSD_SOURCE /* for endian.h */
29
30 #include <endian.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/ioctl.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <sys/poll.h>
41 #include <unistd.h>
42 #include <stdbool.h>
43 #include <sys/eventfd.h>
44
45 #include "libaio.h"
46 #define IOCB_FLAG_RESFD         (1 << 0)
47
48 #include <linux/usb/functionfs.h>
49
50 #define BUF_LEN         8192
51
52 /******************** Descriptors and Strings *******************************/
53
54 static const struct {
55         struct usb_functionfs_descs_head_v2 header;
56         __le32 fs_count;
57         __le32 hs_count;
58         struct {
59                 struct usb_interface_descriptor intf;
60                 struct usb_endpoint_descriptor_no_audio bulk_sink;
61                 struct usb_endpoint_descriptor_no_audio bulk_source;
62         } __attribute__ ((__packed__)) fs_descs, hs_descs;
63 } __attribute__ ((__packed__)) descriptors = {
64         .header = {
65                 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
66                 .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
67                                      FUNCTIONFS_HAS_HS_DESC),
68                 .length = htole32(sizeof(descriptors)),
69         },
70         .fs_count = htole32(3),
71         .fs_descs = {
72                 .intf = {
73                         .bLength = sizeof(descriptors.fs_descs.intf),
74                         .bDescriptorType = USB_DT_INTERFACE,
75                         .bNumEndpoints = 2,
76                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
77                         .iInterface = 1,
78                 },
79                 .bulk_sink = {
80                         .bLength = sizeof(descriptors.fs_descs.bulk_sink),
81                         .bDescriptorType = USB_DT_ENDPOINT,
82                         .bEndpointAddress = 1 | USB_DIR_IN,
83                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
84                 },
85                 .bulk_source = {
86                         .bLength = sizeof(descriptors.fs_descs.bulk_source),
87                         .bDescriptorType = USB_DT_ENDPOINT,
88                         .bEndpointAddress = 2 | USB_DIR_OUT,
89                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
90                 },
91         },
92         .hs_count = htole32(3),
93         .hs_descs = {
94                 .intf = {
95                         .bLength = sizeof(descriptors.hs_descs.intf),
96                         .bDescriptorType = USB_DT_INTERFACE,
97                         .bNumEndpoints = 2,
98                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
99                         .iInterface = 1,
100                 },
101                 .bulk_sink = {
102                         .bLength = sizeof(descriptors.hs_descs.bulk_sink),
103                         .bDescriptorType = USB_DT_ENDPOINT,
104                         .bEndpointAddress = 1 | USB_DIR_IN,
105                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
106                 },
107                 .bulk_source = {
108                         .bLength = sizeof(descriptors.hs_descs.bulk_source),
109                         .bDescriptorType = USB_DT_ENDPOINT,
110                         .bEndpointAddress = 2 | USB_DIR_OUT,
111                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
112                 },
113         },
114 };
115
116 #define STR_INTERFACE "AIO Test"
117
118 static const struct {
119         struct usb_functionfs_strings_head header;
120         struct {
121                 __le16 code;
122                 const char str1[sizeof(STR_INTERFACE)];
123         } __attribute__ ((__packed__)) lang0;
124 } __attribute__ ((__packed__)) strings = {
125         .header = {
126                 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
127                 .length = htole32(sizeof(strings)),
128                 .str_count = htole32(1),
129                 .lang_count = htole32(1),
130         },
131         .lang0 = {
132                 htole16(0x0409), /* en-us */
133                 STR_INTERFACE,
134         },
135 };
136
137 /******************** Endpoints handling *******************************/
138
139 static void display_event(struct usb_functionfs_event *event)
140 {
141         static const char *const names[] = {
142                 [FUNCTIONFS_BIND] = "BIND",
143                 [FUNCTIONFS_UNBIND] = "UNBIND",
144                 [FUNCTIONFS_ENABLE] = "ENABLE",
145                 [FUNCTIONFS_DISABLE] = "DISABLE",
146                 [FUNCTIONFS_SETUP] = "SETUP",
147                 [FUNCTIONFS_SUSPEND] = "SUSPEND",
148                 [FUNCTIONFS_RESUME] = "RESUME",
149         };
150         switch (event->type) {
151         case FUNCTIONFS_BIND:
152         case FUNCTIONFS_UNBIND:
153         case FUNCTIONFS_ENABLE:
154         case FUNCTIONFS_DISABLE:
155         case FUNCTIONFS_SETUP:
156         case FUNCTIONFS_SUSPEND:
157         case FUNCTIONFS_RESUME:
158                 printf("Event %s\n", names[event->type]);
159         }
160 }
161
162 static void handle_ep0(int ep0, bool *ready)
163 {
164         struct usb_functionfs_event event;
165         int ret;
166
167         struct pollfd pfds[1];
168         pfds[0].fd = ep0;
169         pfds[0].events = POLLIN;
170
171         ret = poll(pfds, 1, 0);
172
173         if (ret && (pfds[0].revents & POLLIN)) {
174                 ret = read(ep0, &event, sizeof(event));
175                 if (!ret) {
176                         perror("unable to read event from ep0");
177                         return;
178                 }
179                 display_event(&event);
180                 switch (event.type) {
181                 case FUNCTIONFS_SETUP:
182                         if (event.u.setup.bRequestType & USB_DIR_IN)
183                                 write(ep0, NULL, 0);
184                         else
185                                 read(ep0, NULL, 0);
186                         break;
187
188                 case FUNCTIONFS_ENABLE:
189                         *ready = true;
190                         break;
191
192                 case FUNCTIONFS_DISABLE:
193                         *ready = false;
194                         break;
195
196                 default:
197                         break;
198                 }
199         }
200 }
201
202 int main(int argc, char *argv[])
203 {
204         int i, ret;
205         char *ep_path;
206
207         int ep0;
208         int ep[2];
209
210         io_context_t ctx;
211
212         int evfd;
213         fd_set rfds;
214
215         char *buf_in, *buf_out;
216         struct iocb *iocb_in, *iocb_out;
217         int req_in = 0, req_out = 0;
218         bool ready;
219
220         if (argc != 2) {
221                 printf("ffs directory not specified!\n");
222                 return 1;
223         }
224
225         ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
226         if (!ep_path) {
227                 perror("malloc");
228                 return 1;
229         }
230
231         /* open endpoint files */
232         sprintf(ep_path, "%s/ep0", argv[1]);
233         ep0 = open(ep_path, O_RDWR);
234         if (ep0 < 0) {
235                 perror("unable to open ep0");
236                 return 1;
237         }
238         if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
239                 perror("unable do write descriptors");
240                 return 1;
241         }
242         if (write(ep0, &strings, sizeof(strings)) < 0) {
243                 perror("unable to write strings");
244                 return 1;
245         }
246         for (i = 0; i < 2; ++i) {
247                 sprintf(ep_path, "%s/ep%d", argv[1], i+1);
248                 ep[i] = open(ep_path, O_RDWR);
249                 if (ep[i] < 0) {
250                         printf("unable to open ep%d: %s\n", i+1,
251                                strerror(errno));
252                         return 1;
253                 }
254         }
255
256         free(ep_path);
257
258         memset(&ctx, 0, sizeof(ctx));
259         /* setup aio context to handle up to 2 requests */
260         if (io_setup(2, &ctx) < 0) {
261                 perror("unable to setup aio");
262                 return 1;
263         }
264
265         evfd = eventfd(0, 0);
266         if (evfd < 0) {
267                 perror("unable to open eventfd");
268                 return 1;
269         }
270
271         /* alloc buffers and requests */
272         buf_in = malloc(BUF_LEN);
273         buf_out = malloc(BUF_LEN);
274         iocb_in = malloc(sizeof(*iocb_in));
275         iocb_out = malloc(sizeof(*iocb_out));
276
277         while (1) {
278                 FD_ZERO(&rfds);
279                 FD_SET(ep0, &rfds);
280                 FD_SET(evfd, &rfds);
281
282                 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
283                              &rfds, NULL, NULL, NULL);
284                 if (ret < 0) {
285                         if (errno == EINTR)
286                                 continue;
287                         perror("select");
288                         break;
289                 }
290
291                 if (FD_ISSET(ep0, &rfds))
292                         handle_ep0(ep0, &ready);
293
294                 /* we are waiting for function ENABLE */
295                 if (!ready)
296                         continue;
297
298                 /* if something was submitted we wait for event */
299                 if (FD_ISSET(evfd, &rfds)) {
300                         uint64_t ev_cnt;
301                         ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
302                         if (ret < 0) {
303                                 perror("unable to read eventfd");
304                                 break;
305                         }
306
307                         struct io_event e[2];
308                         /* we wait for one event */
309                         ret = io_getevents(ctx, 1, 2, e, NULL);
310                         /* if we got event */
311                         for (i = 0; i < ret; ++i) {
312                                 if (e[i].obj->aio_fildes == ep[0]) {
313                                         printf("ev=in; ret=%lu\n", e[i].res);
314                                         req_in = 0;
315                                 } else if (e[i].obj->aio_fildes == ep[1]) {
316                                         printf("ev=out; ret=%lu\n", e[i].res);
317                                         req_out = 0;
318                                 }
319                         }
320                 }
321
322                 if (!req_in) { /* if IN transfer not requested*/
323                         /* prepare write request */
324                         io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
325                         /* enable eventfd notification */
326                         iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
327                         iocb_in->u.c.resfd = evfd;
328                         /* submit table of requests */
329                         ret = io_submit(ctx, 1, &iocb_in);
330                         if (ret >= 0) { /* if ret > 0 request is queued */
331                                 req_in = 1;
332                                 printf("submit: in\n");
333                         } else
334                                 perror("unable to submit request");
335                 }
336                 if (!req_out) { /* if OUT transfer not requested */
337                         /* prepare read request */
338                         io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
339                         /* enable eventfs notification */
340                         iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
341                         iocb_out->u.c.resfd = evfd;
342                         /* submit table of requests */
343                         ret = io_submit(ctx, 1, &iocb_out);
344                         if (ret >= 0) { /* if ret > 0 request is queued */
345                                 req_out = 1;
346                                 printf("submit: out\n");
347                         } else
348                                 perror("unable to submit request");
349                 }
350         }
351
352         /* free resources */
353
354         io_destroy(ctx);
355
356         free(buf_in);
357         free(buf_out);
358         free(iocb_in);
359         free(iocb_out);
360
361         for (i = 0; i < 2; ++i)
362                 close(ep[i]);
363         close(ep0);
364
365         return 0;
366 }