2 * This is free and unencumbered software released into the public domain.
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
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.
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.
25 * For more information, please refer to <http://unlicense.org/>
28 #define _BSD_SOURCE /* for endian.h */
37 #include <sys/ioctl.h>
39 #include <sys/types.h>
43 #include <sys/eventfd.h>
46 #define IOCB_FLAG_RESFD (1 << 0)
48 #include <linux/usb/functionfs.h>
52 #define AIO_MAX (BUFS_MAX*2)
54 /******************** Descriptors and Strings *******************************/
57 struct usb_functionfs_descs_head_v2 header
;
61 struct usb_interface_descriptor intf
;
62 struct usb_endpoint_descriptor_no_audio bulk_sink
;
63 struct usb_endpoint_descriptor_no_audio bulk_source
;
64 } __attribute__ ((__packed__
)) fs_descs
, hs_descs
;
65 } __attribute__ ((__packed__
)) descriptors
= {
67 .magic
= htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2
),
68 .flags
= htole32(FUNCTIONFS_HAS_FS_DESC
|
69 FUNCTIONFS_HAS_HS_DESC
),
70 .length
= htole32(sizeof(descriptors
)),
72 .fs_count
= htole32(3),
75 .bLength
= sizeof(descriptors
.fs_descs
.intf
),
76 .bDescriptorType
= USB_DT_INTERFACE
,
78 .bInterfaceClass
= USB_CLASS_VENDOR_SPEC
,
82 .bLength
= sizeof(descriptors
.fs_descs
.bulk_sink
),
83 .bDescriptorType
= USB_DT_ENDPOINT
,
84 .bEndpointAddress
= 1 | USB_DIR_IN
,
85 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
88 .bLength
= sizeof(descriptors
.fs_descs
.bulk_source
),
89 .bDescriptorType
= USB_DT_ENDPOINT
,
90 .bEndpointAddress
= 2 | USB_DIR_OUT
,
91 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
94 .hs_count
= htole32(3),
97 .bLength
= sizeof(descriptors
.hs_descs
.intf
),
98 .bDescriptorType
= USB_DT_INTERFACE
,
100 .bInterfaceClass
= USB_CLASS_VENDOR_SPEC
,
104 .bLength
= sizeof(descriptors
.hs_descs
.bulk_sink
),
105 .bDescriptorType
= USB_DT_ENDPOINT
,
106 .bEndpointAddress
= 1 | USB_DIR_IN
,
107 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
108 .wMaxPacketSize
= htole16(512),
111 .bLength
= sizeof(descriptors
.hs_descs
.bulk_source
),
112 .bDescriptorType
= USB_DT_ENDPOINT
,
113 .bEndpointAddress
= 2 | USB_DIR_OUT
,
114 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
115 .wMaxPacketSize
= htole16(512),
120 #define STR_INTERFACE "AIO Test"
122 static const struct {
123 struct usb_functionfs_strings_head header
;
126 const char str1
[sizeof(STR_INTERFACE
)];
127 } __attribute__ ((__packed__
)) lang0
;
128 } __attribute__ ((__packed__
)) strings
= {
130 .magic
= htole32(FUNCTIONFS_STRINGS_MAGIC
),
131 .length
= htole32(sizeof(strings
)),
132 .str_count
= htole32(1),
133 .lang_count
= htole32(1),
136 htole16(0x0409), /* en-us */
141 /********************** Buffer structure *******************************/
151 /******************** Endpoints handling *******************************/
153 static void display_event(struct usb_functionfs_event
*event
)
155 static const char *const names
[] = {
156 [FUNCTIONFS_BIND
] = "BIND",
157 [FUNCTIONFS_UNBIND
] = "UNBIND",
158 [FUNCTIONFS_ENABLE
] = "ENABLE",
159 [FUNCTIONFS_DISABLE
] = "DISABLE",
160 [FUNCTIONFS_SETUP
] = "SETUP",
161 [FUNCTIONFS_SUSPEND
] = "SUSPEND",
162 [FUNCTIONFS_RESUME
] = "RESUME",
164 switch (event
->type
) {
165 case FUNCTIONFS_BIND
:
166 case FUNCTIONFS_UNBIND
:
167 case FUNCTIONFS_ENABLE
:
168 case FUNCTIONFS_DISABLE
:
169 case FUNCTIONFS_SETUP
:
170 case FUNCTIONFS_SUSPEND
:
171 case FUNCTIONFS_RESUME
:
172 printf("Event %s\n", names
[event
->type
]);
176 static void handle_ep0(int ep0
, bool *ready
)
179 struct usb_functionfs_event event
;
181 ret
= read(ep0
, &event
, sizeof(event
));
183 perror("unable to read event from ep0");
186 display_event(&event
);
187 switch (event
.type
) {
188 case FUNCTIONFS_SETUP
:
189 if (event
.u
.setup
.bRequestType
& USB_DIR_IN
)
195 case FUNCTIONFS_ENABLE
:
199 case FUNCTIONFS_DISABLE
:
208 void init_bufs(struct io_buffer
*iobuf
, unsigned n
, unsigned len
)
211 iobuf
->buf
= malloc(n
*sizeof(*iobuf
->buf
));
212 iobuf
->iocb
= malloc(n
*sizeof(*iobuf
->iocb
));
215 iobuf
->requested
= 0;
216 for (i
= 0; i
< n
; ++i
) {
217 iobuf
->buf
[i
] = malloc(len
*sizeof(**iobuf
->buf
));
218 iobuf
->iocb
[i
] = malloc(sizeof(**iobuf
->iocb
));
223 void delete_bufs(struct io_buffer
*iobuf
)
226 for (i
= 0; i
< iobuf
->cnt
; ++i
) {
228 free(iobuf
->iocb
[i
]);
234 int main(int argc
, char *argv
[])
247 struct io_buffer iobuf
[2];
252 printf("ffs directory not specified!\n");
256 ep_path
= malloc(strlen(argv
[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
262 /* open endpoint files */
263 sprintf(ep_path
, "%s/ep0", argv
[1]);
264 ep0
= open(ep_path
, O_RDWR
);
266 perror("unable to open ep0");
269 if (write(ep0
, &descriptors
, sizeof(descriptors
)) < 0) {
270 perror("unable do write descriptors");
273 if (write(ep0
, &strings
, sizeof(strings
)) < 0) {
274 perror("unable to write strings");
277 sprintf(ep_path
, "%s/ep1", argv
[1]);
278 ep1
= open(ep_path
, O_RDWR
);
280 perror("unable to open ep1");
286 memset(&ctx
, 0, sizeof(ctx
));
287 /* setup aio context to handle up to AIO_MAX requests */
288 if (io_setup(AIO_MAX
, &ctx
) < 0) {
289 perror("unable to setup aio");
293 evfd
= eventfd(0, 0);
295 perror("unable to open eventfd");
299 for (i
= 0; i
< sizeof(iobuf
)/sizeof(*iobuf
); ++i
)
300 init_bufs(&iobuf
[i
], BUFS_MAX
, BUF_LEN
);
307 ret
= select(((ep0
> evfd
) ? ep0
: evfd
)+1,
308 &rfds
, NULL
, NULL
, NULL
);
316 if (FD_ISSET(ep0
, &rfds
))
317 handle_ep0(ep0
, &ready
);
319 /* we are waiting for function ENABLE */
324 * when we're preparing new data to submit,
325 * second buffer being transmitted
327 for (i
= 0; i
< sizeof(iobuf
)/sizeof(*iobuf
); ++i
) {
328 if (iobuf
[i
].requested
)
330 /* prepare requests */
331 for (j
= 0; j
< iobuf
[i
].cnt
; ++j
) {
332 io_prep_pwrite(iobuf
[i
].iocb
[j
], ep1
,
335 /* enable eventfd notification */
336 iobuf
[i
].iocb
[j
]->u
.c
.flags
|= IOCB_FLAG_RESFD
;
337 iobuf
[i
].iocb
[j
]->u
.c
.resfd
= evfd
;
339 /* submit table of requests */
340 ret
= io_submit(ctx
, iobuf
[i
].cnt
, iobuf
[i
].iocb
);
342 iobuf
[i
].requested
= ret
;
343 printf("submit: %d requests buf: %d\n", ret
, i
);
345 perror("unable to submit requests");
348 /* if event is ready to read */
349 if (!FD_ISSET(evfd
, &rfds
))
353 ret
= read(evfd
, &ev_cnt
, sizeof(ev_cnt
));
355 perror("unable to read eventfd");
359 struct io_event e
[BUFS_MAX
];
360 /* we read aio events */
361 ret
= io_getevents(ctx
, 1, BUFS_MAX
, e
, NULL
);
362 if (ret
> 0) /* if we got events */
363 iobuf
[actual
].requested
-= ret
;
365 /* if all req's from iocb completed */
366 if (!iobuf
[actual
].requested
)
367 actual
= (actual
+ 1)%(sizeof(iobuf
)/sizeof(*iobuf
));
372 for (i
= 0; i
< sizeof(iobuf
)/sizeof(*iobuf
); ++i
)
373 delete_bufs(&iobuf
[i
]);