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