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 #define BUFS_MAX 128 25 #define AIO_MAX (BUFS_MAX*2) 26 27 /******************** Descriptors and Strings *******************************/ 28 29 static const struct { 30 struct usb_functionfs_descs_head header; 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), 39 .length = htole32(sizeof(descriptors)), 40 .fs_count = 3, 41 .hs_count = 3, 42 }, 43 .fs_descs = { 44 .intf = { 45 .bLength = sizeof(descriptors.fs_descs.intf), 46 .bDescriptorType = USB_DT_INTERFACE, 47 .bNumEndpoints = 2, 48 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 49 .iInterface = 1, 50 }, 51 .bulk_sink = { 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, 56 }, 57 .bulk_source = { 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, 62 }, 63 }, 64 .hs_descs = { 65 .intf = { 66 .bLength = sizeof(descriptors.hs_descs.intf), 67 .bDescriptorType = USB_DT_INTERFACE, 68 .bNumEndpoints = 2, 69 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 70 .iInterface = 1, 71 }, 72 .bulk_sink = { 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), 78 }, 79 .bulk_source = { 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), 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 /********************** Buffer structure *******************************/ 111 112 struct io_buffer { 113 struct iocb **iocb; 114 unsigned char **buf; 115 unsigned cnt; 116 unsigned len; 117 unsigned requested; 118 }; 119 120 /******************** Endpoints handling *******************************/ 121 122 static void display_event(struct usb_functionfs_event *event) 123 { 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", 132 }; 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]); 142 } 143 } 144 145 static void handle_ep0(int ep0, bool *ready) 146 { 147 int ret; 148 struct usb_functionfs_event event; 149 150 ret = read(ep0, &event, sizeof(event)); 151 if (!ret) { 152 perror("unable to read event from ep0"); 153 return; 154 } 155 display_event(&event); 156 switch (event.type) { 157 case FUNCTIONFS_SETUP: 158 if (event.u.setup.bRequestType & USB_DIR_IN) 159 write(ep0, NULL, 0); 160 else 161 read(ep0, NULL, 0); 162 break; 163 164 case FUNCTIONFS_ENABLE: 165 *ready = true; 166 break; 167 168 case FUNCTIONFS_DISABLE: 169 *ready = false; 170 break; 171 172 default: 173 break; 174 } 175 } 176 177 void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len) 178 { 179 unsigned i; 180 iobuf->buf = malloc(n*sizeof(*iobuf->buf)); 181 iobuf->iocb = malloc(n*sizeof(*iobuf->iocb)); 182 iobuf->cnt = n; 183 iobuf->len = len; 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)); 188 } 189 iobuf->cnt = n; 190 } 191 192 void delete_bufs(struct io_buffer *iobuf) 193 { 194 unsigned i; 195 for (i = 0; i < iobuf->cnt; ++i) { 196 free(iobuf->buf[i]); 197 free(iobuf->iocb[i]); 198 } 199 free(iobuf->buf); 200 free(iobuf->iocb); 201 } 202 203 int main(int argc, char *argv[]) 204 { 205 int ret; 206 unsigned i, j; 207 char *ep_path; 208 209 int ep0, ep1; 210 211 io_context_t ctx; 212 213 int evfd; 214 fd_set rfds; 215 216 struct io_buffer iobuf[2]; 217 int actual = 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 sprintf(ep_path, "%s/ep1", argv[1]); 247 ep1 = open(ep_path, O_RDWR); 248 if (ep1 < 0) { 249 perror("unable to open ep1"); 250 return 1; 251 } 252 253 free(ep_path); 254 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"); 259 return 1; 260 } 261 262 evfd = eventfd(0, 0); 263 if (evfd < 0) { 264 perror("unable to open eventfd"); 265 return 1; 266 } 267 268 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) 269 init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN); 270 271 while (1) { 272 FD_ZERO(&rfds); 273 FD_SET(ep0, &rfds); 274 FD_SET(evfd, &rfds); 275 276 ret = select(((ep0 > evfd) ? ep0 : evfd)+1, 277 &rfds, NULL, NULL, NULL); 278 if (ret < 0) { 279 if (errno == EINTR) 280 continue; 281 perror("select"); 282 break; 283 } 284 285 if (FD_ISSET(ep0, &rfds)) 286 handle_ep0(ep0, &ready); 287 288 /* we are waiting for function ENABLE */ 289 if (!ready) 290 continue; 291 292 /* 293 * when we're preparing new data to submit, 294 * second buffer being transmitted 295 */ 296 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) { 297 if (iobuf[i].requested) 298 continue; 299 /* prepare requests */ 300 for (j = 0; j < iobuf[i].cnt; ++j) { 301 io_prep_pwrite(iobuf[i].iocb[j], ep1, 302 iobuf[i].buf[j], 303 iobuf[i].len, 0); 304 /* enable eventfd notification */ 305 iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD; 306 iobuf[i].iocb[j]->u.c.resfd = evfd; 307 } 308 /* submit table of requests */ 309 ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb); 310 if (ret >= 0) { 311 iobuf[i].requested = ret; 312 printf("submit: %d requests buf: %d\n", ret, i); 313 } else 314 perror("unable to submit reqests"); 315 } 316 317 /* if event is ready to read */ 318 if (!FD_ISSET(evfd, &rfds)) 319 continue; 320 321 uint64_t ev_cnt; 322 ret = read(evfd, &ev_cnt, sizeof(ev_cnt)); 323 if (ret < 0) { 324 perror("unable to read eventfd"); 325 break; 326 } 327 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; 333 334 /* if all req's from iocb completed */ 335 if (!iobuf[actual].requested) 336 actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf)); 337 } 338 339 /* free resources */ 340 341 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) 342 delete_bufs(&iobuf[i]); 343 io_destroy(ctx); 344 345 close(ep1); 346 close(ep0); 347 348 return 0; 349 } 350