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 #define AIO_MAX (BUFS_MAX*2)
27 /******************** Descriptors and Strings *******************************/
30 struct usb_functionfs_descs_head_v2 header;
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 = {
40 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
41 .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
42 FUNCTIONFS_HAS_HS_DESC),
43 .length = htole32(sizeof(descriptors)),
45 .fs_count = htole32(3),
48 .bLength = sizeof(descriptors.fs_descs.intf),
49 .bDescriptorType = USB_DT_INTERFACE,
51 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
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,
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,
67 .hs_count = htole32(3),
70 .bLength = sizeof(descriptors.hs_descs.intf),
71 .bDescriptorType = USB_DT_INTERFACE,
73 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
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),
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),
93 #define STR_INTERFACE "AIO Test"
96 struct usb_functionfs_strings_head header;
99 const char str1[sizeof(STR_INTERFACE)];
100 } __attribute__ ((__packed__)) lang0;
101 } __attribute__ ((__packed__)) strings = {
103 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
104 .length = htole32(sizeof(strings)),
105 .str_count = htole32(1),
106 .lang_count = htole32(1),
109 htole16(0x0409), /* en-us */
114 /********************** Buffer structure *******************************/
124 /******************** Endpoints handling *******************************/
126 static void display_event(struct usb_functionfs_event *event)
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",
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]);
149 static void handle_ep0(int ep0, bool *ready)
152 struct usb_functionfs_event event;
154 ret = read(ep0, &event, sizeof(event));
156 perror("unable to read event from ep0");
159 display_event(&event);
160 switch (event.type) {
161 case FUNCTIONFS_SETUP:
162 if (event.u.setup.bRequestType & USB_DIR_IN)
168 case FUNCTIONFS_ENABLE:
172 case FUNCTIONFS_DISABLE:
181 void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
184 iobuf->buf = malloc(n*sizeof(*iobuf->buf));
185 iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
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));
196 void delete_bufs(struct io_buffer *iobuf)
199 for (i = 0; i < iobuf->cnt; ++i) {
201 free(iobuf->iocb[i]);
207 int main(int argc, char *argv[])
220 struct io_buffer iobuf[2];
225 printf("ffs directory not specified!\n");
229 ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
235 /* open endpoint files */
236 sprintf(ep_path, "%s/ep0", argv[1]);
237 ep0 = open(ep_path, O_RDWR);
239 perror("unable to open ep0");
242 if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
243 perror("unable do write descriptors");
246 if (write(ep0, &strings, sizeof(strings)) < 0) {
247 perror("unable to write strings");
250 sprintf(ep_path, "%s/ep1", argv[1]);
251 ep1 = open(ep_path, O_RDWR);
253 perror("unable to open ep1");
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");
266 evfd = eventfd(0, 0);
268 perror("unable to open eventfd");
272 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
273 init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
280 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
281 &rfds, NULL, NULL, NULL);
289 if (FD_ISSET(ep0, &rfds))
290 handle_ep0(ep0, &ready);
292 /* we are waiting for function ENABLE */
297 * when we're preparing new data to submit,
298 * second buffer being transmitted
300 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
301 if (iobuf[i].requested)
303 /* prepare requests */
304 for (j = 0; j < iobuf[i].cnt; ++j) {
305 io_prep_pwrite(iobuf[i].iocb[j], ep1,
308 /* enable eventfd notification */
309 iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
310 iobuf[i].iocb[j]->u.c.resfd = evfd;
312 /* submit table of requests */
313 ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
315 iobuf[i].requested = ret;
316 printf("submit: %d requests buf: %d\n", ret, i);
318 perror("unable to submit reqests");
321 /* if event is ready to read */
322 if (!FD_ISSET(evfd, &rfds))
326 ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
328 perror("unable to read eventfd");
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;
338 /* if all req's from iocb completed */
339 if (!iobuf[actual].requested)
340 actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
345 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
346 delete_bufs(&iobuf[i]);