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 header
;
32 struct usb_interface_descriptor intf
;
33 struct usb_endpoint_descriptor_no_audio bulk_sink
;
34 struct usb_endpoint_descriptor_no_audio bulk_source
;
35 } __attribute__ ((__packed__
)) fs_descs
, hs_descs
;
36 } __attribute__ ((__packed__
)) descriptors
= {
38 .magic
= htole32(FUNCTIONFS_DESCRIPTORS_MAGIC
),
39 .length
= htole32(sizeof(descriptors
)),
45 .bLength
= sizeof(descriptors
.fs_descs
.intf
),
46 .bDescriptorType
= USB_DT_INTERFACE
,
48 .bInterfaceClass
= USB_CLASS_VENDOR_SPEC
,
52 .bLength
= sizeof(descriptors
.fs_descs
.bulk_sink
),
53 .bDescriptorType
= USB_DT_ENDPOINT
,
54 .bEndpointAddress
= 1 | USB_DIR_IN
,
55 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
58 .bLength
= sizeof(descriptors
.fs_descs
.bulk_source
),
59 .bDescriptorType
= USB_DT_ENDPOINT
,
60 .bEndpointAddress
= 2 | USB_DIR_OUT
,
61 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
66 .bLength
= sizeof(descriptors
.hs_descs
.intf
),
67 .bDescriptorType
= USB_DT_INTERFACE
,
69 .bInterfaceClass
= USB_CLASS_VENDOR_SPEC
,
73 .bLength
= sizeof(descriptors
.hs_descs
.bulk_sink
),
74 .bDescriptorType
= USB_DT_ENDPOINT
,
75 .bEndpointAddress
= 1 | USB_DIR_IN
,
76 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
77 .wMaxPacketSize
= htole16(512),
80 .bLength
= sizeof(descriptors
.hs_descs
.bulk_source
),
81 .bDescriptorType
= USB_DT_ENDPOINT
,
82 .bEndpointAddress
= 2 | USB_DIR_OUT
,
83 .bmAttributes
= USB_ENDPOINT_XFER_BULK
,
84 .wMaxPacketSize
= htole16(512),
89 #define STR_INTERFACE "AIO Test"
92 struct usb_functionfs_strings_head header
;
95 const char str1
[sizeof(STR_INTERFACE
)];
96 } __attribute__ ((__packed__
)) lang0
;
97 } __attribute__ ((__packed__
)) strings
= {
99 .magic
= htole32(FUNCTIONFS_STRINGS_MAGIC
),
100 .length
= htole32(sizeof(strings
)),
101 .str_count
= htole32(1),
102 .lang_count
= htole32(1),
105 htole16(0x0409), /* en-us */
110 /********************** Buffer structure *******************************/
120 /******************** Endpoints handling *******************************/
122 static void display_event(struct usb_functionfs_event
*event
)
124 static const char *const names
[] = {
125 [FUNCTIONFS_BIND
] = "BIND",
126 [FUNCTIONFS_UNBIND
] = "UNBIND",
127 [FUNCTIONFS_ENABLE
] = "ENABLE",
128 [FUNCTIONFS_DISABLE
] = "DISABLE",
129 [FUNCTIONFS_SETUP
] = "SETUP",
130 [FUNCTIONFS_SUSPEND
] = "SUSPEND",
131 [FUNCTIONFS_RESUME
] = "RESUME",
133 switch (event
->type
) {
134 case FUNCTIONFS_BIND
:
135 case FUNCTIONFS_UNBIND
:
136 case FUNCTIONFS_ENABLE
:
137 case FUNCTIONFS_DISABLE
:
138 case FUNCTIONFS_SETUP
:
139 case FUNCTIONFS_SUSPEND
:
140 case FUNCTIONFS_RESUME
:
141 printf("Event %s\n", names
[event
->type
]);
145 static void handle_ep0(int ep0
, bool *ready
)
148 struct usb_functionfs_event event
;
150 ret
= read(ep0
, &event
, sizeof(event
));
152 perror("unable to read event from ep0");
155 display_event(&event
);
156 switch (event
.type
) {
157 case FUNCTIONFS_SETUP
:
158 if (event
.u
.setup
.bRequestType
& USB_DIR_IN
)
164 case FUNCTIONFS_ENABLE
:
168 case FUNCTIONFS_DISABLE
:
177 void init_bufs(struct io_buffer
*iobuf
, unsigned n
, unsigned len
)
180 iobuf
->buf
= malloc(n
*sizeof(*iobuf
->buf
));
181 iobuf
->iocb
= malloc(n
*sizeof(*iobuf
->iocb
));
184 iobuf
->requested
= 0;
185 for (i
= 0; i
< n
; ++i
) {
186 iobuf
->buf
[i
] = malloc(len
*sizeof(**iobuf
->buf
));
187 iobuf
->iocb
[i
] = malloc(sizeof(**iobuf
->iocb
));
192 void delete_bufs(struct io_buffer
*iobuf
)
195 for (i
= 0; i
< iobuf
->cnt
; ++i
) {
197 free(iobuf
->iocb
[i
]);
203 int main(int argc
, char *argv
[])
216 struct io_buffer iobuf
[2];
221 printf("ffs directory not specified!\n");
225 ep_path
= malloc(strlen(argv
[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
231 /* open endpoint files */
232 sprintf(ep_path
, "%s/ep0", argv
[1]);
233 ep0
= open(ep_path
, O_RDWR
);
235 perror("unable to open ep0");
238 if (write(ep0
, &descriptors
, sizeof(descriptors
)) < 0) {
239 perror("unable do write descriptors");
242 if (write(ep0
, &strings
, sizeof(strings
)) < 0) {
243 perror("unable to write strings");
246 sprintf(ep_path
, "%s/ep1", argv
[1]);
247 ep1
= open(ep_path
, O_RDWR
);
249 perror("unable to open ep1");
255 memset(&ctx
, 0, sizeof(ctx
));
256 /* setup aio context to handle up to AIO_MAX requests */
257 if (io_setup(AIO_MAX
, &ctx
) < 0) {
258 perror("unable to setup aio");
262 evfd
= eventfd(0, 0);
264 perror("unable to open eventfd");
268 for (i
= 0; i
< sizeof(iobuf
)/sizeof(*iobuf
); ++i
)
269 init_bufs(&iobuf
[i
], BUFS_MAX
, BUF_LEN
);
276 ret
= select(((ep0
> evfd
) ? ep0
: evfd
)+1,
277 &rfds
, NULL
, NULL
, NULL
);
285 if (FD_ISSET(ep0
, &rfds
))
286 handle_ep0(ep0
, &ready
);
288 /* we are waiting for function ENABLE */
293 * when we're preparing new data to submit,
294 * second buffer being transmitted
296 for (i
= 0; i
< sizeof(iobuf
)/sizeof(*iobuf
); ++i
) {
297 if (iobuf
[i
].requested
)
299 /* prepare requests */
300 for (j
= 0; j
< iobuf
[i
].cnt
; ++j
) {
301 io_prep_pwrite(iobuf
[i
].iocb
[j
], ep1
,
304 /* enable eventfd notification */
305 iobuf
[i
].iocb
[j
]->u
.c
.flags
|= IOCB_FLAG_RESFD
;
306 iobuf
[i
].iocb
[j
]->u
.c
.resfd
= evfd
;
308 /* submit table of requests */
309 ret
= io_submit(ctx
, iobuf
[i
].cnt
, iobuf
[i
].iocb
);
311 iobuf
[i
].requested
= ret
;
312 printf("submit: %d requests buf: %d\n", ret
, i
);
314 perror("unable to submit reqests");
317 /* if event is ready to read */
318 if (!FD_ISSET(evfd
, &rfds
))
322 ret
= read(evfd
, &ev_cnt
, sizeof(ev_cnt
));
324 perror("unable to read eventfd");
328 struct io_event e
[BUFS_MAX
];
329 /* we read aio events */
330 ret
= io_getevents(ctx
, 1, BUFS_MAX
, e
, NULL
);
331 if (ret
> 0) /* if we got events */
332 iobuf
[actual
].requested
-= ret
;
334 /* if all req's from iocb completed */
335 if (!iobuf
[actual
].requested
)
336 actual
= (actual
+ 1)%(sizeof(iobuf
)/sizeof(*iobuf
));
341 for (i
= 0; i
< sizeof(iobuf
)/sizeof(*iobuf
); ++i
)
342 delete_bufs(&iobuf
[i
]);