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