1 /* $NetBSD: audiotest.c,v 1.7 2020/03/04 14:20:44 isaki Exp $ */ 2 3 /* 4 * Copyright (C) 2019 Tetsuya Isaki. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __RCSID("$NetBSD: audiotest.c,v 1.7 2020/03/04 14:20:44 isaki Exp $"); 30 31 #include <errno.h> 32 #include <fcntl.h> 33 #define __STDC_FORMAT_MACROS /* for PRIx64 */ 34 #include <inttypes.h> 35 #include <pthread.h> 36 #include <stdarg.h> 37 #include <stdbool.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <util.h> 43 #include <sys/audioio.h> 44 #include <sys/event.h> 45 #include <sys/ioctl.h> 46 #include <sys/mman.h> 47 #include <sys/poll.h> 48 #include <sys/sysctl.h> 49 #include <sys/time.h> 50 #include <sys/wait.h> 51 #if !defined(NO_RUMP) 52 #include <rump/rump.h> 53 #include <rump/rump_syscalls.h> 54 #endif 55 56 #if !defined(AUDIO_ENCODING_SLINEAR_NE) 57 #if BYTE_ORDER == LITTLE_ENDIAN 58 #define AUDIO_ENCODING_SLINEAR_NE AUDIO_ENCODING_SLINEAR_LE 59 #define AUDIO_ENCODING_ULINEAR_NE AUDIO_ENCODING_ULINEAR_LE 60 #define AUDIO_ENCODING_SLINEAR_OE AUDIO_ENCODING_SLINEAR_BE 61 #define AUDIO_ENCODING_ULINEAR_OE AUDIO_ENCODING_ULINEAR_BE 62 #else 63 #define AUDIO_ENCODING_SLINEAR_NE AUDIO_ENCODING_SLINEAR_BE 64 #define AUDIO_ENCODING_ULINEAR_NE AUDIO_ENCODING_ULINEAR_BE 65 #define AUDIO_ENCODING_SLINEAR_OE AUDIO_ENCODING_SLINEAR_LE 66 #define AUDIO_ENCODING_ULINEAR_OE AUDIO_ENCODING_ULINEAR_LE 67 #endif 68 #endif 69 70 struct testentry { 71 const char *name; 72 void (*func)(void); 73 }; 74 75 void usage(void) __dead; 76 void xp_err(int, int, const char *, ...) __printflike(3, 4) __dead; 77 void xp_errx(int, int, const char *, ...) __printflike(3, 4) __dead; 78 void xxx_close_wait(void); 79 int mixer_get_outputs_master(int); 80 void do_test(int); 81 int rump_or_open(const char *, int); 82 int rump_or_write(int, const void *, size_t); 83 int rump_or_read(int, void *, size_t); 84 int rump_or_ioctl(int, u_long, void *); 85 int rump_or_close(int); 86 int rump_or_fcntl(int, int, ...); 87 int rump_or_poll(struct pollfd *, nfds_t, int); 88 int rump_or_kqueue(void); 89 int rump_or_kevent(int, const struct kevent *, size_t, 90 struct kevent *, size_t, const struct timespec *); 91 int hw_canplay(void); 92 int hw_canrec(void); 93 int hw_bidir(void); 94 int hw_fulldup(void); 95 void init(int); 96 void *consumer_thread(void *); 97 void cleanup_audiofd(void); 98 void TEST(const char *, ...) __printflike(1, 2); 99 bool xp_fail(int, const char *, ...) __printflike(2, 3); 100 void xp_skip(int, const char *, ...) __printflike(2, 3); 101 bool xp_eq(int, int, int, const char *); 102 bool xp_eq_str(int, const char *, const char *, const char *); 103 bool xp_ne(int, int, int, const char *); 104 bool xp_if(int, bool, const char *); 105 bool xp_sys_eq(int, int, int, const char *); 106 bool xp_sys_ok(int, int, const char *); 107 bool xp_sys_ng(int, int, int, const char *); 108 bool xp_sys_ptr(int, int, void *, const char *); 109 int debug_open(int, const char *, int); 110 int debug_write(int, int, const void *, size_t); 111 int debug_read(int, int, void *, size_t); 112 int debug_ioctl(int, int, u_long, const char *, void *, const char *, ...) 113 __printflike(6, 7); 114 int debug_fcntl(int, int, int, const char *, ...) __printflike(4, 5); 115 int debug_close(int, int); 116 void *debug_mmap(int, void *, size_t, int, int, int, off_t); 117 int debug_munmap(int, void *, int); 118 const char *event_tostr(int); 119 int debug_poll(int, struct pollfd *, int, int); 120 int debug_kqueue(int); 121 int debug_kevent_set(int, int, const struct kevent *, size_t); 122 int debug_kevent_poll(int, int, struct kevent *, size_t, 123 const struct timespec *); 124 void debug_kev(int, const char *, const struct kevent *); 125 uid_t debug_getuid(int); 126 int debug_seteuid(int, uid_t); 127 int debug_sysctlbyname(int, const char *, void *, size_t *, const void *, 128 size_t); 129 130 int openable_mode(void); 131 int mode2aumode(int); 132 int mode2play(int); 133 int mode2rec(int); 134 void reset_after_mmap(void); 135 136 /* from audio.c */ 137 static const char *encoding_names[] __unused = { 138 "none", 139 AudioEmulaw, 140 AudioEalaw, 141 "pcm16", 142 "pcm8", 143 AudioEadpcm, 144 AudioEslinear_le, 145 AudioEslinear_be, 146 AudioEulinear_le, 147 AudioEulinear_be, 148 AudioEslinear, 149 AudioEulinear, 150 AudioEmpeg_l1_stream, 151 AudioEmpeg_l1_packets, 152 AudioEmpeg_l1_system, 153 AudioEmpeg_l2_stream, 154 AudioEmpeg_l2_packets, 155 AudioEmpeg_l2_system, 156 AudioEac3, 157 }; 158 159 int debug; 160 int props; 161 int hwfull; 162 int netbsd; 163 bool opt_atf; 164 char testname[64]; 165 int testcount; 166 int failcount; 167 int skipcount; 168 int unit; 169 bool use_rump; 170 bool use_pad; 171 int padfd; 172 int maxfd; 173 pthread_t th; 174 char devicename[16]; /* "audioN" */ 175 char devaudio[16]; /* "/dev/audioN" */ 176 char devsound[16]; /* "/dev/soundN" */ 177 char devaudioctl[16]; /* "/dev/audioctlN" */ 178 char devmixer[16]; /* "/dev/mixerN" */ 179 extern struct testentry testtable[]; 180 181 void 182 usage(void) 183 { 184 fprintf(stderr, "usage:\t%s [<options>] [<testname>...]\n", 185 getprogname()); 186 fprintf(stderr, "\t-A : make output suitable for ATF\n"); 187 fprintf(stderr, "\t-a : Test all\n"); 188 fprintf(stderr, "\t-d : Increase debug level\n"); 189 fprintf(stderr, "\t-l : List all tests\n"); 190 fprintf(stderr, "\t-p : Open pad\n"); 191 #if !defined(NO_RUMP) 192 fprintf(stderr, "\t-R : Use rump (implies -p)\n"); 193 #endif 194 fprintf(stderr, "\t-u <unit> : Use audio<unit> (default:0)\n"); 195 exit(1); 196 } 197 198 /* Customized err(3) */ 199 void 200 xp_err(int code, int line, const char *fmt, ...) 201 { 202 va_list ap; 203 int backup_errno; 204 205 backup_errno = errno; 206 printf("%s %d: ", (opt_atf ? "Line" : " ERROR:"), line); 207 va_start(ap, fmt); 208 vprintf(fmt, ap); 209 va_end(ap); 210 printf(": %s\n", strerror(backup_errno)); 211 212 exit(code); 213 } 214 215 /* Customized errx(3) */ 216 void 217 xp_errx(int code, int line, const char *fmt, ...) 218 { 219 va_list ap; 220 221 printf("%s %d: ", (opt_atf ? "Line" : " ERROR:"), line); 222 va_start(ap, fmt); 223 vprintf(fmt, ap); 224 va_end(ap); 225 printf("\n"); 226 227 exit(code); 228 } 229 230 int 231 main(int argc, char *argv[]) 232 { 233 int i; 234 int j; 235 int c; 236 enum { 237 CMD_TEST, 238 CMD_ALL, 239 CMD_LIST, 240 } cmd; 241 bool found; 242 243 props = -1; 244 hwfull = 0; 245 unit = 0; 246 cmd = CMD_TEST; 247 use_pad = false; 248 padfd = -1; 249 250 while ((c = getopt(argc, argv, "AadlpRu:")) != -1) { 251 switch (c) { 252 case 'A': 253 opt_atf = true; 254 break; 255 case 'a': 256 cmd = CMD_ALL; 257 break; 258 case 'd': 259 debug++; 260 break; 261 case 'l': 262 cmd = CMD_LIST; 263 break; 264 case 'p': 265 use_pad = true; 266 break; 267 case 'R': 268 #if !defined(NO_RUMP) 269 use_rump = true; 270 use_pad = true; 271 #else 272 usage(); 273 #endif 274 break; 275 case 'u': 276 unit = atoi(optarg); 277 break; 278 default: 279 usage(); 280 } 281 } 282 argc -= optind; 283 argv += optind; 284 285 if (cmd == CMD_LIST) { 286 /* List all */ 287 for (i = 0; testtable[i].name != NULL; i++) 288 printf("%s\n", testtable[i].name); 289 return 0; 290 } 291 292 init(unit); 293 294 if (cmd == CMD_ALL) { 295 /* Test all */ 296 if (argc > 0) 297 usage(); 298 for (i = 0; testtable[i].name != NULL; i++) 299 do_test(i); 300 } else { 301 /* Test only matched */ 302 if (argc == 0) 303 usage(); 304 305 found = false; 306 for (j = 0; j < argc; j++) { 307 for (i = 0; testtable[i].name != NULL; i++) { 308 if (strncmp(argv[j], testtable[i].name, 309 strlen(argv[j])) == 0) { 310 do_test(i); 311 found = true; 312 } 313 } 314 } 315 if (!found) { 316 printf("test not found\n"); 317 exit(1); 318 } 319 } 320 321 if (opt_atf == false) { 322 printf("Result: %d tests, %d success", 323 testcount, 324 testcount - failcount - skipcount); 325 if (failcount > 0) 326 printf(", %d failed", failcount); 327 if (skipcount > 0) 328 printf(", %d skipped", skipcount); 329 printf("\n"); 330 } 331 332 if (skipcount > 0) 333 return 2; 334 if (failcount > 0) 335 return 1; 336 337 return 0; 338 } 339 340 /* 341 * XXX 342 * Some hardware drivers (e.g. hdafg(4)) require a little "rest" between 343 * close(2) and re-open(2). 344 * audio(4) uses hw_if->close() to tell the hardware to close. However, 345 * there is no agreement to wait for completion between MI and MD layer. 346 * audio(4) immediately shifts the "closed" state, and that is, the next 347 * open() will be acceptable immediately in audio layer. But the real 348 * hardware may not have been closed actually at that point. 349 * It's troublesome issue but should be fixed... 350 * 351 * However, the most frequently used pad(4) (for ATF tests) doesn't have 352 * such problem, so avoids it to reduce time. 353 */ 354 void 355 xxx_close_wait(void) 356 { 357 358 if (!use_pad) 359 usleep(500 * 1000); 360 } 361 362 void 363 do_test(int testnumber) 364 { 365 /* Sentinel */ 366 strlcpy(testname, "<NoName>", sizeof(testname)); 367 /* Do test */ 368 testtable[testnumber].func(); 369 370 cleanup_audiofd(); 371 xxx_close_wait(); 372 } 373 374 /* 375 * system call wrappers for rump. 376 */ 377 378 /* open(2) or rump_sys_open(3) */ 379 int 380 rump_or_open(const char *filename, int flag) 381 { 382 int r; 383 384 #if !defined(NO_RUMP) 385 if (use_rump) 386 r = rump_sys_open(filename, flag); 387 else 388 #endif 389 r = open(filename, flag); 390 391 if (r > maxfd) 392 maxfd = r; 393 return r; 394 } 395 396 /* write(2) or rump_sys_write(3) */ 397 int 398 rump_or_write(int fd, const void *buf, size_t len) 399 { 400 int r; 401 402 #if !defined(NO_RUMP) 403 if (use_rump) 404 r = rump_sys_write(fd, buf, len); 405 else 406 #endif 407 r = write(fd, buf, len); 408 return r; 409 } 410 411 /* read(2) or rump_sys_read(3) */ 412 int 413 rump_or_read(int fd, void *buf, size_t len) 414 { 415 int r; 416 417 #if !defined(NO_RUMP) 418 if (use_rump) 419 r = rump_sys_read(fd, buf, len); 420 else 421 #endif 422 r = read(fd, buf, len); 423 return r; 424 } 425 426 /* ioctl(2) or rump_sys_ioctl(3) */ 427 int 428 rump_or_ioctl(int fd, u_long cmd, void *arg) 429 { 430 int r; 431 432 #if !defined(NO_RUMP) 433 if (use_rump) 434 r = rump_sys_ioctl(fd, cmd, arg); 435 else 436 #endif 437 r = ioctl(fd, cmd, arg); 438 return r; 439 } 440 441 /* close(2) or rump_sys_close(3) */ 442 int 443 rump_or_close(int fd) 444 { 445 int r; 446 447 #if !defined(NO_RUMP) 448 if (use_rump) 449 r = rump_sys_close(fd); 450 else 451 #endif 452 r = close(fd); 453 454 /* maxfd-1 may not valid fd but no matter */ 455 if (fd == maxfd) 456 maxfd--; 457 return r; 458 } 459 460 /* fcntl(2) or rump_sys_fcntl(3) */ 461 /* XXX Supported only with no arguments for now */ 462 int 463 rump_or_fcntl(int fd, int cmd, ...) 464 { 465 int r; 466 467 #if !defined(NO_RUMP) 468 if (use_rump) 469 r = rump_sys_fcntl(fd, cmd); 470 else 471 #endif 472 r = fcntl(fd, cmd); 473 return r; 474 } 475 476 /* poll(2) or rump_sys_poll(3) */ 477 int 478 rump_or_poll(struct pollfd *fds, nfds_t nfds, int timeout) 479 { 480 int r; 481 482 #if !defined(NO_RUMP) 483 if (use_rump) 484 r = rump_sys_poll(fds, nfds, timeout); 485 else 486 #endif 487 r = poll(fds, nfds, timeout); 488 return r; 489 } 490 491 /* kqueue(2) or rump_sys_kqueue(3) */ 492 int 493 rump_or_kqueue(void) 494 { 495 int r; 496 497 #if !defined(NO_RUMP) 498 if (use_rump) 499 r = rump_sys_kqueue(); 500 else 501 #endif 502 r = kqueue(); 503 return r; 504 } 505 506 /* kevent(2) or rump_sys_kevent(3) */ 507 int 508 rump_or_kevent(int kq, const struct kevent *chlist, size_t nch, 509 struct kevent *evlist, size_t nev, 510 const struct timespec *timeout) 511 { 512 int r; 513 514 #if !defined(NO_RUMP) 515 if (use_rump) 516 r = rump_sys_kevent(kq, chlist, nch, evlist, nev, timeout); 517 else 518 #endif 519 r = kevent(kq, chlist, nch, evlist, nev, timeout); 520 return r; 521 } 522 523 int 524 hw_canplay(void) 525 { 526 return (props & AUDIO_PROP_PLAYBACK) ? 1 : 0; 527 } 528 529 int 530 hw_canrec(void) 531 { 532 return (props & AUDIO_PROP_CAPTURE) ? 1 : 0; 533 } 534 535 int 536 hw_bidir(void) 537 { 538 return hw_canplay() & hw_canrec(); 539 } 540 541 int 542 hw_fulldup(void) 543 { 544 return (props & AUDIO_PROP_FULLDUPLEX) ? 1 : 0; 545 } 546 547 #define DPRINTF(fmt...) do { \ 548 if (debug) \ 549 printf(fmt); \ 550 } while (0) 551 552 #define DPRINTFF(line, fmt...) do { \ 553 if (debug) { \ 554 printf(" > %d: ", line); \ 555 DPRINTF(fmt); \ 556 fflush(stdout); \ 557 } \ 558 } while (0) 559 560 #define DRESULT(r) do { \ 561 int backup_errno = errno; \ 562 if (r == -1) { \ 563 DPRINTF(" = %d, err#%d %s\n", \ 564 r, backup_errno, \ 565 strerror(backup_errno)); \ 566 } else { \ 567 DPRINTF(" = %d\n", r); \ 568 } \ 569 errno = backup_errno; \ 570 return r; \ 571 } while (0) 572 573 /* pointer variants for mmap */ 574 #define DRESULT_PTR(r) do { \ 575 int backup_errno = errno; \ 576 if (r == (void *)-1) { \ 577 DPRINTF(" = -1, err#%d %s\n", \ 578 backup_errno, \ 579 strerror(backup_errno)); \ 580 } else { \ 581 DPRINTF(" = %p\n", r); \ 582 } \ 583 errno = backup_errno; \ 584 return r; \ 585 } while (0) 586 587 588 /* 589 * requnit < 0: Use auto by pad (not implemented). 590 * requnit >= 0: Use audio<requnit>. 591 */ 592 void 593 init(int requnit) 594 { 595 struct audio_device devinfo; 596 size_t len; 597 int rel; 598 int fd; 599 int r; 600 601 /* XXX */ 602 atexit(cleanup_audiofd); 603 604 if (requnit < 0) { 605 xp_errx(1, __LINE__, "requnit < 0 not implemented."); 606 } else { 607 unit = requnit; 608 } 609 610 /* Set device name */ 611 snprintf(devicename, sizeof(devicename), "audio%d", unit); 612 snprintf(devaudio, sizeof(devaudio), "/dev/audio%d", unit); 613 snprintf(devsound, sizeof(devsound), "/dev/sound%d", unit); 614 snprintf(devaudioctl, sizeof(devaudioctl), "/dev/audioctl%d", unit); 615 snprintf(devmixer, sizeof(devmixer), "/dev/mixer%d", unit); 616 617 /* 618 * version 619 * audio2 is merged in 8.99.39. 620 */ 621 len = sizeof(rel); 622 r = sysctlbyname("kern.osrevision", &rel, &len, NULL, 0); 623 if (r == -1) 624 xp_err(1, __LINE__, "sysctl kern.osrevision"); 625 netbsd = rel / 100000000; 626 if (rel >= 899003900) 627 netbsd = 9; 628 629 #if !defined(NO_RUMP) 630 if (use_rump) { 631 DPRINTF(" use rump\n"); 632 rump_init(); 633 } 634 #endif 635 636 /* 637 * Open pad device before all accesses (including /dev/audioctl). 638 */ 639 if (use_pad) { 640 padfd = rump_or_open("/dev/pad0", O_RDONLY); 641 if (padfd == -1) 642 xp_err(1, __LINE__, "rump_or_open"); 643 644 /* Create consumer thread */ 645 pthread_create(&th, NULL, consumer_thread, NULL); 646 /* Set this thread's name */ 647 pthread_setname_np(pthread_self(), "main", NULL); 648 } 649 650 /* 651 * Get device properties, etc. 652 */ 653 fd = rump_or_open(devaudioctl, O_RDONLY); 654 if (fd == -1) 655 xp_err(1, __LINE__, "open %s", devaudioctl); 656 r = rump_or_ioctl(fd, AUDIO_GETPROPS, &props); 657 if (r == -1) 658 xp_err(1, __LINE__, "AUDIO_GETPROPS"); 659 r = rump_or_ioctl(fd, AUDIO_GETDEV, &devinfo); 660 if (r == -1) 661 xp_err(1, __LINE__, "AUDIO_GETDEV"); 662 rump_or_close(fd); 663 664 if (debug) { 665 printf(" device = %s, %s, %s\n", 666 devinfo.name, devinfo.version, devinfo.config); 667 printf(" hw props ="); 668 if (hw_canplay()) 669 printf(" playback"); 670 if (hw_canrec()) 671 printf(" capture"); 672 if (hw_fulldup()) 673 printf(" fullduplex"); 674 printf("\n"); 675 } 676 677 } 678 679 /* Consumer thread used by pad */ 680 void * 681 consumer_thread(void *arg) 682 { 683 char buf[1024]; 684 int r; 685 686 pthread_setname_np(pthread_self(), "consumer", NULL); 687 pthread_detach(pthread_self()); 688 689 /* throw away data anyway */ 690 for (;;) { 691 r = read(padfd, buf, sizeof(buf)); 692 if (r < 1) 693 break; 694 } 695 696 pthread_exit(NULL); 697 } 698 699 /* 700 * XXX 701 * Closing pad descriptor before audio descriptor causes panic (kern/54427). 702 * To avoid this, close non-pad descriptor first using atexit(3) for now. 703 * This is just a workaround and this function should be removed. 704 */ 705 void cleanup_audiofd() 706 { 707 int fd; 708 709 for (fd = 3; fd <= maxfd; fd++) { 710 if (fd != padfd) 711 close(fd); 712 } 713 maxfd = 3; 714 } 715 716 /* 717 * Support functions 718 */ 719 720 /* Set testname */ 721 void 722 TEST(const char *name, ...) 723 { 724 va_list ap; 725 726 va_start(ap, name); 727 vsnprintf(testname, sizeof(testname), name, ap); 728 va_end(ap); 729 if (opt_atf == false) { 730 printf("%s\n", testname); 731 fflush(stdout); 732 } 733 } 734 735 /* 736 * XP_FAIL() should be called when this test fails. 737 * If caller already count up testcount, call xp_fail() instead. 738 */ 739 #define XP_FAIL(fmt...) do { \ 740 testcount++; \ 741 xp_fail(__LINE__, fmt); \ 742 } while (0) 743 bool xp_fail(int line, const char *fmt, ...) 744 { 745 va_list ap; 746 747 printf("%s %d: ", (opt_atf ? "Line" : " FAIL:"), line); 748 va_start(ap, fmt); 749 vprintf(fmt, ap); 750 va_end(ap); 751 printf("\n"); 752 fflush(stdout); 753 failcount++; 754 755 return false; 756 } 757 758 /* 759 * XP_SKIP() should be called when you want to skip this test. 760 * If caller already count up testcount, call xp_skip() instead. 761 */ 762 #define XP_SKIP(fmt...) do { \ 763 testcount++; \ 764 xp_skip(__LINE__, fmt); \ 765 } while (0) 766 void xp_skip(int line, const char *fmt, ...) 767 { 768 va_list ap; 769 770 printf("%s %d: ", (opt_atf ? "Line" : " SKIP:"), line); 771 va_start(ap, fmt); 772 vprintf(fmt, ap); 773 va_end(ap); 774 printf("\n"); 775 fflush(stdout); 776 skipcount++; 777 } 778 779 #define XP_EQ(exp, act) xp_eq(__LINE__, exp, act, #act) 780 bool xp_eq(int line, int exp, int act, const char *varname) 781 { 782 bool r = true; 783 784 testcount++; 785 if (exp != act) { 786 r = xp_fail(line, "%s expects %d but %d", varname, exp, act); 787 } 788 return r; 789 } 790 #define XP_EQ_STR(exp, act) xp_eq_str(__LINE__, exp, act, #act) 791 bool xp_eq_str(int line, const char *exp, const char *act, const char *varname) 792 { 793 bool r = true; 794 795 testcount++; 796 if (strcmp(exp, act) != 0) { 797 r = xp_fail(line, "%s expects \"%s\" but \"%s\"", 798 varname, exp, act); 799 } 800 return r; 801 } 802 803 #define XP_NE(exp, act) xp_ne(__LINE__, exp, act, #act) 804 bool xp_ne(int line, int exp, int act, const char *varname) 805 { 806 bool r = true; 807 808 testcount++; 809 if (exp == act) { 810 r = xp_fail(line, "%s expects != %d but %d", varname, exp, act); 811 } 812 return r; 813 } 814 815 /* This expects that result is expressed in expr. */ 816 /* GCC extension */ 817 #define XP_IF(expr) xp_if(__LINE__, (expr), #expr) 818 bool xp_if(int line, bool expr, const char *exprname) 819 { 820 bool r = true; 821 testcount++; 822 if (!expr) { 823 r = xp_fail(__LINE__, "(%s) is expected but not met", exprname); 824 } 825 return r; 826 } 827 828 /* This expects that the system call returns 'exp'. */ 829 #define XP_SYS_EQ(exp, act) xp_sys_eq(__LINE__, exp, act, #act) 830 bool xp_sys_eq(int line, int exp, int act, const char *varname) 831 { 832 bool r = true; 833 834 testcount++; 835 if (act == -1) { 836 r = xp_fail(line, "%s expects %d but -1,err#%d(%s)", 837 varname, exp, errno, strerror(errno)); 838 } else { 839 r = xp_eq(line, exp, act, varname); 840 } 841 return r; 842 } 843 844 /* 845 * This expects that system call succeeds. 846 * This is useful when you expect the system call succeeds but don't know 847 * the expected return value, such as open(2). 848 */ 849 #define XP_SYS_OK(act) xp_sys_ok(__LINE__, act, #act) 850 bool xp_sys_ok(int line, int act, const char *varname) 851 { 852 bool r = true; 853 854 testcount++; 855 if (act == -1) { 856 r = xp_fail(line, "%s expects success but -1,err#%d(%s)", 857 varname, errno, strerror(errno)); 858 } 859 return r; 860 } 861 862 /* This expects that the system call fails with 'experrno'. */ 863 #define XP_SYS_NG(experrno, act) xp_sys_ng(__LINE__, experrno, act, #act) 864 bool xp_sys_ng(int line, int experrno, int act, const char *varname) 865 { 866 bool r = true; 867 868 testcount++; 869 if (act != -1) { 870 r = xp_fail(line, "%s expects -1,err#%d but %d", 871 varname, experrno, act); 872 } else if (experrno != errno) { 873 char acterrbuf[100]; 874 int acterrno = errno; 875 strlcpy(acterrbuf, strerror(acterrno), sizeof(acterrbuf)); 876 r = xp_fail(line, "%s expects -1,err#%d(%s) but -1,err#%d(%s)", 877 varname, experrno, strerror(experrno), 878 acterrno, acterrbuf); 879 } 880 return r; 881 } 882 883 /* 884 * When exp == 0, this expects that the system call succeeds with returned 885 * pointer is not -1. 886 * When exp != 0, this expects that the system call fails with returned 887 * pointer is -1 and its errno is exp. 888 * It's only for mmap(). 889 */ 890 #define XP_SYS_PTR(exp, act) xp_sys_ptr(__LINE__, exp, act, #act) 891 bool xp_sys_ptr(int line, int exp, void *act, const char *varname) 892 { 893 char errbuf[256]; 894 int actual_errno; 895 bool r = true; 896 897 testcount++; 898 if (exp == 0) { 899 /* expects to succeed */ 900 if (act == (void *)-1) { 901 r = xp_fail(line, 902 "%s expects success but -1,err#%d(%s)", 903 varname, errno, strerror(errno)); 904 } 905 } else { 906 /* expects to fail */ 907 if (act != (void *)-1) { 908 r = xp_fail(line, 909 "%s expects -1,err#%d(%s) but success", 910 varname, exp, strerror(exp)); 911 } else if (exp != errno) { 912 actual_errno = errno; 913 strerror_r(actual_errno, errbuf, sizeof(errbuf)); 914 r = xp_fail(line, 915 "%s expects -1,err#%d(%s) but -1,err#%d(%s)", 916 varname, exp, strerror(exp), actual_errno, errbuf); 917 } 918 } 919 return r; 920 } 921 922 923 /* 924 * REQUIRED_* return immediately if condition does not meet. 925 */ 926 #define REQUIRED_EQ(e, a) do { if (!XP_EQ(e, a)) return; } while (0) 927 #define REQUIRED_NE(e, a) do { if (!XP_NE(e, a)) return; } while (0) 928 #define REQUIRED_IF(expr) do { if (!XP_IF(expr)) return; } while (0) 929 #define REQUIRED_SYS_EQ(e, a) do { if (!XP_SYS_EQ(e, a)) return; } while (0) 930 #define REQUIRED_SYS_OK(a) do { if (!XP_SYS_OK(a)) return; } while (0) 931 932 933 static const char *openmode_str[] = { 934 "O_RDONLY", 935 "O_WRONLY", 936 "O_RDWR", 937 }; 938 939 940 /* 941 * All system calls in following tests should be called with these macros. 942 */ 943 944 #define OPEN(name, mode) \ 945 debug_open(__LINE__, name, mode) 946 int debug_open(int line, const char *name, int mode) 947 { 948 char modestr[32]; 949 int n; 950 951 if ((mode & 3) != 3) { 952 n = snprintf(modestr, sizeof(modestr), "%s", 953 openmode_str[mode & 3]); 954 } else { 955 n = snprintf(modestr, sizeof(modestr), "%d", mode & 3); 956 } 957 if ((mode & O_NONBLOCK)) 958 n += snprintf(modestr + n, sizeof(modestr) - n, "|O_NONBLOCK"); 959 960 DPRINTFF(line, "open(\"%s\", %s)", name, modestr); 961 int r = rump_or_open(name, mode); 962 DRESULT(r); 963 } 964 965 #define WRITE(fd, addr, len) \ 966 debug_write(__LINE__, fd, addr, len) 967 int debug_write(int line, int fd, const void *addr, size_t len) 968 { 969 DPRINTFF(line, "write(%d, %p, %zd)", fd, addr, len); 970 int r = rump_or_write(fd, addr, len); 971 DRESULT(r); 972 } 973 974 #define READ(fd, addr, len) \ 975 debug_read(__LINE__, fd, addr, len) 976 int debug_read(int line, int fd, void *addr, size_t len) 977 { 978 DPRINTFF(line, "read(%d, %p, %zd)", fd, addr, len); 979 int r = rump_or_read(fd, addr, len); 980 DRESULT(r); 981 } 982 983 /* 984 * addrstr is the comment for debug message. 985 * int onoff = 0; 986 * ioctl(fd, SWITCH, onoff); -> IOCTL(fd, SWITCH, onoff, "off"); 987 */ 988 #define IOCTL(fd, name, addr, addrfmt...) \ 989 debug_ioctl(__LINE__, fd, name, #name, addr, addrfmt) 990 int debug_ioctl(int line, int fd, u_long name, const char *namestr, 991 void *addr, const char *addrfmt, ...) 992 { 993 char addrbuf[100]; 994 va_list ap; 995 996 va_start(ap, addrfmt); 997 vsnprintf(addrbuf, sizeof(addrbuf), addrfmt, ap); 998 va_end(ap); 999 DPRINTFF(line, "ioctl(%d, %s, %s)", fd, namestr, addrbuf); 1000 int r = rump_or_ioctl(fd, name, addr); 1001 DRESULT(r); 1002 } 1003 1004 #define FCNTL(fd, name...) \ 1005 debug_fcntl(__LINE__, fd, name, #name) 1006 int debug_fcntl(int line, int fd, int name, const char *namestr, ...) 1007 { 1008 int r; 1009 1010 switch (name) { 1011 case F_GETFL: /* no arguments */ 1012 DPRINTFF(line, "fcntl(%d, %s)", fd, namestr); 1013 r = rump_or_fcntl(fd, name); 1014 break; 1015 default: 1016 __unreachable(); 1017 } 1018 DRESULT(r); 1019 return r; 1020 } 1021 1022 #define CLOSE(fd) \ 1023 debug_close(__LINE__, fd) 1024 int debug_close(int line, int fd) 1025 { 1026 DPRINTFF(line, "close(%d)", fd); 1027 int r = rump_or_close(fd); 1028 DRESULT(r); 1029 } 1030 1031 #define MMAP(ptr, len, prot, flags, fd, offset) \ 1032 debug_mmap(__LINE__, ptr, len, prot, flags, fd, offset) 1033 void *debug_mmap(int line, void *ptr, size_t len, int prot, int flags, int fd, 1034 off_t offset) 1035 { 1036 char protbuf[256]; 1037 char flagbuf[256]; 1038 int n; 1039 1040 #define ADDFLAG(buf, var, name) do { \ 1041 if (((var) & (name))) \ 1042 n = strlcat(buf, "|" #name, sizeof(buf)); \ 1043 var &= ~(name); \ 1044 } while (0) 1045 1046 n = 0; 1047 protbuf[n] = '\0'; 1048 if (prot == 0) { 1049 strlcpy(protbuf, "|PROT_NONE", sizeof(protbuf)); 1050 } else { 1051 ADDFLAG(protbuf, prot, PROT_EXEC); 1052 ADDFLAG(protbuf, prot, PROT_WRITE); 1053 ADDFLAG(protbuf, prot, PROT_READ); 1054 if (prot != 0) { 1055 snprintf(protbuf + n, sizeof(protbuf) - n, 1056 "|prot=0x%x", prot); 1057 } 1058 } 1059 1060 n = 0; 1061 flagbuf[n] = '\0'; 1062 if (flags == 0) { 1063 strlcpy(flagbuf, "|MAP_FILE", sizeof(flagbuf)); 1064 } else { 1065 ADDFLAG(flagbuf, flags, MAP_SHARED); 1066 ADDFLAG(flagbuf, flags, MAP_PRIVATE); 1067 ADDFLAG(flagbuf, flags, MAP_FIXED); 1068 ADDFLAG(flagbuf, flags, MAP_INHERIT); 1069 ADDFLAG(flagbuf, flags, MAP_HASSEMAPHORE); 1070 ADDFLAG(flagbuf, flags, MAP_TRYFIXED); 1071 ADDFLAG(flagbuf, flags, MAP_WIRED); 1072 ADDFLAG(flagbuf, flags, MAP_ANON); 1073 if (flags != 0) { 1074 n += snprintf(flagbuf + n, sizeof(flagbuf) - n, 1075 "|flag=0x%x", flags); 1076 } 1077 } 1078 1079 DPRINTFF(line, "mmap(%p, %zd, %s, %s, %d, %jd)", 1080 ptr, len, protbuf + 1, flagbuf + 1, fd, offset); 1081 void *r = mmap(ptr, len, prot, flags, fd, offset); 1082 DRESULT_PTR(r); 1083 } 1084 1085 #define MUNMAP(ptr, len) \ 1086 debug_munmap(__LINE__, ptr, len) 1087 int debug_munmap(int line, void *ptr, int len) 1088 { 1089 #if !defined(NO_RUMP) 1090 if (use_rump) 1091 xp_errx(1, __LINE__, "rump doesn't support munmap"); 1092 #endif 1093 DPRINTFF(line, "munmap(%p, %d)", ptr, len); 1094 int r = munmap(ptr, len); 1095 DRESULT(r); 1096 } 1097 1098 const char * 1099 event_tostr(int events) 1100 { 1101 static char buf[64]; 1102 1103 snprintb(buf, sizeof(buf), 1104 "\177\020" \ 1105 "b\10WRBAND\0" \ 1106 "b\7RDBAND\0" "b\6RDNORM\0" "b\5NVAL\0" "b\4HUP\0" \ 1107 "b\3ERR\0" "b\2OUT\0" "b\1PRI\0" "b\0IN\0", 1108 events); 1109 return buf; 1110 } 1111 1112 #define POLL(pfd, nfd, timeout) \ 1113 debug_poll(__LINE__, pfd, nfd, timeout) 1114 int debug_poll(int line, struct pollfd *pfd, int nfd, int timeout) 1115 { 1116 char buf[256]; 1117 int n = 0; 1118 buf[n] = '\0'; 1119 for (int i = 0; i < nfd; i++) { 1120 n += snprintf(buf + n, sizeof(buf) - n, "{fd=%d,events=%s}", 1121 pfd[i].fd, event_tostr(pfd[i].events)); 1122 } 1123 DPRINTFF(line, "poll(%s, %d, %d)", buf, nfd, timeout); 1124 int r = rump_or_poll(pfd, nfd, timeout); 1125 DRESULT(r); 1126 } 1127 1128 #define KQUEUE() \ 1129 debug_kqueue(__LINE__) 1130 int debug_kqueue(int line) 1131 { 1132 DPRINTFF(line, "kqueue()"); 1133 int r = rump_or_kqueue(); 1134 DRESULT(r); 1135 } 1136 1137 #define KEVENT_SET(kq, kev, nev) \ 1138 debug_kevent_set(__LINE__, kq, kev, nev) 1139 int debug_kevent_set(int line, int kq, const struct kevent *kev, size_t nev) 1140 { 1141 DPRINTFF(line, "kevent_set(%d, %p, %zd)", kq, kev, nev); 1142 int r = rump_or_kevent(kq, kev, nev, NULL, 0, NULL); 1143 DRESULT(r); 1144 } 1145 1146 #define KEVENT_POLL(kq, kev, nev, ts) \ 1147 debug_kevent_poll(__LINE__, kq, kev, nev, ts) 1148 int debug_kevent_poll(int line, int kq, struct kevent *kev, size_t nev, 1149 const struct timespec *ts) 1150 { 1151 char tsbuf[32]; 1152 1153 if (ts == NULL) { 1154 snprintf(tsbuf, sizeof(tsbuf), "NULL"); 1155 } else if (ts->tv_sec == 0 && ts->tv_nsec == 0) { 1156 snprintf(tsbuf, sizeof(tsbuf), "0.0"); 1157 } else { 1158 snprintf(tsbuf, sizeof(tsbuf), "%d.%09ld", 1159 (int)ts->tv_sec, ts->tv_nsec); 1160 } 1161 DPRINTFF(line, "kevent_poll(%d, %p, %zd, %s)", kq, kev, nev, tsbuf); 1162 int r = rump_or_kevent(kq, NULL, 0, kev, nev, ts); 1163 DRESULT(r); 1164 } 1165 1166 #define DEBUG_KEV(name, kev) \ 1167 debug_kev(__LINE__, name, kev) 1168 void debug_kev(int line, const char *name, const struct kevent *kev) 1169 { 1170 char flagbuf[256]; 1171 const char *filterbuf; 1172 uint32_t v; 1173 int n; 1174 1175 n = 0; 1176 flagbuf[n] = '\0'; 1177 if (kev->flags == 0) { 1178 strcpy(flagbuf, "|0?"); 1179 } else { 1180 v = kev->flags; 1181 ADDFLAG(flagbuf, v, EV_ADD); 1182 if (v != 0) 1183 snprintf(flagbuf + n, sizeof(flagbuf)-n, "|0x%x", v); 1184 } 1185 1186 switch (kev->filter) { 1187 case EVFILT_READ: filterbuf = "EVFILT_READ"; break; 1188 case EVFILT_WRITE: filterbuf = "EVFILT_WRITE"; break; 1189 default: filterbuf = "EVFILT_?"; break; 1190 } 1191 1192 DPRINTFF(line, 1193 "%s={id:%d,%s,%s,fflags:0x%x,data:0x%" PRIx64 ",udata:0x%x}\n", 1194 name, 1195 (int)kev->ident, 1196 flagbuf + 1, 1197 filterbuf, 1198 kev->fflags, 1199 kev->data, 1200 (int)(intptr_t)kev->udata); 1201 } 1202 1203 /* XXX rump? */ 1204 #define GETUID() \ 1205 debug_getuid(__LINE__) 1206 uid_t debug_getuid(int line) 1207 { 1208 DPRINTFF(line, "getuid"); 1209 uid_t r = getuid(); 1210 /* getuid() never fails */ 1211 DPRINTF(" = %u\n", r); 1212 return r; 1213 } 1214 1215 /* XXX rump? */ 1216 #define SETEUID(id) \ 1217 debug_seteuid(__LINE__, id) 1218 int debug_seteuid(int line, uid_t id) 1219 { 1220 DPRINTFF(line, "seteuid(%d)", (int)id); 1221 int r = seteuid(id); 1222 DRESULT(r); 1223 } 1224 1225 #define SYSCTLBYNAME(name, oldp, oldlenp, newp, newlen) \ 1226 debug_sysctlbyname(__LINE__, name, oldp, oldlenp, newp, newlen) 1227 int debug_sysctlbyname(int line, const char *name, void *oldp, size_t *oldlenp, 1228 const void *newp, size_t newlen) 1229 { 1230 DPRINTFF(line, "sysctlbyname(\"%s\")", name); 1231 int r = sysctlbyname(name, oldp, oldlenp, newp, newlen); 1232 DRESULT(r); 1233 } 1234 1235 1236 /* Return openable mode on this hardware property */ 1237 int 1238 openable_mode(void) 1239 { 1240 if (hw_bidir()) 1241 return O_RDWR; 1242 if (hw_canplay()) 1243 return O_WRONLY; 1244 else 1245 return O_RDONLY; 1246 } 1247 1248 int mode2aumode_full[] = { 1249 AUMODE_RECORD, /* O_RDONLY */ 1250 AUMODE_PLAY | AUMODE_PLAY_ALL, /* O_WRONLY */ 1251 AUMODE_PLAY | AUMODE_PLAY_ALL | AUMODE_RECORD, /* O_RDWR */ 1252 }; 1253 1254 /* Convert openmode(O_*) to AUMODE_*, with hardware property */ 1255 int 1256 mode2aumode(int mode) 1257 { 1258 int aumode; 1259 1260 aumode = mode2aumode_full[mode]; 1261 if (hw_canplay() == 0) 1262 aumode &= ~(AUMODE_PLAY | AUMODE_PLAY_ALL); 1263 if (hw_canrec() == 0) 1264 aumode &= ~AUMODE_RECORD; 1265 1266 if (netbsd >= 9) { 1267 /* half-duplex treats O_RDWR as O_WRONLY */ 1268 if (mode == O_RDWR && hw_bidir() && hw_fulldup() == 0) 1269 aumode &= ~AUMODE_RECORD; 1270 } 1271 1272 return aumode; 1273 } 1274 1275 /* Is this mode + hardware playable? */ 1276 int 1277 mode2play(int mode) 1278 { 1279 int aumode; 1280 1281 aumode = mode2aumode(mode); 1282 return ((aumode & AUMODE_PLAY)) ? 1 : 0; 1283 } 1284 1285 /* Is this mode + hardware recordable? */ 1286 int 1287 mode2rec(int mode) 1288 { 1289 int aumode; 1290 1291 aumode = mode2aumode(mode); 1292 return ((aumode & AUMODE_RECORD)) ? 1 : 0; 1293 } 1294 1295 /* 1296 * On NetBSD7, open() after-closing-mmap fails due to a bug. 1297 * It happens once every two times like flip-flop, so the workaround is 1298 * to open it again. 1299 */ 1300 void 1301 reset_after_mmap(void) 1302 { 1303 int fd; 1304 1305 if (netbsd < 8) { 1306 fd = OPEN(devaudio, O_WRONLY); 1307 if (fd != -1) 1308 CLOSE(fd); 1309 } 1310 } 1311 1312 /* 1313 * Lookup "outputs.master" and return its mixer device index. 1314 * It may not be strict but I'm not sure. 1315 */ 1316 int 1317 mixer_get_outputs_master(int mixerfd) 1318 { 1319 const char * const typename[] = { "CLASS", "ENUM", "SET", "VALUE" }; 1320 mixer_devinfo_t di; 1321 int class_outputs; 1322 int i; 1323 int r; 1324 1325 class_outputs = -1; 1326 for (i = 0; ; i++) { 1327 memset(&di, 0, sizeof(di)); 1328 di.index = i; 1329 r = IOCTL(mixerfd, AUDIO_MIXER_DEVINFO, &di, "index=%d", i); 1330 if (r < 0) 1331 break; 1332 DPRINTF(" > type=%s(%d) mixer_class=%d name=%s\n", 1333 (0 <= di.type && di.type <= 3) ? typename[di.type] : "", 1334 di.type, di.mixer_class, di.label.name); 1335 if (di.type == AUDIO_MIXER_CLASS && 1336 strcmp(di.label.name, "outputs") == 0) { 1337 class_outputs = di.mixer_class; 1338 DPRINTF(" > class_output=%d\n", class_outputs); 1339 continue; 1340 } 1341 if (di.type == AUDIO_MIXER_VALUE && 1342 di.mixer_class == class_outputs && 1343 strcmp(di.label.name, "master") == 0) { 1344 return i; 1345 } 1346 } 1347 /* Not found */ 1348 return -1; 1349 } 1350 1351 /* 1352 * Tests 1353 */ 1354 1355 void test_open_mode(int); 1356 void test_open(const char *, int); 1357 void test_open_simul(int, int); 1358 void try_open_multiuser(bool); 1359 void test_open_multiuser(bool); 1360 void test_rdwr_fallback(int, bool, bool); 1361 void test_rdwr_two(int, int); 1362 void test_mmap_mode(int, int); 1363 void test_poll_mode(int, int, int); 1364 void test_kqueue_mode(int, int, int); 1365 volatile int sigio_caught; 1366 void signal_FIOASYNC(int); 1367 void test_AUDIO_SETFD_xxONLY(int); 1368 void test_AUDIO_SETINFO_mode(int, int, int, int); 1369 void test_AUDIO_SETINFO_params_set(int, int, int); 1370 void test_AUDIO_SETINFO_pause(int, int, int); 1371 int getenc_make_table(int, int[][5]); 1372 void xp_getenc(int[][5], int, int, int, struct audio_prinfo *); 1373 void getenc_check_encodings(int, int[][5]); 1374 void test_AUDIO_ERROR(int); 1375 void test_audioctl_open_1(int, int); 1376 void test_audioctl_open_2(int, int); 1377 void try_audioctl_open_multiuser(const char *, const char *); 1378 void test_audioctl_open_multiuser(bool, const char *, const char *); 1379 void test_audioctl_rw(int); 1380 1381 #define DEF(name) \ 1382 void test__ ## name (void); \ 1383 void test__ ## name (void) 1384 1385 /* 1386 * Whether it can be open()ed with specified mode. 1387 */ 1388 void 1389 test_open_mode(int mode) 1390 { 1391 int fd; 1392 int r; 1393 1394 TEST("open_mode_%s", openmode_str[mode] + 2); 1395 1396 fd = OPEN(devaudio, mode); 1397 if (mode2aumode(mode) != 0) { 1398 XP_SYS_OK(fd); 1399 } else { 1400 XP_SYS_NG(ENXIO, fd); 1401 } 1402 1403 if (fd >= 0) { 1404 r = CLOSE(fd); 1405 XP_SYS_EQ(0, r); 1406 } 1407 } 1408 DEF(open_mode_RDONLY) { test_open_mode(O_RDONLY); } 1409 DEF(open_mode_WRONLY) { test_open_mode(O_WRONLY); } 1410 DEF(open_mode_RDWR) { test_open_mode(O_RDWR); } 1411 1412 /* 1413 * Check the initial parameters and stickiness. 1414 * /dev/audio 1415 * The initial parameters are always the same whenever you open. 1416 * /dev/sound and /dev/audioctl 1417 * The initial parameters are inherited from the last /dev/sound or 1418 * /dev/audio. 1419 */ 1420 void 1421 test_open(const char *devname, int mode) 1422 { 1423 struct audio_info ai; 1424 struct audio_info ai0; 1425 char devfile[16]; 1426 int fd; 1427 int r; 1428 int can_play; 1429 int can_rec; 1430 int exp_mode; 1431 int exp_encoding; 1432 int exp_precision; 1433 int exp_channels; 1434 int exp_sample_rate; 1435 int exp_pause; 1436 int exp_popen; 1437 int exp_ropen; 1438 1439 TEST("open_%s_%s", devname, openmode_str[mode] + 2); 1440 1441 snprintf(devfile, sizeof(devfile), "/dev/%s%d", devname, unit); 1442 can_play = mode2play(mode); 1443 can_rec = mode2rec(mode); 1444 if (strcmp(devname, "audioctl") != 0) { 1445 if (can_play + can_rec == 0) { 1446 /* Check whether it cannot be opened */ 1447 fd = OPEN(devaudio, mode); 1448 XP_SYS_NG(ENXIO, fd); 1449 return; 1450 } 1451 } 1452 1453 /* /dev/audio is always initialized */ 1454 if (strcmp(devname, "audio") == 0) { 1455 exp_encoding = AUDIO_ENCODING_ULAW; 1456 exp_precision = 8; 1457 exp_channels = 1; 1458 exp_sample_rate = 8000; 1459 exp_pause = 0; 1460 } else { 1461 exp_encoding = AUDIO_ENCODING_SLINEAR_LE; 1462 exp_precision = 16; 1463 exp_channels = 2; 1464 exp_sample_rate = 11025; 1465 exp_pause = 1; 1466 } 1467 1468 /* /dev/audioctl is always "not opened" */ 1469 if (strcmp(devname, "audioctl") == 0) { 1470 exp_mode = 0; 1471 exp_popen = 0; 1472 exp_ropen = 0; 1473 } else { 1474 exp_mode = mode2aumode(mode); 1475 exp_popen = can_play; 1476 exp_ropen = can_rec; 1477 } 1478 1479 1480 /* 1481 * At first, initialize the sticky parameters both of play and rec. 1482 * This uses /dev/audio to verify /dev/audio. It's not good way but 1483 * I don't have better one... 1484 */ 1485 fd = OPEN(devaudio, openable_mode()); 1486 REQUIRED_SYS_OK(fd); 1487 r = CLOSE(fd); 1488 REQUIRED_SYS_EQ(0, r); 1489 1490 /* 1491 * Open target device and check the initial parameters 1492 * At this moment, all devices are initialized by default. 1493 */ 1494 fd = OPEN(devfile, mode); 1495 REQUIRED_SYS_OK(fd); 1496 memset(&ai, 0, sizeof(ai)); 1497 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 1498 REQUIRED_SYS_EQ(0, r); 1499 1500 XP_NE(0, ai.blocksize); 1501 /* hiwat/lowat */ 1502 XP_EQ(exp_mode, ai.mode); 1503 /* ai.play */ 1504 XP_EQ(8000, ai.play.sample_rate); 1505 XP_EQ(1, ai.play.channels); 1506 XP_EQ(8, ai.play.precision); 1507 XP_EQ(AUDIO_ENCODING_ULAW, ai.play.encoding); 1508 /* gain */ 1509 /* port */ 1510 XP_EQ(0, ai.play.seek); 1511 /* avail_ports */ 1512 XP_NE(0, ai.play.buffer_size); 1513 XP_EQ(0, ai.play.samples); 1514 XP_EQ(0, ai.play.eof); 1515 XP_EQ(0, ai.play.pause); 1516 XP_EQ(0, ai.play.error); 1517 XP_EQ(0, ai.play.waiting); 1518 /* balance */ 1519 XP_EQ(exp_popen, ai.play.open); 1520 XP_EQ(0, ai.play.active); 1521 /* ai.record */ 1522 XP_EQ(8000, ai.record.sample_rate); 1523 XP_EQ(1, ai.record.channels); 1524 XP_EQ(8, ai.record.precision); 1525 XP_EQ(AUDIO_ENCODING_ULAW, ai.record.encoding); 1526 /* gain */ 1527 /* port */ 1528 XP_EQ(0, ai.record.seek); 1529 /* avail_ports */ 1530 XP_NE(0, ai.record.buffer_size); 1531 XP_EQ(0, ai.record.samples); 1532 XP_EQ(0, ai.record.eof); 1533 XP_EQ(0, ai.record.pause); 1534 XP_EQ(0, ai.record.error); 1535 XP_EQ(0, ai.record.waiting); 1536 /* balance */ 1537 XP_EQ(exp_ropen, ai.record.open); 1538 /* 1539 * NetBSD7,8 (may?) be active when opened in recording mode but 1540 * recording has not started yet. (?) 1541 * NetBSD9 is not active at that time. 1542 */ 1543 if (netbsd < 9) { 1544 } else { 1545 XP_EQ(0, ai.record.active); 1546 } 1547 /* Save it */ 1548 ai0 = ai; 1549 1550 /* 1551 * Change much as possible 1552 */ 1553 AUDIO_INITINFO(&ai); 1554 ai.mode = ai0.mode ^ AUMODE_PLAY_ALL; 1555 ai.play.sample_rate = 11025; 1556 ai.play.channels = 2; 1557 ai.play.precision = 16; 1558 ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE; 1559 ai.play.pause = 1; 1560 ai.record.sample_rate = 11025; 1561 ai.record.channels = 2; 1562 ai.record.precision = 16; 1563 ai.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 1564 ai.record.pause = 1; 1565 r = IOCTL(fd, AUDIO_SETINFO, &ai, "ai"); 1566 REQUIRED_SYS_EQ(0, r); 1567 r = CLOSE(fd); 1568 REQUIRED_SYS_EQ(0, r); 1569 1570 /* 1571 * Open the same target device again and check 1572 */ 1573 fd = OPEN(devfile, mode); 1574 REQUIRED_SYS_OK(fd); 1575 memset(&ai, 0, sizeof(ai)); 1576 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 1577 REQUIRED_SYS_EQ(0, r); 1578 1579 XP_NE(0, ai.blocksize); 1580 /* hiwat/lowat */ 1581 if (netbsd < 8) { 1582 /* 1583 * On NetBSD7, the behavior when changing ai.mode on 1584 * /dev/audioctl can not be explained yet but I won't 1585 * verify it more over. 1586 */ 1587 } else { 1588 /* On NetBSD9, changing mode never affects other fds */ 1589 XP_EQ(exp_mode, ai.mode); 1590 } 1591 /* ai.play */ 1592 XP_EQ(exp_sample_rate, ai.play.sample_rate); 1593 XP_EQ(exp_channels, ai.play.channels); 1594 XP_EQ(exp_precision, ai.play.precision); 1595 XP_EQ(exp_encoding, ai.play.encoding); 1596 /* gain */ 1597 /* port */ 1598 XP_EQ(0, ai.play.seek); 1599 /* avail_ports */ 1600 XP_NE(0, ai.play.buffer_size); 1601 XP_EQ(0, ai.play.samples); 1602 XP_EQ(0, ai.play.eof); 1603 XP_EQ(exp_pause, ai.play.pause); 1604 XP_EQ(0, ai.play.error); 1605 XP_EQ(0, ai.play.waiting); 1606 /* balance */ 1607 XP_EQ(exp_popen, ai.play.open); 1608 XP_EQ(0, ai.play.active); 1609 /* ai.record */ 1610 XP_EQ(exp_sample_rate, ai.record.sample_rate); 1611 XP_EQ(exp_channels, ai.record.channels); 1612 XP_EQ(exp_precision, ai.record.precision); 1613 XP_EQ(exp_encoding, ai.record.encoding); 1614 /* gain */ 1615 /* port */ 1616 XP_EQ(0, ai.record.seek); 1617 /* avail_ports */ 1618 XP_NE(0, ai.record.buffer_size); 1619 XP_EQ(0, ai.record.samples); 1620 XP_EQ(0, ai.record.eof); 1621 XP_EQ(exp_pause, ai.record.pause); 1622 XP_EQ(0, ai.record.error); 1623 XP_EQ(0, ai.record.waiting); 1624 /* balance */ 1625 XP_EQ(exp_ropen, ai.record.open); 1626 if (netbsd < 9) { 1627 } else { 1628 XP_EQ(0, ai.record.active); 1629 } 1630 1631 r = CLOSE(fd); 1632 REQUIRED_SYS_EQ(0, r); 1633 } 1634 DEF(open_audio_RDONLY) { test_open("audio", O_RDONLY); } 1635 DEF(open_audio_WRONLY) { test_open("audio", O_WRONLY); } 1636 DEF(open_audio_RDWR) { test_open("audio", O_RDWR); } 1637 DEF(open_sound_RDONLY) { test_open("sound", O_RDONLY); } 1638 DEF(open_sound_WRONLY) { test_open("sound", O_WRONLY); } 1639 DEF(open_sound_RDWR) { test_open("sound", O_RDWR); } 1640 DEF(open_audioctl_RDONLY) { test_open("audioctl", O_RDONLY); } 1641 DEF(open_audioctl_WRONLY) { test_open("audioctl", O_WRONLY); } 1642 DEF(open_audioctl_RDWR) { test_open("audioctl", O_RDWR); } 1643 1644 /* 1645 * Open (1) /dev/sound -> (2) /dev/audio -> (3) /dev/sound, 1646 * Both of /dev/audio and /dev/sound share the sticky parameters, 1647 * /dev/sound inherits and use it but /dev/audio initialize and use it. 1648 * So 2nd audio descriptor affects 3rd sound descriptor. 1649 */ 1650 DEF(open_sound_sticky) 1651 { 1652 struct audio_info ai; 1653 int fd; 1654 int r; 1655 int openmode; 1656 1657 TEST("open_sound_sticky"); 1658 1659 openmode = openable_mode(); 1660 1661 /* First, open /dev/sound and change encoding as a delegate */ 1662 fd = OPEN(devsound, openmode); 1663 REQUIRED_SYS_OK(fd); 1664 AUDIO_INITINFO(&ai); 1665 ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE; 1666 ai.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 1667 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 1668 REQUIRED_SYS_EQ(0, r); 1669 r = CLOSE(fd); 1670 REQUIRED_SYS_EQ(0, r); 1671 1672 /* Next, open /dev/audio. It makes the encoding mulaw */ 1673 fd = OPEN(devaudio, openmode); 1674 REQUIRED_SYS_OK(fd); 1675 r = CLOSE(fd); 1676 REQUIRED_SYS_EQ(0, r); 1677 1678 /* And then, open /dev/sound again */ 1679 fd = OPEN(devsound, openmode); 1680 REQUIRED_SYS_OK(fd); 1681 memset(&ai, 0, sizeof(ai)); 1682 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 1683 REQUIRED_SYS_EQ(0, r); 1684 XP_EQ(AUDIO_ENCODING_ULAW, ai.play.encoding); 1685 XP_EQ(AUDIO_ENCODING_ULAW, ai.record.encoding); 1686 r = CLOSE(fd); 1687 REQUIRED_SYS_EQ(0, r); 1688 } 1689 1690 /* 1691 * /dev/audioctl has stickiness like /dev/sound. 1692 */ 1693 DEF(open_audioctl_sticky) 1694 { 1695 struct audio_info ai; 1696 int fd; 1697 int r; 1698 int openmode; 1699 1700 TEST("open_audioctl_sticky"); 1701 1702 openmode = openable_mode(); 1703 1704 /* First, open /dev/audio and change encoding */ 1705 fd = OPEN(devaudio, openmode); 1706 REQUIRED_SYS_OK(fd); 1707 AUDIO_INITINFO(&ai); 1708 ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE; 1709 ai.play.precision = 16; 1710 ai.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 1711 ai.record.precision = 16; 1712 r = IOCTL(fd, AUDIO_SETINFO, &ai, "SLINEAR_LE"); 1713 REQUIRED_SYS_EQ(0, r); 1714 r = CLOSE(fd); 1715 REQUIRED_SYS_EQ(0, r); 1716 1717 /* Next, open /dev/audioctl. It should be affected */ 1718 fd = OPEN(devaudioctl, openmode); 1719 REQUIRED_SYS_OK(fd); 1720 memset(&ai, 0, sizeof(ai)); 1721 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 1722 REQUIRED_SYS_EQ(0, r); 1723 XP_EQ(AUDIO_ENCODING_SLINEAR_LE, ai.play.encoding); 1724 XP_EQ(16, ai.play.precision); 1725 XP_EQ(AUDIO_ENCODING_SLINEAR_LE, ai.record.encoding); 1726 XP_EQ(16, ai.record.precision); 1727 1728 /* Then, change /dev/audioctl */ 1729 AUDIO_INITINFO(&ai); 1730 ai.play.encoding = AUDIO_ENCODING_ULAW; 1731 ai.play.precision = 8; 1732 ai.record.encoding = AUDIO_ENCODING_ULAW; 1733 ai.record.precision = 8; 1734 r = IOCTL(fd, AUDIO_SETINFO, &ai, "ULAW"); 1735 REQUIRED_SYS_EQ(0, r); 1736 r = CLOSE(fd); 1737 REQUIRED_SYS_EQ(0, r); 1738 1739 /* Finally, open /dev/sound. It also should be affected */ 1740 fd = OPEN(devsound, openmode); 1741 REQUIRED_SYS_OK(fd); 1742 memset(&ai, 0, sizeof(ai)); 1743 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 1744 REQUIRED_SYS_EQ(0, r); 1745 XP_EQ(AUDIO_ENCODING_ULAW, ai.play.encoding); 1746 XP_EQ(8, ai.play.precision); 1747 XP_EQ(AUDIO_ENCODING_ULAW, ai.record.encoding); 1748 XP_EQ(8, ai.record.precision); 1749 r = CLOSE(fd); 1750 REQUIRED_SYS_EQ(0, r); 1751 } 1752 1753 /* 1754 * Open two descriptors simultaneously. 1755 */ 1756 void 1757 test_open_simul(int mode0, int mode1) 1758 { 1759 struct audio_info ai; 1760 int fd0, fd1; 1761 int i; 1762 int r; 1763 int actmode; 1764 #define AUMODE_BOTH (AUMODE_PLAY | AUMODE_RECORD) 1765 struct { 1766 int mode0; 1767 int mode1; 1768 } expfulltable[] = { 1769 /* expected fd0 expected fd1 (-errno expects error) */ 1770 { AUMODE_RECORD, AUMODE_RECORD }, // REC, REC 1771 { AUMODE_RECORD, AUMODE_PLAY }, // REC, PLAY 1772 { AUMODE_RECORD, AUMODE_BOTH }, // REC, BOTH 1773 { AUMODE_PLAY, AUMODE_RECORD }, // PLAY, REC 1774 { AUMODE_PLAY, AUMODE_PLAY }, // PLAY, PLAY 1775 { AUMODE_PLAY, AUMODE_BOTH }, // PLAY, BOTH 1776 { AUMODE_BOTH, AUMODE_RECORD }, // BOTH, REC 1777 { AUMODE_BOTH, AUMODE_PLAY }, // BOTH, PLAY 1778 { AUMODE_BOTH, AUMODE_BOTH }, // BOTH, BOTH 1779 }, 1780 exphalftable[] = { 1781 /* expected fd0 expected fd1 (-errno expects error) */ 1782 { AUMODE_RECORD, AUMODE_RECORD }, // REC, REC 1783 { AUMODE_RECORD, -ENODEV }, // REC, PLAY 1784 { AUMODE_RECORD, -ENODEV }, // REC, BOTH 1785 { AUMODE_PLAY, -ENODEV }, // PLAY, REC 1786 { AUMODE_PLAY, AUMODE_PLAY }, // PLAY, PLAY 1787 { AUMODE_PLAY, AUMODE_PLAY }, // PLAY, BOTH 1788 { AUMODE_PLAY, -ENODEV }, // BOTH, REC 1789 { AUMODE_PLAY, AUMODE_PLAY }, // BOTH, PLAY 1790 { AUMODE_PLAY, AUMODE_PLAY }, // BOTH, BOTH 1791 }, *exptable; 1792 1793 /* The expected values are different in half-duplex or full-duplex */ 1794 if (hw_fulldup()) { 1795 exptable = expfulltable; 1796 } else { 1797 exptable = exphalftable; 1798 } 1799 1800 TEST("open_simul_%s_%s", 1801 openmode_str[mode0] + 2, 1802 openmode_str[mode1] + 2); 1803 1804 if (netbsd < 8) { 1805 XP_SKIP("Multiple open is not supported"); 1806 return; 1807 } 1808 1809 if (mode2aumode(mode0) == 0 || mode2aumode(mode1) == 0) { 1810 XP_SKIP("Operation not allowed on this hardware property"); 1811 return; 1812 } 1813 1814 i = mode0 * 3 + mode1; 1815 1816 /* Open first one */ 1817 fd0 = OPEN(devaudio, mode0); 1818 REQUIRED_SYS_OK(fd0); 1819 r = IOCTL(fd0, AUDIO_GETBUFINFO, &ai, ""); 1820 REQUIRED_SYS_EQ(0, r); 1821 actmode = ai.mode & AUMODE_BOTH; 1822 XP_EQ(exptable[i].mode0, actmode); 1823 1824 /* Open second one */ 1825 fd1 = OPEN(devaudio, mode1); 1826 if (exptable[i].mode1 >= 0) { 1827 /* Case to expect to be able to open */ 1828 REQUIRED_SYS_OK(fd1); 1829 r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, ""); 1830 XP_SYS_EQ(0, r); 1831 if (r == 0) { 1832 actmode = ai.mode & AUMODE_BOTH; 1833 XP_EQ(exptable[i].mode1, actmode); 1834 } 1835 } else { 1836 /* Case to expect not to be able to open */ 1837 XP_SYS_NG(ENODEV, fd1); 1838 if (fd1 == -1) { 1839 XP_EQ(-exptable[i].mode1, errno); 1840 } else { 1841 r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, ""); 1842 XP_SYS_EQ(0, r); 1843 if (r == 0) { 1844 actmode = ai.mode & AUMODE_BOTH; 1845 XP_FAIL("expects error but %d", actmode); 1846 } 1847 } 1848 } 1849 1850 if (fd1 >= 0) { 1851 r = CLOSE(fd1); 1852 XP_SYS_EQ(0, r); 1853 } 1854 1855 r = CLOSE(fd0); 1856 XP_SYS_EQ(0, r); 1857 } 1858 DEF(open_simul_RDONLY_RDONLY) { test_open_simul(O_RDONLY, O_RDONLY); } 1859 DEF(open_simul_RDONLY_WRONLY) { test_open_simul(O_RDONLY, O_WRONLY); } 1860 DEF(open_simul_RDONLY_RDWR) { test_open_simul(O_RDONLY, O_RDWR); } 1861 DEF(open_simul_WRONLY_RDONLY) { test_open_simul(O_WRONLY, O_RDONLY); } 1862 DEF(open_simul_WRONLY_WRONLY) { test_open_simul(O_WRONLY, O_WRONLY); } 1863 DEF(open_simul_WRONLY_RDWR) { test_open_simul(O_WRONLY, O_RDWR); } 1864 DEF(open_simul_RDWR_RDONLY) { test_open_simul(O_RDWR, O_RDONLY); } 1865 DEF(open_simul_RDWR_WRONLY) { test_open_simul(O_RDWR, O_WRONLY); } 1866 DEF(open_simul_RDWR_RDWR) { test_open_simul(O_RDWR, O_RDWR); } 1867 1868 /* 1869 * /dev/audio can be opened by other user who opens /dev/audio. 1870 */ 1871 void 1872 try_open_multiuser(bool multiuser) 1873 { 1874 int fd0; 1875 int fd1; 1876 int r; 1877 uid_t ouid; 1878 1879 /* 1880 * Test1: Open as root first and then unprivileged user. 1881 */ 1882 1883 /* At first, open as root */ 1884 fd0 = OPEN(devaudio, openable_mode()); 1885 REQUIRED_SYS_OK(fd0); 1886 1887 ouid = GETUID(); 1888 r = SETEUID(1); 1889 REQUIRED_SYS_EQ(0, r); 1890 1891 /* Then, open as unprivileged user */ 1892 fd1 = OPEN(devaudio, openable_mode()); 1893 if (multiuser) { 1894 /* If multiuser, another user also can open */ 1895 XP_SYS_OK(fd1); 1896 } else { 1897 /* If not multiuser, another user cannot open */ 1898 XP_SYS_NG(EPERM, fd1); 1899 } 1900 if (fd1 != -1) { 1901 r = CLOSE(fd1); 1902 XP_SYS_EQ(0, r); 1903 } 1904 1905 r = SETEUID(ouid); 1906 REQUIRED_SYS_EQ(0, r); 1907 1908 r = CLOSE(fd0); 1909 XP_SYS_EQ(0, r); 1910 1911 /* 1912 * Test2: Open as unprivileged user first and then root. 1913 */ 1914 1915 /* At first, open as unprivileged user */ 1916 ouid = GETUID(); 1917 r = SETEUID(1); 1918 REQUIRED_SYS_EQ(0, r); 1919 1920 fd0 = OPEN(devaudio, openable_mode()); 1921 REQUIRED_SYS_OK(fd0); 1922 1923 /* Then open as root */ 1924 r = SETEUID(ouid); 1925 REQUIRED_SYS_EQ(0, r); 1926 1927 /* root always can open */ 1928 fd1 = OPEN(devaudio, openable_mode()); 1929 XP_SYS_OK(fd1); 1930 if (fd1 != -1) { 1931 r = CLOSE(fd1); 1932 XP_SYS_EQ(0, r); 1933 } 1934 1935 /* Close first one as unprivileged user */ 1936 r = SETEUID(1); 1937 REQUIRED_SYS_EQ(0, r); 1938 r = CLOSE(fd0); 1939 XP_SYS_EQ(0, r); 1940 r = SETEUID(ouid); 1941 REQUIRED_SYS_EQ(0, r); 1942 } 1943 /* 1944 * This is a wrapper for open_multiuser. 1945 * XXX XP_* macros are not compatible with on-error-goto, we need try-catch... 1946 */ 1947 void 1948 test_open_multiuser(bool multiuser) 1949 { 1950 char mibname[32]; 1951 bool oldval; 1952 size_t oldlen; 1953 int r; 1954 1955 TEST("open_multiuser_%d", multiuser); 1956 if (netbsd < 8) { 1957 XP_SKIP("Multiple open is not supported"); 1958 return; 1959 } 1960 if (netbsd < 9) { 1961 /* NetBSD8 has no way (difficult) to determine device name */ 1962 XP_SKIP("NetBSD8 cannot determine device name"); 1963 return; 1964 } 1965 if (geteuid() != 0) { 1966 XP_SKIP("Must be run as a privileged user"); 1967 return; 1968 } 1969 1970 /* Get current multiuser mode (and save it) */ 1971 snprintf(mibname, sizeof(mibname), "hw.%s.multiuser", devicename); 1972 oldlen = sizeof(oldval); 1973 r = SYSCTLBYNAME(mibname, &oldval, &oldlen, NULL, 0); 1974 REQUIRED_SYS_EQ(0, r); 1975 DPRINTF(" > multiuser=%d\n", oldval); 1976 1977 /* Change if necessary */ 1978 if (oldval != multiuser) { 1979 r = SYSCTLBYNAME(mibname, NULL, NULL, &multiuser, 1980 sizeof(multiuser)); 1981 REQUIRED_SYS_EQ(0, r); 1982 DPRINTF(" > new multiuser=%d\n", multiuser); 1983 } 1984 1985 /* Do test */ 1986 try_open_multiuser(multiuser); 1987 1988 /* Restore multiuser mode */ 1989 if (oldval != multiuser) { 1990 DPRINTF(" > restore multiuser to %d\n", oldval); 1991 r = SYSCTLBYNAME(mibname, NULL, NULL, &oldval, sizeof(oldval)); 1992 REQUIRED_SYS_EQ(0, r); 1993 } 1994 } 1995 DEF(open_multiuser_0) { test_open_multiuser(false); } 1996 DEF(open_multiuser_1) { test_open_multiuser(true); } 1997 1998 /* 1999 * Normal playback (with PLAY_ALL). 2000 * It does not verify real playback data. 2001 */ 2002 DEF(write_PLAY_ALL) 2003 { 2004 char buf[8000]; 2005 int fd; 2006 int r; 2007 2008 TEST("write_PLAY_ALL"); 2009 2010 fd = OPEN(devaudio, O_WRONLY); 2011 if (hw_canplay()) { 2012 REQUIRED_SYS_OK(fd); 2013 } else { 2014 XP_SYS_NG(ENXIO, fd); 2015 return; 2016 } 2017 2018 /* mulaw 1sec silence */ 2019 memset(buf, 0xff, sizeof(buf)); 2020 r = WRITE(fd, buf, sizeof(buf)); 2021 XP_SYS_EQ(sizeof(buf), r); 2022 2023 r = CLOSE(fd); 2024 XP_SYS_EQ(0, r); 2025 } 2026 2027 /* 2028 * Normal playback (without PLAY_ALL). 2029 * It does not verify real playback data. 2030 */ 2031 DEF(write_PLAY) 2032 { 2033 struct audio_info ai; 2034 char *wav; 2035 int wavsize; 2036 int totalsize; 2037 int fd; 2038 int r; 2039 2040 TEST("write_PLAY"); 2041 2042 fd = OPEN(devaudio, O_WRONLY); 2043 if (hw_canplay()) { 2044 REQUIRED_SYS_OK(fd); 2045 } else { 2046 XP_SYS_NG(ENXIO, fd); 2047 return; 2048 } 2049 2050 /* Drop PLAY_ALL */ 2051 AUDIO_INITINFO(&ai); 2052 ai.mode = AUMODE_PLAY; 2053 r = IOCTL(fd, AUDIO_SETINFO, &ai, "mode"); 2054 REQUIRED_SYS_EQ(0, r); 2055 2056 /* Check mode and get blocksize */ 2057 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 2058 REQUIRED_SYS_EQ(0, r); 2059 XP_EQ(AUMODE_PLAY, ai.mode); 2060 2061 wavsize = ai.blocksize; 2062 wav = (char *)malloc(wavsize); 2063 REQUIRED_IF(wav != NULL); 2064 memset(wav, 0xff, wavsize); 2065 2066 /* Write blocks until 1sec */ 2067 for (totalsize = 0; totalsize < 8000; ) { 2068 r = WRITE(fd, wav, wavsize); 2069 XP_SYS_EQ(wavsize, r); 2070 if (r == -1) 2071 break; /* XXX */ 2072 totalsize += r; 2073 } 2074 2075 /* XXX What should I test it? */ 2076 /* Check ai.play.error */ 2077 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 2078 REQUIRED_SYS_EQ(0, r); 2079 XP_EQ(0, ai.play.error); 2080 2081 /* Playback data is no longer necessary */ 2082 r = IOCTL(fd, AUDIO_FLUSH, NULL, ""); 2083 REQUIRED_SYS_EQ(0, r); 2084 2085 r = CLOSE(fd); 2086 REQUIRED_SYS_EQ(0, r); 2087 2088 free(wav); 2089 } 2090 2091 /* 2092 * Normal recording. 2093 * It does not verify real recorded data. 2094 */ 2095 DEF(read) 2096 { 2097 char buf[8000]; 2098 int fd; 2099 int r; 2100 2101 TEST("read"); 2102 2103 fd = OPEN(devaudio, O_RDONLY); 2104 if (hw_canrec()) { 2105 REQUIRED_SYS_OK(fd); 2106 } else { 2107 XP_SYS_NG(ENXIO, fd); 2108 return; 2109 } 2110 2111 /* mulaw 1sec */ 2112 r = READ(fd, buf, sizeof(buf)); 2113 XP_SYS_EQ(sizeof(buf), r); 2114 2115 r = CLOSE(fd); 2116 XP_SYS_EQ(0, r); 2117 } 2118 2119 /* 2120 * Repeat open-write-close cycle. 2121 */ 2122 DEF(rept_write) 2123 { 2124 struct timeval start, end, result; 2125 double res; 2126 char buf[8000]; /* 1sec in 8bit-mulaw,1ch,8000Hz */ 2127 int fd; 2128 int r; 2129 int n; 2130 2131 TEST("rept_write"); 2132 2133 if (hw_canplay() == 0) { 2134 XP_SKIP("This test is only for playable device"); 2135 return; 2136 } 2137 2138 /* XXX It may timeout on some hardware driver. */ 2139 XP_SKIP("not yet"); 2140 return; 2141 2142 memset(buf, 0xff, sizeof(buf)); 2143 n = 3; 2144 gettimeofday(&start, NULL); 2145 for (int i = 0; i < n; i++) { 2146 fd = OPEN(devaudio, O_WRONLY); 2147 REQUIRED_SYS_OK(fd); 2148 2149 r = WRITE(fd, buf, sizeof(buf)); 2150 XP_SYS_EQ(sizeof(buf), r); 2151 2152 r = CLOSE(fd); 2153 XP_SYS_EQ(0, r); 2154 } 2155 gettimeofday(&end, NULL); 2156 timersub(&end, &start, &result); 2157 res = (double)result.tv_sec + (double)result.tv_usec / 1000000; 2158 /* Make judgement but not too strict */ 2159 if (res >= n * 1.5) { 2160 XP_FAIL("expects %d sec but %4.1f sec", n, res); 2161 return; 2162 } 2163 } 2164 2165 /* 2166 * Repeat open-read-close cycle. 2167 */ 2168 DEF(rept_read) 2169 { 2170 struct timeval start, end, result; 2171 double res; 2172 char buf[8000]; /* 1sec in 8bit-mulaw,1ch,8000Hz */ 2173 int fd; 2174 int r; 2175 int n; 2176 2177 TEST("rept_read"); 2178 2179 if (hw_canrec() == 0) { 2180 XP_SKIP("This test is only for recordable device"); 2181 return; 2182 } 2183 2184 /* XXX It may timeout on some hardware driver. */ 2185 XP_SKIP("not yet"); 2186 return; 2187 2188 n = 3; 2189 gettimeofday(&start, NULL); 2190 for (int i = 0; i < n; i++) { 2191 fd = OPEN(devaudio, O_RDONLY); 2192 REQUIRED_SYS_OK(fd); 2193 2194 r = READ(fd, buf, sizeof(buf)); 2195 XP_SYS_EQ(sizeof(buf), r); 2196 2197 r = CLOSE(fd); 2198 XP_SYS_EQ(0, r); 2199 } 2200 gettimeofday(&end, NULL); 2201 timersub(&end, &start, &result); 2202 res = (double)result.tv_sec + (double)result.tv_usec / 1000000; 2203 /* Make judgement but not too strict */ 2204 if (res >= n * 1.5) { 2205 XP_FAIL("expects %d sec but %4.1f sec", n, res); 2206 return; 2207 } 2208 } 2209 2210 /* 2211 * Opening with O_RDWR on half-duplex hardware falls back to O_WRONLY. 2212 * expwrite: expected to be able to play. 2213 * expread : expected to be able to recored. 2214 */ 2215 void 2216 test_rdwr_fallback(int openmode, bool expwrite, bool expread) 2217 { 2218 struct audio_info ai; 2219 char buf[10]; 2220 int fd; 2221 int r; 2222 2223 TEST("rdwr_fallback_%s", openmode_str[openmode] + 2); 2224 2225 if (hw_bidir() == 0) { 2226 XP_SKIP("This test is only for bi-directional device"); 2227 return; 2228 } 2229 2230 AUDIO_INITINFO(&ai); 2231 ai.play.pause = 1; 2232 ai.record.pause = 1; 2233 2234 fd = OPEN(devaudio, openmode); 2235 REQUIRED_SYS_OK(fd); 2236 2237 /* Set pause not to play noise */ 2238 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause"); 2239 REQUIRED_SYS_EQ(0, r); 2240 2241 memset(buf, 0xff, sizeof(buf)); 2242 r = WRITE(fd, buf, sizeof(buf)); 2243 if (expwrite) { 2244 XP_SYS_EQ(sizeof(buf), r); 2245 } else { 2246 XP_SYS_NG(EBADF, r); 2247 } 2248 2249 r = READ(fd, buf, 0); 2250 if (expread) { 2251 XP_SYS_EQ(0, r); 2252 } else { 2253 XP_SYS_NG(EBADF, r); 2254 } 2255 2256 r = CLOSE(fd); 2257 REQUIRED_SYS_EQ(0, r); 2258 } 2259 DEF(rdwr_fallback_RDONLY) { test_rdwr_fallback(O_RDONLY, false, true); } 2260 DEF(rdwr_fallback_WRONLY) { test_rdwr_fallback(O_WRONLY, true, false); } 2261 DEF(rdwr_fallback_RDWR) { 2262 bool expread; 2263 /* 2264 * On NetBSD7, O_RDWR on half-duplex is accepted. It's possible to 2265 * read and write if they don't occur at the same time. 2266 * On NetBSD9, O_RDWR on half-duplex falls back O_WRONLY. 2267 */ 2268 if (netbsd < 8) { 2269 expread = true; 2270 } else { 2271 expread = hw_fulldup() ? true : false; 2272 } 2273 test_rdwr_fallback(O_RDWR, true, expread); 2274 } 2275 2276 /* 2277 * On full-duplex hardware, the second descriptor's readablity/writability 2278 * is not depend on the first descriptor('s open mode). 2279 * On half-duplex hardware, it depends on the first descriptor's open mode. 2280 */ 2281 void 2282 test_rdwr_two(int mode0, int mode1) 2283 { 2284 struct audio_info ai; 2285 char wbuf[100]; /* 1/80sec in 8bit-mulaw,1ch,8000Hz */ 2286 char rbuf[100]; /* 1/80sec in 8bit-mulaw,1ch,8000Hz */ 2287 bool canopen; 2288 bool canwrite; 2289 bool canread; 2290 int fd0; 2291 int fd1; 2292 int r; 2293 struct { 2294 bool canopen; 2295 bool canwrite; 2296 bool canread; 2297 } exptable_full[] = { 2298 /* open write read 1st, 2nd mode */ 2299 { 1, 0, 1 }, /* REC, REC */ 2300 { 1, 1, 0 }, /* REC, PLAY */ 2301 { 1, 1, 1 }, /* REC, BOTH */ 2302 { 1, 0, 1 }, /* PLAY, REC */ 2303 { 1, 1, 0 }, /* PLAY, PLAY */ 2304 { 1, 1, 1 }, /* PLAY, BOTH */ 2305 { 1, 0, 1 }, /* BOTH, REC */ 2306 { 1, 1, 0 }, /* BOTH, PLAY */ 2307 { 1, 1, 1 }, /* BOTH, BOTH */ 2308 }, 2309 exptable_half[] = { 2310 { 1, 0, 1 }, /* REC, REC */ 2311 { 0, 0, 0 }, /* REC, PLAY */ 2312 { 0, 0, 0 }, /* REC, BOTH */ 2313 { 0, 0, 0 }, /* PLAY, REC */ 2314 { 1, 1, 0 }, /* PLAY, PLAY */ 2315 { 1, 1, 0 }, /* PLAY, BOTH */ 2316 { 0, 0, 0 }, /* BOTH, REC */ 2317 { 1, 1, 0 }, /* BOTH, PLAY */ 2318 { 0, 0, 0 }, /* BOTH, BOTH */ 2319 }, *exptable; 2320 2321 TEST("rdwr_two_%s_%s", 2322 openmode_str[mode0] + 2, 2323 openmode_str[mode1] + 2); 2324 2325 if (netbsd < 8) { 2326 XP_SKIP("Multiple open is not supported"); 2327 return; 2328 } 2329 if (hw_bidir() == 0) { 2330 XP_SKIP("This test is only for bi-directional device"); 2331 return; 2332 } 2333 2334 exptable = hw_fulldup() ? exptable_full : exptable_half; 2335 2336 canopen = exptable[mode0 * 3 + mode1].canopen; 2337 canwrite = exptable[mode0 * 3 + mode1].canwrite; 2338 canread = exptable[mode0 * 3 + mode1].canread; 2339 2340 if (!canopen) { 2341 XP_SKIP("This combination is not openable on half-duplex"); 2342 return; 2343 } 2344 2345 fd0 = OPEN(devaudio, mode0); 2346 REQUIRED_SYS_OK(fd0); 2347 2348 fd1 = OPEN(devaudio, mode1); 2349 REQUIRED_SYS_OK(fd1); 2350 2351 /* Silent data to make no sound */ 2352 memset(&wbuf, 0xff, sizeof(wbuf)); 2353 /* Pause to make no sound */ 2354 AUDIO_INITINFO(&ai); 2355 ai.play.pause = 1; 2356 r = IOCTL(fd0, AUDIO_SETINFO, &ai, "pause"); 2357 XP_SYS_EQ(0, r); 2358 2359 /* write(fd1) */ 2360 r = WRITE(fd1, wbuf, sizeof(wbuf)); 2361 if (canwrite) { 2362 XP_SYS_EQ(100, r); 2363 } else { 2364 XP_SYS_NG(EBADF, r); 2365 } 2366 2367 /* read(fd1) */ 2368 r = READ(fd1, rbuf, sizeof(rbuf)); 2369 if (canread) { 2370 XP_SYS_EQ(100, r); 2371 } else { 2372 XP_SYS_NG(EBADF, r); 2373 } 2374 2375 r = CLOSE(fd0); 2376 XP_SYS_EQ(0, r); 2377 r = CLOSE(fd1); 2378 XP_SYS_EQ(0, r); 2379 } 2380 DEF(rdwr_two_RDONLY_RDONLY) { test_rdwr_two(O_RDONLY, O_RDONLY); } 2381 DEF(rdwr_two_RDONLY_WRONLY) { test_rdwr_two(O_RDONLY, O_WRONLY); } 2382 DEF(rdwr_two_RDONLY_RDWR) { test_rdwr_two(O_RDONLY, O_RDWR); } 2383 DEF(rdwr_two_WRONLY_RDONLY) { test_rdwr_two(O_WRONLY, O_RDONLY); } 2384 DEF(rdwr_two_WRONLY_WRONLY) { test_rdwr_two(O_WRONLY, O_WRONLY); } 2385 DEF(rdwr_two_WRONLY_RDWR) { test_rdwr_two(O_WRONLY, O_RDWR); } 2386 DEF(rdwr_two_RDWR_RDONLY) { test_rdwr_two(O_RDWR, O_RDONLY); } 2387 DEF(rdwr_two_RDWR_WRONLY) { test_rdwr_two(O_RDWR, O_WRONLY); } 2388 DEF(rdwr_two_RDWR_RDWR) { test_rdwr_two(O_RDWR, O_RDWR); } 2389 2390 /* 2391 * Read and write different descriptors simultaneously. 2392 * Only on full-duplex. 2393 */ 2394 DEF(rdwr_simul) 2395 { 2396 char wbuf[1000]; /* 1/8sec in mulaw,1ch,8kHz */ 2397 char rbuf[1000]; 2398 int fd0; 2399 int fd1; 2400 int r; 2401 int status; 2402 pid_t pid; 2403 2404 TEST("rdwr_simul"); 2405 if (netbsd < 8) { 2406 XP_SKIP("Multiple open is not supported"); 2407 return; 2408 } 2409 if (!hw_fulldup()) { 2410 XP_SKIP("This test is only for full-duplex device"); 2411 return; 2412 } 2413 2414 /* Silence data to make no sound */ 2415 memset(wbuf, 0xff, sizeof(wbuf)); 2416 2417 fd0 = OPEN(devaudio, O_WRONLY); 2418 REQUIRED_SYS_OK(fd0); 2419 fd1 = OPEN(devaudio, O_RDONLY); 2420 REQUIRED_SYS_OK(fd1); 2421 2422 fflush(stdout); 2423 fflush(stderr); 2424 pid = fork(); 2425 if (pid == -1) 2426 xp_err(1, __LINE__, "fork"); 2427 2428 if (pid == 0) { 2429 /* child (read) */ 2430 for (int i = 0; i < 10; i++) { 2431 r = READ(fd1, rbuf, sizeof(rbuf)); 2432 if (r == -1) 2433 xp_err(1, __LINE__, "read(i=%d)", i); 2434 } 2435 exit(0); 2436 } else { 2437 /* parent (write) */ 2438 for (int i = 0; i < 10; i++) { 2439 r = WRITE(fd0, wbuf, sizeof(wbuf)); 2440 if (r == -1) 2441 xp_err(1, __LINE__, "write(i=%d)", i); 2442 } 2443 waitpid(pid, &status, 0); 2444 } 2445 2446 CLOSE(fd0); 2447 CLOSE(fd1); 2448 /* If you reach here, consider as success */ 2449 XP_EQ(0, 0); 2450 } 2451 2452 /* 2453 * DRAIN should work even on incomplete data left. 2454 */ 2455 DEF(drain_incomplete) 2456 { 2457 struct audio_info ai; 2458 int r; 2459 int fd; 2460 2461 TEST("drain_incomplete"); 2462 2463 if (hw_canplay() == 0) { 2464 XP_SKIP("This test is only for playable device"); 2465 return; 2466 } 2467 2468 fd = OPEN(devaudio, O_WRONLY); 2469 REQUIRED_SYS_OK(fd); 2470 2471 AUDIO_INITINFO(&ai); 2472 /* let precision > 8 */ 2473 ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE; 2474 ai.play.precision = 16; 2475 ai.mode = AUMODE_PLAY; 2476 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 2477 REQUIRED_SYS_EQ(0, r); 2478 /* Write one byte and then close */ 2479 r = WRITE(fd, &r, 1); 2480 XP_SYS_EQ(1, r); 2481 r = CLOSE(fd); 2482 XP_SYS_EQ(0, r); 2483 } 2484 2485 /* 2486 * DRAIN should work even in pause. 2487 */ 2488 DEF(drain_pause) 2489 { 2490 struct audio_info ai; 2491 int r; 2492 int fd; 2493 2494 TEST("drain_pause"); 2495 2496 if (hw_canplay() == 0) { 2497 XP_SKIP("This test is only for playable device"); 2498 return; 2499 } 2500 2501 fd = OPEN(devaudio, O_WRONLY); 2502 REQUIRED_SYS_OK(fd); 2503 2504 /* Set pause */ 2505 AUDIO_INITINFO(&ai); 2506 ai.play.pause = 1; 2507 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 2508 XP_SYS_EQ(0, r); 2509 /* Write some data and then close */ 2510 r = WRITE(fd, &r, 4); 2511 XP_SYS_EQ(4, r); 2512 r = CLOSE(fd); 2513 XP_SYS_EQ(0, r); 2514 } 2515 2516 /* 2517 * DRAIN does not affect for record-only descriptor. 2518 */ 2519 DEF(drain_onrec) 2520 { 2521 int fd; 2522 int r; 2523 2524 TEST("drain_onrec"); 2525 2526 if (hw_canrec() == 0) { 2527 XP_SKIP("This test is only for recordable device"); 2528 return; 2529 } 2530 2531 fd = OPEN(devaudio, O_RDONLY); 2532 REQUIRED_SYS_OK(fd); 2533 2534 r = IOCTL(fd, AUDIO_DRAIN, NULL, ""); 2535 XP_SYS_EQ(0, r); 2536 2537 r = CLOSE(fd); 2538 XP_SYS_EQ(0, r); 2539 } 2540 2541 /* 2542 * Whether mmap() succeeds with specified parameter. 2543 */ 2544 void 2545 test_mmap_mode(int mode, int prot) 2546 { 2547 char buf[10]; 2548 struct audio_info ai; 2549 const char *protstr; 2550 int expected; 2551 int fd; 2552 int r; 2553 int len; 2554 void *ptr; 2555 2556 if (prot == PROT_NONE) { 2557 protstr = "NONE"; 2558 } else if (prot == PROT_READ) { 2559 protstr = "READ"; 2560 } else if (prot == PROT_WRITE) { 2561 protstr = "WRITE"; 2562 } else if (prot == (PROT_READ | PROT_WRITE)) { 2563 protstr = "READWRITE"; 2564 } else { 2565 xp_errx(1, __LINE__, "unknown prot %x\n", prot); 2566 } 2567 TEST("mmap_%s_%s", openmode_str[mode] + 2, protstr); 2568 if ((props & AUDIO_PROP_MMAP) == 0) { 2569 XP_SKIP("This test is only for mmap-able device"); 2570 return; 2571 } 2572 if (mode2aumode(mode) == 0) { 2573 XP_SKIP("Operation not allowed on this hardware property"); 2574 return; 2575 } 2576 #if !defined(NO_RUMP) 2577 if (use_rump) { 2578 XP_SKIP("rump doesn't support mmap"); 2579 return; 2580 } 2581 #endif 2582 2583 /* 2584 * On NetBSD7 and 8, mmap() always succeeds regardless of open mode. 2585 * On NetBSD9, mmap() succeeds only for writable descriptor. 2586 */ 2587 expected = mode2play(mode); 2588 if (netbsd < 9) { 2589 expected = true; 2590 } 2591 2592 fd = OPEN(devaudio, mode); 2593 REQUIRED_SYS_OK(fd); 2594 2595 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "get"); 2596 REQUIRED_SYS_EQ(0, r); 2597 2598 len = ai.play.buffer_size; 2599 2600 /* Make it pause */ 2601 AUDIO_INITINFO(&ai); 2602 ai.play.pause = 1; 2603 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause"); 2604 REQUIRED_SYS_EQ(0, r); 2605 2606 ptr = MMAP(NULL, len, prot, MAP_FILE, fd, 0); 2607 XP_SYS_PTR(expected ? 0 : EACCES, ptr); 2608 if (expected) { 2609 /* XXX Doing mmap(2) doesn't inhibit read(2) */ 2610 if (mode2rec(mode)) { 2611 r = READ(fd, buf, 0); 2612 XP_SYS_EQ(0, r); 2613 } 2614 /* Doing mmap(2) inhibits write(2) */ 2615 if (mode2play(mode)) { 2616 /* NetBSD9 changes errno */ 2617 r = WRITE(fd, buf, 0); 2618 if (netbsd < 9) { 2619 XP_SYS_NG(EINVAL, r); 2620 } else { 2621 XP_SYS_NG(EPERM, r); 2622 } 2623 } 2624 } 2625 if (ptr != MAP_FAILED) { 2626 r = MUNMAP(ptr, len); 2627 XP_SYS_EQ(0, r); 2628 } 2629 2630 /* Whether the pause is still valid */ 2631 if (mode2play(mode)) { 2632 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 2633 XP_SYS_EQ(0, r); 2634 XP_EQ(1, ai.play.pause); 2635 } 2636 2637 r = CLOSE(fd); 2638 XP_SYS_EQ(0, r); 2639 2640 reset_after_mmap(); 2641 } 2642 #define PROT_READWRITE (PROT_READ | PROT_WRITE) 2643 DEF(mmap_mode_RDONLY_NONE) { test_mmap_mode(O_RDONLY, PROT_NONE); } 2644 DEF(mmap_mode_RDONLY_READ) { test_mmap_mode(O_RDONLY, PROT_READ); } 2645 DEF(mmap_mode_RDONLY_WRITE) { test_mmap_mode(O_RDONLY, PROT_WRITE); } 2646 DEF(mmap_mode_RDONLY_READWRITE) { test_mmap_mode(O_RDONLY, PROT_READWRITE); } 2647 DEF(mmap_mode_WRONLY_NONE) { test_mmap_mode(O_WRONLY, PROT_NONE); } 2648 DEF(mmap_mode_WRONLY_READ) { test_mmap_mode(O_WRONLY, PROT_READ); } 2649 DEF(mmap_mode_WRONLY_WRITE) { test_mmap_mode(O_WRONLY, PROT_WRITE); } 2650 DEF(mmap_mode_WRONLY_READWRITE) { test_mmap_mode(O_WRONLY, PROT_READWRITE); } 2651 DEF(mmap_mode_RDWR_NONE) { test_mmap_mode(O_RDWR, PROT_NONE); } 2652 DEF(mmap_mode_RDWR_READ) { test_mmap_mode(O_RDWR, PROT_READ); } 2653 DEF(mmap_mode_RDWR_WRITE) { test_mmap_mode(O_RDWR, PROT_WRITE); } 2654 DEF(mmap_mode_RDWR_READWRITE) { test_mmap_mode(O_RDWR, PROT_READWRITE); } 2655 2656 /* 2657 * Check mmap()'s length and offset. 2658 */ 2659 DEF(mmap_len) 2660 { 2661 struct audio_info ai; 2662 int fd; 2663 int r; 2664 size_t len; 2665 off_t offset; 2666 void *ptr; 2667 int bufsize; 2668 int pagesize; 2669 int lsize; 2670 2671 TEST("mmap_len"); 2672 if ((props & AUDIO_PROP_MMAP) == 0) { 2673 XP_SKIP("This test is only for mmap-able device"); 2674 return; 2675 } 2676 #if !defined(NO_RUMP) 2677 if (use_rump) { 2678 XP_SKIP("rump doesn't support mmap"); 2679 return; 2680 } 2681 #endif 2682 2683 len = sizeof(pagesize); 2684 r = SYSCTLBYNAME("hw.pagesize", &pagesize, &len, NULL, 0); 2685 REQUIRED_SYS_EQ(0, r); 2686 2687 fd = OPEN(devaudio, O_WRONLY); 2688 REQUIRED_SYS_OK(r); 2689 2690 /* Get buffer_size */ 2691 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 2692 REQUIRED_SYS_EQ(0, r); 2693 bufsize = ai.play.buffer_size; 2694 2695 /* 2696 * XXX someone refers bufsize and another one does pagesize. 2697 * I'm not sure. 2698 */ 2699 lsize = roundup2(bufsize, pagesize); 2700 struct { 2701 size_t len; 2702 off_t offset; 2703 int exp; 2704 } table[] = { 2705 /* len offset expected */ 2706 2707 { 0, 0, 0 }, /* len is 0 */ 2708 { 1, 0, 0 }, /* len is smaller than lsize */ 2709 { lsize, 0, 0 }, /* len is the same as lsize */ 2710 { lsize + 1, 0, EOVERFLOW }, /* len is larger */ 2711 2712 { 0, -1, EINVAL }, /* offset is negative */ 2713 { 0, lsize, 0 }, /* pointless param but ok */ 2714 { 0, lsize + 1, EOVERFLOW }, /* exceed */ 2715 { 1, lsize, EOVERFLOW }, /* exceed */ 2716 2717 /* 2718 * When you treat offset as 32bit, offset will be 0 2719 * and thus it incorrectly succeeds. 2720 */ 2721 { lsize, 1ULL<<32, EOVERFLOW }, 2722 }; 2723 2724 for (int i = 0; i < (int)__arraycount(table); i++) { 2725 len = table[i].len; 2726 offset = table[i].offset; 2727 int exp = table[i].exp; 2728 2729 ptr = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd, offset); 2730 if (exp == 0) { 2731 XP_SYS_PTR(0, ptr); 2732 } else { 2733 /* NetBSD8 introduces EOVERFLOW */ 2734 if (netbsd < 8 && exp == EOVERFLOW) 2735 exp = EINVAL; 2736 XP_SYS_PTR(exp, ptr); 2737 } 2738 2739 if (ptr != MAP_FAILED) { 2740 r = MUNMAP(ptr, len); 2741 XP_SYS_EQ(0, r); 2742 } 2743 } 2744 2745 r = CLOSE(fd); 2746 XP_SYS_EQ(0, r); 2747 2748 reset_after_mmap(); 2749 } 2750 2751 /* 2752 * mmap() the same descriptor twice. 2753 */ 2754 DEF(mmap_twice) 2755 { 2756 struct audio_info ai; 2757 int fd; 2758 int r; 2759 int len; 2760 void *ptr1; 2761 void *ptr2; 2762 2763 TEST("mmap_twice"); 2764 if ((props & AUDIO_PROP_MMAP) == 0) { 2765 XP_SKIP("This test is only for mmap-able device"); 2766 return; 2767 } 2768 #if !defined(NO_RUMP) 2769 if (use_rump) { 2770 XP_SKIP("rump doesn't support mmap"); 2771 return; 2772 } 2773 #endif 2774 2775 fd = OPEN(devaudio, O_WRONLY); 2776 REQUIRED_SYS_OK(fd); 2777 2778 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "get"); 2779 REQUIRED_SYS_EQ(0, r); 2780 len = ai.play.buffer_size; 2781 2782 ptr1 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd, 0); 2783 XP_SYS_PTR(0, ptr1); 2784 2785 /* XXX I'm not sure this sucess is intended. Anyway I follow it */ 2786 ptr2 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd, 0); 2787 XP_SYS_PTR(0, ptr2); 2788 2789 if (ptr2 != MAP_FAILED) { 2790 r = MUNMAP(ptr2, len); 2791 XP_SYS_EQ(0, r); 2792 } 2793 if (ptr1 != MAP_FAILED) { 2794 r = MUNMAP(ptr1, len); 2795 XP_SYS_EQ(0, r); 2796 } 2797 2798 r = CLOSE(fd); 2799 XP_SYS_EQ(0, r); 2800 2801 reset_after_mmap(); 2802 } 2803 2804 /* 2805 * mmap() different descriptors. 2806 */ 2807 DEF(mmap_multi) 2808 { 2809 struct audio_info ai; 2810 int fd0; 2811 int fd1; 2812 int r; 2813 int len; 2814 void *ptr0; 2815 void *ptr1; 2816 2817 TEST("mmap_multi"); 2818 if (netbsd < 8) { 2819 XP_SKIP("Multiple open is not supported"); 2820 return; 2821 } 2822 if ((props & AUDIO_PROP_MMAP) == 0) { 2823 XP_SKIP("This test is only for mmap-able device"); 2824 return; 2825 } 2826 #if !defined(NO_RUMP) 2827 if (use_rump) { 2828 XP_SKIP("rump doesn't support mmap"); 2829 return; 2830 } 2831 #endif 2832 2833 fd0 = OPEN(devaudio, O_WRONLY); 2834 REQUIRED_SYS_OK(fd0); 2835 2836 r = IOCTL(fd0, AUDIO_GETBUFINFO, &ai, "get"); 2837 REQUIRED_SYS_EQ(0, r); 2838 len = ai.play.buffer_size; 2839 2840 fd1 = OPEN(devaudio, O_WRONLY); 2841 REQUIRED_SYS_OK(fd1); 2842 2843 ptr0 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd0, 0); 2844 XP_SYS_PTR(0, ptr0); 2845 2846 ptr1 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd1, 0); 2847 XP_SYS_PTR(0, ptr1); 2848 2849 if (ptr0 != MAP_FAILED) { 2850 r = MUNMAP(ptr1, len); 2851 XP_SYS_EQ(0, r); 2852 } 2853 2854 r = CLOSE(fd1); 2855 XP_SYS_EQ(0, r); 2856 2857 if (ptr1 != MAP_FAILED) { 2858 r = MUNMAP(ptr0, len); 2859 XP_SYS_EQ(0, r); 2860 } 2861 2862 r = CLOSE(fd0); 2863 XP_SYS_EQ(0, r); 2864 2865 reset_after_mmap(); 2866 } 2867 2868 #define IN POLLIN 2869 #define OUT POLLOUT 2870 /* 2871 * Whether poll() succeeds with specified mode. 2872 */ 2873 void 2874 test_poll_mode(int mode, int events, int expected_revents) 2875 { 2876 struct pollfd pfd; 2877 const char *events_str; 2878 int fd; 2879 int r; 2880 int expected_r; 2881 2882 if (events == IN) { 2883 events_str = "IN"; 2884 } else if (events == OUT) { 2885 events_str = "OUT"; 2886 } else if (events == (IN | OUT)) { 2887 events_str = "INOUT"; 2888 } else { 2889 events_str = "?"; 2890 } 2891 TEST("poll_mode_%s_%s", openmode_str[mode] + 2, events_str); 2892 if (mode2aumode(mode) == 0) { 2893 XP_SKIP("Operation not allowed on this hardware property"); 2894 return; 2895 } 2896 2897 expected_r = (expected_revents != 0) ? 1 : 0; 2898 2899 fd = OPEN(devaudio, mode); 2900 REQUIRED_SYS_OK(fd); 2901 2902 memset(&pfd, 0, sizeof(pfd)); 2903 pfd.fd = fd; 2904 pfd.events = events; 2905 2906 r = POLL(&pfd, 1, 100); 2907 /* It's a bit complicated.. */ 2908 if (r < 0 || r > 1) { 2909 /* 2910 * Check these two cases first: 2911 * - system call fails. 2912 * - poll() with one nfds returns >1. It's strange. 2913 */ 2914 XP_SYS_EQ(expected_r, r); 2915 } else { 2916 /* 2917 * Otherwise, poll() returned 0 or 1. 2918 */ 2919 DPRINTF(" > pfd.revents=%s\n", event_tostr(pfd.revents)); 2920 2921 /* NetBSD7,8 have several strange behavior. It must be bug. */ 2922 2923 XP_SYS_EQ(expected_r, r); 2924 XP_EQ(expected_revents, pfd.revents); 2925 } 2926 r = CLOSE(fd); 2927 XP_SYS_EQ(0, r); 2928 } 2929 DEF(poll_mode_RDONLY_IN) { test_poll_mode(O_RDONLY, IN, 0); } 2930 DEF(poll_mode_RDONLY_OUT) { test_poll_mode(O_RDONLY, OUT, 0); } 2931 DEF(poll_mode_RDONLY_INOUT) { test_poll_mode(O_RDONLY, IN|OUT, 0); } 2932 DEF(poll_mode_WRONLY_IN) { test_poll_mode(O_WRONLY, IN, 0); } 2933 DEF(poll_mode_WRONLY_OUT) { test_poll_mode(O_WRONLY, OUT, OUT); } 2934 DEF(poll_mode_WRONLY_INOUT) { test_poll_mode(O_WRONLY, IN|OUT, OUT); } 2935 DEF(poll_mode_RDWR_IN) { test_poll_mode(O_RDWR, IN, 0); } 2936 DEF(poll_mode_RDWR_OUT) { test_poll_mode(O_RDWR, OUT, OUT); } 2937 DEF(poll_mode_RDWR_INOUT) { test_poll_mode(O_RDWR, IN|OUT, OUT); } 2938 2939 /* 2940 * Poll(OUT) when buffer is empty. 2941 */ 2942 DEF(poll_out_empty) 2943 { 2944 struct pollfd pfd; 2945 int fd; 2946 int r; 2947 2948 TEST("poll_out_empty"); 2949 2950 fd = OPEN(devaudio, O_WRONLY); 2951 REQUIRED_SYS_OK(fd); 2952 2953 memset(&pfd, 0, sizeof(pfd)); 2954 pfd.fd = fd; 2955 pfd.events = POLLOUT; 2956 2957 /* Check when empty. It should succeed even if timeout == 0 */ 2958 r = POLL(&pfd, 1, 0); 2959 XP_SYS_EQ(1, r); 2960 XP_EQ(POLLOUT, pfd.revents); 2961 2962 r = CLOSE(fd); 2963 XP_SYS_EQ(0, r); 2964 } 2965 2966 /* 2967 * Poll(OUT) when buffer is full. 2968 */ 2969 DEF(poll_out_full) 2970 { 2971 struct audio_info ai; 2972 struct pollfd pfd; 2973 int fd; 2974 int r; 2975 char *buf; 2976 int buflen; 2977 2978 TEST("poll_out_full"); 2979 2980 fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 2981 REQUIRED_SYS_OK(fd); 2982 2983 /* Pause */ 2984 AUDIO_INITINFO(&ai); 2985 ai.play.pause = 1; 2986 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 2987 XP_SYS_EQ(0, r); 2988 2989 /* Get buffer size */ 2990 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 2991 XP_SYS_EQ(0, r); 2992 2993 /* Write until full */ 2994 buflen = ai.play.buffer_size; 2995 buf = (char *)malloc(buflen); 2996 REQUIRED_IF(buf != NULL); 2997 memset(buf, 0xff, buflen); 2998 do { 2999 r = WRITE(fd, buf, buflen); 3000 } while (r == buflen); 3001 if (r == -1) { 3002 XP_SYS_NG(EAGAIN, r); 3003 } 3004 3005 /* Do poll */ 3006 memset(&pfd, 0, sizeof(pfd)); 3007 pfd.fd = fd; 3008 pfd.events = POLLOUT; 3009 r = POLL(&pfd, 1, 0); 3010 XP_SYS_EQ(0, r); 3011 XP_EQ(0, pfd.revents); 3012 3013 r = CLOSE(fd); 3014 XP_SYS_EQ(0, r); 3015 free(buf); 3016 } 3017 3018 /* 3019 * Poll(OUT) when buffer is full but hiwat sets lower than full. 3020 */ 3021 DEF(poll_out_hiwat) 3022 { 3023 struct audio_info ai; 3024 struct pollfd pfd; 3025 int fd; 3026 int r; 3027 char *buf; 3028 int buflen; 3029 int newhiwat; 3030 3031 TEST("poll_out_hiwat"); 3032 3033 fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3034 REQUIRED_SYS_OK(fd); 3035 3036 /* Get buffer size and hiwat */ 3037 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3038 XP_SYS_EQ(0, r); 3039 /* Change hiwat some different value */ 3040 newhiwat = ai.lowat; 3041 3042 /* Set pause and hiwat */ 3043 AUDIO_INITINFO(&ai); 3044 ai.play.pause = 1; 3045 ai.hiwat = newhiwat; 3046 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1;hiwat"); 3047 XP_SYS_EQ(0, r); 3048 3049 /* Get the set hiwat again */ 3050 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3051 XP_SYS_EQ(0, r); 3052 3053 /* Write until full */ 3054 buflen = ai.blocksize * ai.hiwat; 3055 buf = (char *)malloc(buflen); 3056 REQUIRED_IF(buf != NULL); 3057 memset(buf, 0xff, buflen); 3058 do { 3059 r = WRITE(fd, buf, buflen); 3060 } while (r == buflen); 3061 if (r == -1) { 3062 XP_SYS_NG(EAGAIN, r); 3063 } 3064 3065 /* Do poll */ 3066 memset(&pfd, 0, sizeof(pfd)); 3067 pfd.fd = fd; 3068 pfd.events = POLLOUT; 3069 r = POLL(&pfd, 1, 0); 3070 XP_SYS_EQ(0, r); 3071 XP_EQ(0, pfd.revents); 3072 3073 r = CLOSE(fd); 3074 XP_SYS_EQ(0, r); 3075 free(buf); 3076 } 3077 3078 /* 3079 * Unpause from buffer full, POLLOUT should raise. 3080 * XXX poll(2) on NetBSD7 is really incomplete and wierd. I don't test it. 3081 */ 3082 DEF(poll_out_unpause) 3083 { 3084 struct audio_info ai; 3085 struct pollfd pfd; 3086 int fd; 3087 int r; 3088 char *buf; 3089 int buflen; 3090 u_int blocksize; 3091 int hiwat; 3092 int lowat; 3093 3094 TEST("poll_out_unpause"); 3095 if (netbsd < 8) { 3096 XP_SKIP("NetBSD7's poll() is too incomplete to test."); 3097 return; 3098 } 3099 3100 /* Non-blocking open */ 3101 fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3102 REQUIRED_SYS_OK(fd); 3103 3104 /* Adjust block size and hiwat/lowat to make the test time 1sec */ 3105 blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */ 3106 hiwat = 12; /* 1.5sec */ 3107 lowat = 4; /* 0.5sec */ 3108 AUDIO_INITINFO(&ai); 3109 ai.blocksize = blocksize; 3110 ai.hiwat = hiwat; 3111 ai.lowat = lowat; 3112 /* and also set encoding */ 3113 /* 3114 * XXX NetBSD7 has different results depending on whether the input 3115 * encoding is emulated (AUDIO_ENCODINGFLAG_EMULATED) or not. It's 3116 * not easy to ensure this situation on all hardware environment. 3117 * On NetBSD9, the result is the same regardless of input encoding. 3118 */ 3119 r = IOCTL(fd, AUDIO_SETINFO, &ai, "blocksize=%d", blocksize); 3120 XP_SYS_EQ(0, r); 3121 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3122 if (ai.blocksize != blocksize) { 3123 /* 3124 * NetBSD9 can not change the blocksize. Then, 3125 * adjust using hiwat/lowat. 3126 */ 3127 blocksize = ai.blocksize; 3128 hiwat = howmany(8000 * 1.5, blocksize); 3129 lowat = howmany(8000 * 0.5, blocksize); 3130 } 3131 /* Anyway, set the parameters */ 3132 AUDIO_INITINFO(&ai); 3133 ai.blocksize = blocksize; 3134 ai.hiwat = hiwat; 3135 ai.lowat = lowat; 3136 ai.play.pause = 1; 3137 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1"); 3138 XP_SYS_EQ(0, r); 3139 3140 /* Get the set parameters again */ 3141 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3142 XP_SYS_EQ(0, r); 3143 3144 /* Write until full */ 3145 buflen = ai.blocksize * ai.hiwat; 3146 buf = (char *)malloc(buflen); 3147 REQUIRED_IF(buf != NULL); 3148 memset(buf, 0xff, buflen); 3149 do { 3150 r = WRITE(fd, buf, buflen); 3151 } while (r == buflen); 3152 if (r == -1) { 3153 XP_SYS_NG(EAGAIN, r); 3154 } 3155 3156 /* At this time, POLLOUT should not be set because buffer is full */ 3157 memset(&pfd, 0, sizeof(pfd)); 3158 pfd.fd = fd; 3159 pfd.events = POLLOUT; 3160 r = POLL(&pfd, 1, 0); 3161 XP_SYS_EQ(0, r); 3162 XP_EQ(0, pfd.revents); 3163 3164 /* Unpause */ 3165 AUDIO_INITINFO(&ai); 3166 ai.play.pause = 0; 3167 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=0"); 3168 XP_SYS_EQ(0, r); 3169 3170 /* 3171 * When unpause occurs: 3172 * - NetBSD7 (emul=0) -> the buffer remains. 3173 * - NetBSD7 (emul=1) -> the buffer is cleared. 3174 * - NetBSD8 -> the buffer remains. 3175 * - NetBSD9 -> the buffer remains. 3176 */ 3177 3178 /* Check poll() up to 2sec */ 3179 pfd.revents = 0; 3180 r = POLL(&pfd, 1, 2000); 3181 XP_SYS_EQ(1, r); 3182 XP_EQ(POLLOUT, pfd.revents); 3183 3184 /* 3185 * Since POLLOUT is set, it should be writable. 3186 * But at this time, no all buffer may be writable. 3187 */ 3188 r = WRITE(fd, buf, buflen); 3189 XP_SYS_OK(r); 3190 3191 /* Flush it because there is no need to play it */ 3192 r = IOCTL(fd, AUDIO_FLUSH, NULL, ""); 3193 XP_SYS_EQ(0, r); 3194 3195 r = CLOSE(fd); 3196 XP_SYS_EQ(0, r); 3197 free(buf); 3198 } 3199 3200 /* 3201 * poll(2) must not be affected by playback of other descriptors. 3202 */ 3203 DEF(poll_out_simul) 3204 { 3205 struct audio_info ai; 3206 struct pollfd pfd[2]; 3207 int fd[2]; 3208 int r; 3209 char *buf; 3210 u_int blocksize; 3211 int hiwat; 3212 int lowat; 3213 int buflen; 3214 int time; 3215 3216 TEST("poll_out_simul"); 3217 if (netbsd < 8) { 3218 XP_SKIP("Multiple open is not supported"); 3219 return; 3220 } 3221 3222 /* Make sure that it's not affected by descriptor order */ 3223 for (int i = 0; i < 2; i++) { 3224 int a = i; 3225 int b = 1 - i; 3226 3227 fd[0] = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3228 REQUIRED_SYS_OK(fd[0]); 3229 fd[1] = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3230 REQUIRED_SYS_OK(fd[1]); 3231 3232 /* 3233 * Adjust block size and hiwat/lowat. 3234 * I want to choice suitable blocksize (if possible). 3235 */ 3236 blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */ 3237 hiwat = 12; /* 1.5sec */ 3238 lowat = 4; /* 0.5sec */ 3239 AUDIO_INITINFO(&ai); 3240 ai.blocksize = blocksize; 3241 ai.hiwat = hiwat; 3242 ai.lowat = lowat; 3243 r = IOCTL(fd[0], AUDIO_SETINFO, &ai, "blocksize=1000"); 3244 XP_SYS_EQ(0, r); 3245 r = IOCTL(fd[0], AUDIO_GETBUFINFO, &ai, "read back blocksize"); 3246 if (ai.blocksize != blocksize) { 3247 /* 3248 * NetBSD9 can not change the blocksize. Then, 3249 * adjust using hiwat/lowat. 3250 */ 3251 blocksize = ai.blocksize; 3252 hiwat = howmany(8000 * 1.5, blocksize); 3253 lowat = howmany(8000 * 0.5, blocksize); 3254 } 3255 /* Anyway, set the parameters */ 3256 AUDIO_INITINFO(&ai); 3257 ai.blocksize = blocksize; 3258 ai.hiwat = hiwat; 3259 ai.lowat = lowat; 3260 /* Pause fdA */ 3261 ai.play.pause = 1; 3262 r = IOCTL(fd[a], AUDIO_SETINFO, &ai, "pause=1"); 3263 XP_SYS_EQ(0, r); 3264 /* Unpause fdB */ 3265 ai.play.pause = 0; 3266 r = IOCTL(fd[b], AUDIO_SETINFO, &ai, "pause=0"); 3267 XP_SYS_EQ(0, r); 3268 3269 /* Get again. XXX two individual ioctls are correct */ 3270 r = IOCTL(fd[0], AUDIO_GETBUFINFO, &ai, ""); 3271 XP_SYS_EQ(0, r); 3272 DPRINTF(" > blocksize=%d lowat=%d hiwat=%d\n", 3273 ai.blocksize, ai.lowat, ai.hiwat); 3274 3275 /* Enough long time than the playback time */ 3276 time = (ai.hiwat - ai.lowat) * blocksize / 8; /*[msec]*/ 3277 time *= 2; 3278 3279 /* Write fdA full */ 3280 buflen = blocksize * ai.lowat; 3281 buf = (char *)malloc(buflen); 3282 REQUIRED_IF(buf != NULL); 3283 memset(buf, 0xff, buflen); 3284 do { 3285 r = WRITE(fd[a], buf, buflen); 3286 } while (r == buflen); 3287 if (r == -1) { 3288 XP_SYS_NG(EAGAIN, r); 3289 } 3290 3291 /* POLLOUT should not be set, because fdA is buffer full */ 3292 memset(pfd, 0, sizeof(pfd)); 3293 pfd[0].fd = fd[a]; 3294 pfd[0].events = POLLOUT; 3295 r = POLL(pfd, 1, 0); 3296 XP_SYS_EQ(0, r); 3297 XP_EQ(0, pfd[0].revents); 3298 3299 /* Write fdB at least lowat */ 3300 r = WRITE(fd[b], buf, buflen); 3301 XP_SYS_EQ(buflen, r); 3302 r = WRITE(fd[b], buf, buflen); 3303 if (r == -1) { 3304 XP_SYS_NG(EAGAIN, r); 3305 } 3306 3307 /* Only fdB should become POLLOUT */ 3308 memset(pfd, 0, sizeof(pfd)); 3309 pfd[0].fd = fd[0]; 3310 pfd[0].events = POLLOUT; 3311 pfd[1].fd = fd[1]; 3312 pfd[1].events = POLLOUT; 3313 r = POLL(pfd, 2, time); 3314 XP_SYS_EQ(1, r); 3315 if (r != -1) { 3316 XP_EQ(0, pfd[a].revents); 3317 XP_EQ(POLLOUT, pfd[b].revents); 3318 } 3319 3320 /* Drop the rest */ 3321 r = IOCTL(fd[0], AUDIO_FLUSH, NULL, ""); 3322 XP_SYS_EQ(0, r); 3323 r = IOCTL(fd[1], AUDIO_FLUSH, NULL, ""); 3324 XP_SYS_EQ(0, r); 3325 3326 r = CLOSE(fd[0]); 3327 XP_SYS_EQ(0, r); 3328 r = CLOSE(fd[1]); 3329 XP_SYS_EQ(0, r); 3330 free(buf); 3331 3332 xxx_close_wait(); 3333 } 3334 } 3335 3336 /* 3337 * poll(2) must not be affected by other recording descriptors even if 3338 * playback descriptor waits with POLLIN (though it's not normal usage). 3339 * In other words, two POLLIN must not interfere. 3340 */ 3341 DEF(poll_in_simul) 3342 { 3343 struct audio_info ai; 3344 struct pollfd pfd; 3345 int fd[2]; 3346 int r; 3347 char *buf; 3348 int blocksize; 3349 3350 TEST("poll_in_simul"); 3351 if (netbsd < 8) { 3352 XP_SKIP("Multiple open is not supported"); 3353 return; 3354 } 3355 if (hw_fulldup() == 0) { 3356 XP_SKIP("This test is only for full-duplex device"); 3357 return; 3358 } 3359 3360 int play = 0; 3361 int rec = 1; 3362 3363 fd[play] = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3364 REQUIRED_SYS_OK(fd[play]); 3365 fd[rec] = OPEN(devaudio, O_RDONLY); 3366 REQUIRED_SYS_OK(fd[rec]); 3367 3368 /* Get block size */ 3369 r = IOCTL(fd[rec], AUDIO_GETBUFINFO, &ai, ""); 3370 XP_SYS_EQ(0, r); 3371 blocksize = ai.blocksize; 3372 3373 buf = (char *)malloc(blocksize); 3374 REQUIRED_IF(buf != NULL); 3375 3376 /* 3377 * At first, make sure the playback one doesn't return POLLIN. 3378 */ 3379 memset(&pfd, 0, sizeof(pfd)); 3380 pfd.fd = fd[play]; 3381 pfd.events = POLLIN; 3382 r = POLL(&pfd, 1, 0); 3383 if (r == 0 && pfd.revents == 0) { 3384 XP_SYS_EQ(0, r); 3385 XP_EQ(0, pfd.revents); 3386 } else { 3387 XP_FAIL("play fd returns POLLIN"); 3388 goto abort; 3389 } 3390 3391 /* Start recording */ 3392 r = READ(fd[rec], buf, blocksize); 3393 XP_SYS_EQ(blocksize, r); 3394 3395 /* Poll()ing playback descriptor with POLLIN should not raise */ 3396 r = POLL(&pfd, 1, 1000); 3397 XP_SYS_EQ(0, r); 3398 XP_EQ(0, pfd.revents); 3399 3400 /* Poll()ing recording descriptor with POLLIN should raise */ 3401 pfd.fd = fd[rec]; 3402 r = POLL(&pfd, 1, 0); 3403 XP_SYS_EQ(1, r); 3404 XP_EQ(POLLIN, pfd.revents); 3405 3406 abort: 3407 r = CLOSE(fd[play]); 3408 XP_SYS_EQ(0, r); 3409 r = CLOSE(fd[rec]); 3410 XP_SYS_EQ(0, r); 3411 free(buf); 3412 } 3413 3414 /* 3415 * Whether kqueue() succeeds with specified mode. 3416 */ 3417 void 3418 test_kqueue_mode(int openmode, int filt, int expected) 3419 { 3420 struct kevent kev; 3421 struct timespec ts; 3422 int fd; 3423 int kq; 3424 int r; 3425 3426 TEST("kqueue_mode_%s_%s", 3427 openmode_str[openmode] + 2, 3428 (filt == EVFILT_READ) ? "READ" : "WRITE"); 3429 if (mode2aumode(openmode) == 0) { 3430 XP_SKIP("Operation not allowed on this hardware property"); 3431 return; 3432 } 3433 3434 ts.tv_sec = 0; 3435 ts.tv_nsec = 100 * 1000 * 1000; // 100msec 3436 3437 kq = KQUEUE(); 3438 XP_SYS_OK(kq); 3439 3440 fd = OPEN(devaudio, openmode); 3441 REQUIRED_SYS_OK(fd); 3442 3443 /* 3444 * Check whether the specified filter can be set. 3445 * Any filters can always be set, even if pointless combination. 3446 * For example, EVFILT_READ can be set on O_WRONLY descriptor 3447 * though it will never raise. 3448 * I will not mention about good or bad of this behavior here. 3449 */ 3450 EV_SET(&kev, fd, filt, EV_ADD, 0, 0, 0); 3451 r = KEVENT_SET(kq, &kev, 1); 3452 XP_SYS_EQ(0, r); 3453 3454 if (r == 0) { 3455 /* If the filter can be set, try kevent(poll) */ 3456 r = KEVENT_POLL(kq, &kev, 1, &ts); 3457 XP_SYS_EQ(expected, r); 3458 3459 /* Delete it */ 3460 EV_SET(&kev, fd, filt, EV_DELETE, 0, 0, 0); 3461 r = KEVENT_SET(kq, &kev, 1); 3462 XP_SYS_EQ(0, r); 3463 } 3464 3465 r = CLOSE(fd); 3466 XP_SYS_EQ(0, r); 3467 r = CLOSE(kq); 3468 XP_SYS_EQ(0, r); 3469 } 3470 DEF(kqueue_mode_RDONLY_READ) { 3471 /* Should not raise yet (NetBSD7 has bugs?) */ 3472 int expected = (netbsd < 8) ? 1 : 0; 3473 test_kqueue_mode(O_RDONLY, EVFILT_READ, expected); 3474 } 3475 DEF(kqueue_mode_RDONLY_WRITE) { 3476 /* Should never raise (NetBSD7 has bugs) */ 3477 int expected = (netbsd < 8) ? 1 : 0; 3478 test_kqueue_mode(O_RDONLY, EVFILT_WRITE, expected); 3479 } 3480 DEF(kqueue_mode_WRONLY_READ) { 3481 /* Should never raise */ 3482 test_kqueue_mode(O_WRONLY, EVFILT_READ, 0); 3483 } 3484 DEF(kqueue_mode_WRONLY_WRITE) { 3485 /* Should raise */ 3486 test_kqueue_mode(O_WRONLY, EVFILT_WRITE, 1); 3487 } 3488 DEF(kqueue_mode_RDWR_READ) { 3489 /* Should not raise yet (NetBSD7 is something strange) */ 3490 int expected = (netbsd < 8 && hw_fulldup()) ? 1 : 0; 3491 test_kqueue_mode(O_RDWR, EVFILT_READ, expected); 3492 } 3493 DEF(kqueue_mode_RDWR_WRITE) { 3494 /* Should raise */ 3495 test_kqueue_mode(O_RDWR, EVFILT_WRITE, 1); 3496 } 3497 3498 /* 3499 * kqueue(2) when buffer is empty. 3500 */ 3501 DEF(kqueue_empty) 3502 { 3503 struct audio_info ai; 3504 struct kevent kev; 3505 struct timespec ts; 3506 int kq; 3507 int fd; 3508 int r; 3509 3510 TEST("kqueue_empty"); 3511 3512 fd = OPEN(devaudio, O_WRONLY); 3513 REQUIRED_SYS_OK(fd); 3514 3515 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3516 XP_SYS_EQ(0, r); 3517 3518 kq = KQUEUE(); 3519 XP_SYS_OK(kq); 3520 3521 EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0); 3522 r = KEVENT_SET(kq, &kev, 1); 3523 XP_SYS_EQ(0, r); 3524 3525 /* When the buffer is empty, it should succeed even if timeout == 0 */ 3526 memset(&ts, 0, sizeof(ts)); 3527 r = KEVENT_POLL(kq, &kev, 1, &ts); 3528 XP_SYS_EQ(1, r); 3529 XP_EQ(fd, kev.ident); 3530 /* 3531 * XXX According to kqueue(2) manpage, returned kev.data contains 3532 * "the amount of space remaining in the write buffer". 3533 * NetBSD7 returns buffer_size. Shouldn't it be blocksize * hiwat? 3534 */ 3535 /* XP_EQ(ai.blocksize * ai.hiwat, kev.data); */ 3536 XP_EQ(ai.play.buffer_size, kev.data); 3537 3538 r = CLOSE(fd); 3539 XP_SYS_EQ(0, r); 3540 r = CLOSE(kq); 3541 XP_SYS_EQ(0, r); 3542 } 3543 3544 /* 3545 * kqueue(2) when buffer is full. 3546 */ 3547 DEF(kqueue_full) 3548 { 3549 struct audio_info ai; 3550 struct kevent kev; 3551 struct timespec ts; 3552 int kq; 3553 int fd; 3554 int r; 3555 char *buf; 3556 int buflen; 3557 3558 TEST("kqueue_full"); 3559 3560 fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3561 REQUIRED_SYS_OK(fd); 3562 3563 /* Pause */ 3564 AUDIO_INITINFO(&ai); 3565 ai.play.pause = 1; 3566 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 3567 XP_SYS_EQ(0, r); 3568 3569 /* Get buffer size */ 3570 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3571 XP_SYS_EQ(0, r); 3572 3573 /* Write until full */ 3574 buflen = ai.play.buffer_size; 3575 buf = (char *)malloc(buflen); 3576 REQUIRED_IF(buf != NULL); 3577 memset(buf, 0xff, buflen); 3578 do { 3579 r = WRITE(fd, buf, buflen); 3580 } while (r == buflen); 3581 if (r == -1) { 3582 XP_SYS_NG(EAGAIN, r); 3583 } 3584 3585 kq = KQUEUE(); 3586 XP_SYS_OK(kq); 3587 3588 EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0); 3589 r = KEVENT_SET(kq, &kev, 1); 3590 XP_SYS_EQ(0, r); 3591 3592 /* kevent() should not raise */ 3593 ts.tv_sec = 0; 3594 ts.tv_nsec = 100L * 1000 * 1000; /* 100msec */ 3595 r = KEVENT_POLL(kq, &kev, 1, &ts); 3596 XP_SYS_EQ(0, r); 3597 if (r > 0) { 3598 XP_EQ(fd, kev.ident); 3599 XP_EQ(0, kev.data); 3600 } 3601 3602 r = CLOSE(fd); 3603 XP_SYS_EQ(0, r); 3604 r = CLOSE(kq); 3605 XP_SYS_EQ(0, r); 3606 free(buf); 3607 } 3608 3609 /* 3610 * kqueue(2) when buffer is full but hiwat sets lower than full. 3611 */ 3612 DEF(kqueue_hiwat) 3613 { 3614 struct audio_info ai; 3615 struct kevent kev; 3616 struct timespec ts; 3617 int kq; 3618 int fd; 3619 int r; 3620 char *buf; 3621 int buflen; 3622 int newhiwat; 3623 3624 TEST("kqueue_hiwat"); 3625 3626 fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3627 REQUIRED_SYS_OK(fd); 3628 3629 /* Get buffer size and hiwat */ 3630 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "hiwat"); 3631 XP_SYS_EQ(0, r); 3632 /* Change hiwat some different value */ 3633 newhiwat = ai.hiwat - 1; 3634 3635 /* Set pause and hiwat */ 3636 AUDIO_INITINFO(&ai); 3637 ai.play.pause = 1; 3638 ai.hiwat = newhiwat; 3639 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1;hiwat"); 3640 XP_SYS_EQ(0, r); 3641 3642 /* Get the set parameters again */ 3643 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3644 XP_SYS_EQ(0, r); 3645 XP_EQ(1, ai.play.pause); 3646 XP_EQ(newhiwat, ai.hiwat); 3647 3648 /* Write until full */ 3649 buflen = ai.blocksize * ai.hiwat; 3650 buf = (char *)malloc(buflen); 3651 REQUIRED_IF(buf != NULL); 3652 memset(buf, 0xff, buflen); 3653 do { 3654 r = WRITE(fd, buf, buflen); 3655 } while (r == buflen); 3656 if (r == -1) { 3657 XP_SYS_NG(EAGAIN, r); 3658 } 3659 3660 kq = KQUEUE(); 3661 XP_SYS_OK(kq); 3662 3663 EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0); 3664 r = KEVENT_SET(kq, &kev, 1); 3665 XP_SYS_EQ(0, r); 3666 3667 /* Should not raise because it's not possible to write */ 3668 ts.tv_sec = 0; 3669 ts.tv_nsec = 100L * 1000 * 1000; /* 100msec */ 3670 r = KEVENT_POLL(kq, &kev, 1, &ts); 3671 if (r > 0) 3672 DEBUG_KEV("kev", &kev); 3673 XP_SYS_EQ(0, r); 3674 3675 r = CLOSE(fd); 3676 XP_SYS_EQ(0, r); 3677 r = CLOSE(kq); 3678 XP_SYS_EQ(0, r); 3679 free(buf); 3680 } 3681 3682 /* 3683 * Unpause from buffer full, kevent() should raise. 3684 */ 3685 DEF(kqueue_unpause) 3686 { 3687 struct audio_info ai; 3688 struct kevent kev; 3689 struct timespec ts; 3690 int fd; 3691 int r; 3692 int kq; 3693 char *buf; 3694 int buflen; 3695 u_int blocksize; 3696 int hiwat; 3697 int lowat; 3698 3699 TEST("kqueue_unpause"); 3700 3701 /* Non-blocking open */ 3702 fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3703 REQUIRED_SYS_OK(fd); 3704 3705 /* Adjust block size and hiwat/lowat to make the test time 1sec */ 3706 blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */ 3707 hiwat = 12; /* 1.5sec */ 3708 lowat = 4; /* 0.5sec */ 3709 AUDIO_INITINFO(&ai); 3710 ai.blocksize = blocksize; 3711 ai.hiwat = hiwat; 3712 ai.lowat = lowat; 3713 /* and also set encoding */ 3714 /* 3715 * XXX NetBSD7 has different results depending on whether the input 3716 * encoding is emulated (AUDIO_ENCODINGFLAG_EMULATED) or not. It's 3717 * not easy to ensure this situation on all hardware environment. 3718 * On NetBSD9, the result is the same regardless of input encoding. 3719 */ 3720 r = IOCTL(fd, AUDIO_SETINFO, &ai, "blocksize=%d", blocksize); 3721 XP_SYS_EQ(0, r); 3722 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3723 if (ai.blocksize != blocksize) { 3724 /* 3725 * NetBSD9 can not change the blocksize. Then, 3726 * adjust using hiwat/lowat. 3727 */ 3728 blocksize = ai.blocksize; 3729 hiwat = howmany(8000 * 1.5, blocksize); 3730 lowat = howmany(8000 * 0.5, blocksize); 3731 } 3732 /* Anyway, set the parameters */ 3733 AUDIO_INITINFO(&ai); 3734 ai.blocksize = blocksize; 3735 ai.hiwat = hiwat; 3736 ai.lowat = lowat; 3737 ai.play.pause = 1; 3738 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1"); 3739 XP_SYS_EQ(0, r); 3740 3741 /* Get the set parameters again */ 3742 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 3743 XP_SYS_EQ(0, r); 3744 DPRINTF(" > blocksize=%d hiwat=%d lowat=%d buffer_size=%d\n", 3745 ai.blocksize, ai.hiwat, ai.lowat, ai.play.buffer_size); 3746 3747 /* Write until full */ 3748 buflen = ai.blocksize * ai.hiwat; 3749 buf = (char *)malloc(buflen); 3750 REQUIRED_IF(buf != NULL); 3751 memset(buf, 0xff, buflen); 3752 do { 3753 r = WRITE(fd, buf, buflen); 3754 } while (r == buflen); 3755 if (r == -1) { 3756 XP_SYS_NG(EAGAIN, r); 3757 } 3758 3759 kq = KQUEUE(); 3760 XP_SYS_OK(kq); 3761 3762 EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0); 3763 r = KEVENT_SET(kq, &kev, 1); 3764 XP_SYS_EQ(0, r); 3765 3766 /* Unpause */ 3767 AUDIO_INITINFO(&ai); 3768 ai.play.pause = 0; 3769 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=0"); 3770 XP_SYS_EQ(0, r); 3771 3772 /* Check kevent() up to 2sec */ 3773 ts.tv_sec = 2; 3774 ts.tv_nsec = 0; 3775 r = KEVENT_POLL(kq, &kev, 1, &ts); 3776 if (r >= 1) 3777 DEBUG_KEV("kev", &kev); 3778 if (netbsd < 8) { 3779 /* 3780 * NetBSD7 with EMULATED_FLAG unset has bugs. Unpausing 3781 * unintentionally clears buffer (and therefore it becomes 3782 * writable) but it doesn't raise EVFILT_WRITE. 3783 */ 3784 } else { 3785 XP_SYS_EQ(1, r); 3786 } 3787 3788 /* Flush it because there is no need to play it */ 3789 r = IOCTL(fd, AUDIO_FLUSH, NULL, ""); 3790 XP_SYS_EQ(0, r); 3791 3792 r = CLOSE(fd); 3793 XP_SYS_EQ(0, r); 3794 r = CLOSE(kq); 3795 XP_SYS_EQ(0, r); 3796 free(buf); 3797 } 3798 3799 /* 3800 * kevent(2) must not be affected by other audio descriptors. 3801 */ 3802 DEF(kqueue_simul) 3803 { 3804 struct audio_info ai; 3805 struct audio_info ai2; 3806 struct kevent kev[2]; 3807 struct timespec ts; 3808 int fd[2]; 3809 int r; 3810 int kq; 3811 u_int blocksize; 3812 int hiwat; 3813 int lowat; 3814 char *buf; 3815 int buflen; 3816 3817 TEST("kqueue_simul"); 3818 if (netbsd < 8) { 3819 XP_SKIP("Multiple open is not supported"); 3820 return; 3821 } 3822 3823 memset(&ts, 0, sizeof(ts)); 3824 3825 /* Make sure that it's not affected by descriptor order */ 3826 for (int i = 0; i < 2; i++) { 3827 int a = i; 3828 int b = 1 - i; 3829 3830 fd[0] = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3831 REQUIRED_SYS_OK(fd[0]); 3832 fd[1] = OPEN(devaudio, O_WRONLY | O_NONBLOCK); 3833 REQUIRED_SYS_OK(fd[1]); 3834 3835 /* 3836 * Adjust block size and hiwat/lowat. 3837 * I want to choice suitable blocksize (if possible). 3838 */ 3839 blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */ 3840 hiwat = 12; /* 1.5sec */ 3841 lowat = 4; /* 0.5sec */ 3842 AUDIO_INITINFO(&ai); 3843 ai.blocksize = blocksize; 3844 ai.hiwat = hiwat; 3845 ai.lowat = lowat; 3846 r = IOCTL(fd[0], AUDIO_SETINFO, &ai, "blocksize=1000"); 3847 XP_SYS_EQ(0, r); 3848 r = IOCTL(fd[0], AUDIO_GETBUFINFO, &ai, "read back blocksize"); 3849 if (ai.blocksize != blocksize) { 3850 /* 3851 * NetBSD9 can not change the blocksize. Then, 3852 * adjust using hiwat/lowat. 3853 */ 3854 blocksize = ai.blocksize; 3855 hiwat = howmany(8000 * 1.5, blocksize); 3856 lowat = howmany(8000 * 0.5, blocksize); 3857 } 3858 /* Anyway, set the parameters to both */ 3859 AUDIO_INITINFO(&ai); 3860 ai.blocksize = blocksize; 3861 ai.hiwat = hiwat; 3862 ai.lowat = lowat; 3863 ai.play.pause = 1; 3864 r = IOCTL(fd[a], AUDIO_SETINFO, &ai, "pause=1"); 3865 XP_SYS_EQ(0, r); 3866 r = IOCTL(fd[b], AUDIO_SETINFO, &ai, "pause=1"); 3867 XP_SYS_EQ(0, r); 3868 3869 /* Write both until full */ 3870 buflen = ai.blocksize * ai.hiwat; 3871 buf = (char *)malloc(buflen); 3872 REQUIRED_IF(buf != NULL); 3873 memset(buf, 0xff, buflen); 3874 /* Write fdA */ 3875 do { 3876 r = WRITE(fd[a], buf, buflen); 3877 } while (r == buflen); 3878 if (r == -1) { 3879 XP_SYS_NG(EAGAIN, r); 3880 } 3881 /* Write fdB */ 3882 do { 3883 r = WRITE(fd[b], buf, buflen); 3884 } while (r == buflen); 3885 if (r == -1) { 3886 XP_SYS_NG(EAGAIN, r); 3887 } 3888 3889 /* Get fdB's initial seek for later */ 3890 r = IOCTL(fd[b], AUDIO_GETBUFINFO, &ai2, ""); 3891 XP_SYS_EQ(0, r); 3892 3893 kq = KQUEUE(); 3894 XP_SYS_OK(kq); 3895 3896 /* Both aren't raised at this point */ 3897 EV_SET(&kev[0], fd[a], EV_ADD, EVFILT_WRITE, 0, 0, 0); 3898 EV_SET(&kev[1], fd[b], EV_ADD, EVFILT_WRITE, 0, 0, 0); 3899 r = KEVENT_SET(kq, kev, 2); 3900 XP_SYS_EQ(0, r); 3901 3902 /* Unpause only fdA */ 3903 AUDIO_INITINFO(&ai); 3904 ai.play.pause = 0; 3905 r = IOCTL(fd[a], AUDIO_SETINFO, &ai, "pause=0"); 3906 XP_SYS_EQ(0, r); 3907 3908 /* kevent() up to 2sec */ 3909 ts.tv_sec = 2; 3910 ts.tv_nsec = 0; 3911 r = KEVENT_POLL(kq, &kev[0], 1, &ts); 3912 if (r >= 1) 3913 DEBUG_KEV("kev", &kev[0]); 3914 /* fdA should raise */ 3915 XP_SYS_EQ(1, r); 3916 XP_EQ(fd[a], kev[0].ident); 3917 3918 /* Make sure that fdB keeps whole data */ 3919 r = IOCTL(fd[b], AUDIO_GETBUFINFO, &ai, ""); 3920 XP_EQ(ai2.play.seek, ai.play.seek); 3921 3922 /* Flush it because there is no need to play it */ 3923 r = IOCTL(fd[0], AUDIO_FLUSH, NULL, ""); 3924 XP_SYS_EQ(0, r); 3925 r = IOCTL(fd[1], AUDIO_FLUSH, NULL, ""); 3926 XP_SYS_EQ(0, r); 3927 3928 r = CLOSE(fd[0]); 3929 XP_SYS_EQ(0, r); 3930 r = CLOSE(fd[1]); 3931 XP_SYS_EQ(0, r); 3932 r = CLOSE(kq); 3933 XP_SYS_EQ(0, r); 3934 free(buf); 3935 3936 xxx_close_wait(); 3937 } 3938 } 3939 3940 /* Shared data between threads for ioctl_while_write */ 3941 struct ioctl_while_write_data { 3942 int fd; 3943 struct timeval start; 3944 int terminated; 3945 }; 3946 3947 /* Test thread for ioctl_while_write */ 3948 void *thread_ioctl_while_write(void *); 3949 void * 3950 thread_ioctl_while_write(void *arg) 3951 { 3952 struct ioctl_while_write_data *data = arg; 3953 struct timeval now, res; 3954 struct audio_info ai; 3955 int r; 3956 3957 /* If 0.5 seconds have elapsed since writing, assume it's blocked */ 3958 do { 3959 usleep(100); 3960 gettimeofday(&now, NULL); 3961 timersub(&now, &data->start, &res); 3962 } while (res.tv_usec < 500000); 3963 3964 /* Then, do ioctl() */ 3965 r = IOCTL(data->fd, AUDIO_GETBUFINFO, &ai, ""); 3966 XP_SYS_EQ(0, r); 3967 3968 /* Terminate */ 3969 data->terminated = 1; 3970 3971 /* Resume write() by unpause */ 3972 AUDIO_INITINFO(&ai); 3973 if (netbsd < 8) { 3974 /* 3975 * XXX NetBSD7 has bugs and it cannot be unpaused. 3976 * However, it also has another bug and it clears buffer 3977 * when encoding is changed. I use it. :-P 3978 */ 3979 ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE; 3980 } 3981 ai.play.pause = 0; 3982 r = IOCTL(data->fd, AUDIO_SETINFO, &ai, "pause=0"); 3983 XP_SYS_EQ(0, r); 3984 3985 return NULL; 3986 } 3987 3988 /* 3989 * ioctl(2) can be issued while write(2)-ing. 3990 */ 3991 DEF(ioctl_while_write) 3992 { 3993 struct audio_info ai; 3994 struct ioctl_while_write_data data0, *data; 3995 char buf[8000]; /* 1sec in mulaw,1ch,8000Hz */ 3996 pthread_t tid; 3997 int r; 3998 3999 TEST("ioctl_while_write"); 4000 4001 data = &data0; 4002 memset(data, 0, sizeof(*data)); 4003 memset(buf, 0xff, sizeof(buf)); 4004 4005 data->fd = OPEN(devaudio, O_WRONLY); 4006 REQUIRED_SYS_OK(data->fd); 4007 4008 /* Pause to block write(2)ing */ 4009 AUDIO_INITINFO(&ai); 4010 ai.play.pause = 1; 4011 r = IOCTL(data->fd, AUDIO_SETINFO, &ai, "pause=1"); 4012 XP_SYS_EQ(0, r); 4013 4014 gettimeofday(&data->start, NULL); 4015 4016 pthread_create(&tid, NULL, thread_ioctl_while_write, data); 4017 4018 /* Write until blocking */ 4019 for (;;) { 4020 r = WRITE(data->fd, buf, sizeof(buf)); 4021 if (data->terminated) 4022 break; 4023 XP_SYS_EQ(sizeof(buf), r); 4024 4025 /* Update written time */ 4026 gettimeofday(&data->start, NULL); 4027 } 4028 4029 pthread_join(tid, NULL); 4030 4031 /* Flush */ 4032 r = IOCTL(data->fd, AUDIO_FLUSH, NULL, ""); 4033 XP_SYS_EQ(0, r); 4034 r = CLOSE(data->fd); 4035 XP_SYS_EQ(0, r); 4036 } 4037 4038 volatile int sigio_caught; 4039 void 4040 signal_FIOASYNC(int signo) 4041 { 4042 if (signo == SIGIO) { 4043 sigio_caught = 1; 4044 DPRINTF(" > %d: pid %d got SIGIO\n", __LINE__, (int)getpid()); 4045 } 4046 } 4047 4048 /* 4049 * FIOASYNC between two descriptors should be splitted. 4050 */ 4051 DEF(FIOASYNC_reset) 4052 { 4053 int fd0, fd1; 4054 int r; 4055 int val; 4056 4057 TEST("FIOASYNC_reset"); 4058 if (netbsd < 8) { 4059 XP_SKIP("Multiple open is not supported"); 4060 return; 4061 } 4062 4063 /* The first one opens */ 4064 fd0 = OPEN(devaudio, O_WRONLY); 4065 REQUIRED_SYS_OK(fd0); 4066 4067 /* The second one opens, enables ASYNC, and closes */ 4068 fd1 = OPEN(devaudio, O_WRONLY); 4069 REQUIRED_SYS_OK(fd1); 4070 val = 1; 4071 r = IOCTL(fd1, FIOASYNC, &val, "on"); 4072 XP_SYS_EQ(0, r); 4073 r = CLOSE(fd1); 4074 XP_SYS_EQ(0, r); 4075 4076 /* Again, the second one opens and enables ASYNC */ 4077 fd1 = OPEN(devaudio, O_WRONLY); 4078 REQUIRED_SYS_OK(fd1); 4079 val = 1; 4080 r = IOCTL(fd1, FIOASYNC, &val, "on"); 4081 XP_SYS_EQ(0, r); /* NetBSD8 fails */ 4082 r = CLOSE(fd1); 4083 XP_SYS_EQ(0, r); 4084 r = CLOSE(fd0); 4085 XP_SYS_EQ(0, r); 4086 } 4087 4088 /* 4089 * Whether SIGIO is emitted on plyaback. 4090 * XXX I don't understand conditions that NetBSD7 emits signal. 4091 */ 4092 DEF(FIOASYNC_play_signal) 4093 { 4094 struct audio_info ai; 4095 int r; 4096 int fd; 4097 int val; 4098 char *data; 4099 int i; 4100 4101 TEST("FIOASYNC_play_signal"); 4102 if (hw_canplay() == 0) { 4103 XP_SKIP("This test is only for playable device"); 4104 return; 4105 } 4106 4107 signal(SIGIO, signal_FIOASYNC); 4108 sigio_caught = 0; 4109 4110 fd = OPEN(devaudio, O_WRONLY); 4111 REQUIRED_SYS_OK(fd); 4112 4113 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4114 REQUIRED_SYS_EQ(0, r); 4115 REQUIRED_IF(ai.blocksize != 0); 4116 data = (char *)malloc(ai.blocksize); 4117 REQUIRED_IF(data != NULL); 4118 memset(data, 0xff, ai.blocksize); 4119 4120 val = 1; 4121 r = IOCTL(fd, FIOASYNC, &val, "on"); 4122 XP_SYS_EQ(0, r); 4123 4124 r = WRITE(fd, data, ai.blocksize); 4125 XP_SYS_EQ(ai.blocksize, r); 4126 4127 /* Waits signal until 1sec */ 4128 for (i = 0; i < 100 && sigio_caught == 0; i++) { 4129 usleep(10000); 4130 } 4131 signal(SIGIO, SIG_IGN); 4132 XP_EQ(1, sigio_caught); 4133 4134 r = CLOSE(fd); 4135 XP_SYS_EQ(0, r); 4136 4137 free(data); 4138 signal(SIGIO, SIG_IGN); 4139 sigio_caught = 0; 4140 } 4141 4142 /* 4143 * Whether SIGIO is emitted on recording. 4144 */ 4145 DEF(FIOASYNC_rec_signal) 4146 { 4147 char buf[10]; 4148 int r; 4149 int fd; 4150 int val; 4151 int i; 4152 4153 TEST("FIOASYNC_rec_signal"); 4154 if (hw_canrec() == 0) { 4155 XP_SKIP("This test is only for recordable device"); 4156 return; 4157 } 4158 4159 signal(SIGIO, signal_FIOASYNC); 4160 sigio_caught = 0; 4161 4162 fd = OPEN(devaudio, O_RDONLY); 4163 REQUIRED_SYS_OK(fd); 4164 4165 val = 1; 4166 r = IOCTL(fd, FIOASYNC, &val, "on"); 4167 XP_SYS_EQ(0, r); 4168 4169 r = READ(fd, buf, sizeof(buf)); 4170 XP_SYS_EQ(sizeof(buf), r); 4171 4172 /* Wait signal until 1sec */ 4173 for (i = 0; i < 100 && sigio_caught == 0; i++) { 4174 usleep(10000); 4175 } 4176 signal(SIGIO, SIG_IGN); 4177 XP_EQ(1, sigio_caught); 4178 4179 r = CLOSE(fd); 4180 XP_SYS_EQ(0, r); 4181 4182 signal(SIGIO, SIG_IGN); 4183 sigio_caught = 0; 4184 } 4185 4186 /* 4187 * FIOASYNC doesn't affect other descriptor. 4188 * For simplify, test only for playback... 4189 */ 4190 DEF(FIOASYNC_multi) 4191 { 4192 struct audio_info ai; 4193 char *buf; 4194 char pipebuf[1]; 4195 int r; 4196 int i; 4197 int fd1; 4198 int fd2; 4199 int pd[2]; 4200 int val; 4201 pid_t pid; 4202 int status; 4203 4204 TEST("FIOASYNC_multi"); 4205 if (netbsd < 8) { 4206 XP_SKIP("Multiple open is not supported"); 4207 return; 4208 } 4209 if (hw_canplay() == 0) { 4210 XP_SKIP("This test is only for playable device"); 4211 return; 4212 } 4213 4214 /* Pipe used between parent and child */ 4215 r = pipe(pd); 4216 REQUIRED_SYS_EQ(0, r); 4217 4218 fd1 = OPEN(devaudio, O_WRONLY); 4219 REQUIRED_SYS_OK(fd1); 4220 fd2 = OPEN(devaudio, O_WRONLY); 4221 REQUIRED_SYS_OK(fd2); 4222 4223 /* Pause fd2 */ 4224 AUDIO_INITINFO(&ai); 4225 ai.play.pause = 1; 4226 r = IOCTL(fd2, AUDIO_SETINFO, &ai, "pause"); 4227 REQUIRED_SYS_EQ(0, r); 4228 4229 /* Fill both */ 4230 r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, ""); 4231 REQUIRED_SYS_EQ(0, r); 4232 REQUIRED_IF(ai.blocksize != 0); 4233 buf = (char *)malloc(ai.blocksize); 4234 REQUIRED_IF(buf != NULL); 4235 memset(buf, 0xff, ai.blocksize); 4236 r = WRITE(fd1, buf, ai.blocksize); 4237 XP_SYS_EQ(ai.blocksize, r); 4238 4239 sigio_caught = 0; 4240 val = 1; 4241 4242 fflush(stdout); 4243 fflush(stderr); 4244 pid = fork(); 4245 if (pid == -1) { 4246 REQUIRED_SYS_OK(pid); 4247 } 4248 if (pid == 0) { 4249 /* Child */ 4250 close(fd1); 4251 4252 /* Child enables ASYNC on fd2 */ 4253 signal(SIGIO, signal_FIOASYNC); 4254 r = IOCTL(fd2, FIOASYNC, &val, "on"); 4255 /* It cannot count errors because here is a child process */ 4256 /* XP_SYS_EQ(0, r); */ 4257 4258 /* 4259 * Waits signal until 1sec. 4260 * But fd2 is paused so it should never raise. 4261 */ 4262 for (i = 0; i < 100 && sigio_caught == 0; i++) { 4263 usleep(10000); 4264 } 4265 signal(SIGIO, SIG_IGN); 4266 pipebuf[0] = sigio_caught; 4267 /* This is not WRITE() macro here */ 4268 write(pd[1], pipebuf, sizeof(pipebuf)); 4269 4270 /* XXX? */ 4271 close(fd2); 4272 sleep(1); 4273 exit(0); 4274 } else { 4275 /* Parent */ 4276 DPRINTF(" > fork() = %d\n", (int)pid); 4277 4278 /* Parent enables ASYNC on fd1 */ 4279 signal(SIGIO, signal_FIOASYNC); 4280 r = IOCTL(fd1, FIOASYNC, &val, "on"); 4281 XP_SYS_EQ(0, r); 4282 4283 /* Waits signal until 1sec */ 4284 for (i = 0; i < 100 && sigio_caught == 0; i++) { 4285 usleep(10000); 4286 } 4287 signal(SIGIO, SIG_IGN); 4288 XP_EQ(1, sigio_caught); 4289 4290 /* Then read child's result from pipe */ 4291 r = read(pd[0], pipebuf, sizeof(pipebuf)); 4292 if (r != 1) { 4293 XP_FAIL("reading from child failed"); 4294 } 4295 DPRINTF(" > child's sigio_cauht = %d\n", pipebuf[0]); 4296 XP_EQ(0, pipebuf[0]); 4297 4298 waitpid(pid, &status, 0); 4299 } 4300 4301 r = CLOSE(fd1); 4302 XP_SYS_EQ(0, r); 4303 r = CLOSE(fd2); 4304 XP_SYS_EQ(0, r); 4305 4306 signal(SIGIO, SIG_IGN); 4307 sigio_caught = 0; 4308 free(buf); 4309 } 4310 4311 /* 4312 * Check AUDIO_WSEEK behavior. 4313 */ 4314 DEF(AUDIO_WSEEK) 4315 { 4316 char buf[4]; 4317 struct audio_info ai; 4318 int r; 4319 int fd; 4320 int n; 4321 4322 TEST("AUDIO_WSEEK"); 4323 4324 fd = OPEN(devaudio, O_WRONLY); 4325 REQUIRED_SYS_OK(fd); 4326 4327 /* Pause to count sample data */ 4328 AUDIO_INITINFO(&ai); 4329 ai.play.pause = 1; 4330 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1"); 4331 REQUIRED_SYS_EQ(0, r); 4332 4333 /* On the initial state, it should be 0 bytes */ 4334 n = 0; 4335 r = IOCTL(fd, AUDIO_WSEEK, &n, ""); 4336 XP_SYS_EQ(0, r); 4337 XP_EQ(0, n); 4338 4339 /* When writing 4 bytes, it should be 4 bytes */ 4340 memset(buf, 0xff, sizeof(buf)); 4341 r = WRITE(fd, buf, sizeof(buf)); 4342 REQUIRED_EQ(sizeof(buf), r); 4343 r = IOCTL(fd, AUDIO_WSEEK, &n, ""); 4344 XP_SYS_EQ(0, r); 4345 if (netbsd < 9) { 4346 /* 4347 * On NetBSD7, it will return 0. 4348 * Perhaps, WSEEK returns the number of pustream bytes but 4349 * data has already advanced... 4350 */ 4351 XP_EQ(0, n); 4352 } else { 4353 /* Data less than one block remains here */ 4354 XP_EQ(4, n); 4355 } 4356 4357 r = CLOSE(fd); 4358 XP_SYS_EQ(0, r); 4359 } 4360 4361 /* 4362 * Check AUDIO_SETFD behavior for O_*ONLY descriptor. 4363 * On NetBSD7, SETFD modify audio layer's state (and MD driver's state) 4364 * regardless of open mode. GETFD obtains audio layer's duplex. 4365 * On NetBSD9, SETFD is obsoleted. GETFD obtains hardware's duplex. 4366 */ 4367 void 4368 test_AUDIO_SETFD_xxONLY(int openmode) 4369 { 4370 struct audio_info ai; 4371 int r; 4372 int fd; 4373 int n; 4374 4375 TEST("AUDIO_SETFD_%s", openmode_str[openmode] + 2); 4376 if (openmode == O_RDONLY && hw_canrec() == 0) { 4377 XP_SKIP("This test is for recordable device"); 4378 return; 4379 } 4380 if (openmode == O_WRONLY && hw_canplay() == 0) { 4381 XP_SKIP("This test is for playable device"); 4382 return; 4383 } 4384 4385 fd = OPEN(devaudio, openmode); 4386 REQUIRED_SYS_OK(fd); 4387 4388 /* 4389 * Just after open(2), 4390 * - On NetBSD7, it's always half-duplex. 4391 * - On NetBSD9, it's the same as hardware one regardless of openmode. 4392 */ 4393 n = 0; 4394 r = IOCTL(fd, AUDIO_GETFD, &n, ""); 4395 XP_SYS_EQ(0, r); 4396 if (netbsd < 9) { 4397 XP_EQ(0, n); 4398 } else { 4399 XP_EQ(hw_fulldup(), n); 4400 } 4401 4402 /* 4403 * When trying to set to full-duplex, 4404 * - On NetBSD7, it will succeed if the hardware is full-duplex, or 4405 * will fail if the hardware is half-duplex. 4406 * - On NetBSD9, it will always succeed but will not be modified. 4407 */ 4408 n = 1; 4409 r = IOCTL(fd, AUDIO_SETFD, &n, "on"); 4410 if (netbsd < 8) { 4411 if (hw_fulldup()) { 4412 XP_SYS_EQ(0, r); 4413 } else { 4414 XP_SYS_NG(ENOTTY, r); 4415 } 4416 } else if (netbsd == 8) { 4417 XP_FAIL("expected result is unknown"); 4418 } else { 4419 XP_SYS_EQ(0, r); 4420 } 4421 4422 /* 4423 * When obtain it, 4424 * - On NetBSD7, it will be 1 if the hardware is full-duplex or 4425 * 0 if half-duplex. 4426 * - On NetBSD9, it will never be changed because it's the hardware 4427 * property. 4428 */ 4429 n = 0; 4430 r = IOCTL(fd, AUDIO_GETFD, &n, ""); 4431 XP_SYS_EQ(0, r); 4432 if (netbsd < 8) { 4433 XP_EQ(hw_fulldup(), n); 4434 } else if (netbsd == 8) { 4435 XP_FAIL("expected result is unknown"); 4436 } else { 4437 XP_EQ(hw_fulldup(), n); 4438 } 4439 4440 /* Some track parameters like ai.*.open should not change */ 4441 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4442 XP_SYS_EQ(0, r); 4443 XP_EQ(mode2play(openmode), ai.play.open); 4444 XP_EQ(mode2rec(openmode), ai.record.open); 4445 4446 /* 4447 * When trying to set to half-duplex, 4448 * - On NetBSD7, it will succeed if the hardware is full-duplex, or 4449 * it will succeed with nothing happens. 4450 * - On NetBSD9, it will always succeed but nothing happens. 4451 */ 4452 n = 0; 4453 r = IOCTL(fd, AUDIO_SETFD, &n, "off"); 4454 XP_SYS_EQ(0, r); 4455 4456 /* 4457 * When obtain it again, 4458 * - On NetBSD7, it will be 0 if the hardware is full-duplex, or 4459 * still 0 if half-duplex. 4460 * - On NetBSD9, it should not change. 4461 */ 4462 n = 0; 4463 r = IOCTL(fd, AUDIO_GETFD, &n, ""); 4464 XP_SYS_EQ(0, r); 4465 if (netbsd < 9) { 4466 XP_EQ(0, n); 4467 } else { 4468 XP_EQ(hw_fulldup(), n); 4469 } 4470 4471 /* Some track parameters like ai.*.open should not change */ 4472 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4473 XP_SYS_EQ(0, r); 4474 XP_EQ(mode2play(openmode), ai.play.open); 4475 XP_EQ(mode2rec(openmode), ai.record.open); 4476 4477 r = CLOSE(fd); 4478 XP_SYS_EQ(0, r); 4479 } 4480 DEF(AUDIO_SETFD_RDONLY) { test_AUDIO_SETFD_xxONLY(O_RDONLY); } 4481 DEF(AUDIO_SETFD_WRONLY) { test_AUDIO_SETFD_xxONLY(O_WRONLY); } 4482 4483 /* 4484 * Check AUDIO_SETFD behavior for O_RDWR descriptor. 4485 */ 4486 DEF(AUDIO_SETFD_RDWR) 4487 { 4488 struct audio_info ai; 4489 int r; 4490 int fd; 4491 int n; 4492 4493 TEST("AUDIO_SETFD_RDWR"); 4494 if (!hw_fulldup()) { 4495 XP_SKIP("This test is only for full-duplex device"); 4496 return; 4497 } 4498 4499 fd = OPEN(devaudio, O_RDWR); 4500 REQUIRED_SYS_OK(fd); 4501 4502 /* 4503 * - audio(4) manpage until NetBSD7 said "If a full-duplex capable 4504 * audio device is opened for both reading and writing it will 4505 * start in half-duplex play mode", but implementation doesn't 4506 * seem to follow it. It returns full-duplex. 4507 * - On NetBSD9, it should return full-duplex on full-duplex, or 4508 * half-duplex on half-duplex. 4509 */ 4510 n = 0; 4511 r = IOCTL(fd, AUDIO_GETFD, &n, ""); 4512 XP_SYS_EQ(0, r); 4513 XP_EQ(hw_fulldup(), n); 4514 4515 /* 4516 * When trying to set to full-duplex, 4517 * - On NetBSD7, it will succeed with nothing happens if full-duplex, 4518 * or will fail if half-duplex. 4519 * - On NetBSD9, it will always succeed with nothing happens. 4520 */ 4521 n = 1; 4522 r = IOCTL(fd, AUDIO_SETFD, &n, "on"); 4523 if (netbsd < 9) { 4524 if (hw_fulldup()) { 4525 XP_SYS_EQ(0, r); 4526 } else { 4527 XP_SYS_NG(ENOTTY, r); 4528 } 4529 } else { 4530 XP_SYS_EQ(0, r); 4531 } 4532 4533 /* When obtains it, it retuns half/full-duplex as is */ 4534 n = 0; 4535 r = IOCTL(fd, AUDIO_GETFD, &n, ""); 4536 XP_SYS_EQ(0, r); 4537 XP_EQ(hw_fulldup(), n); 4538 4539 /* Some track parameters like ai.*.open should not change */ 4540 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4541 XP_SYS_EQ(0, r); 4542 XP_EQ(1, ai.play.open); 4543 XP_EQ(mode2rec(O_RDWR), ai.record.open); 4544 4545 /* 4546 * When trying to set to half-duplex, 4547 * - On NetBSD7, it will succeed if the hardware is full-duplex, or 4548 * it will succeed with nothing happens. 4549 * - On NetBSD9, it will always succeed but nothing happens. 4550 */ 4551 n = 0; 4552 r = IOCTL(fd, AUDIO_SETFD, &n, "off"); 4553 if (netbsd < 8) { 4554 XP_SYS_EQ(0, r); 4555 } else if (netbsd == 8) { 4556 XP_FAIL("expected result is unknown"); 4557 } else { 4558 XP_SYS_EQ(0, r); 4559 } 4560 4561 /* 4562 * When obtain it again, 4563 * - On NetBSD7, it will be 0 if the hardware is full-duplex, or 4564 * still 0 if half-duplex. 4565 * - On NetBSD9, it should be 1 if the hardware is full-duplex, or 4566 * 0 if half-duplex. 4567 */ 4568 n = 0; 4569 r = IOCTL(fd, AUDIO_GETFD, &n, ""); 4570 XP_SYS_EQ(0, r); 4571 if (netbsd < 8) { 4572 XP_EQ(0, n); 4573 } else if (netbsd == 8) { 4574 XP_FAIL("expected result is unknown"); 4575 } else { 4576 XP_EQ(hw_fulldup(), n); 4577 } 4578 4579 /* Some track parameters like ai.*.open should not change */ 4580 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4581 XP_SYS_EQ(0, r); 4582 XP_EQ(1, ai.play.open); 4583 XP_EQ(mode2rec(O_RDWR), ai.record.open); 4584 4585 r = CLOSE(fd); 4586 XP_SYS_EQ(0, r); 4587 } 4588 4589 /* 4590 * Check AUDIO_GETINFO.eof behavior. 4591 */ 4592 DEF(AUDIO_GETINFO_eof) 4593 { 4594 struct audio_info ai; 4595 char buf[4]; 4596 int r; 4597 int fd, fd1; 4598 4599 TEST("AUDIO_GETINFO_eof"); 4600 if (hw_canplay() == 0) { 4601 XP_SKIP("This test is for playable device"); 4602 return; 4603 } 4604 4605 fd = OPEN(devaudio, O_RDWR); 4606 REQUIRED_SYS_OK(fd); 4607 4608 /* Pause to make no sound */ 4609 AUDIO_INITINFO(&ai); 4610 ai.play.pause = 1; 4611 r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause"); 4612 REQUIRED_SYS_EQ(0, r); 4613 4614 /* It should be 0 initially */ 4615 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4616 XP_SYS_EQ(0, r); 4617 XP_EQ(0, ai.play.eof); 4618 XP_EQ(0, ai.record.eof); 4619 4620 /* Writing zero bytes should increment it */ 4621 r = WRITE(fd, &r, 0); 4622 REQUIRED_SYS_OK(r); 4623 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4624 XP_SYS_EQ(0, r); 4625 XP_EQ(1, ai.play.eof); 4626 XP_EQ(0, ai.record.eof); 4627 4628 /* Writing one ore more bytes should noto increment it */ 4629 memset(buf, 0xff, sizeof(buf)); 4630 r = WRITE(fd, buf, sizeof(buf)); 4631 REQUIRED_SYS_OK(r); 4632 memset(&ai, 0, sizeof(ai)); 4633 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4634 XP_SYS_EQ(0, r); 4635 XP_EQ(1, ai.play.eof); 4636 XP_EQ(0, ai.record.eof); 4637 4638 /* Writing zero bytes again should increment it */ 4639 r = WRITE(fd, buf, 0); 4640 REQUIRED_SYS_OK(r); 4641 memset(&ai, 0, sizeof(ai)); 4642 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4643 XP_SYS_EQ(0, r); 4644 XP_EQ(2, ai.play.eof); 4645 XP_EQ(0, ai.record.eof); 4646 4647 /* Reading zero bytes should not increment it */ 4648 if (hw_fulldup()) { 4649 r = READ(fd, buf, 0); 4650 REQUIRED_SYS_OK(r); 4651 memset(&ai, 0, sizeof(ai)); 4652 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4653 XP_SYS_EQ(0, r); 4654 XP_EQ(2, ai.play.eof); 4655 XP_EQ(0, ai.record.eof); 4656 } 4657 4658 /* should not interfere with other descriptor */ 4659 if (netbsd >= 8) { 4660 fd1 = OPEN(devaudio, O_RDWR); 4661 REQUIRED_SYS_OK(fd1); 4662 memset(&ai, 0, sizeof(ai)); 4663 r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, ""); 4664 XP_SYS_EQ(0, r); 4665 XP_EQ(0, ai.play.eof); 4666 XP_EQ(0, ai.record.eof); 4667 r = CLOSE(fd1); 4668 XP_SYS_EQ(0, r); 4669 } 4670 4671 r = CLOSE(fd); 4672 XP_SYS_EQ(0, r); 4673 4674 xxx_close_wait(); 4675 4676 /* When reopen, it should reset the counter */ 4677 fd = OPEN(devaudio, O_RDWR); 4678 REQUIRED_SYS_OK(fd); 4679 4680 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4681 XP_SYS_EQ(0, r); 4682 XP_EQ(0, ai.play.eof); 4683 XP_EQ(0, ai.record.eof); 4684 4685 r = CLOSE(fd); 4686 XP_SYS_EQ(0, r); 4687 } 4688 4689 /* 4690 * Check relationship between openmode and mode set by AUDIO_SETINFO. 4691 */ 4692 void 4693 test_AUDIO_SETINFO_mode(int openmode, int index, int setmode, int expected) 4694 { 4695 struct audio_info ai; 4696 char buf[10]; 4697 int inimode; 4698 int r; 4699 int fd; 4700 bool canwrite; 4701 bool canread; 4702 4703 /* index was passed only for displaying here */ 4704 TEST("AUDIO_SETINFO_mode_%s_%d", openmode_str[openmode] + 2, index); 4705 if (mode2aumode(openmode) == 0) { 4706 XP_SKIP("Operation not allowed on this hardware property"); 4707 return; 4708 } 4709 4710 inimode = mode2aumode(openmode); 4711 4712 fd = OPEN(devaudio, openmode); 4713 REQUIRED_SYS_OK(fd); 4714 4715 /* When just after opening */ 4716 memset(&ai, 0, sizeof(ai)); 4717 r = IOCTL(fd, AUDIO_GETINFO, &ai, ""); 4718 REQUIRED_SYS_EQ(0, r); 4719 XP_EQ(inimode, ai.mode); 4720 XP_EQ(mode2play(openmode), ai.play.open); 4721 XP_EQ(mode2rec(openmode), ai.record.open); 4722 XP_NE(0, ai.play.buffer_size); 4723 XP_NE(0, ai.record.buffer_size); 4724 4725 /* Change mode (and pause here) */ 4726 ai.mode = setmode; 4727 ai.play.pause = 1; 4728 ai.record.pause = 1; 4729 r = IOCTL(fd, AUDIO_SETINFO, &ai, "mode"); 4730 XP_SYS_EQ(0, r); 4731 if (r == 0) { 4732 r = IOCTL(fd, AUDIO_GETINFO, &ai, ""); 4733 XP_SYS_EQ(0, r); 4734 XP_EQ(expected, ai.mode); 4735 4736 /* It seems to keep the initial openmode regardless of mode */ 4737 XP_EQ(mode2play(openmode), ai.play.open); 4738 XP_EQ(mode2rec(openmode), ai.record.open); 4739 XP_NE(0, ai.play.buffer_size); 4740 XP_NE(0, ai.record.buffer_size); 4741 } 4742 4743 /* 4744 * On NetBSD7, whether writable depends openmode when open. 4745 * On NetBSD9, whether writable should depend inimode when open. 4746 * Modifying after open should not affect this mode. 4747 */ 4748 if (netbsd < 9) { 4749 canwrite = (openmode != O_RDONLY); 4750 } else { 4751 canwrite = ((inimode & AUMODE_PLAY) != 0); 4752 } 4753 r = WRITE(fd, buf, 0); 4754 if (canwrite) { 4755 XP_SYS_EQ(0, r); 4756 } else { 4757 XP_SYS_NG(EBADF, r); 4758 } 4759 4760 /* 4761 * On NetBSD7, whether readable depends openmode when open. 4762 * On NetBSD9, whether readable should depend inimode when open. 4763 * Modifying after open should not affect this mode. 4764 */ 4765 if (netbsd < 9) { 4766 canread = (openmode != O_WRONLY); 4767 } else { 4768 canread = ((inimode & AUMODE_RECORD) != 0); 4769 } 4770 r = READ(fd, buf, 0); 4771 if (canread) { 4772 XP_SYS_EQ(0, r); 4773 } else { 4774 XP_SYS_NG(EBADF, r); 4775 } 4776 4777 r = CLOSE(fd); 4778 XP_SYS_EQ(0, r); 4779 } 4780 /* 4781 * XXX hmm... it's too complex 4782 */ 4783 /* shortcut for table form */ 4784 #define P AUMODE_PLAY 4785 #define A AUMODE_PLAY_ALL 4786 #define R AUMODE_RECORD 4787 struct setinfo_mode_t { 4788 int setmode; /* mode used in SETINFO */ 4789 int expmode7; /* expected mode on NetBSD7 */ 4790 int expmode9; /* expected mode on NetBSD9 */ 4791 }; 4792 /* 4793 * The following tables show this operation on NetBSD7 is almost 'undefined'. 4794 * In contrast, NetBSD9 never changes mode by AUDIO_SETINFO except 4795 * AUMODE_PLAY_ALL. 4796 * 4797 * setmode == 0 and 8 are out of range and invalid input samples. 4798 * But NetBSD7 seems to accept it as is. 4799 */ 4800 struct setinfo_mode_t table_SETINFO_mode_O_RDONLY[] = { 4801 /* setmode expmode7 expmode9 */ 4802 { 0, 0, R }, 4803 { P, P, R }, 4804 { A , A|P, R }, 4805 { A|P, A|P, R }, 4806 { R , R , R }, 4807 { R| P, P, R }, 4808 { R|A , A|P, R }, 4809 { R|A|P, A|P, R }, 4810 { 8, 8, R }, 4811 }; 4812 struct setinfo_mode_t table_SETINFO_mode_O_WRONLY[] = { 4813 /* setmode expmode7 expmode9 */ 4814 { 0, 0, P }, 4815 { P, P, P }, 4816 { A , A|P, A|P }, 4817 { A|P, A|P, A|P }, 4818 { R , R , P }, 4819 { R| P, P, P }, 4820 { R|A , A|P, A|P }, 4821 { R|A|P, A|P, A|P }, 4822 { 8, 8, P }, 4823 }; 4824 #define f(openmode, index) do { \ 4825 struct setinfo_mode_t *table = table_SETINFO_mode_##openmode; \ 4826 int setmode = table[index].setmode; \ 4827 int expected = (netbsd < 9) \ 4828 ? table[index].expmode7 \ 4829 : table[index].expmode9; \ 4830 test_AUDIO_SETINFO_mode(openmode, index, setmode, expected); \ 4831 } while (0) 4832 DEF(AUDIO_SETINFO_mode_RDONLY_0) { f(O_RDONLY, 0); } 4833 DEF(AUDIO_SETINFO_mode_RDONLY_1) { f(O_RDONLY, 1); } 4834 DEF(AUDIO_SETINFO_mode_RDONLY_2) { f(O_RDONLY, 2); } 4835 DEF(AUDIO_SETINFO_mode_RDONLY_3) { f(O_RDONLY, 3); } 4836 DEF(AUDIO_SETINFO_mode_RDONLY_4) { f(O_RDONLY, 4); } 4837 DEF(AUDIO_SETINFO_mode_RDONLY_5) { f(O_RDONLY, 5); } 4838 DEF(AUDIO_SETINFO_mode_RDONLY_6) { f(O_RDONLY, 6); } 4839 DEF(AUDIO_SETINFO_mode_RDONLY_7) { f(O_RDONLY, 7); } 4840 DEF(AUDIO_SETINFO_mode_RDONLY_8) { f(O_RDONLY, 8); } 4841 DEF(AUDIO_SETINFO_mode_WRONLY_0) { f(O_WRONLY, 0); } 4842 DEF(AUDIO_SETINFO_mode_WRONLY_1) { f(O_WRONLY, 1); } 4843 DEF(AUDIO_SETINFO_mode_WRONLY_2) { f(O_WRONLY, 2); } 4844 DEF(AUDIO_SETINFO_mode_WRONLY_3) { f(O_WRONLY, 3); } 4845 DEF(AUDIO_SETINFO_mode_WRONLY_4) { f(O_WRONLY, 4); } 4846 DEF(AUDIO_SETINFO_mode_WRONLY_5) { f(O_WRONLY, 5); } 4847 DEF(AUDIO_SETINFO_mode_WRONLY_6) { f(O_WRONLY, 6); } 4848 DEF(AUDIO_SETINFO_mode_WRONLY_7) { f(O_WRONLY, 7); } 4849 DEF(AUDIO_SETINFO_mode_WRONLY_8) { f(O_WRONLY, 8); } 4850 #undef f 4851 /* 4852 * The following tables also show that NetBSD7's behavior is almost 4853 * 'undefined'. 4854 */ 4855 struct setinfo_mode_t table_SETINFO_mode_O_RDWR_full[] = { 4856 /* setmode expmode7 expmode9 */ 4857 { 0, 0, R| P }, 4858 { P, P, R| P }, 4859 { A , A|P, R|A|P }, 4860 { A|P, A|P, R|A|P }, 4861 { R , R , R| P }, 4862 { R| P, R| P, R| P }, 4863 { R|A , R|A|P, R|A|P }, 4864 { R|A|P, R|A|P, R|A|P }, 4865 { 8, 8, R| P }, 4866 }; 4867 struct setinfo_mode_t table_SETINFO_mode_O_RDWR_half[] = { 4868 /* setmode expmode7 expmode9 */ 4869 { 0, 0, P }, 4870 { P, P, P }, 4871 { A , A|P, A|P }, 4872 { A|P, A|P, A|P }, 4873 { R , R , P }, 4874 { R| P, P, P }, 4875 { R|A , A|P, A|P }, 4876 { R|A|P, A|P, A|P }, 4877 { 8, 8, P }, 4878 }; 4879 #define f(index) do { \ 4880 struct setinfo_mode_t *table = (hw_fulldup()) \ 4881 ? table_SETINFO_mode_O_RDWR_full \ 4882 : table_SETINFO_mode_O_RDWR_half; \ 4883 int setmode = table[index].setmode; \ 4884 int expected = (netbsd < 9) \ 4885 ? table[index].expmode7 \ 4886 : table[index].expmode9; \ 4887 test_AUDIO_SETINFO_mode(O_RDWR, index, setmode, expected); \ 4888 } while (0) 4889 DEF(AUDIO_SETINFO_mode_RDWR_0) { f(0); } 4890 DEF(AUDIO_SETINFO_mode_RDWR_1) { f(1); } 4891 DEF(AUDIO_SETINFO_mode_RDWR_2) { f(2); } 4892 DEF(AUDIO_SETINFO_mode_RDWR_3) { f(3); } 4893 DEF(AUDIO_SETINFO_mode_RDWR_4) { f(4); } 4894 DEF(AUDIO_SETINFO_mode_RDWR_5) { f(5); } 4895 DEF(AUDIO_SETINFO_mode_RDWR_6) { f(6); } 4896 DEF(AUDIO_SETINFO_mode_RDWR_7) { f(7); } 4897 DEF(AUDIO_SETINFO_mode_RDWR_8) { f(8); } 4898 #undef f 4899 #undef P 4900 #undef A 4901 #undef R 4902 4903 /* 4904 * Check whether encoding params can be set. 4905 */ 4906 void 4907 test_AUDIO_SETINFO_params_set(int openmode, int aimode, int pause) 4908 { 4909 struct audio_info ai; 4910 int r; 4911 int fd; 4912 4913 /* 4914 * aimode is bool value that indicates whether to change ai.mode. 4915 * pause is bool value that indicates whether to change ai.*.pause. 4916 */ 4917 4918 TEST("AUDIO_SETINFO_params_%s_%d_%d", 4919 openmode_str[openmode] + 2, aimode, pause); 4920 if (mode2aumode(openmode) == 0) { 4921 XP_SKIP("Operation not allowed on this hardware property"); 4922 return; 4923 } 4924 4925 /* On half-duplex, O_RDWR is the same as O_WRONLY, so skip it */ 4926 if (!hw_fulldup() && openmode == O_RDWR) { 4927 XP_SKIP("This is the same with O_WRONLY on half-duplex"); 4928 return; 4929 } 4930 4931 fd = OPEN(devaudio, openmode); 4932 REQUIRED_SYS_OK(fd); 4933 4934 AUDIO_INITINFO(&ai); 4935 /* 4936 * It takes time and effort to check all parameters independently, 4937 * so that use sample_rate as a representative. 4938 */ 4939 ai.play.sample_rate = 11025; 4940 ai.record.sample_rate = 11025; 4941 if (aimode) 4942 ai.mode = mode2aumode(openmode) & ~AUMODE_PLAY_ALL; 4943 if (pause) { 4944 ai.play.pause = 1; 4945 ai.record.pause = 1; 4946 } 4947 4948 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 4949 XP_SYS_EQ(0, r); 4950 4951 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 4952 XP_SYS_EQ(0, r); 4953 int expmode = (aimode) 4954 ? (mode2aumode(openmode) & ~AUMODE_PLAY_ALL) 4955 : mode2aumode(openmode); 4956 XP_EQ(expmode, ai.mode); 4957 XP_EQ(11025, ai.play.sample_rate); 4958 XP_EQ(pause, ai.play.pause); 4959 XP_EQ(11025, ai.record.sample_rate); 4960 XP_EQ(pause, ai.record.pause); 4961 4962 r = CLOSE(fd); 4963 XP_SYS_EQ(0, r); 4964 } 4965 #define f(a,b,c) test_AUDIO_SETINFO_params_set(a, b, c) 4966 DEF(AUDIO_SETINFO_params_set_RDONLY_0) { f(O_RDONLY, 0, 0); } 4967 DEF(AUDIO_SETINFO_params_set_RDONLY_1) { f(O_RDONLY, 0, 1); } 4968 /* On RDONLY, ai.mode is not changable 4969 * AUDIO_SETINFO_params_set_RDONLY_2) { f(O_RDONLY, 1, 0); } 4970 * AUDIO_SETINFO_params_set_RDONLY_3) { f(O_RDONLY, 1, 1); } 4971 */ 4972 DEF(AUDIO_SETINFO_params_set_WRONLY_0) { f(O_WRONLY, 0, 0); } 4973 DEF(AUDIO_SETINFO_params_set_WRONLY_1) { f(O_WRONLY, 0, 1); } 4974 DEF(AUDIO_SETINFO_params_set_WRONLY_2) { f(O_WRONLY, 1, 0); } 4975 DEF(AUDIO_SETINFO_params_set_WRONLY_3) { f(O_WRONLY, 1, 1); } 4976 DEF(AUDIO_SETINFO_params_set_RDWR_0) { f(O_RDWR, 0, 0); } 4977 DEF(AUDIO_SETINFO_params_set_RDWR_1) { f(O_RDWR, 0, 1); } 4978 DEF(AUDIO_SETINFO_params_set_RDWR_2) { f(O_RDWR, 1, 0); } 4979 DEF(AUDIO_SETINFO_params_set_RDWR_3) { f(O_RDWR, 1, 1); } 4980 #undef f 4981 4982 /* 4983 * AUDIO_SETINFO for existing track should not be interfered by other 4984 * descriptor. 4985 * AUDIO_SETINFO for non-existing track affects/is affected sticky parameters 4986 * for backward compatibility. 4987 */ 4988 DEF(AUDIO_SETINFO_params_simul) 4989 { 4990 struct audio_info ai; 4991 int fd0; 4992 int fd1; 4993 int r; 4994 4995 TEST("AUDIO_SETINFO_params_simul"); 4996 if (netbsd < 8) { 4997 XP_SKIP("Multiple open is not supported"); 4998 return; 4999 } 5000 if (hw_canplay() == 0) { 5001 XP_SKIP("This test is for playable device"); 5002 return; 5003 } 5004 5005 /* Open the 1st one as playback only */ 5006 fd0 = OPEN(devaudio, O_WRONLY); 5007 REQUIRED_SYS_OK(fd0); 5008 5009 /* Open the 2nd one as both of playback and recording */ 5010 fd1 = OPEN(devaudio, O_RDWR); 5011 REQUIRED_SYS_OK(fd1); 5012 5013 /* Change some parameters of both track on the 2nd one */ 5014 AUDIO_INITINFO(&ai); 5015 ai.play.sample_rate = 11025; 5016 ai.record.sample_rate = 11025; 5017 r = IOCTL(fd1, AUDIO_SETINFO, &ai, ""); 5018 XP_SYS_EQ(0, r); 5019 5020 /* 5021 * The 1st one doesn't have recording track so that only recording 5022 * parameter is affected by sticky parameter. 5023 */ 5024 memset(&ai, 0, sizeof(ai)); 5025 r = IOCTL(fd0, AUDIO_GETBUFINFO, &ai, ""); 5026 XP_SYS_EQ(0, r); 5027 XP_EQ(8000, ai.play.sample_rate); 5028 XP_EQ(11025, ai.record.sample_rate); 5029 5030 /* Next, change some parameters of both track on the 1st one */ 5031 AUDIO_INITINFO(&ai); 5032 ai.play.sample_rate = 16000; 5033 ai.record.sample_rate = 16000; 5034 r = IOCTL(fd0, AUDIO_SETINFO, &ai, ""); 5035 XP_SYS_EQ(0, r); 5036 5037 /* 5038 * On bi-directional device, the 2nd one has both track so that 5039 * both track are not affected by sticky parameter. 5040 * On uni-directional device, the 2nd one has only playback track 5041 * so that playback track is not affected by sticky parameter. 5042 */ 5043 memset(&ai, 0, sizeof(ai)); 5044 r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, ""); 5045 XP_SYS_EQ(0, r); 5046 XP_EQ(11025, ai.play.sample_rate); 5047 if (hw_bidir()) { 5048 XP_EQ(11025, ai.record.sample_rate); 5049 } else { 5050 XP_EQ(16000, ai.record.sample_rate); 5051 } 5052 5053 r = CLOSE(fd0); 5054 XP_SYS_EQ(0, r); 5055 r = CLOSE(fd1); 5056 XP_SYS_EQ(0, r); 5057 } 5058 5059 /* 5060 * AUDIO_SETINFO(encoding/precision) is tested in AUDIO_GETENC_range below. 5061 */ 5062 5063 /* 5064 * Check whether the number of channels can be set. 5065 */ 5066 DEF(AUDIO_SETINFO_channels) 5067 { 5068 struct audio_info hwinfo; 5069 struct audio_info ai; 5070 int mode; 5071 int r; 5072 int fd; 5073 int i; 5074 unsigned int ch; 5075 struct { 5076 int ch; 5077 bool expected; 5078 } table[] = { 5079 { 0, false }, 5080 { 1, true }, /* monaural */ 5081 { 2, true }, /* stereo */ 5082 }; 5083 5084 TEST("AUDIO_SETINFO_channels"); 5085 if (netbsd < 8) { 5086 /* 5087 * On NetBSD7, the result depends the hardware and there is 5088 * no way to know it. 5089 */ 5090 XP_SKIP("The test doesn't make sense on NetBSD7"); 5091 return; 5092 } 5093 5094 mode = openable_mode(); 5095 fd = OPEN(devaudio, mode); 5096 REQUIRED_SYS_OK(fd); 5097 5098 /* 5099 * The audio layer always supports monaural and stereo regardless of 5100 * the hardware capability. 5101 */ 5102 for (i = 0; i < (int)__arraycount(table); i++) { 5103 ch = table[i].ch; 5104 bool expected = table[i].expected; 5105 5106 AUDIO_INITINFO(&ai); 5107 if (mode != O_RDONLY) 5108 ai.play.channels = ch; 5109 if (mode != O_WRONLY) 5110 ai.record.channels = ch; 5111 r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch); 5112 if (expected) { 5113 /* Expects to succeed */ 5114 XP_SYS_EQ(0, r); 5115 5116 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 5117 XP_SYS_EQ(0, r); 5118 if (mode != O_RDONLY) 5119 XP_EQ(ch, ai.play.channels); 5120 if (mode != O_WRONLY) 5121 XP_EQ(ch, ai.record.channels); 5122 } else { 5123 /* Expects to fail */ 5124 XP_SYS_NG(EINVAL, r); 5125 } 5126 } 5127 5128 /* 5129 * The maximum number of supported channels depends the hardware. 5130 */ 5131 /* Get the number of channels that the hardware supports */ 5132 r = IOCTL(fd, AUDIO_GETFORMAT, &hwinfo, ""); 5133 REQUIRED_SYS_EQ(0, r); 5134 5135 if ((hwinfo.mode & AUMODE_PLAY)) { 5136 DPRINTF(" > hwinfo.play.channels = %d\n", 5137 hwinfo.play.channels); 5138 for (ch = 3; ch <= hwinfo.play.channels; ch++) { 5139 AUDIO_INITINFO(&ai); 5140 ai.play.channels = ch; 5141 r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch); 5142 XP_SYS_EQ(0, r); 5143 5144 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 5145 XP_SYS_EQ(0, r); 5146 XP_EQ(ch, ai.play.channels); 5147 } 5148 5149 AUDIO_INITINFO(&ai); 5150 ai.play.channels = ch; 5151 r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch); 5152 XP_SYS_NG(EINVAL, r); 5153 } 5154 if ((hwinfo.mode & AUMODE_RECORD)) { 5155 DPRINTF(" > hwinfo.record.channels = %d\n", 5156 hwinfo.record.channels); 5157 for (ch = 3; ch <= hwinfo.record.channels; ch++) { 5158 AUDIO_INITINFO(&ai); 5159 ai.record.channels = ch; 5160 r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch); 5161 XP_SYS_EQ(0, r); 5162 5163 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 5164 XP_SYS_EQ(0, r); 5165 XP_EQ(ch, ai.record.channels); 5166 } 5167 5168 AUDIO_INITINFO(&ai); 5169 ai.record.channels = ch; 5170 r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch); 5171 XP_SYS_NG(EINVAL, r); 5172 } 5173 5174 r = CLOSE(fd); 5175 XP_SYS_EQ(0, r); 5176 } 5177 5178 /* 5179 * Check whether the sample rate can be set. 5180 */ 5181 DEF(AUDIO_SETINFO_sample_rate) 5182 { 5183 struct audio_info ai; 5184 int mode; 5185 int r; 5186 int fd; 5187 int i; 5188 struct { 5189 int freq; 5190 bool expected; 5191 } table[] = { 5192 { 999, false }, 5193 { 1000, true }, /* lower limit */ 5194 { 48000, true }, 5195 { 192000, true }, /* upper limit */ 5196 { 192001, false }, 5197 }; 5198 5199 TEST("AUDIO_SETINFO_sample_rate"); 5200 if (netbsd < 8) { 5201 /* 5202 * On NetBSD7, the result depends the hardware and there is 5203 * no way to know it. 5204 */ 5205 XP_SKIP("The test doesn't make sense on NetBSD7"); 5206 return; 5207 } 5208 5209 mode = openable_mode(); 5210 fd = OPEN(devaudio, mode); 5211 REQUIRED_SYS_OK(fd); 5212 5213 for (i = 0; i < (int)__arraycount(table); i++) { 5214 int freq = table[i].freq; 5215 bool expected = table[i].expected; 5216 5217 AUDIO_INITINFO(&ai); 5218 if (mode != O_RDONLY) 5219 ai.play.sample_rate = freq; 5220 if (mode != O_WRONLY) 5221 ai.record.sample_rate = freq; 5222 r = IOCTL(fd, AUDIO_SETINFO, &ai, "sample_rate=%d", freq); 5223 if (expected) { 5224 /* Expects to succeed */ 5225 XP_SYS_EQ(0, r); 5226 5227 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 5228 XP_SYS_EQ(0, r); 5229 if (mode != O_RDONLY) 5230 XP_EQ(freq, ai.play.sample_rate); 5231 if (mode != O_WRONLY) 5232 XP_EQ(freq, ai.record.sample_rate); 5233 } else { 5234 /* Expects to fail */ 5235 XP_SYS_NG(EINVAL, r); 5236 } 5237 } 5238 5239 r = CLOSE(fd); 5240 XP_SYS_EQ(0, r); 5241 } 5242 5243 /* 5244 * SETINFO(sample_rate = 0) should fail correctly. 5245 */ 5246 DEF(AUDIO_SETINFO_sample_rate_0) 5247 { 5248 struct audio_info ai; 5249 int mode; 5250 int r; 5251 int fd; 5252 5253 TEST("AUDIO_SETINFO_sample_rate_0"); 5254 if (netbsd < 9) { 5255 /* 5256 * On NetBSD7,8 this will block system call and you will not 5257 * even be able to shutdown... 5258 */ 5259 XP_SKIP("This will cause an infinate loop in the kernel"); 5260 return; 5261 } 5262 5263 mode = openable_mode(); 5264 fd = OPEN(devaudio, mode); 5265 REQUIRED_SYS_OK(fd); 5266 5267 AUDIO_INITINFO(&ai); 5268 ai.play.sample_rate = 0; 5269 ai.record.sample_rate = 0; 5270 r = IOCTL(fd, AUDIO_SETINFO, &ai, "sample_rate=0"); 5271 /* Expects to fail */ 5272 XP_SYS_NG(EINVAL, r); 5273 5274 r = CLOSE(fd); 5275 XP_SYS_EQ(0, r); 5276 } 5277 5278 /* 5279 * Check whether the pause/unpause works. 5280 */ 5281 void 5282 test_AUDIO_SETINFO_pause(int openmode, int aimode, int param) 5283 { 5284 struct audio_info ai; 5285 int r; 5286 int fd; 5287 5288 /* 5289 * aimode is bool value that indicates whether to change ai.mode. 5290 * param is bool value that indicates whether to change encoding 5291 * parameters of ai.{play,record}.*. 5292 */ 5293 5294 TEST("AUDIO_SETINFO_pause_%s_%d_%d", 5295 openmode_str[openmode] + 2, aimode, param); 5296 if (mode2aumode(openmode) == 0) { 5297 XP_SKIP("Operation not allowed on this hardware property"); 5298 return; 5299 } 5300 5301 /* On half-duplex, O_RDWR is the same as O_WRONLY, so skip it */ 5302 if (!hw_fulldup() && openmode == O_RDWR) { 5303 XP_SKIP("This is the same with O_WRONLY on half-duplex"); 5304 return; 5305 } 5306 5307 fd = OPEN(devaudio, openmode); 5308 REQUIRED_SYS_OK(fd); 5309 5310 /* Set pause */ 5311 AUDIO_INITINFO(&ai); 5312 ai.play.pause = 1; 5313 ai.record.pause = 1; 5314 if (aimode) 5315 ai.mode = mode2aumode(openmode) & ~AUMODE_PLAY_ALL; 5316 if (param) { 5317 ai.play.sample_rate = 11025; 5318 ai.record.sample_rate = 11025; 5319 } 5320 5321 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 5322 XP_SYS_EQ(0, r); 5323 5324 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 5325 XP_SYS_EQ(0, r); 5326 int expmode = (aimode) 5327 ? (mode2aumode(openmode) & ~AUMODE_PLAY_ALL) 5328 : mode2aumode(openmode); 5329 XP_EQ(expmode, ai.mode); 5330 XP_EQ(1, ai.play.pause); 5331 XP_EQ(param ? 11025 : 8000, ai.play.sample_rate); 5332 XP_EQ(1, ai.record.pause); 5333 XP_EQ(param ? 11025 : 8000, ai.record.sample_rate); 5334 5335 /* Set unpause (?) */ 5336 AUDIO_INITINFO(&ai); 5337 ai.play.pause = 0; 5338 ai.record.pause = 0; 5339 if (aimode) 5340 ai.mode = mode2aumode(openmode); 5341 if (param) { 5342 ai.play.sample_rate = 16000; 5343 ai.record.sample_rate = 16000; 5344 } 5345 5346 r = IOCTL(fd, AUDIO_SETINFO, &ai, ""); 5347 XP_SYS_EQ(0, r); 5348 5349 r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, ""); 5350 XP_SYS_EQ(0, r); 5351 XP_EQ(mode2aumode(openmode), ai.mode); 5352 XP_EQ(0, ai.play.pause); 5353 XP_EQ(0, ai.record.pause); 5354 if (openmode != O_RDONLY) 5355 XP_EQ(param ? 16000 : 8000, ai.play.sample_rate); 5356 if (openmode != O_WRONLY) 5357 XP_EQ(param ? 16000 : 8000, ai.record.sample_rate); 5358 5359 r = CLOSE(fd); 5360 XP_SYS_EQ(0, r); 5361 } 5362 DEF(AUDIO_SETINFO_pause_RDONLY_0) { test_AUDIO_SETINFO_pause(O_RDONLY, 0, 0); } 5363 DEF(AUDIO_SETINFO_pause_RDONLY_1) { test_AUDIO_SETINFO_pause(O_RDONLY, 0, 1); } 5364 /* On RDONLY, ai.mode is not changable 5365 * AUDIO_SETINFO_pause_RDONLY_2) { test_AUDIO_SETINFO_pause(O_RDONLY, 1, 0); } 5366 * AUDIO_SETINFO_pause_RDONLY_3) { test_AUDIO_SETINFO_pause(O_RDONLY, 1, 1); } 5367 */ 5368 DEF(AUDIO_SETINFO_pause_WRONLY_0) { test_AUDIO_SETINFO_pause(O_WRONLY, 0, 0); } 5369 DEF(AUDIO_SETINFO_pause_WRONLY_1) { test_AUDIO_SETINFO_pause(O_WRONLY, 0, 1); } 5370 DEF(AUDIO_SETINFO_pause_WRONLY_2) { test_AUDIO_SETINFO_pause(O_WRONLY, 1, 0); } 5371 DEF(AUDIO_SETINFO_pause_WRONLY_3) { test_AUDIO_SETINFO_pause(O_WRONLY, 1, 1); } 5372 DEF(AUDIO_SETINFO_pause_RDWR_0) { test_AUDIO_SETINFO_pause(O_RDWR, 0, 0); } 5373 DEF(AUDIO_SETINFO_pause_RDWR_1) { test_AUDIO_SETINFO_pause(O_RDWR, 0, 1); } 5374 DEF(AUDIO_SETINFO_pause_RDWR_2) { test_AUDIO_SETINFO_pause(O_RDWR, 1, 0); } 5375 DEF(AUDIO_SETINFO_pause_RDWR_3) { test_AUDIO_SETINFO_pause(O_RDWR, 1, 1); } 5376 5377 /* 5378 * Check whether gain can be obtained/set. 5379 * And the gain should work with rich mixer. 5380 * PR kern/52781 5381 */ 5382 DEF(AUDIO_SETINFO_gain) 5383 { 5384 struct audio_info ai; 5385 mixer_ctrl_t m; 5386 int index; 5387 int master; 5388 int master_backup; 5389 int gain; 5390 int fd; 5391 int mixerfd; 5392 int r; 5393 5394 TEST("AUDIO_SETINFO_gain"); 5395 5396 /* Open /dev/mixer */ 5397 mixerfd = OPEN(devmixer, O_RDWR); 5398 REQUIRED_SYS_OK(mixerfd); 5399 index = mixer_get_outputs_master(mixerfd); 5400 if (index == -1) { 5401 XP_SKIP("Hardware has no outputs.master"); 5402 CLOSE(mixerfd); 5403 return; 5404 } 5405 5406 /* 5407 * Get current outputs.master. 5408 * auich(4) requires class type (m.type) and number of channels 5409 * (un.value.num_channels) in addition to the index (m.dev)... 5410 * What is the index...? 5411 */ 5412 memset(&m, 0, sizeof(m)); 5413 m.dev = index; 5414 m.type = AUDIO_MIXER_VALUE; 5415 m.un.value.num_channels = 1; /* dummy */ 5416 r = IOCTL(mixerfd, AUDIO_MIXER_READ, &m, "m.dev=%d", m.dev); 5417 REQUIRED_SYS_EQ(0, r); 5418 master = m.un.value.level[0]; 5419 DPRINTF(" > outputs.master = %d\n", master); 5420 master_backup = master; 5421 5422 /* Open /dev/audio */ 5423 fd = OPEN(devaudio, O_WRONLY); 5424 REQUIRED_SYS_OK(fd); 5425 5426 /* Check ai.play.gain */ 5427 r = IOCTL(fd, AUDIO_GETINFO, &ai, ""); 5428 XP_SYS_EQ(0, r); 5429 XP_EQ(master, ai.play.gain); 5430 5431 /* Change it some different value */ 5432 AUDIO_INITINFO(&ai); 5433 if (master == 0) 5434 gain = 255; 5435 else 5436 gain = 0; 5437 ai.play.gain = gain; 5438 r = IOCTL(fd, AUDIO_SETINFO, &ai, "play.gain=%d", ai.play.gain); 5439 XP_SYS_EQ(0, r); 5440 5441 /* Check gain has changed */ 5442 r = IOCTL(fd, AUDIO_GETINFO, &ai, "play.gain"); 5443 XP_SYS_EQ(0, r); 5444 XP_NE(master, ai.play.gain); 5445 5446 /* Check whether outputs.master work with gain */ 5447 r = IOCTL(mixerfd, AUDIO_MIXER_READ, &m, ""); 5448 XP_SYS_EQ(0, r); 5449 XP_EQ(ai.play.gain, m.un.value.level[0]); 5450 5451 /* Restore outputs.master */ 5452 AUDIO_INITINFO(&ai); 5453 ai.play.gain = master_backup; 5454 r = IOCTL(fd, AUDIO_SETINFO, &ai, "play.gain=%d", ai.play.gain); 5455 XP_SYS_EQ(0, r); 5456 5457 r = CLOSE(fd); 5458 XP_SYS_EQ(0, r); 5459 r = CLOSE(mixerfd); 5460 XP_SYS_EQ(0, r); 5461 } 5462 5463 #define NENC (AUDIO_ENCODING_AC3 + 1) 5464 #define NPREC (5) 5465 /* 5466 * Make table of encoding+precision supported by this device. 5467 * Return last used index . 5468 * This function is called from test_AUDIO_GETENC_*() 5469 */ 5470 int 5471 getenc_make_table(int fd, int expected[][5]) 5472 { 5473 audio_encoding_t ae; 5474 int idx; 5475 int p; 5476 int r; 5477 5478 /* 5479 * expected[][] is two dimensional table. 5480 * encoding \ precision| 4 8 16 24 32 5481 * --------------------+----------------- 5482 * AUDIO_ENCODING_NONE | 5483 * AUDIO_ENCODING_ULAW | 5484 * : 5485 * 5486 * Each cell has expected behavior. 5487 * 0: the hardware doesn't support this encoding/precision. 5488 * 1: the hardware supports this encoding/precision. 5489 * 2: the hardware doesn't support this encoding/precision but 5490 * audio layer will respond as supported for compatibility. 5491 */ 5492 for (idx = 0; ; idx++) { 5493 memset(&ae, 0, sizeof(ae)); 5494 ae.index = idx; 5495 r = IOCTL(fd, AUDIO_GETENC, &ae, "index=%d", idx); 5496 if (r != 0) { 5497 XP_SYS_NG(EINVAL, r); 5498 break; 5499 } 5500 5501 XP_EQ(idx, ae.index); 5502 if (0 <= ae.encoding && ae.encoding <= AUDIO_ENCODING_AC3) { 5503 XP_EQ_STR(encoding_names[ae.encoding], ae.name); 5504 } else { 5505 XP_FAIL("ae.encoding %d", ae.encoding); 5506 } 5507 5508 if (ae.precision != 4 && 5509 ae.precision != 8 && 5510 ae.precision != 16 && 5511 ae.precision != 24 && 5512 ae.precision != 32) 5513 { 5514 XP_FAIL("ae.precision %d", ae.precision); 5515 } 5516 /* Other bits should not be set */ 5517 XP_EQ(0, (ae.flags & ~AUDIO_ENCODINGFLAG_EMULATED)); 5518 5519 expected[ae.encoding][ae.precision / 8] = 1; 5520 DPRINTF(" > encoding=%s precision=%d\n", 5521 encoding_names[ae.encoding], ae.precision); 5522 } 5523 5524 /* 5525 * Backward compatibility bandaid. 5526 * 5527 * - Some encoding/precision pairs are obviously inconsistent 5528 * (e.g., encoding=AUDIO_ENCODING_PCM8, precision=16) but 5529 * it's due to historical reasons. 5530 * - It's incomplete for NetBSD7 and NetBSD8. I don't really 5531 * understand thier rule... This is just memo, not specification. 5532 */ 5533 #define SET(x) do { \ 5534 if ((x) == 0) \ 5535 x = 2; \ 5536 } while (0) 5537 #define p4 (0) 5538 #define p8 (1) 5539 #define p16 (2) 5540 #define p24 (3) 5541 #define p32 (4) 5542 5543 if (expected[AUDIO_ENCODING_SLINEAR][p8]) { 5544 SET(expected[AUDIO_ENCODING_SLINEAR_LE][p8]); 5545 SET(expected[AUDIO_ENCODING_SLINEAR_BE][p8]); 5546 } 5547 if (expected[AUDIO_ENCODING_ULINEAR][p8]) { 5548 SET(expected[AUDIO_ENCODING_ULINEAR_LE][p8]); 5549 SET(expected[AUDIO_ENCODING_ULINEAR_BE][p8]); 5550 SET(expected[AUDIO_ENCODING_PCM8][p8]); 5551 SET(expected[AUDIO_ENCODING_PCM16][p8]); 5552 } 5553 for (p = p16; p <= p32; p++) { 5554 #if !defined(AUDIO_SUPPORT_LINEAR24) 5555 if (p == p24) 5556 continue; 5557 #endif 5558 if (expected[AUDIO_ENCODING_SLINEAR_NE][p]) { 5559 SET(expected[AUDIO_ENCODING_SLINEAR][p]); 5560 SET(expected[AUDIO_ENCODING_PCM16][p]); 5561 } 5562 if (expected[AUDIO_ENCODING_ULINEAR_NE][p]) { 5563 SET(expected[AUDIO_ENCODING_ULINEAR][p]); 5564 } 5565 } 5566 5567 if (netbsd < 9) { 5568 if (expected[AUDIO_ENCODING_SLINEAR_LE][p16] || 5569 expected[AUDIO_ENCODING_SLINEAR_BE][p16] || 5570 expected[AUDIO_ENCODING_ULINEAR_LE][p16] || 5571 expected[AUDIO_ENCODING_ULINEAR_BE][p16]) 5572 { 5573 SET(expected[AUDIO_ENCODING_PCM8][p8]); 5574 SET(expected[AUDIO_ENCODING_PCM16][p8]); 5575 SET(expected[AUDIO_ENCODING_SLINEAR_LE][p8]); 5576 SET(expected[AUDIO_ENCODING_SLINEAR_BE][p8]); 5577 SET(expected[AUDIO_ENCODING_ULINEAR_LE][p8]); 5578 SET(expected[AUDIO_ENCODING_ULINEAR_BE][p8]); 5579 SET(expected[AUDIO_ENCODING_SLINEAR][p8]); 5580 SET(expected[AUDIO_ENCODING_ULINEAR][p8]); 5581 } 5582 } 5583 5584 /* Return last used index */ 5585 return idx; 5586 #undef SET 5587 #undef p4 5588 #undef p8 5589 #undef p16 5590 #undef p24 5591 #undef p32 5592 } 5593 5594 /* 5595 * This function is called from test_AUDIO_GETENC below. 5596 */ 5597 void 5598 xp_getenc(int expected[][5], int enc, int j, int r, struct audio_prinfo *pr) 5599 { 5600 int prec = (j == 0) ? 4 : j * 8; 5601 5602 if (expected[enc][j]) { 5603 /* expect to succeed */ 5604 XP_SYS_EQ(0, r); 5605 5606 XP_EQ(enc, pr->encoding); 5607 XP_EQ(prec, pr->precision); 5608 } else { 5609 /* expect to fail */ 5610 XP_SYS_NG(EINVAL, r); 5611 } 5612 } 5613 5614 /* 5615 * This function is called from test_AUDIO_GETENC below. 5616 */ 5617 void 5618 getenc_check_encodings(int openmode, int expected[][5]) 5619 { 5620 struct audio_info ai; 5621 int fd; 5622 int i, j; 5623 int r; 5624 5625 fd = OPEN(devaudio, openmode); 5626 REQUIRED_SYS_OK(fd); 5627 5628 for (i = 0; i < NENC; i++) { 5629 for (j = 0; j < NPREC; j++) { 5630 /* precisions are 4 and 8, 16, 24, 32 */ 5631 int prec = (j == 0) ? 4 : j * 8; 5632 5633 /* 5634 * AUDIO_GETENC has no way to know range of 5635 * supported channels and sample_rate. 5636 */ 5637 AUDIO_INITINFO(&ai); 5638 ai.play.encoding = i; 5639 ai.play.precision = prec; 5640 ai.record.encoding = i; 5641 ai.record.precision = prec; 5642 5643 r = IOCTL(fd, AUDIO_SETINFO, &ai, "%s:%d", 5644 encoding_names[i], prec); 5645 if (mode2play(openmode)) 5646 xp_getenc(expected, i, j, r, &ai.play); 5647 if (mode2rec(openmode)) 5648 xp_getenc(expected, i, j, r, &ai.record); 5649 } 5650 } 5651 r = CLOSE(fd); 5652 XP_SYS_EQ(0, r); 5653 } 5654 5655 /* 5656 * Check whether encoding+precision obtained by AUDIO_GETENC can be set. 5657 */ 5658 DEF(AUDIO_GETENC_range) 5659 { 5660 audio_encoding_t ae; 5661 int fd; 5662 int r; 5663 int expected[NENC][NPREC]; 5664 int i, j; 5665 5666 TEST("AUDIO_GETENC_range"); 5667 5668 fd = OPEN(devaudio, openable_mode()); 5669 REQUIRED_SYS_OK(fd); 5670 5671 memset(&expected, 0, sizeof(expected)); 5672 i = getenc_make_table(fd, expected); 5673 5674 /* When error has occured, the next index should also occur error */ 5675 ae.index = i + 1; 5676 r = IOCTL(fd, AUDIO_GETENC, &ae, "index=%d", ae.index); 5677 XP_SYS_NG(EINVAL, r); 5678 5679 r = CLOSE(fd); 5680 XP_SYS_EQ(0, r); 5681 5682 /* For debug */ 5683 if (debug) { 5684 for (i = 0; i < NENC; i++) { 5685 printf("expected[%2d] %15s", i, encoding_names[i]); 5686 for (j = 0; j < NPREC; j++) { 5687 printf(" %d", expected[i][j]); 5688 } 5689 printf("\n"); 5690 } 5691 } 5692 5693 /* Whether obtained encodings can be actually set */ 5694 if (hw_fulldup()) { 5695 /* Test both R/W at once using single descriptor */ 5696 getenc_check_encodings(O_RDWR, expected); 5697 } else { 5698 /* Test playback and recording if available */ 5699 if (hw_canplay()) { 5700 getenc_check_encodings(O_WRONLY, expected); 5701 } 5702 if (hw_canplay() && hw_canrec()) { 5703 xxx_close_wait(); 5704 } 5705 if (hw_canrec()) { 5706 getenc_check_encodings(O_RDONLY, expected); 5707 } 5708 } 5709 } 5710 #undef NENC 5711 #undef NPREC 5712 5713 /* 5714 * Check AUDIO_GETENC out of range. 5715 */ 5716 DEF(AUDIO_GETENC_error) 5717 { 5718 audio_encoding_t e; 5719 int fd; 5720 int r; 5721 5722 TEST("AUDIO_GETENC_error"); 5723 5724 fd = OPEN(devaudio, openable_mode()); 5725 REQUIRED_SYS_OK(fd); 5726 5727 memset(&e, 0, sizeof(e)); 5728 e.index = -1; 5729 r = IOCTL(fd, AUDIO_GETENC, &e, "index=-1"); 5730 /* NetBSD7 may not fail depending on hardware driver */ 5731 XP_SYS_NG(EINVAL, r); 5732 5733 r = CLOSE(fd); 5734 XP_SYS_EQ(0, r); 5735 } 5736 5737 /* 5738 * AUDIO_[PR]ERROR should be zero on the initial state even on non-existent 5739 * track. 5740 */ 5741 void 5742 test_AUDIO_ERROR(int openmode) 5743 { 5744 int fd; 5745 int r; 5746 int errors; 5747 5748 TEST("AUDIO_ERROR_%s", openmode_str[openmode] + 2); 5749 if (mode2aumode(openmode) == 0) { 5750 XP_SKIP("Operation not allowed on this hardware property"); 5751 return; 5752 } 5753 5754 fd = OPEN(devaudio, openmode); 5755 REQUIRED_SYS_OK(fd); 5756 5757 /* Check PERROR */ 5758 errors = 0xdeadbeef; 5759 r = IOCTL(fd, AUDIO_PERROR, &errors, ""); 5760 XP_SYS_EQ(0, r); 5761 XP_EQ(0, errors); 5762 5763 /* Check RERROR */ 5764 errors = 0xdeadbeef; 5765 r = IOCTL(fd, AUDIO_RERROR, &errors, ""); 5766 XP_SYS_EQ(0, r); 5767 XP_EQ(0, errors); 5768 5769 r = CLOSE(fd); 5770 XP_SYS_EQ(0, r); 5771 } 5772 DEF(AUDIO_ERROR_RDONLY) { test_AUDIO_ERROR(O_RDONLY); } 5773 DEF(AUDIO_ERROR_WRONLY) { test_AUDIO_ERROR(O_WRONLY); } 5774 DEF(AUDIO_ERROR_RDWR) { test_AUDIO_ERROR(O_RDWR); } 5775 5776 /* 5777 * /dev/audioctl can always be opened while /dev/audio is open. 5778 */ 5779 void 5780 test_audioctl_open_1(int fmode, int cmode) 5781 { 5782 int fd; 5783 int ctl; 5784 int r; 5785 5786 TEST("audioctl_open_1_%s_%s", 5787 openmode_str[fmode] + 2, openmode_str[cmode] + 2); 5788 if (hw_canplay() == 0 && fmode == O_WRONLY) { 5789 XP_SKIP("This test is for playable device"); 5790 return; 5791 } 5792 if (hw_canrec() == 0 && fmode == O_RDONLY) { 5793 XP_SKIP("This test is for recordable device"); 5794 return; 5795 } 5796 5797 fd = OPEN(devaudio, fmode); 5798 REQUIRED_SYS_OK(fd); 5799 5800 ctl = OPEN(devaudioctl, cmode); 5801 XP_SYS_OK(ctl); 5802 5803 r = CLOSE(ctl); 5804 XP_SYS_EQ(0, r); 5805 5806 r = CLOSE(fd); 5807 XP_SYS_EQ(0, r); 5808 } 5809 DEF(audioctl_open_1_RDONLY_RDONLY) { test_audioctl_open_1(O_RDONLY, O_RDONLY); } 5810 DEF(audioctl_open_1_RDONLY_RWONLY) { test_audioctl_open_1(O_RDONLY, O_WRONLY); } 5811 DEF(audioctl_open_1_RDONLY_RDWR) { test_audioctl_open_1(O_RDONLY, O_RDWR); } 5812 DEF(audioctl_open_1_WRONLY_RDONLY) { test_audioctl_open_1(O_WRONLY, O_RDONLY); } 5813 DEF(audioctl_open_1_WRONLY_RWONLY) { test_audioctl_open_1(O_WRONLY, O_WRONLY); } 5814 DEF(audioctl_open_1_WRONLY_RDWR) { test_audioctl_open_1(O_WRONLY, O_RDWR); } 5815 DEF(audioctl_open_1_RDWR_RDONLY) { test_audioctl_open_1(O_RDWR, O_RDONLY); } 5816 DEF(audioctl_open_1_RDWR_RWONLY) { test_audioctl_open_1(O_RDWR, O_WRONLY); } 5817 DEF(audioctl_open_1_RDWR_RDWR) { test_audioctl_open_1(O_RDWR, O_RDWR); } 5818 5819 /* 5820 * /dev/audio can always be opened while /dev/audioctl is open. 5821 */ 5822 void 5823 test_audioctl_open_2(int fmode, int cmode) 5824 { 5825 int fd; 5826 int ctl; 5827 int r; 5828 5829 TEST("audioctl_open_2_%s_%s", 5830 openmode_str[fmode] + 2, openmode_str[cmode] + 2); 5831 if (hw_canplay() == 0 && fmode == O_WRONLY) { 5832 XP_SKIP("This test is for playable device"); 5833 return; 5834 } 5835 if (hw_canrec() == 0 && fmode == O_RDONLY) { 5836 XP_SKIP("This test is for recordable device"); 5837 return; 5838 } 5839 5840 ctl = OPEN(devaudioctl, cmode); 5841 REQUIRED_SYS_OK(ctl); 5842 5843 fd = OPEN(devaudio, fmode); 5844 XP_SYS_OK(fd); 5845 5846 r = CLOSE(fd); 5847 XP_SYS_EQ(0, r); 5848 5849 r = CLOSE(ctl); 5850 XP_SYS_EQ(0, r); 5851 } 5852 DEF(audioctl_open_2_RDONLY_RDONLY) { test_audioctl_open_2(O_RDONLY, O_RDONLY); } 5853 DEF(audioctl_open_2_RDONLY_RWONLY) { test_audioctl_open_2(O_RDONLY, O_WRONLY); } 5854 DEF(audioctl_open_2_RDONLY_RDWR) { test_audioctl_open_2(O_RDONLY, O_RDWR); } 5855 DEF(audioctl_open_2_WRONLY_RDONLY) { test_audioctl_open_2(O_WRONLY, O_RDONLY); } 5856 DEF(audioctl_open_2_WRONLY_RWONLY) { test_audioctl_open_2(O_WRONLY, O_WRONLY); } 5857 DEF(audioctl_open_2_WRONLY_RDWR) { test_audioctl_open_2(O_WRONLY, O_RDWR); } 5858 DEF(audioctl_open_2_RDWR_RDONLY) { test_audioctl_open_2(O_RDWR, O_RDONLY); } 5859 DEF(audioctl_open_2_RDWR_RWONLY) { test_audioctl_open_2(O_RDWR, O_WRONLY); } 5860 DEF(audioctl_open_2_RDWR_RDWR) { test_audioctl_open_2(O_RDWR, O_RDWR); } 5861 5862 /* 5863 * Open multiple /dev/audioctl. 5864 */ 5865 DEF(audioctl_open_simul) 5866 { 5867 int ctl0; 5868 int ctl1; 5869 int r; 5870 5871 TEST("audioctl_open_simul"); 5872 5873 ctl0 = OPEN(devaudioctl, O_RDWR); 5874 REQUIRED_SYS_OK(ctl0); 5875 5876 ctl1 = OPEN(devaudioctl, O_RDWR); 5877 XP_SYS_OK(ctl1); 5878 5879 r = CLOSE(ctl0); 5880 XP_SYS_EQ(0, r); 5881 5882 r = CLOSE(ctl1); 5883 XP_SYS_EQ(0, r); 5884 } 5885 5886 /* 5887 * /dev/audioctl can be opened by other user who opens /dev/audioctl, 5888 * /dev/audioctl can be opened by other user who opens /dev/audio, 5889 * /dev/audio can be opened by other user who opens /dev/audioctl, 5890 * regardless of multiuser mode. 5891 */ 5892 void 5893 try_audioctl_open_multiuser(const char *dev1, const char *dev2) 5894 { 5895 int fd1; 5896 int fd2; 5897 int r; 5898 uid_t ouid; 5899 5900 /* 5901 * At first, open dev1 as root. 5902 * And then open dev2 as unprivileged user. 5903 */ 5904 5905 fd1 = OPEN(dev1, O_RDWR); 5906 REQUIRED_SYS_OK(fd1); 5907 5908 ouid = GETUID(); 5909 r = SETEUID(1); 5910 REQUIRED_SYS_EQ(0, r); 5911 5912 fd2 = OPEN(dev2, O_RDWR); 5913 XP_SYS_OK(fd2); 5914 5915 /* Close */ 5916 r = CLOSE(fd2); 5917 XP_SYS_EQ(0, r); 5918 5919 r = SETEUID(ouid); 5920 REQUIRED_SYS_EQ(0, r); 5921 5922 r = CLOSE(fd1); 5923 XP_SYS_EQ(0, r); 5924 } 5925 /* 5926 * This is a wrapper for audioctl_open_multiuser. 5927 * XXX XP_* macros are not compatible with on-error-goto, we need try-catch... 5928 */ 5929 void 5930 test_audioctl_open_multiuser(bool multiuser, 5931 const char *dev1, const char *dev2) 5932 { 5933 char mibname[32]; 5934 bool oldval; 5935 size_t oldlen; 5936 int r; 5937 5938 if (netbsd < 8 && multiuser == 1) { 5939 XP_SKIP("multiuser is not supported"); 5940 return; 5941 } 5942 if (netbsd < 9) { 5943 /* NetBSD8 has no way (difficult) to determine device name */ 5944 XP_SKIP("NetBSD8 cannot determine device name"); 5945 return; 5946 } 5947 if (geteuid() != 0) { 5948 XP_SKIP("This test must be priviledged user"); 5949 return; 5950 } 5951 5952 /* Get current multiuser mode (and save it) */ 5953 snprintf(mibname, sizeof(mibname), "hw.%s.multiuser", devicename); 5954 oldlen = sizeof(oldval); 5955 r = SYSCTLBYNAME(mibname, &oldval, &oldlen, NULL, 0); 5956 REQUIRED_SYS_EQ(0, r); 5957 DPRINTF(" > multiuser=%d\n", oldval); 5958 5959 /* Change if necessary */ 5960 if (oldval != multiuser) { 5961 r = SYSCTLBYNAME(mibname, NULL, NULL, &multiuser, 5962 sizeof(multiuser)); 5963 REQUIRED_SYS_EQ(0, r); 5964 DPRINTF(" > new multiuser=%d\n", multiuser); 5965 } 5966 5967 /* Do test */ 5968 try_audioctl_open_multiuser(dev1, dev2); 5969 5970 /* Restore multiuser mode */ 5971 if (oldval != multiuser) { 5972 DPRINTF(" > restore multiuser to %d\n", oldval); 5973 r = SYSCTLBYNAME(mibname, NULL, NULL, &oldval, sizeof(oldval)); 5974 XP_SYS_EQ(0, r); 5975 } 5976 } 5977 DEF(audioctl_open_multiuser0_audio1) { 5978 TEST("audioctl_open_multiuser0_audio1"); 5979 test_audioctl_open_multiuser(false, devaudio, devaudioctl); 5980 } 5981 DEF(audioctl_open_multiuser1_audio1) { 5982 TEST("audioctl_open_multiuser1_audio1"); 5983 test_audioctl_open_multiuser(true, devaudio, devaudioctl); 5984 } 5985 DEF(audioctl_open_multiuser0_audio2) { 5986 TEST("audioctl_open_multiuser0_audio2"); 5987 test_audioctl_open_multiuser(false, devaudioctl, devaudio); 5988 } 5989 DEF(audioctl_open_multiuser1_audio2) { 5990 TEST("audioctl_open_multiuser1_audio2"); 5991 test_audioctl_open_multiuser(true, devaudioctl, devaudio); 5992 } 5993 DEF(audioctl_open_multiuser0_audioctl) { 5994 TEST("audioctl_open_multiuser0_audioctl"); 5995 test_audioctl_open_multiuser(false, devaudioctl, devaudioctl); 5996 } 5997 DEF(audioctl_open_multiuser1_audioctl) { 5998 TEST("audioctl_open_multiuser1_audioctl"); 5999 test_audioctl_open_multiuser(true, devaudioctl, devaudioctl); 6000 } 6001 6002 /* 6003 * /dev/audioctl cannot be read/written regardless of its open mode. 6004 */ 6005 void 6006 test_audioctl_rw(int openmode) 6007 { 6008 char buf[1]; 6009 int fd; 6010 int r; 6011 6012 TEST("audioctl_rw_%s", openmode_str[openmode] + 2); 6013 6014 fd = OPEN(devaudioctl, openmode); 6015 REQUIRED_SYS_OK(fd); 6016 6017 if (mode2play(openmode)) { 6018 r = WRITE(fd, buf, sizeof(buf)); 6019 XP_SYS_NG(ENODEV, r); 6020 } 6021 6022 if (mode2rec(openmode)) { 6023 r = READ(fd, buf, sizeof(buf)); 6024 XP_SYS_NG(ENODEV, r); 6025 } 6026 6027 r = CLOSE(fd); 6028 XP_SYS_EQ(0, r); 6029 } 6030 DEF(audioctl_rw_RDONLY) { test_audioctl_rw(O_RDONLY); } 6031 DEF(audioctl_rw_WRONLY) { test_audioctl_rw(O_WRONLY); } 6032 DEF(audioctl_rw_RDWR) { test_audioctl_rw(O_RDWR); } 6033 6034 /* 6035 * poll(2) for /dev/audioctl should never raise. 6036 * I'm not sure about consistency between poll(2) and kqueue(2) but 6037 * anyway I follow it. 6038 * XXX Omit checking each openmode 6039 */ 6040 DEF(audioctl_poll) 6041 { 6042 struct pollfd pfd; 6043 int fd; 6044 int r; 6045 6046 TEST("audioctl_poll"); 6047 6048 fd = OPEN(devaudioctl, O_WRONLY); 6049 REQUIRED_SYS_OK(fd); 6050 6051 pfd.fd = fd; 6052 pfd.events = POLLOUT; 6053 r = POLL(&pfd, 1, 100); 6054 XP_SYS_EQ(0, r); 6055 XP_EQ(0, pfd.revents); 6056 6057 r = CLOSE(fd); 6058 XP_SYS_EQ(0, r); 6059 } 6060 6061 /* 6062 * kqueue(2) for /dev/audioctl fails. 6063 * I'm not sure about consistency between poll(2) and kqueue(2) but 6064 * anyway I follow it. 6065 * XXX Omit checking each openmode 6066 */ 6067 DEF(audioctl_kqueue) 6068 { 6069 struct kevent kev; 6070 int fd; 6071 int kq; 6072 int r; 6073 6074 TEST("audioctl_kqueue"); 6075 6076 fd = OPEN(devaudioctl, O_WRONLY); 6077 REQUIRED_SYS_OK(fd); 6078 6079 kq = KQUEUE(); 6080 XP_SYS_OK(kq); 6081 6082 EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); 6083 r = KEVENT_SET(kq, &kev, 1); 6084 /* 6085 * NetBSD7 has a bug. It looks to wanted to treat it as successful 6086 * but returned 1(== EPERM). 6087 * On NetBSD9, I decided to return ENODEV. 6088 */ 6089 if (netbsd < 8) { 6090 XP_SYS_NG(1/*EPERM*/, r); 6091 } else { 6092 XP_SYS_NG(ENODEV, r); 6093 } 6094 6095 r = CLOSE(fd); 6096 XP_SYS_EQ(0, r); 6097 } 6098 6099 6100 /* 6101 * This table is processed by t_audio.awk! 6102 * Keep /^\tENT(testname),/ format in order to add to atf. 6103 */ 6104 #define ENT(x) { #x, test__ ## x } 6105 struct testentry testtable[] = { 6106 ENT(open_mode_RDONLY), 6107 ENT(open_mode_WRONLY), 6108 ENT(open_mode_RDWR), 6109 ENT(open_audio_RDONLY), 6110 ENT(open_audio_WRONLY), 6111 ENT(open_audio_RDWR), 6112 ENT(open_sound_RDONLY), 6113 ENT(open_sound_WRONLY), 6114 ENT(open_sound_RDWR), 6115 ENT(open_audioctl_RDONLY), 6116 ENT(open_audioctl_WRONLY), 6117 ENT(open_audioctl_RDWR), 6118 ENT(open_sound_sticky), 6119 ENT(open_audioctl_sticky), 6120 ENT(open_simul_RDONLY_RDONLY), 6121 ENT(open_simul_RDONLY_WRONLY), 6122 ENT(open_simul_RDONLY_RDWR), 6123 ENT(open_simul_WRONLY_RDONLY), 6124 ENT(open_simul_WRONLY_WRONLY), 6125 ENT(open_simul_WRONLY_RDWR), 6126 ENT(open_simul_RDWR_RDONLY), 6127 ENT(open_simul_RDWR_WRONLY), 6128 ENT(open_simul_RDWR_RDWR), 6129 /**/ ENT(open_multiuser_0), // XXX TODO sysctl 6130 /**/ ENT(open_multiuser_1), // XXX TODO sysctl 6131 ENT(write_PLAY_ALL), 6132 ENT(write_PLAY), 6133 ENT(read), 6134 ENT(rept_write), 6135 ENT(rept_read), 6136 ENT(rdwr_fallback_RDONLY), 6137 ENT(rdwr_fallback_WRONLY), 6138 ENT(rdwr_fallback_RDWR), 6139 ENT(rdwr_two_RDONLY_RDONLY), 6140 ENT(rdwr_two_RDONLY_WRONLY), 6141 ENT(rdwr_two_RDONLY_RDWR), 6142 ENT(rdwr_two_WRONLY_RDONLY), 6143 ENT(rdwr_two_WRONLY_WRONLY), 6144 ENT(rdwr_two_WRONLY_RDWR), 6145 ENT(rdwr_two_RDWR_RDONLY), 6146 ENT(rdwr_two_RDWR_WRONLY), 6147 ENT(rdwr_two_RDWR_RDWR), 6148 ENT(rdwr_simul), 6149 ENT(drain_incomplete), 6150 ENT(drain_pause), 6151 ENT(drain_onrec), 6152 /**/ ENT(mmap_mode_RDONLY_NONE), // XXX rump doesn't supprot mmap 6153 /**/ ENT(mmap_mode_RDONLY_READ), // XXX rump doesn't supprot mmap 6154 /**/ ENT(mmap_mode_RDONLY_WRITE), // XXX rump doesn't supprot mmap 6155 /**/ ENT(mmap_mode_RDONLY_READWRITE),// XXX rump doesn't supprot mmap 6156 /**/ ENT(mmap_mode_WRONLY_NONE), // XXX rump doesn't supprot mmap 6157 /**/ ENT(mmap_mode_WRONLY_READ), // XXX rump doesn't supprot mmap 6158 /**/ ENT(mmap_mode_WRONLY_WRITE), // XXX rump doesn't supprot mmap 6159 /**/ ENT(mmap_mode_WRONLY_READWRITE),// XXX rump doesn't supprot mmap 6160 /**/ ENT(mmap_mode_RDWR_NONE), // XXX rump doesn't supprot mmap 6161 /**/ ENT(mmap_mode_RDWR_READ), // XXX rump doesn't supprot mmap 6162 /**/ ENT(mmap_mode_RDWR_WRITE), // XXX rump doesn't supprot mmap 6163 /**/ ENT(mmap_mode_RDWR_READWRITE), // XXX rump doesn't supprot mmap 6164 /**/ ENT(mmap_len), // XXX rump doesn't supprot mmap 6165 /**/ ENT(mmap_twice), // XXX rump doesn't supprot mmap 6166 /**/ ENT(mmap_multi), // XXX rump doesn't supprot mmap 6167 ENT(poll_mode_RDONLY_IN), 6168 ENT(poll_mode_RDONLY_OUT), 6169 ENT(poll_mode_RDONLY_INOUT), 6170 ENT(poll_mode_WRONLY_IN), 6171 ENT(poll_mode_WRONLY_OUT), 6172 ENT(poll_mode_WRONLY_INOUT), 6173 ENT(poll_mode_RDWR_IN), 6174 ENT(poll_mode_RDWR_OUT), 6175 ENT(poll_mode_RDWR_INOUT), 6176 ENT(poll_out_empty), 6177 ENT(poll_out_full), 6178 ENT(poll_out_hiwat), 6179 /**/ ENT(poll_out_unpause), // XXX does not seem to work on rump 6180 /**/ ENT(poll_out_simul), // XXX does not seem to work on rump 6181 ENT(poll_in_simul), 6182 ENT(kqueue_mode_RDONLY_READ), 6183 ENT(kqueue_mode_RDONLY_WRITE), 6184 ENT(kqueue_mode_WRONLY_READ), 6185 ENT(kqueue_mode_WRONLY_WRITE), 6186 ENT(kqueue_mode_RDWR_READ), 6187 ENT(kqueue_mode_RDWR_WRITE), 6188 ENT(kqueue_empty), 6189 ENT(kqueue_full), 6190 ENT(kqueue_hiwat), 6191 /**/ ENT(kqueue_unpause), // XXX does not seem to work on rump 6192 /**/ ENT(kqueue_simul), // XXX does not seem to work on rump 6193 ENT(ioctl_while_write), 6194 ENT(FIOASYNC_reset), 6195 ENT(FIOASYNC_play_signal), 6196 ENT(FIOASYNC_rec_signal), 6197 /**/ ENT(FIOASYNC_multi), // XXX does not seem to work on rump 6198 ENT(AUDIO_WSEEK), 6199 ENT(AUDIO_SETFD_RDONLY), 6200 ENT(AUDIO_SETFD_WRONLY), 6201 ENT(AUDIO_SETFD_RDWR), 6202 ENT(AUDIO_GETINFO_eof), 6203 ENT(AUDIO_SETINFO_mode_RDONLY_0), 6204 ENT(AUDIO_SETINFO_mode_RDONLY_1), 6205 ENT(AUDIO_SETINFO_mode_RDONLY_2), 6206 ENT(AUDIO_SETINFO_mode_RDONLY_3), 6207 ENT(AUDIO_SETINFO_mode_RDONLY_4), 6208 ENT(AUDIO_SETINFO_mode_RDONLY_5), 6209 ENT(AUDIO_SETINFO_mode_RDONLY_6), 6210 ENT(AUDIO_SETINFO_mode_RDONLY_7), 6211 ENT(AUDIO_SETINFO_mode_RDONLY_8), 6212 ENT(AUDIO_SETINFO_mode_WRONLY_0), 6213 ENT(AUDIO_SETINFO_mode_WRONLY_1), 6214 ENT(AUDIO_SETINFO_mode_WRONLY_2), 6215 ENT(AUDIO_SETINFO_mode_WRONLY_3), 6216 ENT(AUDIO_SETINFO_mode_WRONLY_4), 6217 ENT(AUDIO_SETINFO_mode_WRONLY_5), 6218 ENT(AUDIO_SETINFO_mode_WRONLY_6), 6219 ENT(AUDIO_SETINFO_mode_WRONLY_7), 6220 ENT(AUDIO_SETINFO_mode_WRONLY_8), 6221 ENT(AUDIO_SETINFO_mode_RDWR_0), 6222 ENT(AUDIO_SETINFO_mode_RDWR_1), 6223 ENT(AUDIO_SETINFO_mode_RDWR_2), 6224 ENT(AUDIO_SETINFO_mode_RDWR_3), 6225 ENT(AUDIO_SETINFO_mode_RDWR_4), 6226 ENT(AUDIO_SETINFO_mode_RDWR_5), 6227 ENT(AUDIO_SETINFO_mode_RDWR_6), 6228 ENT(AUDIO_SETINFO_mode_RDWR_7), 6229 ENT(AUDIO_SETINFO_mode_RDWR_8), 6230 ENT(AUDIO_SETINFO_params_set_RDONLY_0), 6231 ENT(AUDIO_SETINFO_params_set_RDONLY_1), 6232 ENT(AUDIO_SETINFO_params_set_WRONLY_0), 6233 ENT(AUDIO_SETINFO_params_set_WRONLY_1), 6234 ENT(AUDIO_SETINFO_params_set_WRONLY_2), 6235 ENT(AUDIO_SETINFO_params_set_WRONLY_3), 6236 ENT(AUDIO_SETINFO_params_set_RDWR_0), 6237 ENT(AUDIO_SETINFO_params_set_RDWR_1), 6238 ENT(AUDIO_SETINFO_params_set_RDWR_2), 6239 ENT(AUDIO_SETINFO_params_set_RDWR_3), 6240 ENT(AUDIO_SETINFO_params_simul), 6241 ENT(AUDIO_SETINFO_channels), 6242 ENT(AUDIO_SETINFO_sample_rate), 6243 ENT(AUDIO_SETINFO_sample_rate_0), 6244 ENT(AUDIO_SETINFO_pause_RDONLY_0), 6245 ENT(AUDIO_SETINFO_pause_RDONLY_1), 6246 ENT(AUDIO_SETINFO_pause_WRONLY_0), 6247 ENT(AUDIO_SETINFO_pause_WRONLY_1), 6248 ENT(AUDIO_SETINFO_pause_WRONLY_2), 6249 ENT(AUDIO_SETINFO_pause_WRONLY_3), 6250 ENT(AUDIO_SETINFO_pause_RDWR_0), 6251 ENT(AUDIO_SETINFO_pause_RDWR_1), 6252 ENT(AUDIO_SETINFO_pause_RDWR_2), 6253 ENT(AUDIO_SETINFO_pause_RDWR_3), 6254 ENT(AUDIO_SETINFO_gain), 6255 ENT(AUDIO_GETENC_range), 6256 ENT(AUDIO_GETENC_error), 6257 ENT(AUDIO_ERROR_RDONLY), 6258 ENT(AUDIO_ERROR_WRONLY), 6259 ENT(AUDIO_ERROR_RDWR), 6260 ENT(audioctl_open_1_RDONLY_RDONLY), 6261 ENT(audioctl_open_1_RDONLY_RWONLY), 6262 ENT(audioctl_open_1_RDONLY_RDWR), 6263 ENT(audioctl_open_1_WRONLY_RDONLY), 6264 ENT(audioctl_open_1_WRONLY_RWONLY), 6265 ENT(audioctl_open_1_WRONLY_RDWR), 6266 ENT(audioctl_open_1_RDWR_RDONLY), 6267 ENT(audioctl_open_1_RDWR_RWONLY), 6268 ENT(audioctl_open_1_RDWR_RDWR), 6269 ENT(audioctl_open_2_RDONLY_RDONLY), 6270 ENT(audioctl_open_2_RDONLY_RWONLY), 6271 ENT(audioctl_open_2_RDONLY_RDWR), 6272 ENT(audioctl_open_2_WRONLY_RDONLY), 6273 ENT(audioctl_open_2_WRONLY_RWONLY), 6274 ENT(audioctl_open_2_WRONLY_RDWR), 6275 ENT(audioctl_open_2_RDWR_RDONLY), 6276 ENT(audioctl_open_2_RDWR_RWONLY), 6277 ENT(audioctl_open_2_RDWR_RDWR), 6278 ENT(audioctl_open_simul), 6279 /**/ ENT(audioctl_open_multiuser0_audio1), // XXX TODO sysctl 6280 /**/ ENT(audioctl_open_multiuser1_audio1), // XXX TODO sysctl 6281 /**/ ENT(audioctl_open_multiuser0_audio2), // XXX TODO sysctl 6282 /**/ ENT(audioctl_open_multiuser1_audio2), // XXX TODO sysctl 6283 /**/ ENT(audioctl_open_multiuser0_audioctl), // XXX TODO sysctl 6284 /**/ ENT(audioctl_open_multiuser1_audioctl), // XXX TODO sysctl 6285 ENT(audioctl_rw_RDONLY), 6286 ENT(audioctl_rw_WRONLY), 6287 ENT(audioctl_rw_RDWR), 6288 ENT(audioctl_poll), 6289 ENT(audioctl_kqueue), 6290 {.name = NULL}, 6291 }; 6292