1 /* 2 * This is free and unencumbered software released into the public domain. 3 * 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 7 * means. 8 * 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. 16 * 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. 24 * 25 * For more information, please refer to <http://unlicense.org/> 26 */ 27 28 #define _BSD_SOURCE /* for endian.h */ 29 30 #include <endian.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <stdarg.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sys/ioctl.h> 38 #include <sys/stat.h> 39 #include <sys/types.h> 40 #include <sys/poll.h> 41 #include <unistd.h> 42 #include <stdbool.h> 43 #include <sys/eventfd.h> 44 45 #include "libaio.h" 46 #define IOCB_FLAG_RESFD (1 << 0) 47 48 #include <linux/usb/functionfs.h> 49 50 #define BUF_LEN 8192 51 52 /******************** Descriptors and Strings *******************************/ 53 54 static const struct { 55 struct usb_functionfs_descs_head_v2 header; 56 __le32 fs_count; 57 __le32 hs_count; 58 struct { 59 struct usb_interface_descriptor intf; 60 struct usb_endpoint_descriptor_no_audio bulk_sink; 61 struct usb_endpoint_descriptor_no_audio bulk_source; 62 } __attribute__ ((__packed__)) fs_descs, hs_descs; 63 } __attribute__ ((__packed__)) descriptors = { 64 .header = { 65 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), 66 .flags = htole32(FUNCTIONFS_HAS_FS_DESC | 67 FUNCTIONFS_HAS_HS_DESC), 68 .length = htole32(sizeof(descriptors)), 69 }, 70 .fs_count = htole32(3), 71 .fs_descs = { 72 .intf = { 73 .bLength = sizeof(descriptors.fs_descs.intf), 74 .bDescriptorType = USB_DT_INTERFACE, 75 .bNumEndpoints = 2, 76 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 77 .iInterface = 1, 78 }, 79 .bulk_sink = { 80 .bLength = sizeof(descriptors.fs_descs.bulk_sink), 81 .bDescriptorType = USB_DT_ENDPOINT, 82 .bEndpointAddress = 1 | USB_DIR_IN, 83 .bmAttributes = USB_ENDPOINT_XFER_BULK, 84 }, 85 .bulk_source = { 86 .bLength = sizeof(descriptors.fs_descs.bulk_source), 87 .bDescriptorType = USB_DT_ENDPOINT, 88 .bEndpointAddress = 2 | USB_DIR_OUT, 89 .bmAttributes = USB_ENDPOINT_XFER_BULK, 90 }, 91 }, 92 .hs_count = htole32(3), 93 .hs_descs = { 94 .intf = { 95 .bLength = sizeof(descriptors.hs_descs.intf), 96 .bDescriptorType = USB_DT_INTERFACE, 97 .bNumEndpoints = 2, 98 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 99 .iInterface = 1, 100 }, 101 .bulk_sink = { 102 .bLength = sizeof(descriptors.hs_descs.bulk_sink), 103 .bDescriptorType = USB_DT_ENDPOINT, 104 .bEndpointAddress = 1 | USB_DIR_IN, 105 .bmAttributes = USB_ENDPOINT_XFER_BULK, 106 }, 107 .bulk_source = { 108 .bLength = sizeof(descriptors.hs_descs.bulk_source), 109 .bDescriptorType = USB_DT_ENDPOINT, 110 .bEndpointAddress = 2 | USB_DIR_OUT, 111 .bmAttributes = USB_ENDPOINT_XFER_BULK, 112 }, 113 }, 114 }; 115 116 #define STR_INTERFACE "AIO Test" 117 118 static const struct { 119 struct usb_functionfs_strings_head header; 120 struct { 121 __le16 code; 122 const char str1[sizeof(STR_INTERFACE)]; 123 } __attribute__ ((__packed__)) lang0; 124 } __attribute__ ((__packed__)) strings = { 125 .header = { 126 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC), 127 .length = htole32(sizeof(strings)), 128 .str_count = htole32(1), 129 .lang_count = htole32(1), 130 }, 131 .lang0 = { 132 htole16(0x0409), /* en-us */ 133 STR_INTERFACE, 134 }, 135 }; 136 137 /******************** Endpoints handling *******************************/ 138 139 static void display_event(struct usb_functionfs_event *event) 140 { 141 static const char *const names[] = { 142 [FUNCTIONFS_BIND] = "BIND", 143 [FUNCTIONFS_UNBIND] = "UNBIND", 144 [FUNCTIONFS_ENABLE] = "ENABLE", 145 [FUNCTIONFS_DISABLE] = "DISABLE", 146 [FUNCTIONFS_SETUP] = "SETUP", 147 [FUNCTIONFS_SUSPEND] = "SUSPEND", 148 [FUNCTIONFS_RESUME] = "RESUME", 149 }; 150 switch (event->type) { 151 case FUNCTIONFS_BIND: 152 case FUNCTIONFS_UNBIND: 153 case FUNCTIONFS_ENABLE: 154 case FUNCTIONFS_DISABLE: 155 case FUNCTIONFS_SETUP: 156 case FUNCTIONFS_SUSPEND: 157 case FUNCTIONFS_RESUME: 158 printf("Event %s\n", names[event->type]); 159 } 160 } 161 162 static void handle_ep0(int ep0, bool *ready) 163 { 164 struct usb_functionfs_event event; 165 int ret; 166 167 struct pollfd pfds[1]; 168 pfds[0].fd = ep0; 169 pfds[0].events = POLLIN; 170 171 ret = poll(pfds, 1, 0); 172 173 if (ret && (pfds[0].revents & POLLIN)) { 174 ret = read(ep0, &event, sizeof(event)); 175 if (!ret) { 176 perror("unable to read event from ep0"); 177 return; 178 } 179 display_event(&event); 180 switch (event.type) { 181 case FUNCTIONFS_SETUP: 182 if (event.u.setup.bRequestType & USB_DIR_IN) 183 write(ep0, NULL, 0); 184 else 185 read(ep0, NULL, 0); 186 break; 187 188 case FUNCTIONFS_ENABLE: 189 *ready = true; 190 break; 191 192 case FUNCTIONFS_DISABLE: 193 *ready = false; 194 break; 195 196 default: 197 break; 198 } 199 } 200 } 201 202 int main(int argc, char *argv[]) 203 { 204 int i, ret; 205 char *ep_path; 206 207 int ep0; 208 int ep[2]; 209 210 io_context_t ctx; 211 212 int evfd; 213 fd_set rfds; 214 215 char *buf_in, *buf_out; 216 struct iocb *iocb_in, *iocb_out; 217 int req_in = 0, req_out = 0; 218 bool ready; 219 220 if (argc != 2) { 221 printf("ffs directory not specified!\n"); 222 return 1; 223 } 224 225 ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */); 226 if (!ep_path) { 227 perror("malloc"); 228 return 1; 229 } 230 231 /* open endpoint files */ 232 sprintf(ep_path, "%s/ep0", argv[1]); 233 ep0 = open(ep_path, O_RDWR); 234 if (ep0 < 0) { 235 perror("unable to open ep0"); 236 return 1; 237 } 238 if (write(ep0, &descriptors, sizeof(descriptors)) < 0) { 239 perror("unable do write descriptors"); 240 return 1; 241 } 242 if (write(ep0, &strings, sizeof(strings)) < 0) { 243 perror("unable to write strings"); 244 return 1; 245 } 246 for (i = 0; i < 2; ++i) { 247 sprintf(ep_path, "%s/ep%d", argv[1], i+1); 248 ep[i] = open(ep_path, O_RDWR); 249 if (ep[i] < 0) { 250 printf("unable to open ep%d: %s\n", i+1, 251 strerror(errno)); 252 return 1; 253 } 254 } 255 256 free(ep_path); 257 258 memset(&ctx, 0, sizeof(ctx)); 259 /* setup aio context to handle up to 2 requests */ 260 if (io_setup(2, &ctx) < 0) { 261 perror("unable to setup aio"); 262 return 1; 263 } 264 265 evfd = eventfd(0, 0); 266 if (evfd < 0) { 267 perror("unable to open eventfd"); 268 return 1; 269 } 270 271 /* alloc buffers and requests */ 272 buf_in = malloc(BUF_LEN); 273 buf_out = malloc(BUF_LEN); 274 iocb_in = malloc(sizeof(*iocb_in)); 275 iocb_out = malloc(sizeof(*iocb_out)); 276 277 while (1) { 278 FD_ZERO(&rfds); 279 FD_SET(ep0, &rfds); 280 FD_SET(evfd, &rfds); 281 282 ret = select(((ep0 > evfd) ? ep0 : evfd)+1, 283 &rfds, NULL, NULL, NULL); 284 if (ret < 0) { 285 if (errno == EINTR) 286 continue; 287 perror("select"); 288 break; 289 } 290 291 if (FD_ISSET(ep0, &rfds)) 292 handle_ep0(ep0, &ready); 293 294 /* we are waiting for function ENABLE */ 295 if (!ready) 296 continue; 297 298 /* if something was submitted we wait for event */ 299 if (FD_ISSET(evfd, &rfds)) { 300 uint64_t ev_cnt; 301 ret = read(evfd, &ev_cnt, sizeof(ev_cnt)); 302 if (ret < 0) { 303 perror("unable to read eventfd"); 304 break; 305 } 306 307 struct io_event e[2]; 308 /* we wait for one event */ 309 ret = io_getevents(ctx, 1, 2, e, NULL); 310 /* if we got event */ 311 for (i = 0; i < ret; ++i) { 312 if (e[i].obj->aio_fildes == ep[0]) { 313 printf("ev=in; ret=%lu\n", e[i].res); 314 req_in = 0; 315 } else if (e[i].obj->aio_fildes == ep[1]) { 316 printf("ev=out; ret=%lu\n", e[i].res); 317 req_out = 0; 318 } 319 } 320 } 321 322 if (!req_in) { /* if IN transfer not requested*/ 323 /* prepare write request */ 324 io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0); 325 /* enable eventfd notification */ 326 iocb_in->u.c.flags |= IOCB_FLAG_RESFD; 327 iocb_in->u.c.resfd = evfd; 328 /* submit table of requests */ 329 ret = io_submit(ctx, 1, &iocb_in); 330 if (ret >= 0) { /* if ret > 0 request is queued */ 331 req_in = 1; 332 printf("submit: in\n"); 333 } else 334 perror("unable to submit request"); 335 } 336 if (!req_out) { /* if OUT transfer not requested */ 337 /* prepare read request */ 338 io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0); 339 /* enable eventfs notification */ 340 iocb_out->u.c.flags |= IOCB_FLAG_RESFD; 341 iocb_out->u.c.resfd = evfd; 342 /* submit table of requests */ 343 ret = io_submit(ctx, 1, &iocb_out); 344 if (ret >= 0) { /* if ret > 0 request is queued */ 345 req_out = 1; 346 printf("submit: out\n"); 347 } else 348 perror("unable to submit request"); 349 } 350 } 351 352 /* free resources */ 353 354 io_destroy(ctx); 355 356 free(buf_in); 357 free(buf_out); 358 free(iocb_in); 359 free(iocb_out); 360 361 for (i = 0; i < 2; ++i) 362 close(ep[i]); 363 close(ep0); 364 365 return 0; 366 } 367