1 #define _BSD_SOURCE /* for endian.h */
10 #include <sys/ioctl.h>
12 #include <sys/types.h>
16 #include <sys/eventfd.h>
19 #define IOCB_FLAG_RESFD (1 << 0)
21 #include <linux/usb/functionfs.h>
25 /******************** Descriptors and Strings *******************************/
28 struct usb_functionfs_descs_head header;
30 struct usb_interface_descriptor intf;
31 struct usb_endpoint_descriptor_no_audio bulk_sink;
32 struct usb_endpoint_descriptor_no_audio bulk_source;
33 } __attribute__ ((__packed__)) fs_descs, hs_descs;
34 } __attribute__ ((__packed__)) descriptors = {
36 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
37 .length = htole32(sizeof(descriptors)),
43 .bLength = sizeof(descriptors.fs_descs.intf),
44 .bDescriptorType = USB_DT_INTERFACE,
46 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
50 .bLength = sizeof(descriptors.fs_descs.bulk_sink),
51 .bDescriptorType = USB_DT_ENDPOINT,
52 .bEndpointAddress = 1 | USB_DIR_IN,
53 .bmAttributes = USB_ENDPOINT_XFER_BULK,
56 .bLength = sizeof(descriptors.fs_descs.bulk_source),
57 .bDescriptorType = USB_DT_ENDPOINT,
58 .bEndpointAddress = 2 | USB_DIR_OUT,
59 .bmAttributes = USB_ENDPOINT_XFER_BULK,
64 .bLength = sizeof(descriptors.hs_descs.intf),
65 .bDescriptorType = USB_DT_INTERFACE,
67 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
71 .bLength = sizeof(descriptors.hs_descs.bulk_sink),
72 .bDescriptorType = USB_DT_ENDPOINT,
73 .bEndpointAddress = 1 | USB_DIR_IN,
74 .bmAttributes = USB_ENDPOINT_XFER_BULK,
77 .bLength = sizeof(descriptors.hs_descs.bulk_source),
78 .bDescriptorType = USB_DT_ENDPOINT,
79 .bEndpointAddress = 2 | USB_DIR_OUT,
80 .bmAttributes = USB_ENDPOINT_XFER_BULK,
85 #define STR_INTERFACE "AIO Test"
88 struct usb_functionfs_strings_head header;
91 const char str1[sizeof(STR_INTERFACE)];
92 } __attribute__ ((__packed__)) lang0;
93 } __attribute__ ((__packed__)) strings = {
95 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
96 .length = htole32(sizeof(strings)),
97 .str_count = htole32(1),
98 .lang_count = htole32(1),
101 htole16(0x0409), /* en-us */
106 /******************** Endpoints handling *******************************/
108 static void display_event(struct usb_functionfs_event *event)
110 static const char *const names[] = {
111 [FUNCTIONFS_BIND] = "BIND",
112 [FUNCTIONFS_UNBIND] = "UNBIND",
113 [FUNCTIONFS_ENABLE] = "ENABLE",
114 [FUNCTIONFS_DISABLE] = "DISABLE",
115 [FUNCTIONFS_SETUP] = "SETUP",
116 [FUNCTIONFS_SUSPEND] = "SUSPEND",
117 [FUNCTIONFS_RESUME] = "RESUME",
119 switch (event->type) {
120 case FUNCTIONFS_BIND:
121 case FUNCTIONFS_UNBIND:
122 case FUNCTIONFS_ENABLE:
123 case FUNCTIONFS_DISABLE:
124 case FUNCTIONFS_SETUP:
125 case FUNCTIONFS_SUSPEND:
126 case FUNCTIONFS_RESUME:
127 printf("Event %s\n", names[event->type]);
131 static void handle_ep0(int ep0, bool *ready)
133 struct usb_functionfs_event event;
136 struct pollfd pfds[1];
138 pfds[0].events = POLLIN;
140 ret = poll(pfds, 1, 0);
142 if (ret && (pfds[0].revents & POLLIN)) {
143 ret = read(ep0, &event, sizeof(event));
145 perror("unable to read event from ep0");
148 display_event(&event);
149 switch (event.type) {
150 case FUNCTIONFS_SETUP:
151 if (event.u.setup.bRequestType & USB_DIR_IN)
157 case FUNCTIONFS_ENABLE:
161 case FUNCTIONFS_DISABLE:
171 int main(int argc, char *argv[])
184 char *buf_in, *buf_out;
185 struct iocb *iocb_in, *iocb_out;
186 int req_in = 0, req_out = 0;
190 printf("ffs directory not specified!\n");
194 ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
200 /* open endpoint files */
201 sprintf(ep_path, "%s/ep0", argv[1]);
202 ep0 = open(ep_path, O_RDWR);
204 perror("unable to open ep0");
207 if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
208 perror("unable do write descriptors");
211 if (write(ep0, &strings, sizeof(strings)) < 0) {
212 perror("unable to write strings");
215 for (i = 0; i < 2; ++i) {
216 sprintf(ep_path, "%s/ep%d", argv[1], i+1);
217 ep[i] = open(ep_path, O_RDWR);
219 printf("unable to open ep%d: %s\n", i+1,
227 memset(&ctx, 0, sizeof(ctx));
228 /* setup aio context to handle up to 2 requests */
229 if (io_setup(2, &ctx) < 0) {
230 perror("unable to setup aio");
234 evfd = eventfd(0, 0);
236 perror("unable to open eventfd");
240 /* alloc buffers and requests */
241 buf_in = malloc(BUF_LEN);
242 buf_out = malloc(BUF_LEN);
243 iocb_in = malloc(sizeof(*iocb_in));
244 iocb_out = malloc(sizeof(*iocb_out));
251 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
252 &rfds, NULL, NULL, NULL);
260 if (FD_ISSET(ep0, &rfds))
261 handle_ep0(ep0, &ready);
263 /* we are waiting for function ENABLE */
267 /* if something was submitted we wait for event */
268 if (FD_ISSET(evfd, &rfds)) {
270 ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
272 perror("unable to read eventfd");
276 struct io_event e[2];
277 /* we wait for one event */
278 ret = io_getevents(ctx, 1, 2, e, NULL);
279 /* if we got event */
280 for (i = 0; i < ret; ++i) {
281 if (e[i].obj->aio_fildes == ep[0]) {
282 printf("ev=in; ret=%lu\n", e[i].res);
284 } else if (e[i].obj->aio_fildes == ep[1]) {
285 printf("ev=out; ret=%lu\n", e[i].res);
291 if (!req_in) { /* if IN transfer not requested*/
292 /* prepare write request */
293 io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
294 /* enable eventfd notification */
295 iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
296 iocb_in->u.c.resfd = evfd;
297 /* submit table of requests */
298 ret = io_submit(ctx, 1, &iocb_in);
299 if (ret >= 0) { /* if ret > 0 request is queued */
301 printf("submit: in\n");
303 perror("unable to submit request");
305 if (!req_out) { /* if OUT transfer not requested */
306 /* prepare read request */
307 io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
308 /* enable eventfs notification */
309 iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
310 iocb_out->u.c.resfd = evfd;
311 /* submit table of requests */
312 ret = io_submit(ctx, 1, &iocb_out);
313 if (ret >= 0) { /* if ret > 0 request is queued */
315 printf("submit: out\n");
317 perror("unable to submit request");
330 for (i = 0; i < 2; ++i)