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