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