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