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
)