1 /* 2 * ffs-test.c.c -- user mode filesystem api for usb composite function 3 * 4 * Copyright (C) 2010 Samsung Electronics 5 * Author: Michal Nazarewicz <m.nazarewicz@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 /* $(CROSS_COMPILE)cc -Wall -Wextra -g -o ffs-test ffs-test.c -lpthread */ 23 24 25 #define _BSD_SOURCE /* for endian.h */ 26 27 #include <endian.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <pthread.h> 31 #include <stdarg.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <sys/ioctl.h> 36 #include <sys/stat.h> 37 #include <sys/types.h> 38 #include <unistd.h> 39 40 #include <linux/usb/functionfs.h> 41 42 43 /******************** Little Endian Handling ********************************/ 44 45 #define cpu_to_le16(x) htole16(x) 46 #define cpu_to_le32(x) htole32(x) 47 #define le32_to_cpu(x) le32toh(x) 48 #define le16_to_cpu(x) le16toh(x) 49 50 static inline __u16 get_unaligned_le16(const void *_ptr) 51 { 52 const __u8 *ptr = _ptr; 53 return ptr[0] | (ptr[1] << 8); 54 } 55 56 static inline __u32 get_unaligned_le32(const void *_ptr) 57 { 58 const __u8 *ptr = _ptr; 59 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); 60 } 61 62 static inline void put_unaligned_le16(__u16 val, void *_ptr) 63 { 64 __u8 *ptr = _ptr; 65 *ptr++ = val; 66 *ptr++ = val >> 8; 67 } 68 69 static inline void put_unaligned_le32(__u32 val, void *_ptr) 70 { 71 __u8 *ptr = _ptr; 72 *ptr++ = val; 73 *ptr++ = val >> 8; 74 *ptr++ = val >> 16; 75 *ptr++ = val >> 24; 76 } 77 78 79 /******************** Messages and Errors ***********************************/ 80 81 static const char argv0[] = "ffs-test"; 82 83 static unsigned verbosity = 7; 84 85 static void _msg(unsigned level, const char *fmt, ...) 86 { 87 if (level < 2) 88 level = 2; 89 else if (level > 7) 90 level = 7; 91 92 if (level <= verbosity) { 93 static const char levels[8][6] = { 94 [2] = "crit:", 95 [3] = "err: ", 96 [4] = "warn:", 97 [5] = "note:", 98 [6] = "info:", 99 [7] = "dbg: " 100 }; 101 102 int _errno = errno; 103 va_list ap; 104 105 fprintf(stderr, "%s: %s ", argv0, levels[level]); 106 va_start(ap, fmt); 107 vfprintf(stderr, fmt, ap); 108 va_end(ap); 109 110 if (fmt[strlen(fmt) - 1] != '\n') { 111 char buffer[128]; 112 strerror_r(_errno, buffer, sizeof buffer); 113 fprintf(stderr, ": (-%d) %s\n", _errno, buffer); 114 } 115 116 fflush(stderr); 117 } 118 } 119 120 #define die(...) (_msg(2, __VA_ARGS__), exit(1)) 121 #define err(...) _msg(3, __VA_ARGS__) 122 #define warn(...) _msg(4, __VA_ARGS__) 123 #define note(...) _msg(5, __VA_ARGS__) 124 #define info(...) _msg(6, __VA_ARGS__) 125 #define debug(...) _msg(7, __VA_ARGS__) 126 127 #define die_on(cond, ...) do { \ 128 if (cond) \ 129 die(__VA_ARGS__); \ 130 } while (0) 131 132 133 /******************** Descriptors and Strings *******************************/ 134 135 static const struct { 136 struct usb_functionfs_descs_head header; 137 struct { 138 struct usb_interface_descriptor intf; 139 struct usb_endpoint_descriptor_no_audio sink; 140 struct usb_endpoint_descriptor_no_audio source; 141 } __attribute__((packed)) fs_descs, hs_descs; 142 } __attribute__((packed)) descriptors = { 143 .header = { 144 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), 145 .length = cpu_to_le32(sizeof descriptors), 146 .fs_count = 3, 147 .hs_count = 3, 148 }, 149 .fs_descs = { 150 .intf = { 151 .bLength = sizeof descriptors.fs_descs.intf, 152 .bDescriptorType = USB_DT_INTERFACE, 153 .bNumEndpoints = 2, 154 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 155 .iInterface = 1, 156 }, 157 .sink = { 158 .bLength = sizeof descriptors.fs_descs.sink, 159 .bDescriptorType = USB_DT_ENDPOINT, 160 .bEndpointAddress = 1 | USB_DIR_IN, 161 .bmAttributes = USB_ENDPOINT_XFER_BULK, 162 /* .wMaxPacketSize = autoconfiguration (kernel) */ 163 }, 164 .source = { 165 .bLength = sizeof descriptors.fs_descs.source, 166 .bDescriptorType = USB_DT_ENDPOINT, 167 .bEndpointAddress = 2 | USB_DIR_OUT, 168 .bmAttributes = USB_ENDPOINT_XFER_BULK, 169 /* .wMaxPacketSize = autoconfiguration (kernel) */ 170 }, 171 }, 172 .hs_descs = { 173 .intf = { 174 .bLength = sizeof descriptors.fs_descs.intf, 175 .bDescriptorType = USB_DT_INTERFACE, 176 .bNumEndpoints = 2, 177 .bInterfaceClass = USB_CLASS_VENDOR_SPEC, 178 .iInterface = 1, 179 }, 180 .sink = { 181 .bLength = sizeof descriptors.hs_descs.sink, 182 .bDescriptorType = USB_DT_ENDPOINT, 183 .bEndpointAddress = 1 | USB_DIR_IN, 184 .bmAttributes = USB_ENDPOINT_XFER_BULK, 185 .wMaxPacketSize = cpu_to_le16(512), 186 }, 187 .source = { 188 .bLength = sizeof descriptors.hs_descs.source, 189 .bDescriptorType = USB_DT_ENDPOINT, 190 .bEndpointAddress = 2 | USB_DIR_OUT, 191 .bmAttributes = USB_ENDPOINT_XFER_BULK, 192 .wMaxPacketSize = cpu_to_le16(512), 193 .bInterval = 1, /* NAK every 1 uframe */ 194 }, 195 }, 196 }; 197 198 199 #define STR_INTERFACE_ "Source/Sink" 200 201 static const struct { 202 struct usb_functionfs_strings_head header; 203 struct { 204 __le16 code; 205 const char str1[sizeof STR_INTERFACE_]; 206 } __attribute__((packed)) lang0; 207 } __attribute__((packed)) strings = { 208 .header = { 209 .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC), 210 .length = cpu_to_le32(sizeof strings), 211 .str_count = cpu_to_le32(1), 212 .lang_count = cpu_to_le32(1), 213 }, 214 .lang0 = { 215 cpu_to_le16(0x0409), /* en-us */ 216 STR_INTERFACE_, 217 }, 218 }; 219 220 #define STR_INTERFACE strings.lang0.str1 221 222 223 /******************** Files and Threads Handling ****************************/ 224 225 struct thread; 226 227 static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes); 228 static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes); 229 static ssize_t ep0_consume(struct thread *t, const void *buf, size_t nbytes); 230 static ssize_t fill_in_buf(struct thread *t, void *buf, size_t nbytes); 231 static ssize_t empty_out_buf(struct thread *t, const void *buf, size_t nbytes); 232 233 234 static struct thread { 235 const char *const filename; 236 size_t buf_size; 237 238 ssize_t (*in)(struct thread *, void *, size_t); 239 const char *const in_name; 240 241 ssize_t (*out)(struct thread *, const void *, size_t); 242 const char *const out_name; 243 244 int fd; 245 pthread_t id; 246 void *buf; 247 ssize_t status; 248 } threads[] = { 249 { 250 "ep0", 4 * sizeof(struct usb_functionfs_event), 251 read_wrap, NULL, 252 ep0_consume, "<consume>", 253 0, 0, NULL, 0 254 }, 255 { 256 "ep1", 8 * 1024, 257 fill_in_buf, "<in>", 258 write_wrap, NULL, 259 0, 0, NULL, 0 260 }, 261 { 262 "ep2", 8 * 1024, 263 read_wrap, NULL, 264 empty_out_buf, "<out>", 265 0, 0, NULL, 0 266 }, 267 }; 268 269 270 static void init_thread(struct thread *t) 271 { 272 t->buf = malloc(t->buf_size); 273 die_on(!t->buf, "malloc"); 274 275 t->fd = open(t->filename, O_RDWR); 276 die_on(t->fd < 0, "%s", t->filename); 277 } 278 279 static void cleanup_thread(void *arg) 280 { 281 struct thread *t = arg; 282 int ret, fd; 283 284 fd = t->fd; 285 if (t->fd < 0) 286 return; 287 t->fd = -1; 288 289 /* test the FIFO ioctls (non-ep0 code paths) */ 290 if (t != threads) { 291 ret = ioctl(fd, FUNCTIONFS_FIFO_STATUS); 292 if (ret < 0) { 293 /* ENODEV reported after disconnect */ 294 if (errno != ENODEV) 295 err("%s: get fifo status", t->filename); 296 } else if (ret) { 297 warn("%s: unclaimed = %d\n", t->filename, ret); 298 if (ioctl(fd, FUNCTIONFS_FIFO_FLUSH) < 0) 299 err("%s: fifo flush", t->filename); 300 } 301 } 302 303 if (close(fd) < 0) 304 err("%s: close", t->filename); 305 306 free(t->buf); 307 t->buf = NULL; 308 } 309 310 static void *start_thread_helper(void *arg) 311 { 312 const char *name, *op, *in_name, *out_name; 313 struct thread *t = arg; 314 ssize_t ret; 315 316 info("%s: starts\n", t->filename); 317 in_name = t->in_name ? t->in_name : t->filename; 318 out_name = t->out_name ? t->out_name : t->filename; 319 320 pthread_cleanup_push(cleanup_thread, arg); 321 322 for (;;) { 323 pthread_testcancel(); 324 325 ret = t->in(t, t->buf, t->buf_size); 326 if (ret > 0) { 327 ret = t->out(t, t->buf, t->buf_size); 328 name = out_name; 329 op = "write"; 330 } else { 331 name = in_name; 332 op = "read"; 333 } 334 335 if (ret > 0) { 336 /* nop */ 337 } else if (!ret) { 338 debug("%s: %s: EOF", name, op); 339 break; 340 } else if (errno == EINTR || errno == EAGAIN) { 341 debug("%s: %s", name, op); 342 } else { 343 warn("%s: %s", name, op); 344 break; 345 } 346 } 347 348 pthread_cleanup_pop(1); 349 350 t->status = ret; 351 info("%s: ends\n", t->filename); 352 return NULL; 353 } 354 355 static void start_thread(struct thread *t) 356 { 357 debug("%s: starting\n", t->filename); 358 359 die_on(pthread_create(&t->id, NULL, start_thread_helper, t) < 0, 360 "pthread_create(%s)", t->filename); 361 } 362 363 static void join_thread(struct thread *t) 364 { 365 int ret = pthread_join(t->id, NULL); 366 367 if (ret < 0) 368 err("%s: joining thread", t->filename); 369 else 370 debug("%s: joined\n", t->filename); 371 } 372 373 374 static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes) 375 { 376 return read(t->fd, buf, nbytes); 377 } 378 379 static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes) 380 { 381 return write(t->fd, buf, nbytes); 382 } 383 384 385 /******************** Empty/Fill buffer routines ****************************/ 386 387 /* 0 -- stream of zeros, 1 -- i % 63, 2 -- pipe */ 388 enum pattern { PAT_ZERO, PAT_SEQ, PAT_PIPE }; 389 static enum pattern pattern; 390 391 static ssize_t 392 fill_in_buf(struct thread *ignore, void *buf, size_t nbytes) 393 { 394 size_t i; 395 __u8 *p; 396 397 (void)ignore; 398 399 switch (pattern) { 400 case PAT_ZERO: 401 memset(buf, 0, nbytes); 402 break; 403 404 case PAT_SEQ: 405 for (p = buf, i = 0; i < nbytes; ++i, ++p) 406 *p = i % 63; 407 break; 408 409 case PAT_PIPE: 410 return fread(buf, 1, nbytes, stdin); 411 } 412 413 return nbytes; 414 } 415 416 static ssize_t 417 empty_out_buf(struct thread *ignore, const void *buf, size_t nbytes) 418 { 419 const __u8 *p; 420 __u8 expected; 421 ssize_t ret; 422 size_t len; 423 424 (void)ignore; 425 426 switch (pattern) { 427 case PAT_ZERO: 428 expected = 0; 429 for (p = buf, len = 0; len < nbytes; ++p, ++len) 430 if (*p) 431 goto invalid; 432 break; 433 434 case PAT_SEQ: 435 for (p = buf, len = 0; len < nbytes; ++p, ++len) 436 if (*p != len % 63) { 437 expected = len % 63; 438 goto invalid; 439 } 440 break; 441 442 case PAT_PIPE: 443 ret = fwrite(buf, nbytes, 1, stdout); 444 if (ret > 0) 445 fflush(stdout); 446 break; 447 448 invalid: 449 err("bad OUT byte %zd, expected %02x got %02x\n", 450 len, expected, *p); 451 for (p = buf, len = 0; len < nbytes; ++p, ++len) { 452 if (0 == (len % 32)) 453 fprintf(stderr, "%4d:", len); 454 fprintf(stderr, " %02x", *p); 455 if (31 == (len % 32)) 456 fprintf(stderr, "\n"); 457 } 458 fflush(stderr); 459 errno = EILSEQ; 460 return -1; 461 } 462 463 return len; 464 } 465 466 467 /******************** Endpoints routines ************************************/ 468 469 static void handle_setup(const struct usb_ctrlrequest *setup) 470 { 471 printf("bRequestType = %d\n", setup->bRequestType); 472 printf("bRequest = %d\n", setup->bRequest); 473 printf("wValue = %d\n", le16_to_cpu(setup->wValue)); 474 printf("wIndex = %d\n", le16_to_cpu(setup->wIndex)); 475 printf("wLength = %d\n", le16_to_cpu(setup->wLength)); 476 } 477 478 static ssize_t 479 ep0_consume(struct thread *ignore, const void *buf, size_t nbytes) 480 { 481 static const char *const names[] = { 482 [FUNCTIONFS_BIND] = "BIND", 483 [FUNCTIONFS_UNBIND] = "UNBIND", 484 [FUNCTIONFS_ENABLE] = "ENABLE", 485 [FUNCTIONFS_DISABLE] = "DISABLE", 486 [FUNCTIONFS_SETUP] = "SETUP", 487 [FUNCTIONFS_SUSPEND] = "SUSPEND", 488 [FUNCTIONFS_RESUME] = "RESUME", 489 }; 490 491 const struct usb_functionfs_event *event = buf; 492 size_t n; 493 494 (void)ignore; 495 496 for (n = nbytes / sizeof *event; n; --n, ++event) 497 switch (event->type) { 498 case FUNCTIONFS_BIND: 499 case FUNCTIONFS_UNBIND: 500 case FUNCTIONFS_ENABLE: 501 case FUNCTIONFS_DISABLE: 502 case FUNCTIONFS_SETUP: 503 case FUNCTIONFS_SUSPEND: 504 case FUNCTIONFS_RESUME: 505 printf("Event %s\n", names[event->type]); 506 if (event->type == FUNCTIONFS_SETUP) 507 handle_setup(&event->u.setup); 508 break; 509 510 default: 511 printf("Event %03u (unknown)\n", event->type); 512 } 513 514 return nbytes; 515 } 516 517 static void ep0_init(struct thread *t) 518 { 519 ssize_t ret; 520 521 info("%s: writing descriptors\n", t->filename); 522 ret = write(t->fd, &descriptors, sizeof descriptors); 523 die_on(ret < 0, "%s: write: descriptors", t->filename); 524 525 info("%s: writing strings\n", t->filename); 526 ret = write(t->fd, &strings, sizeof strings); 527 die_on(ret < 0, "%s: write: strings", t->filename); 528 } 529 530 531 /******************** Main **************************************************/ 532 533 int main(void) 534 { 535 unsigned i; 536 537 /* XXX TODO: Argument parsing missing */ 538 539 init_thread(threads); 540 ep0_init(threads); 541 542 for (i = 1; i < sizeof threads / sizeof *threads; ++i) 543 init_thread(threads + i); 544 545 for (i = 1; i < sizeof threads / sizeof *threads; ++i) 546 start_thread(threads + i); 547 548 start_thread_helper(threads); 549 550 for (i = 1; i < sizeof threads / sizeof *threads; ++i) 551 join_thread(threads + i); 552 553 return 0; 554 } 555