Annotation of src/tests/dev/audio/audiotest.c, Revision 1.8
1.8 ! isaki 1: /* $NetBSD: audiotest.c,v 1.7 2020/03/04 14:20:44 isaki Exp $ */
1.1 isaki 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>
1.8 ! isaki 29: __RCSID("$NetBSD: audiotest.c,v 1.7 2020/03/04 14:20:44 isaki Exp $");
1.1 isaki 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;
1.8 ! isaki 78: bool match(const char *, const char *);
1.1 isaki 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;
1.8 ! isaki 172: bool exact_match;
1.1 isaki 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");
1.8 ! isaki 191: fprintf(stderr, "\t-e : Use exact match for testnames "
! 192: "(default is forward match)\n");
1.1 isaki 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;
1.8 ! isaki 253: exact_match = false;
1.1 isaki 254:
1.8 ! isaki 255: while ((c = getopt(argc, argv, "AadelpRu:")) != -1) {
1.1 isaki 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;
1.8 ! isaki 266: case 'e':
! 267: exact_match = true;
! 268: break;
1.1 isaki 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++) {
1.8 ! isaki 316: if (match(argv[j], testtable[i].name)) {
1.1 isaki 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:
1.8 ! isaki 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:
1.1 isaki 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 (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);
1.7 isaki 1378: void test_open(const char *, int);
1.1 isaki 1379: void test_open_simul(int, int);
1.4 isaki 1380: void try_open_multiuser(bool);
1381: void test_open_multiuser(bool);
1.1 isaki 1382: void test_rdwr_fallback(int, bool, bool);
1383: void test_rdwr_two(int, int);
1384: void test_mmap_mode(int, int);
1385: void test_poll_mode(int, int, int);
1386: void test_kqueue_mode(int, int, int);
1387: volatile int sigio_caught;
1388: void signal_FIOASYNC(int);
1389: void test_AUDIO_SETFD_xxONLY(int);
1390: void test_AUDIO_SETINFO_mode(int, int, int, int);
1391: void test_AUDIO_SETINFO_params_set(int, int, int);
1392: void test_AUDIO_SETINFO_pause(int, int, int);
1393: int getenc_make_table(int, int[][5]);
1394: void xp_getenc(int[][5], int, int, int, struct audio_prinfo *);
1395: void getenc_check_encodings(int, int[][5]);
1396: void test_AUDIO_ERROR(int);
1397: void test_audioctl_open_1(int, int);
1398: void test_audioctl_open_2(int, int);
1.4 isaki 1399: void try_audioctl_open_multiuser(const char *, const char *);
1400: void test_audioctl_open_multiuser(bool, const char *, const char *);
1.1 isaki 1401: void test_audioctl_rw(int);
1402:
1403: #define DEF(name) \
1404: void test__ ## name (void); \
1405: void test__ ## name (void)
1406:
1407: /*
1408: * Whether it can be open()ed with specified mode.
1409: */
1410: void
1411: test_open_mode(int mode)
1412: {
1413: int fd;
1414: int r;
1415:
1416: TEST("open_mode_%s", openmode_str[mode] + 2);
1417:
1418: fd = OPEN(devaudio, mode);
1419: if (mode2aumode(mode) != 0) {
1420: XP_SYS_OK(fd);
1421: } else {
1422: XP_SYS_NG(ENXIO, fd);
1423: }
1424:
1425: if (fd >= 0) {
1426: r = CLOSE(fd);
1427: XP_SYS_EQ(0, r);
1428: }
1429: }
1430: DEF(open_mode_RDONLY) { test_open_mode(O_RDONLY); }
1431: DEF(open_mode_WRONLY) { test_open_mode(O_WRONLY); }
1432: DEF(open_mode_RDWR) { test_open_mode(O_RDWR); }
1433:
1434: /*
1.7 isaki 1435: * Check the initial parameters and stickiness.
1436: * /dev/audio
1437: * The initial parameters are always the same whenever you open.
1438: * /dev/sound and /dev/audioctl
1439: * The initial parameters are inherited from the last /dev/sound or
1440: * /dev/audio.
1.1 isaki 1441: */
1442: void
1.7 isaki 1443: test_open(const char *devname, int mode)
1.1 isaki 1444: {
1445: struct audio_info ai;
1446: struct audio_info ai0;
1.7 isaki 1447: char devfile[16];
1.1 isaki 1448: int fd;
1449: int r;
1450: int can_play;
1451: int can_rec;
1.7 isaki 1452: int exp_mode;
1453: int exp_encoding;
1454: int exp_precision;
1455: int exp_channels;
1456: int exp_sample_rate;
1457: int exp_pause;
1458: int exp_popen;
1459: int exp_ropen;
1.1 isaki 1460:
1.7 isaki 1461: TEST("open_%s_%s", devname, openmode_str[mode] + 2);
1.1 isaki 1462:
1.7 isaki 1463: snprintf(devfile, sizeof(devfile), "/dev/%s%d", devname, unit);
1.1 isaki 1464: can_play = mode2play(mode);
1465: can_rec = mode2rec(mode);
1.7 isaki 1466: if (strcmp(devname, "audioctl") != 0) {
1467: if (can_play + can_rec == 0) {
1468: /* Check whether it cannot be opened */
1469: fd = OPEN(devaudio, mode);
1470: XP_SYS_NG(ENXIO, fd);
1471: return;
1472: }
1.1 isaki 1473: }
1474:
1.7 isaki 1475: /* /dev/audio is always initialized */
1476: if (strcmp(devname, "audio") == 0) {
1477: exp_encoding = AUDIO_ENCODING_ULAW;
1478: exp_precision = 8;
1479: exp_channels = 1;
1480: exp_sample_rate = 8000;
1481: exp_pause = 0;
1.1 isaki 1482: } else {
1.7 isaki 1483: exp_encoding = AUDIO_ENCODING_SLINEAR_LE;
1484: exp_precision = 16;
1485: exp_channels = 2;
1486: exp_sample_rate = 11025;
1487: exp_pause = 1;
1.1 isaki 1488: }
1489:
1.7 isaki 1490: /* /dev/audioctl is always "not opened" */
1491: if (strcmp(devname, "audioctl") == 0) {
1492: exp_mode = 0;
1493: exp_popen = 0;
1494: exp_ropen = 0;
1.1 isaki 1495: } else {
1.7 isaki 1496: exp_mode = mode2aumode(mode);
1497: exp_popen = can_play;
1498: exp_ropen = can_rec;
1.1 isaki 1499: }
1500:
1501:
1502: /*
1.7 isaki 1503: * At first, initialize the sticky parameters both of play and rec.
1504: * This uses /dev/audio to verify /dev/audio. It's not good way but
1505: * I don't have better one...
1.1 isaki 1506: */
1.7 isaki 1507: fd = OPEN(devaudio, openable_mode());
1.1 isaki 1508: REQUIRED_SYS_OK(fd);
1509: r = CLOSE(fd);
1510: REQUIRED_SYS_EQ(0, r);
1511:
1512: /*
1.7 isaki 1513: * Open target device and check the initial parameters
1514: * At this moment, all devices are initialized by default.
1.1 isaki 1515: */
1.7 isaki 1516: fd = OPEN(devfile, mode);
1.1 isaki 1517: REQUIRED_SYS_OK(fd);
1518: memset(&ai, 0, sizeof(ai));
1519: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
1520: REQUIRED_SYS_EQ(0, r);
1521:
1522: XP_NE(0, ai.blocksize);
1523: /* hiwat/lowat */
1.7 isaki 1524: XP_EQ(exp_mode, ai.mode);
1.1 isaki 1525: /* ai.play */
1526: XP_EQ(8000, ai.play.sample_rate);
1527: XP_EQ(1, ai.play.channels);
1528: XP_EQ(8, ai.play.precision);
1529: XP_EQ(AUDIO_ENCODING_ULAW, ai.play.encoding);
1530: /* gain */
1531: /* port */
1532: XP_EQ(0, ai.play.seek);
1533: /* avail_ports */
1.7 isaki 1534: XP_NE(0, ai.play.buffer_size);
1.1 isaki 1535: XP_EQ(0, ai.play.samples);
1536: XP_EQ(0, ai.play.eof);
1537: XP_EQ(0, ai.play.pause);
1538: XP_EQ(0, ai.play.error);
1539: XP_EQ(0, ai.play.waiting);
1540: /* balance */
1.7 isaki 1541: XP_EQ(exp_popen, ai.play.open);
1.1 isaki 1542: XP_EQ(0, ai.play.active);
1543: /* ai.record */
1544: XP_EQ(8000, ai.record.sample_rate);
1545: XP_EQ(1, ai.record.channels);
1546: XP_EQ(8, ai.record.precision);
1547: XP_EQ(AUDIO_ENCODING_ULAW, ai.record.encoding);
1548: /* gain */
1549: /* port */
1550: XP_EQ(0, ai.record.seek);
1551: /* avail_ports */
1.7 isaki 1552: XP_NE(0, ai.record.buffer_size);
1.1 isaki 1553: XP_EQ(0, ai.record.samples);
1554: XP_EQ(0, ai.record.eof);
1555: XP_EQ(0, ai.record.pause);
1556: XP_EQ(0, ai.record.error);
1557: XP_EQ(0, ai.record.waiting);
1558: /* balance */
1.7 isaki 1559: XP_EQ(exp_ropen, ai.record.open);
1.1 isaki 1560: /*
1561: * NetBSD7,8 (may?) be active when opened in recording mode but
1562: * recording has not started yet. (?)
1563: * NetBSD9 is not active at that time.
1564: */
1565: if (netbsd < 9) {
1566: } else {
1567: XP_EQ(0, ai.record.active);
1568: }
1569: /* Save it */
1570: ai0 = ai;
1571:
1572: /*
1573: * Change much as possible
1574: */
1575: AUDIO_INITINFO(&ai);
1.7 isaki 1576: ai.mode = ai0.mode ^ AUMODE_PLAY_ALL;
1.1 isaki 1577: ai.play.sample_rate = 11025;
1578: ai.play.channels = 2;
1579: ai.play.precision = 16;
1580: ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
1581: ai.play.pause = 1;
1582: ai.record.sample_rate = 11025;
1583: ai.record.channels = 2;
1584: ai.record.precision = 16;
1585: ai.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
1586: ai.record.pause = 1;
1587: r = IOCTL(fd, AUDIO_SETINFO, &ai, "ai");
1588: REQUIRED_SYS_EQ(0, r);
1589: r = CLOSE(fd);
1590: REQUIRED_SYS_EQ(0, r);
1591:
1592: /*
1.7 isaki 1593: * Open the same target device again and check
1.1 isaki 1594: */
1.7 isaki 1595: fd = OPEN(devfile, mode);
1.1 isaki 1596: REQUIRED_SYS_OK(fd);
1597: memset(&ai, 0, sizeof(ai));
1598: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
1599: REQUIRED_SYS_EQ(0, r);
1600:
1.7 isaki 1601: XP_NE(0, ai.blocksize);
1.1 isaki 1602: /* hiwat/lowat */
1603: if (netbsd < 8) {
1604: /*
1.7 isaki 1605: * On NetBSD7, the behavior when changing ai.mode on
1.1 isaki 1606: * /dev/audioctl can not be explained yet but I won't
1607: * verify it more over.
1608: */
1609: } else {
1.7 isaki 1610: /* On NetBSD9, changing mode never affects other fds */
1611: XP_EQ(exp_mode, ai.mode);
1.1 isaki 1612: }
1613: /* ai.play */
1.7 isaki 1614: XP_EQ(exp_sample_rate, ai.play.sample_rate);
1615: XP_EQ(exp_channels, ai.play.channels);
1616: XP_EQ(exp_precision, ai.play.precision);
1617: XP_EQ(exp_encoding, ai.play.encoding);
1.1 isaki 1618: /* gain */
1619: /* port */
1620: XP_EQ(0, ai.play.seek);
1621: /* avail_ports */
1.7 isaki 1622: XP_NE(0, ai.play.buffer_size);
1.1 isaki 1623: XP_EQ(0, ai.play.samples);
1624: XP_EQ(0, ai.play.eof);
1.7 isaki 1625: XP_EQ(exp_pause, ai.play.pause);
1.1 isaki 1626: XP_EQ(0, ai.play.error);
1627: XP_EQ(0, ai.play.waiting);
1628: /* balance */
1.7 isaki 1629: XP_EQ(exp_popen, ai.play.open);
1.1 isaki 1630: XP_EQ(0, ai.play.active);
1631: /* ai.record */
1.7 isaki 1632: XP_EQ(exp_sample_rate, ai.record.sample_rate);
1633: XP_EQ(exp_channels, ai.record.channels);
1634: XP_EQ(exp_precision, ai.record.precision);
1635: XP_EQ(exp_encoding, ai.record.encoding);
1.1 isaki 1636: /* gain */
1637: /* port */
1638: XP_EQ(0, ai.record.seek);
1639: /* avail_ports */
1.7 isaki 1640: XP_NE(0, ai.record.buffer_size);
1.1 isaki 1641: XP_EQ(0, ai.record.samples);
1642: XP_EQ(0, ai.record.eof);
1.7 isaki 1643: XP_EQ(exp_pause, ai.record.pause);
1.1 isaki 1644: XP_EQ(0, ai.record.error);
1645: XP_EQ(0, ai.record.waiting);
1646: /* balance */
1.7 isaki 1647: XP_EQ(exp_ropen, ai.record.open);
1.1 isaki 1648: if (netbsd < 9) {
1649: } else {
1650: XP_EQ(0, ai.record.active);
1651: }
1652:
1653: r = CLOSE(fd);
1654: REQUIRED_SYS_EQ(0, r);
1655: }
1.7 isaki 1656: DEF(open_audio_RDONLY) { test_open("audio", O_RDONLY); }
1657: DEF(open_audio_WRONLY) { test_open("audio", O_WRONLY); }
1658: DEF(open_audio_RDWR) { test_open("audio", O_RDWR); }
1659: DEF(open_sound_RDONLY) { test_open("sound", O_RDONLY); }
1660: DEF(open_sound_WRONLY) { test_open("sound", O_WRONLY); }
1661: DEF(open_sound_RDWR) { test_open("sound", O_RDWR); }
1662: DEF(open_audioctl_RDONLY) { test_open("audioctl", O_RDONLY); }
1663: DEF(open_audioctl_WRONLY) { test_open("audioctl", O_WRONLY); }
1664: DEF(open_audioctl_RDWR) { test_open("audioctl", O_RDWR); }
1.1 isaki 1665:
1666: /*
1667: * Open (1) /dev/sound -> (2) /dev/audio -> (3) /dev/sound,
1668: * Both of /dev/audio and /dev/sound share the sticky parameters,
1669: * /dev/sound inherits and use it but /dev/audio initialize and use it.
1670: * So 2nd audio descriptor affects 3rd sound descriptor.
1671: */
1672: DEF(open_sound_sticky)
1673: {
1674: struct audio_info ai;
1675: int fd;
1676: int r;
1677: int openmode;
1678:
1679: TEST("open_sound_sticky");
1680:
1681: openmode = openable_mode();
1682:
1683: /* First, open /dev/sound and change encoding as a delegate */
1684: fd = OPEN(devsound, openmode);
1685: REQUIRED_SYS_OK(fd);
1686: AUDIO_INITINFO(&ai);
1687: ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
1688: ai.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
1689: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
1690: REQUIRED_SYS_EQ(0, r);
1691: r = CLOSE(fd);
1692: REQUIRED_SYS_EQ(0, r);
1693:
1694: /* Next, open /dev/audio. It makes the encoding mulaw */
1695: fd = OPEN(devaudio, openmode);
1696: REQUIRED_SYS_OK(fd);
1697: r = CLOSE(fd);
1698: REQUIRED_SYS_EQ(0, r);
1699:
1700: /* And then, open /dev/sound again */
1701: fd = OPEN(devsound, openmode);
1702: REQUIRED_SYS_OK(fd);
1703: memset(&ai, 0, sizeof(ai));
1704: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
1705: REQUIRED_SYS_EQ(0, r);
1706: XP_EQ(AUDIO_ENCODING_ULAW, ai.play.encoding);
1707: XP_EQ(AUDIO_ENCODING_ULAW, ai.record.encoding);
1708: r = CLOSE(fd);
1709: REQUIRED_SYS_EQ(0, r);
1710: }
1711:
1712: /*
1.7 isaki 1713: * /dev/audioctl has stickiness like /dev/sound.
1.1 isaki 1714: */
1715: DEF(open_audioctl_sticky)
1716: {
1717: struct audio_info ai;
1718: int fd;
1719: int r;
1720: int openmode;
1721:
1722: TEST("open_audioctl_sticky");
1723:
1724: openmode = openable_mode();
1725:
1.7 isaki 1726: /* First, open /dev/audio and change encoding */
1727: fd = OPEN(devaudio, openmode);
1.1 isaki 1728: REQUIRED_SYS_OK(fd);
1729: AUDIO_INITINFO(&ai);
1730: ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
1.7 isaki 1731: ai.play.precision = 16;
1.1 isaki 1732: ai.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
1.7 isaki 1733: ai.record.precision = 16;
1734: r = IOCTL(fd, AUDIO_SETINFO, &ai, "SLINEAR_LE");
1.1 isaki 1735: REQUIRED_SYS_EQ(0, r);
1736: r = CLOSE(fd);
1737: REQUIRED_SYS_EQ(0, r);
1738:
1.7 isaki 1739: /* Next, open /dev/audioctl. It should be affected */
1.1 isaki 1740: fd = OPEN(devaudioctl, openmode);
1741: REQUIRED_SYS_OK(fd);
1742: memset(&ai, 0, sizeof(ai));
1743: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
1744: REQUIRED_SYS_EQ(0, r);
1745: XP_EQ(AUDIO_ENCODING_SLINEAR_LE, ai.play.encoding);
1.7 isaki 1746: XP_EQ(16, ai.play.precision);
1.1 isaki 1747: XP_EQ(AUDIO_ENCODING_SLINEAR_LE, ai.record.encoding);
1.7 isaki 1748: XP_EQ(16, ai.record.precision);
1749:
1750: /* Then, change /dev/audioctl */
1751: AUDIO_INITINFO(&ai);
1752: ai.play.encoding = AUDIO_ENCODING_ULAW;
1753: ai.play.precision = 8;
1754: ai.record.encoding = AUDIO_ENCODING_ULAW;
1755: ai.record.precision = 8;
1756: r = IOCTL(fd, AUDIO_SETINFO, &ai, "ULAW");
1757: REQUIRED_SYS_EQ(0, r);
1758: r = CLOSE(fd);
1759: REQUIRED_SYS_EQ(0, r);
1760:
1761: /* Finally, open /dev/sound. It also should be affected */
1762: fd = OPEN(devsound, openmode);
1763: REQUIRED_SYS_OK(fd);
1764: memset(&ai, 0, sizeof(ai));
1765: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
1766: REQUIRED_SYS_EQ(0, r);
1767: XP_EQ(AUDIO_ENCODING_ULAW, ai.play.encoding);
1768: XP_EQ(8, ai.play.precision);
1769: XP_EQ(AUDIO_ENCODING_ULAW, ai.record.encoding);
1770: XP_EQ(8, ai.record.precision);
1.1 isaki 1771: r = CLOSE(fd);
1772: REQUIRED_SYS_EQ(0, r);
1773: }
1774:
1775: /*
1776: * Open two descriptors simultaneously.
1777: */
1778: void
1779: test_open_simul(int mode0, int mode1)
1780: {
1781: struct audio_info ai;
1782: int fd0, fd1;
1783: int i;
1784: int r;
1785: int actmode;
1786: #define AUMODE_BOTH (AUMODE_PLAY | AUMODE_RECORD)
1787: struct {
1788: int mode0;
1789: int mode1;
1790: } expfulltable[] = {
1791: /* expected fd0 expected fd1 (-errno expects error) */
1792: { AUMODE_RECORD, AUMODE_RECORD }, // REC, REC
1793: { AUMODE_RECORD, AUMODE_PLAY }, // REC, PLAY
1794: { AUMODE_RECORD, AUMODE_BOTH }, // REC, BOTH
1795: { AUMODE_PLAY, AUMODE_RECORD }, // PLAY, REC
1796: { AUMODE_PLAY, AUMODE_PLAY }, // PLAY, PLAY
1797: { AUMODE_PLAY, AUMODE_BOTH }, // PLAY, BOTH
1798: { AUMODE_BOTH, AUMODE_RECORD }, // BOTH, REC
1799: { AUMODE_BOTH, AUMODE_PLAY }, // BOTH, PLAY
1800: { AUMODE_BOTH, AUMODE_BOTH }, // BOTH, BOTH
1801: },
1802: exphalftable[] = {
1803: /* expected fd0 expected fd1 (-errno expects error) */
1804: { AUMODE_RECORD, AUMODE_RECORD }, // REC, REC
1805: { AUMODE_RECORD, -ENODEV }, // REC, PLAY
1806: { AUMODE_RECORD, -ENODEV }, // REC, BOTH
1807: { AUMODE_PLAY, -ENODEV }, // PLAY, REC
1808: { AUMODE_PLAY, AUMODE_PLAY }, // PLAY, PLAY
1809: { AUMODE_PLAY, AUMODE_PLAY }, // PLAY, BOTH
1810: { AUMODE_PLAY, -ENODEV }, // BOTH, REC
1811: { AUMODE_PLAY, AUMODE_PLAY }, // BOTH, PLAY
1812: { AUMODE_PLAY, AUMODE_PLAY }, // BOTH, BOTH
1813: }, *exptable;
1814:
1815: /* The expected values are different in half-duplex or full-duplex */
1816: if (hw_fulldup()) {
1817: exptable = expfulltable;
1818: } else {
1819: exptable = exphalftable;
1820: }
1821:
1822: TEST("open_simul_%s_%s",
1823: openmode_str[mode0] + 2,
1824: openmode_str[mode1] + 2);
1825:
1826: if (netbsd < 8) {
1827: XP_SKIP("Multiple open is not supported");
1828: return;
1829: }
1830:
1831: if (mode2aumode(mode0) == 0 || mode2aumode(mode1) == 0) {
1832: XP_SKIP("Operation not allowed on this hardware property");
1833: return;
1834: }
1835:
1836: i = mode0 * 3 + mode1;
1837:
1838: /* Open first one */
1839: fd0 = OPEN(devaudio, mode0);
1840: REQUIRED_SYS_OK(fd0);
1841: r = IOCTL(fd0, AUDIO_GETBUFINFO, &ai, "");
1842: REQUIRED_SYS_EQ(0, r);
1843: actmode = ai.mode & AUMODE_BOTH;
1844: XP_EQ(exptable[i].mode0, actmode);
1845:
1846: /* Open second one */
1847: fd1 = OPEN(devaudio, mode1);
1848: if (exptable[i].mode1 >= 0) {
1849: /* Case to expect to be able to open */
1850: REQUIRED_SYS_OK(fd1);
1851: r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, "");
1852: XP_SYS_EQ(0, r);
1853: if (r == 0) {
1854: actmode = ai.mode & AUMODE_BOTH;
1855: XP_EQ(exptable[i].mode1, actmode);
1856: }
1857: } else {
1858: /* Case to expect not to be able to open */
1859: XP_SYS_NG(ENODEV, fd1);
1860: if (fd1 == -1) {
1861: XP_EQ(-exptable[i].mode1, errno);
1862: } else {
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_FAIL("expects error but %d", actmode);
1868: }
1869: }
1870: }
1871:
1872: if (fd1 >= 0) {
1873: r = CLOSE(fd1);
1874: XP_SYS_EQ(0, r);
1875: }
1876:
1877: r = CLOSE(fd0);
1878: XP_SYS_EQ(0, r);
1879: }
1880: DEF(open_simul_RDONLY_RDONLY) { test_open_simul(O_RDONLY, O_RDONLY); }
1881: DEF(open_simul_RDONLY_WRONLY) { test_open_simul(O_RDONLY, O_WRONLY); }
1882: DEF(open_simul_RDONLY_RDWR) { test_open_simul(O_RDONLY, O_RDWR); }
1883: DEF(open_simul_WRONLY_RDONLY) { test_open_simul(O_WRONLY, O_RDONLY); }
1884: DEF(open_simul_WRONLY_WRONLY) { test_open_simul(O_WRONLY, O_WRONLY); }
1885: DEF(open_simul_WRONLY_RDWR) { test_open_simul(O_WRONLY, O_RDWR); }
1886: DEF(open_simul_RDWR_RDONLY) { test_open_simul(O_RDWR, O_RDONLY); }
1887: DEF(open_simul_RDWR_WRONLY) { test_open_simul(O_RDWR, O_WRONLY); }
1888: DEF(open_simul_RDWR_RDWR) { test_open_simul(O_RDWR, O_RDWR); }
1889:
1890: /*
1891: * /dev/audio can be opened by other user who opens /dev/audio.
1892: */
1893: void
1.4 isaki 1894: try_open_multiuser(bool multiuser)
1.1 isaki 1895: {
1896: int fd0;
1897: int fd1;
1898: int r;
1899: uid_t ouid;
1900:
1901: /*
1902: * Test1: Open as root first and then unprivileged user.
1903: */
1904:
1905: /* At first, open as root */
1906: fd0 = OPEN(devaudio, openable_mode());
1907: REQUIRED_SYS_OK(fd0);
1908:
1909: ouid = GETUID();
1910: r = SETEUID(1);
1911: REQUIRED_SYS_EQ(0, r);
1912:
1913: /* Then, open as unprivileged user */
1914: fd1 = OPEN(devaudio, openable_mode());
1915: if (multiuser) {
1916: /* If multiuser, another user also can open */
1917: XP_SYS_OK(fd1);
1918: } else {
1919: /* If not multiuser, another user cannot open */
1920: XP_SYS_NG(EPERM, fd1);
1921: }
1922: if (fd1 != -1) {
1923: r = CLOSE(fd1);
1924: XP_SYS_EQ(0, r);
1925: }
1926:
1927: r = SETEUID(ouid);
1928: REQUIRED_SYS_EQ(0, r);
1929:
1930: r = CLOSE(fd0);
1931: XP_SYS_EQ(0, r);
1932:
1933: /*
1934: * Test2: Open as unprivileged user first and then root.
1935: */
1936:
1937: /* At first, open as unprivileged user */
1938: ouid = GETUID();
1939: r = SETEUID(1);
1940: REQUIRED_SYS_EQ(0, r);
1941:
1942: fd0 = OPEN(devaudio, openable_mode());
1943: REQUIRED_SYS_OK(fd0);
1944:
1945: /* Then open as root */
1946: r = SETEUID(ouid);
1947: REQUIRED_SYS_EQ(0, r);
1948:
1949: /* root always can open */
1950: fd1 = OPEN(devaudio, openable_mode());
1951: XP_SYS_OK(fd1);
1952: if (fd1 != -1) {
1953: r = CLOSE(fd1);
1954: XP_SYS_EQ(0, r);
1955: }
1956:
1957: /* Close first one as unprivileged user */
1958: r = SETEUID(1);
1959: REQUIRED_SYS_EQ(0, r);
1960: r = CLOSE(fd0);
1961: XP_SYS_EQ(0, r);
1962: r = SETEUID(ouid);
1963: REQUIRED_SYS_EQ(0, r);
1964: }
1965: /*
1966: * This is a wrapper for open_multiuser.
1967: * XXX XP_* macros are not compatible with on-error-goto, we need try-catch...
1968: */
1969: void
1.4 isaki 1970: test_open_multiuser(bool multiuser)
1.1 isaki 1971: {
1972: char mibname[32];
1973: bool oldval;
1974: size_t oldlen;
1975: int r;
1976:
1977: TEST("open_multiuser_%d", multiuser);
1978: if (netbsd < 8) {
1979: XP_SKIP("Multiple open is not supported");
1980: return;
1981: }
1982: if (netbsd < 9) {
1983: /* NetBSD8 has no way (difficult) to determine device name */
1984: XP_SKIP("NetBSD8 cannot determine device name");
1985: return;
1986: }
1987: if (geteuid() != 0) {
1988: XP_SKIP("Must be run as a privileged user");
1989: return;
1990: }
1991:
1992: /* Get current multiuser mode (and save it) */
1993: snprintf(mibname, sizeof(mibname), "hw.%s.multiuser", devicename);
1994: oldlen = sizeof(oldval);
1995: r = SYSCTLBYNAME(mibname, &oldval, &oldlen, NULL, 0);
1996: REQUIRED_SYS_EQ(0, r);
1997: DPRINTF(" > multiuser=%d\n", oldval);
1998:
1999: /* Change if necessary */
2000: if (oldval != multiuser) {
1.4 isaki 2001: r = SYSCTLBYNAME(mibname, NULL, NULL, &multiuser,
2002: sizeof(multiuser));
1.1 isaki 2003: REQUIRED_SYS_EQ(0, r);
2004: DPRINTF(" > new multiuser=%d\n", multiuser);
2005: }
2006:
2007: /* Do test */
2008: try_open_multiuser(multiuser);
2009:
2010: /* Restore multiuser mode */
1.4 isaki 2011: if (oldval != multiuser) {
1.1 isaki 2012: DPRINTF(" > restore multiuser to %d\n", oldval);
2013: r = SYSCTLBYNAME(mibname, NULL, NULL, &oldval, sizeof(oldval));
2014: REQUIRED_SYS_EQ(0, r);
2015: }
2016: }
1.4 isaki 2017: DEF(open_multiuser_0) { test_open_multiuser(false); }
2018: DEF(open_multiuser_1) { test_open_multiuser(true); }
1.1 isaki 2019:
2020: /*
2021: * Normal playback (with PLAY_ALL).
2022: * It does not verify real playback data.
2023: */
2024: DEF(write_PLAY_ALL)
2025: {
2026: char buf[8000];
2027: int fd;
2028: int r;
2029:
2030: TEST("write_PLAY_ALL");
2031:
2032: fd = OPEN(devaudio, O_WRONLY);
2033: if (hw_canplay()) {
2034: REQUIRED_SYS_OK(fd);
2035: } else {
2036: XP_SYS_NG(ENXIO, fd);
2037: return;
2038: }
2039:
2040: /* mulaw 1sec silence */
2041: memset(buf, 0xff, sizeof(buf));
2042: r = WRITE(fd, buf, sizeof(buf));
2043: XP_SYS_EQ(sizeof(buf), r);
2044:
2045: r = CLOSE(fd);
2046: XP_SYS_EQ(0, r);
2047: }
2048:
2049: /*
2050: * Normal playback (without PLAY_ALL).
2051: * It does not verify real playback data.
2052: */
2053: DEF(write_PLAY)
2054: {
2055: struct audio_info ai;
2056: char *wav;
2057: int wavsize;
2058: int totalsize;
2059: int fd;
2060: int r;
2061:
2062: TEST("write_PLAY");
2063:
2064: fd = OPEN(devaudio, O_WRONLY);
2065: if (hw_canplay()) {
2066: REQUIRED_SYS_OK(fd);
2067: } else {
2068: XP_SYS_NG(ENXIO, fd);
2069: return;
2070: }
2071:
2072: /* Drop PLAY_ALL */
2073: AUDIO_INITINFO(&ai);
2074: ai.mode = AUMODE_PLAY;
2075: r = IOCTL(fd, AUDIO_SETINFO, &ai, "mode");
2076: REQUIRED_SYS_EQ(0, r);
2077:
2078: /* Check mode and get blocksize */
2079: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
2080: REQUIRED_SYS_EQ(0, r);
2081: XP_EQ(AUMODE_PLAY, ai.mode);
2082:
2083: wavsize = ai.blocksize;
2084: wav = (char *)malloc(wavsize);
2085: REQUIRED_IF(wav != NULL);
2086: memset(wav, 0xff, wavsize);
2087:
2088: /* Write blocks until 1sec */
2089: for (totalsize = 0; totalsize < 8000; ) {
2090: r = WRITE(fd, wav, wavsize);
2091: XP_SYS_EQ(wavsize, r);
2092: if (r == -1)
2093: break; /* XXX */
2094: totalsize += r;
2095: }
2096:
2097: /* XXX What should I test it? */
2098: /* Check ai.play.error */
2099: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
2100: REQUIRED_SYS_EQ(0, r);
2101: XP_EQ(0, ai.play.error);
2102:
2103: /* Playback data is no longer necessary */
2104: r = IOCTL(fd, AUDIO_FLUSH, NULL, "");
2105: REQUIRED_SYS_EQ(0, r);
2106:
2107: r = CLOSE(fd);
2108: REQUIRED_SYS_EQ(0, r);
2109:
2110: free(wav);
2111: }
2112:
2113: /*
2114: * Normal recording.
2115: * It does not verify real recorded data.
2116: */
2117: DEF(read)
2118: {
2119: char buf[8000];
2120: int fd;
2121: int r;
2122:
2123: TEST("read");
2124:
2125: fd = OPEN(devaudio, O_RDONLY);
2126: if (hw_canrec()) {
2127: REQUIRED_SYS_OK(fd);
2128: } else {
2129: XP_SYS_NG(ENXIO, fd);
2130: return;
2131: }
2132:
2133: /* mulaw 1sec */
2134: r = READ(fd, buf, sizeof(buf));
2135: XP_SYS_EQ(sizeof(buf), r);
2136:
2137: r = CLOSE(fd);
2138: XP_SYS_EQ(0, r);
2139: }
2140:
2141: /*
2142: * Repeat open-write-close cycle.
2143: */
2144: DEF(rept_write)
2145: {
2146: struct timeval start, end, result;
2147: double res;
2148: char buf[8000]; /* 1sec in 8bit-mulaw,1ch,8000Hz */
2149: int fd;
2150: int r;
2151: int n;
2152:
2153: TEST("rept_write");
2154:
2155: if (hw_canplay() == 0) {
2156: XP_SKIP("This test is only for playable device");
2157: return;
2158: }
2159:
2160: /* XXX It may timeout on some hardware driver. */
2161: XP_SKIP("not yet");
2162: return;
2163:
2164: memset(buf, 0xff, sizeof(buf));
2165: n = 3;
2166: gettimeofday(&start, NULL);
2167: for (int i = 0; i < n; i++) {
2168: fd = OPEN(devaudio, O_WRONLY);
2169: REQUIRED_SYS_OK(fd);
2170:
2171: r = WRITE(fd, buf, sizeof(buf));
2172: XP_SYS_EQ(sizeof(buf), r);
2173:
2174: r = CLOSE(fd);
2175: XP_SYS_EQ(0, r);
2176: }
2177: gettimeofday(&end, NULL);
2178: timersub(&end, &start, &result);
2179: res = (double)result.tv_sec + (double)result.tv_usec / 1000000;
2180: /* Make judgement but not too strict */
2181: if (res >= n * 1.5) {
2182: XP_FAIL("expects %d sec but %4.1f sec", n, res);
2183: return;
2184: }
2185: }
2186:
2187: /*
2188: * Repeat open-read-close cycle.
2189: */
2190: DEF(rept_read)
2191: {
2192: struct timeval start, end, result;
2193: double res;
2194: char buf[8000]; /* 1sec in 8bit-mulaw,1ch,8000Hz */
2195: int fd;
2196: int r;
2197: int n;
2198:
2199: TEST("rept_read");
2200:
2201: if (hw_canrec() == 0) {
2202: XP_SKIP("This test is only for recordable device");
2203: return;
2204: }
2205:
2206: /* XXX It may timeout on some hardware driver. */
2207: XP_SKIP("not yet");
2208: return;
2209:
2210: n = 3;
2211: gettimeofday(&start, NULL);
2212: for (int i = 0; i < n; i++) {
2213: fd = OPEN(devaudio, O_RDONLY);
2214: REQUIRED_SYS_OK(fd);
2215:
2216: r = READ(fd, buf, sizeof(buf));
2217: XP_SYS_EQ(sizeof(buf), r);
2218:
2219: r = CLOSE(fd);
2220: XP_SYS_EQ(0, r);
2221: }
2222: gettimeofday(&end, NULL);
2223: timersub(&end, &start, &result);
2224: res = (double)result.tv_sec + (double)result.tv_usec / 1000000;
2225: /* Make judgement but not too strict */
2226: if (res >= n * 1.5) {
2227: XP_FAIL("expects %d sec but %4.1f sec", n, res);
2228: return;
2229: }
2230: }
2231:
2232: /*
2233: * Opening with O_RDWR on half-duplex hardware falls back to O_WRONLY.
2234: * expwrite: expected to be able to play.
2235: * expread : expected to be able to recored.
2236: */
2237: void
2238: test_rdwr_fallback(int openmode, bool expwrite, bool expread)
2239: {
2240: struct audio_info ai;
2241: char buf[10];
2242: int fd;
2243: int r;
2244:
2245: TEST("rdwr_fallback_%s", openmode_str[openmode] + 2);
2246:
2247: if (hw_bidir() == 0) {
2248: XP_SKIP("This test is only for bi-directional device");
2249: return;
2250: }
2251:
2252: AUDIO_INITINFO(&ai);
2253: ai.play.pause = 1;
2254: ai.record.pause = 1;
2255:
2256: fd = OPEN(devaudio, openmode);
2257: REQUIRED_SYS_OK(fd);
2258:
2259: /* Set pause not to play noise */
2260: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause");
2261: REQUIRED_SYS_EQ(0, r);
2262:
2263: memset(buf, 0xff, sizeof(buf));
2264: r = WRITE(fd, buf, sizeof(buf));
2265: if (expwrite) {
2266: XP_SYS_EQ(sizeof(buf), r);
2267: } else {
2268: XP_SYS_NG(EBADF, r);
2269: }
2270:
2271: r = READ(fd, buf, 0);
2272: if (expread) {
2273: XP_SYS_EQ(0, r);
2274: } else {
2275: XP_SYS_NG(EBADF, r);
2276: }
2277:
2278: r = CLOSE(fd);
2279: REQUIRED_SYS_EQ(0, r);
2280: }
2281: DEF(rdwr_fallback_RDONLY) { test_rdwr_fallback(O_RDONLY, false, true); }
2282: DEF(rdwr_fallback_WRONLY) { test_rdwr_fallback(O_WRONLY, true, false); }
2283: DEF(rdwr_fallback_RDWR) {
2284: bool expread;
2285: /*
2286: * On NetBSD7, O_RDWR on half-duplex is accepted. It's possible to
2287: * read and write if they don't occur at the same time.
2288: * On NetBSD9, O_RDWR on half-duplex falls back O_WRONLY.
2289: */
2290: if (netbsd < 8) {
2291: expread = true;
2292: } else {
2293: expread = hw_fulldup() ? true : false;
2294: }
2295: test_rdwr_fallback(O_RDWR, true, expread);
2296: }
2297:
2298: /*
2299: * On full-duplex hardware, the second descriptor's readablity/writability
2300: * is not depend on the first descriptor('s open mode).
2301: * On half-duplex hardware, it depends on the first descriptor's open mode.
2302: */
2303: void
2304: test_rdwr_two(int mode0, int mode1)
2305: {
2306: struct audio_info ai;
2307: char wbuf[100]; /* 1/80sec in 8bit-mulaw,1ch,8000Hz */
2308: char rbuf[100]; /* 1/80sec in 8bit-mulaw,1ch,8000Hz */
2309: bool canopen;
2310: bool canwrite;
2311: bool canread;
2312: int fd0;
2313: int fd1;
2314: int r;
2315: struct {
2316: bool canopen;
2317: bool canwrite;
2318: bool canread;
2319: } exptable_full[] = {
2320: /* open write read 1st, 2nd mode */
2321: { 1, 0, 1 }, /* REC, REC */
2322: { 1, 1, 0 }, /* REC, PLAY */
2323: { 1, 1, 1 }, /* REC, BOTH */
2324: { 1, 0, 1 }, /* PLAY, REC */
2325: { 1, 1, 0 }, /* PLAY, PLAY */
2326: { 1, 1, 1 }, /* PLAY, BOTH */
2327: { 1, 0, 1 }, /* BOTH, REC */
2328: { 1, 1, 0 }, /* BOTH, PLAY */
2329: { 1, 1, 1 }, /* BOTH, BOTH */
2330: },
2331: exptable_half[] = {
2332: { 1, 0, 1 }, /* REC, REC */
2333: { 0, 0, 0 }, /* REC, PLAY */
2334: { 0, 0, 0 }, /* REC, BOTH */
2335: { 0, 0, 0 }, /* PLAY, REC */
2336: { 1, 1, 0 }, /* PLAY, PLAY */
2337: { 1, 1, 0 }, /* PLAY, BOTH */
2338: { 0, 0, 0 }, /* BOTH, REC */
2339: { 1, 1, 0 }, /* BOTH, PLAY */
2340: { 0, 0, 0 }, /* BOTH, BOTH */
2341: }, *exptable;
2342:
2343: TEST("rdwr_two_%s_%s",
2344: openmode_str[mode0] + 2,
2345: openmode_str[mode1] + 2);
2346:
2347: if (netbsd < 8) {
2348: XP_SKIP("Multiple open is not supported");
2349: return;
2350: }
2351: if (hw_bidir() == 0) {
2352: XP_SKIP("This test is only for bi-directional device");
2353: return;
2354: }
2355:
2356: exptable = hw_fulldup() ? exptable_full : exptable_half;
2357:
2358: canopen = exptable[mode0 * 3 + mode1].canopen;
2359: canwrite = exptable[mode0 * 3 + mode1].canwrite;
2360: canread = exptable[mode0 * 3 + mode1].canread;
2361:
2362: if (!canopen) {
2363: XP_SKIP("This combination is not openable on half-duplex");
2364: return;
2365: }
2366:
2367: fd0 = OPEN(devaudio, mode0);
2368: REQUIRED_SYS_OK(fd0);
2369:
2370: fd1 = OPEN(devaudio, mode1);
2371: REQUIRED_SYS_OK(fd1);
2372:
2373: /* Silent data to make no sound */
2374: memset(&wbuf, 0xff, sizeof(wbuf));
2375: /* Pause to make no sound */
2376: AUDIO_INITINFO(&ai);
2377: ai.play.pause = 1;
2378: r = IOCTL(fd0, AUDIO_SETINFO, &ai, "pause");
2379: XP_SYS_EQ(0, r);
2380:
2381: /* write(fd1) */
2382: r = WRITE(fd1, wbuf, sizeof(wbuf));
2383: if (canwrite) {
2384: XP_SYS_EQ(100, r);
2385: } else {
2386: XP_SYS_NG(EBADF, r);
2387: }
2388:
2389: /* read(fd1) */
2390: r = READ(fd1, rbuf, sizeof(rbuf));
2391: if (canread) {
2392: XP_SYS_EQ(100, r);
2393: } else {
2394: XP_SYS_NG(EBADF, r);
2395: }
2396:
2397: r = CLOSE(fd0);
2398: XP_SYS_EQ(0, r);
2399: r = CLOSE(fd1);
2400: XP_SYS_EQ(0, r);
2401: }
2402: DEF(rdwr_two_RDONLY_RDONLY) { test_rdwr_two(O_RDONLY, O_RDONLY); }
2403: DEF(rdwr_two_RDONLY_WRONLY) { test_rdwr_two(O_RDONLY, O_WRONLY); }
2404: DEF(rdwr_two_RDONLY_RDWR) { test_rdwr_two(O_RDONLY, O_RDWR); }
2405: DEF(rdwr_two_WRONLY_RDONLY) { test_rdwr_two(O_WRONLY, O_RDONLY); }
2406: DEF(rdwr_two_WRONLY_WRONLY) { test_rdwr_two(O_WRONLY, O_WRONLY); }
2407: DEF(rdwr_two_WRONLY_RDWR) { test_rdwr_two(O_WRONLY, O_RDWR); }
2408: DEF(rdwr_two_RDWR_RDONLY) { test_rdwr_two(O_RDWR, O_RDONLY); }
2409: DEF(rdwr_two_RDWR_WRONLY) { test_rdwr_two(O_RDWR, O_WRONLY); }
2410: DEF(rdwr_two_RDWR_RDWR) { test_rdwr_two(O_RDWR, O_RDWR); }
2411:
2412: /*
2413: * Read and write different descriptors simultaneously.
2414: * Only on full-duplex.
2415: */
2416: DEF(rdwr_simul)
2417: {
2418: char wbuf[1000]; /* 1/8sec in mulaw,1ch,8kHz */
2419: char rbuf[1000];
2420: int fd0;
2421: int fd1;
2422: int r;
2423: int status;
2424: pid_t pid;
2425:
2426: TEST("rdwr_simul");
2427: if (netbsd < 8) {
2428: XP_SKIP("Multiple open is not supported");
2429: return;
2430: }
2431: if (!hw_fulldup()) {
2432: XP_SKIP("This test is only for full-duplex device");
2433: return;
2434: }
2435:
2436: /* Silence data to make no sound */
2437: memset(wbuf, 0xff, sizeof(wbuf));
2438:
2439: fd0 = OPEN(devaudio, O_WRONLY);
2440: REQUIRED_SYS_OK(fd0);
2441: fd1 = OPEN(devaudio, O_RDONLY);
2442: REQUIRED_SYS_OK(fd1);
2443:
2444: fflush(stdout);
2445: fflush(stderr);
2446: pid = fork();
2447: if (pid == -1)
2448: xp_err(1, __LINE__, "fork");
2449:
2450: if (pid == 0) {
2451: /* child (read) */
2452: for (int i = 0; i < 10; i++) {
2453: r = READ(fd1, rbuf, sizeof(rbuf));
2454: if (r == -1)
2455: xp_err(1, __LINE__, "read(i=%d)", i);
2456: }
2457: exit(0);
2458: } else {
2459: /* parent (write) */
2460: for (int i = 0; i < 10; i++) {
2461: r = WRITE(fd0, wbuf, sizeof(wbuf));
2462: if (r == -1)
2463: xp_err(1, __LINE__, "write(i=%d)", i);
2464: }
2465: waitpid(pid, &status, 0);
2466: }
2467:
2468: CLOSE(fd0);
2469: CLOSE(fd1);
2470: /* If you reach here, consider as success */
2471: XP_EQ(0, 0);
2472: }
2473:
2474: /*
2475: * DRAIN should work even on incomplete data left.
2476: */
2477: DEF(drain_incomplete)
2478: {
2479: struct audio_info ai;
2480: int r;
2481: int fd;
2482:
2483: TEST("drain_incomplete");
2484:
2485: if (hw_canplay() == 0) {
2486: XP_SKIP("This test is only for playable device");
2487: return;
2488: }
2489:
2490: fd = OPEN(devaudio, O_WRONLY);
2491: REQUIRED_SYS_OK(fd);
2492:
2493: AUDIO_INITINFO(&ai);
2494: /* let precision > 8 */
2495: ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
2496: ai.play.precision = 16;
2497: ai.mode = AUMODE_PLAY;
2498: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
2499: REQUIRED_SYS_EQ(0, r);
2500: /* Write one byte and then close */
2501: r = WRITE(fd, &r, 1);
2502: XP_SYS_EQ(1, r);
2503: r = CLOSE(fd);
2504: XP_SYS_EQ(0, r);
2505: }
2506:
2507: /*
2508: * DRAIN should work even in pause.
2509: */
2510: DEF(drain_pause)
2511: {
2512: struct audio_info ai;
2513: int r;
2514: int fd;
2515:
2516: TEST("drain_pause");
2517:
2518: if (hw_canplay() == 0) {
2519: XP_SKIP("This test is only for playable device");
2520: return;
2521: }
2522:
2523: fd = OPEN(devaudio, O_WRONLY);
2524: REQUIRED_SYS_OK(fd);
2525:
2526: /* Set pause */
2527: AUDIO_INITINFO(&ai);
2528: ai.play.pause = 1;
2529: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
2530: XP_SYS_EQ(0, r);
2531: /* Write some data and then close */
2532: r = WRITE(fd, &r, 4);
2533: XP_SYS_EQ(4, r);
2534: r = CLOSE(fd);
2535: XP_SYS_EQ(0, r);
2536: }
2537:
2538: /*
2539: * DRAIN does not affect for record-only descriptor.
2540: */
2541: DEF(drain_onrec)
2542: {
2543: int fd;
2544: int r;
2545:
2546: TEST("drain_onrec");
2547:
2548: if (hw_canrec() == 0) {
2549: XP_SKIP("This test is only for recordable device");
2550: return;
2551: }
2552:
2553: fd = OPEN(devaudio, O_RDONLY);
2554: REQUIRED_SYS_OK(fd);
2555:
2556: r = IOCTL(fd, AUDIO_DRAIN, NULL, "");
2557: XP_SYS_EQ(0, r);
2558:
2559: r = CLOSE(fd);
2560: XP_SYS_EQ(0, r);
2561: }
2562:
2563: /*
2564: * Whether mmap() succeeds with specified parameter.
2565: */
2566: void
2567: test_mmap_mode(int mode, int prot)
2568: {
2569: char buf[10];
2570: struct audio_info ai;
2571: const char *protstr;
2572: int expected;
2573: int fd;
2574: int r;
2575: int len;
2576: void *ptr;
2577:
2578: if (prot == PROT_NONE) {
2579: protstr = "NONE";
2580: } else if (prot == PROT_READ) {
2581: protstr = "READ";
2582: } else if (prot == PROT_WRITE) {
2583: protstr = "WRITE";
2584: } else if (prot == (PROT_READ | PROT_WRITE)) {
2585: protstr = "READWRITE";
2586: } else {
2587: xp_errx(1, __LINE__, "unknown prot %x\n", prot);
2588: }
2589: TEST("mmap_%s_%s", openmode_str[mode] + 2, protstr);
2590: if ((props & AUDIO_PROP_MMAP) == 0) {
2591: XP_SKIP("This test is only for mmap-able device");
2592: return;
2593: }
2594: if (mode2aumode(mode) == 0) {
2595: XP_SKIP("Operation not allowed on this hardware property");
2596: return;
2597: }
2598: #if !defined(NO_RUMP)
2599: if (use_rump) {
2600: XP_SKIP("rump doesn't support mmap");
2601: return;
2602: }
2603: #endif
2604:
2605: /*
2606: * On NetBSD7 and 8, mmap() always succeeds regardless of open mode.
2607: * On NetBSD9, mmap() succeeds only for writable descriptor.
2608: */
2609: expected = mode2play(mode);
2610: if (netbsd < 9) {
2611: expected = true;
2612: }
2613:
2614: fd = OPEN(devaudio, mode);
2615: REQUIRED_SYS_OK(fd);
2616:
2617: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "get");
2618: REQUIRED_SYS_EQ(0, r);
2619:
2620: len = ai.play.buffer_size;
2621:
2622: /* Make it pause */
2623: AUDIO_INITINFO(&ai);
2624: ai.play.pause = 1;
2625: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause");
2626: REQUIRED_SYS_EQ(0, r);
2627:
2628: ptr = MMAP(NULL, len, prot, MAP_FILE, fd, 0);
2629: XP_SYS_PTR(expected ? 0 : EACCES, ptr);
2630: if (expected) {
2631: /* XXX Doing mmap(2) doesn't inhibit read(2) */
2632: if (mode2rec(mode)) {
2633: r = READ(fd, buf, 0);
2634: XP_SYS_EQ(0, r);
2635: }
2636: /* Doing mmap(2) inhibits write(2) */
2637: if (mode2play(mode)) {
2638: /* NetBSD9 changes errno */
2639: r = WRITE(fd, buf, 0);
2640: if (netbsd < 9) {
2641: XP_SYS_NG(EINVAL, r);
2642: } else {
2643: XP_SYS_NG(EPERM, r);
2644: }
2645: }
2646: }
2647: if (ptr != MAP_FAILED) {
2648: r = MUNMAP(ptr, len);
2649: XP_SYS_EQ(0, r);
2650: }
2651:
2652: /* Whether the pause is still valid */
2653: if (mode2play(mode)) {
2654: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
2655: XP_SYS_EQ(0, r);
2656: XP_EQ(1, ai.play.pause);
2657: }
2658:
2659: r = CLOSE(fd);
2660: XP_SYS_EQ(0, r);
2661:
2662: reset_after_mmap();
2663: }
2664: #define PROT_READWRITE (PROT_READ | PROT_WRITE)
2665: DEF(mmap_mode_RDONLY_NONE) { test_mmap_mode(O_RDONLY, PROT_NONE); }
2666: DEF(mmap_mode_RDONLY_READ) { test_mmap_mode(O_RDONLY, PROT_READ); }
2667: DEF(mmap_mode_RDONLY_WRITE) { test_mmap_mode(O_RDONLY, PROT_WRITE); }
2668: DEF(mmap_mode_RDONLY_READWRITE) { test_mmap_mode(O_RDONLY, PROT_READWRITE); }
2669: DEF(mmap_mode_WRONLY_NONE) { test_mmap_mode(O_WRONLY, PROT_NONE); }
2670: DEF(mmap_mode_WRONLY_READ) { test_mmap_mode(O_WRONLY, PROT_READ); }
2671: DEF(mmap_mode_WRONLY_WRITE) { test_mmap_mode(O_WRONLY, PROT_WRITE); }
2672: DEF(mmap_mode_WRONLY_READWRITE) { test_mmap_mode(O_WRONLY, PROT_READWRITE); }
2673: DEF(mmap_mode_RDWR_NONE) { test_mmap_mode(O_RDWR, PROT_NONE); }
2674: DEF(mmap_mode_RDWR_READ) { test_mmap_mode(O_RDWR, PROT_READ); }
2675: DEF(mmap_mode_RDWR_WRITE) { test_mmap_mode(O_RDWR, PROT_WRITE); }
2676: DEF(mmap_mode_RDWR_READWRITE) { test_mmap_mode(O_RDWR, PROT_READWRITE); }
2677:
2678: /*
2679: * Check mmap()'s length and offset.
2680: */
2681: DEF(mmap_len)
2682: {
2683: struct audio_info ai;
2684: int fd;
2685: int r;
2686: size_t len;
2687: off_t offset;
2688: void *ptr;
2689: int bufsize;
2690: int pagesize;
2691: int lsize;
2692:
2693: TEST("mmap_len");
2694: if ((props & AUDIO_PROP_MMAP) == 0) {
2695: XP_SKIP("This test is only for mmap-able device");
2696: return;
2697: }
2698: #if !defined(NO_RUMP)
2699: if (use_rump) {
2700: XP_SKIP("rump doesn't support mmap");
2701: return;
2702: }
2703: #endif
2704:
2705: len = sizeof(pagesize);
2706: r = SYSCTLBYNAME("hw.pagesize", &pagesize, &len, NULL, 0);
2707: REQUIRED_SYS_EQ(0, r);
2708:
2709: fd = OPEN(devaudio, O_WRONLY);
2710: REQUIRED_SYS_OK(r);
2711:
2712: /* Get buffer_size */
2713: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
2714: REQUIRED_SYS_EQ(0, r);
2715: bufsize = ai.play.buffer_size;
2716:
2717: /*
2718: * XXX someone refers bufsize and another one does pagesize.
2719: * I'm not sure.
2720: */
2721: lsize = roundup2(bufsize, pagesize);
2722: struct {
2723: size_t len;
2724: off_t offset;
2725: int exp;
2726: } table[] = {
2727: /* len offset expected */
2728:
2729: { 0, 0, 0 }, /* len is 0 */
2730: { 1, 0, 0 }, /* len is smaller than lsize */
2731: { lsize, 0, 0 }, /* len is the same as lsize */
2732: { lsize + 1, 0, EOVERFLOW }, /* len is larger */
2733:
2734: { 0, -1, EINVAL }, /* offset is negative */
2735: { 0, lsize, 0 }, /* pointless param but ok */
2736: { 0, lsize + 1, EOVERFLOW }, /* exceed */
2737: { 1, lsize, EOVERFLOW }, /* exceed */
2738:
2739: /*
2740: * When you treat offset as 32bit, offset will be 0
2741: * and thus it incorrectly succeeds.
2742: */
2743: { lsize, 1ULL<<32, EOVERFLOW },
2744: };
2745:
2746: for (int i = 0; i < (int)__arraycount(table); i++) {
2747: len = table[i].len;
2748: offset = table[i].offset;
2749: int exp = table[i].exp;
2750:
2751: ptr = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd, offset);
2752: if (exp == 0) {
2753: XP_SYS_PTR(0, ptr);
2754: } else {
2755: /* NetBSD8 introduces EOVERFLOW */
2756: if (netbsd < 8 && exp == EOVERFLOW)
2757: exp = EINVAL;
2758: XP_SYS_PTR(exp, ptr);
2759: }
2760:
2761: if (ptr != MAP_FAILED) {
2762: r = MUNMAP(ptr, len);
2763: XP_SYS_EQ(0, r);
2764: }
2765: }
2766:
2767: r = CLOSE(fd);
2768: XP_SYS_EQ(0, r);
2769:
2770: reset_after_mmap();
2771: }
2772:
2773: /*
2774: * mmap() the same descriptor twice.
2775: */
2776: DEF(mmap_twice)
2777: {
2778: struct audio_info ai;
2779: int fd;
2780: int r;
2781: int len;
2782: void *ptr1;
2783: void *ptr2;
2784:
2785: TEST("mmap_twice");
2786: if ((props & AUDIO_PROP_MMAP) == 0) {
2787: XP_SKIP("This test is only for mmap-able device");
2788: return;
2789: }
2790: #if !defined(NO_RUMP)
2791: if (use_rump) {
2792: XP_SKIP("rump doesn't support mmap");
2793: return;
2794: }
2795: #endif
2796:
2797: fd = OPEN(devaudio, O_WRONLY);
2798: REQUIRED_SYS_OK(fd);
2799:
2800: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "get");
2801: REQUIRED_SYS_EQ(0, r);
2802: len = ai.play.buffer_size;
2803:
2804: ptr1 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd, 0);
2805: XP_SYS_PTR(0, ptr1);
2806:
2807: /* XXX I'm not sure this sucess is intended. Anyway I follow it */
2808: ptr2 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd, 0);
2809: XP_SYS_PTR(0, ptr2);
2810:
2811: if (ptr2 != MAP_FAILED) {
2812: r = MUNMAP(ptr2, len);
2813: XP_SYS_EQ(0, r);
2814: }
2815: if (ptr1 != MAP_FAILED) {
2816: r = MUNMAP(ptr1, len);
2817: XP_SYS_EQ(0, r);
2818: }
2819:
2820: r = CLOSE(fd);
2821: XP_SYS_EQ(0, r);
2822:
2823: reset_after_mmap();
2824: }
2825:
2826: /*
2827: * mmap() different descriptors.
2828: */
2829: DEF(mmap_multi)
2830: {
2831: struct audio_info ai;
2832: int fd0;
2833: int fd1;
2834: int r;
2835: int len;
2836: void *ptr0;
2837: void *ptr1;
2838:
2839: TEST("mmap_multi");
2840: if (netbsd < 8) {
2841: XP_SKIP("Multiple open is not supported");
2842: return;
2843: }
2844: if ((props & AUDIO_PROP_MMAP) == 0) {
2845: XP_SKIP("This test is only for mmap-able device");
2846: return;
2847: }
2848: #if !defined(NO_RUMP)
2849: if (use_rump) {
2850: XP_SKIP("rump doesn't support mmap");
2851: return;
2852: }
2853: #endif
2854:
2855: fd0 = OPEN(devaudio, O_WRONLY);
2856: REQUIRED_SYS_OK(fd0);
2857:
2858: r = IOCTL(fd0, AUDIO_GETBUFINFO, &ai, "get");
2859: REQUIRED_SYS_EQ(0, r);
2860: len = ai.play.buffer_size;
2861:
2862: fd1 = OPEN(devaudio, O_WRONLY);
2863: REQUIRED_SYS_OK(fd1);
2864:
2865: ptr0 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd0, 0);
2866: XP_SYS_PTR(0, ptr0);
2867:
2868: ptr1 = MMAP(NULL, len, PROT_WRITE, MAP_FILE, fd1, 0);
2869: XP_SYS_PTR(0, ptr1);
2870:
2871: if (ptr0 != MAP_FAILED) {
2872: r = MUNMAP(ptr1, len);
2873: XP_SYS_EQ(0, r);
2874: }
2875:
2876: r = CLOSE(fd1);
2877: XP_SYS_EQ(0, r);
2878:
2879: if (ptr1 != MAP_FAILED) {
2880: r = MUNMAP(ptr0, len);
2881: XP_SYS_EQ(0, r);
2882: }
2883:
2884: r = CLOSE(fd0);
2885: XP_SYS_EQ(0, r);
2886:
2887: reset_after_mmap();
2888: }
2889:
2890: #define IN POLLIN
2891: #define OUT POLLOUT
2892: /*
2893: * Whether poll() succeeds with specified mode.
2894: */
2895: void
2896: test_poll_mode(int mode, int events, int expected_revents)
2897: {
2898: struct pollfd pfd;
2899: const char *events_str;
2900: int fd;
2901: int r;
2902: int expected_r;
2903:
2904: if (events == IN) {
2905: events_str = "IN";
2906: } else if (events == OUT) {
2907: events_str = "OUT";
2908: } else if (events == (IN | OUT)) {
2909: events_str = "INOUT";
2910: } else {
2911: events_str = "?";
2912: }
2913: TEST("poll_mode_%s_%s", openmode_str[mode] + 2, events_str);
2914: if (mode2aumode(mode) == 0) {
2915: XP_SKIP("Operation not allowed on this hardware property");
2916: return;
2917: }
2918:
2919: expected_r = (expected_revents != 0) ? 1 : 0;
2920:
2921: fd = OPEN(devaudio, mode);
2922: REQUIRED_SYS_OK(fd);
2923:
2924: memset(&pfd, 0, sizeof(pfd));
2925: pfd.fd = fd;
2926: pfd.events = events;
2927:
2928: r = POLL(&pfd, 1, 100);
2929: /* It's a bit complicated.. */
2930: if (r < 0 || r > 1) {
2931: /*
2932: * Check these two cases first:
2933: * - system call fails.
2934: * - poll() with one nfds returns >1. It's strange.
2935: */
2936: XP_SYS_EQ(expected_r, r);
2937: } else {
2938: /*
2939: * Otherwise, poll() returned 0 or 1.
2940: */
2941: DPRINTF(" > pfd.revents=%s\n", event_tostr(pfd.revents));
2942:
2943: /* NetBSD7,8 have several strange behavior. It must be bug. */
2944:
2945: XP_SYS_EQ(expected_r, r);
2946: XP_EQ(expected_revents, pfd.revents);
2947: }
2948: r = CLOSE(fd);
2949: XP_SYS_EQ(0, r);
2950: }
2951: DEF(poll_mode_RDONLY_IN) { test_poll_mode(O_RDONLY, IN, 0); }
2952: DEF(poll_mode_RDONLY_OUT) { test_poll_mode(O_RDONLY, OUT, 0); }
2953: DEF(poll_mode_RDONLY_INOUT) { test_poll_mode(O_RDONLY, IN|OUT, 0); }
2954: DEF(poll_mode_WRONLY_IN) { test_poll_mode(O_WRONLY, IN, 0); }
2955: DEF(poll_mode_WRONLY_OUT) { test_poll_mode(O_WRONLY, OUT, OUT); }
2956: DEF(poll_mode_WRONLY_INOUT) { test_poll_mode(O_WRONLY, IN|OUT, OUT); }
2957: DEF(poll_mode_RDWR_IN) { test_poll_mode(O_RDWR, IN, 0); }
2958: DEF(poll_mode_RDWR_OUT) { test_poll_mode(O_RDWR, OUT, OUT); }
2959: DEF(poll_mode_RDWR_INOUT) { test_poll_mode(O_RDWR, IN|OUT, OUT); }
2960:
2961: /*
2962: * Poll(OUT) when buffer is empty.
2963: */
2964: DEF(poll_out_empty)
2965: {
2966: struct pollfd pfd;
2967: int fd;
2968: int r;
2969:
2970: TEST("poll_out_empty");
2971:
2972: fd = OPEN(devaudio, O_WRONLY);
2973: REQUIRED_SYS_OK(fd);
2974:
2975: memset(&pfd, 0, sizeof(pfd));
2976: pfd.fd = fd;
2977: pfd.events = POLLOUT;
2978:
2979: /* Check when empty. It should succeed even if timeout == 0 */
2980: r = POLL(&pfd, 1, 0);
2981: XP_SYS_EQ(1, r);
2982: XP_EQ(POLLOUT, pfd.revents);
2983:
2984: r = CLOSE(fd);
2985: XP_SYS_EQ(0, r);
2986: }
2987:
2988: /*
2989: * Poll(OUT) when buffer is full.
2990: */
2991: DEF(poll_out_full)
2992: {
2993: struct audio_info ai;
2994: struct pollfd pfd;
2995: int fd;
2996: int r;
2997: char *buf;
2998: int buflen;
2999:
3000: TEST("poll_out_full");
3001:
3002: fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3003: REQUIRED_SYS_OK(fd);
3004:
3005: /* Pause */
3006: AUDIO_INITINFO(&ai);
3007: ai.play.pause = 1;
3008: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
3009: XP_SYS_EQ(0, r);
3010:
3011: /* Get buffer size */
3012: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3013: XP_SYS_EQ(0, r);
3014:
3015: /* Write until full */
3016: buflen = ai.play.buffer_size;
3017: buf = (char *)malloc(buflen);
3018: REQUIRED_IF(buf != NULL);
3019: memset(buf, 0xff, buflen);
3020: do {
3021: r = WRITE(fd, buf, buflen);
3022: } while (r == buflen);
3023: if (r == -1) {
3024: XP_SYS_NG(EAGAIN, r);
3025: }
3026:
3027: /* Do poll */
3028: memset(&pfd, 0, sizeof(pfd));
3029: pfd.fd = fd;
3030: pfd.events = POLLOUT;
3031: r = POLL(&pfd, 1, 0);
3032: XP_SYS_EQ(0, r);
3033: XP_EQ(0, pfd.revents);
3034:
3035: r = CLOSE(fd);
3036: XP_SYS_EQ(0, r);
3037: free(buf);
3038: }
3039:
3040: /*
3041: * Poll(OUT) when buffer is full but hiwat sets lower than full.
3042: */
3043: DEF(poll_out_hiwat)
3044: {
3045: struct audio_info ai;
3046: struct pollfd pfd;
3047: int fd;
3048: int r;
3049: char *buf;
3050: int buflen;
3051: int newhiwat;
3052:
3053: TEST("poll_out_hiwat");
3054:
3055: fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3056: REQUIRED_SYS_OK(fd);
3057:
3058: /* Get buffer size and hiwat */
3059: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3060: XP_SYS_EQ(0, r);
3061: /* Change hiwat some different value */
3062: newhiwat = ai.lowat;
3063:
3064: /* Set pause and hiwat */
3065: AUDIO_INITINFO(&ai);
3066: ai.play.pause = 1;
3067: ai.hiwat = newhiwat;
3068: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1;hiwat");
3069: XP_SYS_EQ(0, r);
3070:
3071: /* Get the set hiwat again */
3072: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3073: XP_SYS_EQ(0, r);
3074:
3075: /* Write until full */
3076: buflen = ai.blocksize * ai.hiwat;
3077: buf = (char *)malloc(buflen);
3078: REQUIRED_IF(buf != NULL);
3079: memset(buf, 0xff, buflen);
3080: do {
3081: r = WRITE(fd, buf, buflen);
3082: } while (r == buflen);
3083: if (r == -1) {
3084: XP_SYS_NG(EAGAIN, r);
3085: }
3086:
3087: /* Do poll */
3088: memset(&pfd, 0, sizeof(pfd));
3089: pfd.fd = fd;
3090: pfd.events = POLLOUT;
3091: r = POLL(&pfd, 1, 0);
3092: XP_SYS_EQ(0, r);
3093: XP_EQ(0, pfd.revents);
3094:
3095: r = CLOSE(fd);
3096: XP_SYS_EQ(0, r);
3097: free(buf);
3098: }
3099:
3100: /*
3101: * Unpause from buffer full, POLLOUT should raise.
3102: * XXX poll(2) on NetBSD7 is really incomplete and wierd. I don't test it.
3103: */
3104: DEF(poll_out_unpause)
3105: {
3106: struct audio_info ai;
3107: struct pollfd pfd;
3108: int fd;
3109: int r;
3110: char *buf;
3111: int buflen;
3112: u_int blocksize;
3113: int hiwat;
3114: int lowat;
3115:
3116: TEST("poll_out_unpause");
3117: if (netbsd < 8) {
3118: XP_SKIP("NetBSD7's poll() is too incomplete to test.");
3119: return;
3120: }
3121:
3122: /* Non-blocking open */
3123: fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3124: REQUIRED_SYS_OK(fd);
3125:
3126: /* Adjust block size and hiwat/lowat to make the test time 1sec */
3127: blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */
3128: hiwat = 12; /* 1.5sec */
3129: lowat = 4; /* 0.5sec */
3130: AUDIO_INITINFO(&ai);
3131: ai.blocksize = blocksize;
3132: ai.hiwat = hiwat;
3133: ai.lowat = lowat;
3134: /* and also set encoding */
3135: /*
3136: * XXX NetBSD7 has different results depending on whether the input
3137: * encoding is emulated (AUDIO_ENCODINGFLAG_EMULATED) or not. It's
3138: * not easy to ensure this situation on all hardware environment.
3139: * On NetBSD9, the result is the same regardless of input encoding.
3140: */
3141: r = IOCTL(fd, AUDIO_SETINFO, &ai, "blocksize=%d", blocksize);
3142: XP_SYS_EQ(0, r);
3143: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3144: if (ai.blocksize != blocksize) {
3145: /*
3146: * NetBSD9 can not change the blocksize. Then,
3147: * adjust using hiwat/lowat.
3148: */
3149: blocksize = ai.blocksize;
3150: hiwat = howmany(8000 * 1.5, blocksize);
3151: lowat = howmany(8000 * 0.5, blocksize);
3152: }
3153: /* Anyway, set the parameters */
3154: AUDIO_INITINFO(&ai);
3155: ai.blocksize = blocksize;
3156: ai.hiwat = hiwat;
3157: ai.lowat = lowat;
3158: ai.play.pause = 1;
3159: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1");
3160: XP_SYS_EQ(0, r);
3161:
3162: /* Get the set parameters again */
3163: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3164: XP_SYS_EQ(0, r);
3165:
3166: /* Write until full */
3167: buflen = ai.blocksize * ai.hiwat;
3168: buf = (char *)malloc(buflen);
3169: REQUIRED_IF(buf != NULL);
3170: memset(buf, 0xff, buflen);
3171: do {
3172: r = WRITE(fd, buf, buflen);
3173: } while (r == buflen);
3174: if (r == -1) {
3175: XP_SYS_NG(EAGAIN, r);
3176: }
3177:
3178: /* At this time, POLLOUT should not be set because buffer is full */
3179: memset(&pfd, 0, sizeof(pfd));
3180: pfd.fd = fd;
3181: pfd.events = POLLOUT;
3182: r = POLL(&pfd, 1, 0);
3183: XP_SYS_EQ(0, r);
3184: XP_EQ(0, pfd.revents);
3185:
3186: /* Unpause */
3187: AUDIO_INITINFO(&ai);
3188: ai.play.pause = 0;
3189: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=0");
3190: XP_SYS_EQ(0, r);
3191:
3192: /*
3193: * When unpause occurs:
3194: * - NetBSD7 (emul=0) -> the buffer remains.
3195: * - NetBSD7 (emul=1) -> the buffer is cleared.
3196: * - NetBSD8 -> the buffer remains.
3197: * - NetBSD9 -> the buffer remains.
3198: */
3199:
3200: /* Check poll() up to 2sec */
3201: pfd.revents = 0;
3202: r = POLL(&pfd, 1, 2000);
3203: XP_SYS_EQ(1, r);
3204: XP_EQ(POLLOUT, pfd.revents);
3205:
3206: /*
3207: * Since POLLOUT is set, it should be writable.
3208: * But at this time, no all buffer may be writable.
3209: */
3210: r = WRITE(fd, buf, buflen);
3211: XP_SYS_OK(r);
3212:
3213: /* Flush it because there is no need to play it */
3214: r = IOCTL(fd, AUDIO_FLUSH, NULL, "");
3215: XP_SYS_EQ(0, r);
3216:
3217: r = CLOSE(fd);
3218: XP_SYS_EQ(0, r);
3219: free(buf);
3220: }
3221:
3222: /*
3223: * poll(2) must not be affected by playback of other descriptors.
3224: */
3225: DEF(poll_out_simul)
3226: {
3227: struct audio_info ai;
3228: struct pollfd pfd[2];
3229: int fd[2];
3230: int r;
3231: char *buf;
3232: u_int blocksize;
3233: int hiwat;
3234: int lowat;
3235: int buflen;
3236: int time;
3237:
3238: TEST("poll_out_simul");
3239: if (netbsd < 8) {
3240: XP_SKIP("Multiple open is not supported");
3241: return;
3242: }
3243:
3244: /* Make sure that it's not affected by descriptor order */
3245: for (int i = 0; i < 2; i++) {
3246: int a = i;
3247: int b = 1 - i;
3248:
3249: fd[0] = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3250: REQUIRED_SYS_OK(fd[0]);
3251: fd[1] = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3252: REQUIRED_SYS_OK(fd[1]);
3253:
3254: /*
3255: * Adjust block size and hiwat/lowat.
3256: * I want to choice suitable blocksize (if possible).
3257: */
3258: blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */
3259: hiwat = 12; /* 1.5sec */
3260: lowat = 4; /* 0.5sec */
3261: AUDIO_INITINFO(&ai);
3262: ai.blocksize = blocksize;
3263: ai.hiwat = hiwat;
3264: ai.lowat = lowat;
3265: r = IOCTL(fd[0], AUDIO_SETINFO, &ai, "blocksize=1000");
3266: XP_SYS_EQ(0, r);
3267: r = IOCTL(fd[0], AUDIO_GETBUFINFO, &ai, "read back blocksize");
3268: if (ai.blocksize != blocksize) {
3269: /*
3270: * NetBSD9 can not change the blocksize. Then,
3271: * adjust using hiwat/lowat.
3272: */
3273: blocksize = ai.blocksize;
3274: hiwat = howmany(8000 * 1.5, blocksize);
3275: lowat = howmany(8000 * 0.5, blocksize);
3276: }
3277: /* Anyway, set the parameters */
3278: AUDIO_INITINFO(&ai);
3279: ai.blocksize = blocksize;
3280: ai.hiwat = hiwat;
3281: ai.lowat = lowat;
3282: /* Pause fdA */
3283: ai.play.pause = 1;
3284: r = IOCTL(fd[a], AUDIO_SETINFO, &ai, "pause=1");
3285: XP_SYS_EQ(0, r);
3286: /* Unpause fdB */
3287: ai.play.pause = 0;
3288: r = IOCTL(fd[b], AUDIO_SETINFO, &ai, "pause=0");
3289: XP_SYS_EQ(0, r);
3290:
3291: /* Get again. XXX two individual ioctls are correct */
3292: r = IOCTL(fd[0], AUDIO_GETBUFINFO, &ai, "");
3293: XP_SYS_EQ(0, r);
3294: DPRINTF(" > blocksize=%d lowat=%d hiwat=%d\n",
3295: ai.blocksize, ai.lowat, ai.hiwat);
3296:
3297: /* Enough long time than the playback time */
3298: time = (ai.hiwat - ai.lowat) * blocksize / 8; /*[msec]*/
3299: time *= 2;
3300:
3301: /* Write fdA full */
3302: buflen = blocksize * ai.lowat;
3303: buf = (char *)malloc(buflen);
3304: REQUIRED_IF(buf != NULL);
3305: memset(buf, 0xff, buflen);
3306: do {
3307: r = WRITE(fd[a], buf, buflen);
3308: } while (r == buflen);
3309: if (r == -1) {
3310: XP_SYS_NG(EAGAIN, r);
3311: }
3312:
3313: /* POLLOUT should not be set, because fdA is buffer full */
3314: memset(pfd, 0, sizeof(pfd));
3315: pfd[0].fd = fd[a];
3316: pfd[0].events = POLLOUT;
3317: r = POLL(pfd, 1, 0);
3318: XP_SYS_EQ(0, r);
3319: XP_EQ(0, pfd[0].revents);
3320:
3321: /* Write fdB at least lowat */
3322: r = WRITE(fd[b], buf, buflen);
3323: XP_SYS_EQ(buflen, r);
3324: r = WRITE(fd[b], buf, buflen);
3325: if (r == -1) {
3326: XP_SYS_NG(EAGAIN, r);
3327: }
3328:
3329: /* Only fdB should become POLLOUT */
3330: memset(pfd, 0, sizeof(pfd));
3331: pfd[0].fd = fd[0];
3332: pfd[0].events = POLLOUT;
3333: pfd[1].fd = fd[1];
3334: pfd[1].events = POLLOUT;
3335: r = POLL(pfd, 2, time);
3336: XP_SYS_EQ(1, r);
3337: if (r != -1) {
3338: XP_EQ(0, pfd[a].revents);
3339: XP_EQ(POLLOUT, pfd[b].revents);
3340: }
3341:
3342: /* Drop the rest */
3343: r = IOCTL(fd[0], AUDIO_FLUSH, NULL, "");
3344: XP_SYS_EQ(0, r);
3345: r = IOCTL(fd[1], AUDIO_FLUSH, NULL, "");
3346: XP_SYS_EQ(0, r);
3347:
3348: r = CLOSE(fd[0]);
3349: XP_SYS_EQ(0, r);
3350: r = CLOSE(fd[1]);
3351: XP_SYS_EQ(0, r);
3352: free(buf);
3353:
3354: xxx_close_wait();
3355: }
3356: }
3357:
3358: /*
3359: * poll(2) must not be affected by other recording descriptors even if
3360: * playback descriptor waits with POLLIN (though it's not normal usage).
3361: * In other words, two POLLIN must not interfere.
3362: */
3363: DEF(poll_in_simul)
3364: {
3365: struct audio_info ai;
3366: struct pollfd pfd;
3367: int fd[2];
3368: int r;
3369: char *buf;
3370: int blocksize;
3371:
3372: TEST("poll_in_simul");
3373: if (netbsd < 8) {
3374: XP_SKIP("Multiple open is not supported");
3375: return;
3376: }
3377: if (hw_fulldup() == 0) {
3378: XP_SKIP("This test is only for full-duplex device");
3379: return;
3380: }
3381:
3382: int play = 0;
3383: int rec = 1;
3384:
3385: fd[play] = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3386: REQUIRED_SYS_OK(fd[play]);
3387: fd[rec] = OPEN(devaudio, O_RDONLY);
3388: REQUIRED_SYS_OK(fd[rec]);
3389:
3390: /* Get block size */
3391: r = IOCTL(fd[rec], AUDIO_GETBUFINFO, &ai, "");
3392: XP_SYS_EQ(0, r);
3393: blocksize = ai.blocksize;
3394:
3395: buf = (char *)malloc(blocksize);
3396: REQUIRED_IF(buf != NULL);
3397:
3398: /*
3399: * At first, make sure the playback one doesn't return POLLIN.
3400: */
3401: memset(&pfd, 0, sizeof(pfd));
3402: pfd.fd = fd[play];
3403: pfd.events = POLLIN;
3404: r = POLL(&pfd, 1, 0);
3405: if (r == 0 && pfd.revents == 0) {
3406: XP_SYS_EQ(0, r);
3407: XP_EQ(0, pfd.revents);
3408: } else {
3409: XP_FAIL("play fd returns POLLIN");
3410: goto abort;
3411: }
3412:
3413: /* Start recording */
3414: r = READ(fd[rec], buf, blocksize);
3415: XP_SYS_EQ(blocksize, r);
3416:
3417: /* Poll()ing playback descriptor with POLLIN should not raise */
3418: r = POLL(&pfd, 1, 1000);
3419: XP_SYS_EQ(0, r);
3420: XP_EQ(0, pfd.revents);
3421:
3422: /* Poll()ing recording descriptor with POLLIN should raise */
3423: pfd.fd = fd[rec];
3424: r = POLL(&pfd, 1, 0);
3425: XP_SYS_EQ(1, r);
3426: XP_EQ(POLLIN, pfd.revents);
3427:
3428: abort:
3429: r = CLOSE(fd[play]);
3430: XP_SYS_EQ(0, r);
3431: r = CLOSE(fd[rec]);
3432: XP_SYS_EQ(0, r);
3433: free(buf);
3434: }
3435:
3436: /*
3437: * Whether kqueue() succeeds with specified mode.
3438: */
3439: void
3440: test_kqueue_mode(int openmode, int filt, int expected)
3441: {
3442: struct kevent kev;
3443: struct timespec ts;
3444: int fd;
3445: int kq;
3446: int r;
3447:
3448: TEST("kqueue_mode_%s_%s",
3449: openmode_str[openmode] + 2,
3450: (filt == EVFILT_READ) ? "READ" : "WRITE");
3451: if (mode2aumode(openmode) == 0) {
3452: XP_SKIP("Operation not allowed on this hardware property");
3453: return;
3454: }
3455:
3456: ts.tv_sec = 0;
3457: ts.tv_nsec = 100 * 1000 * 1000; // 100msec
3458:
3459: kq = KQUEUE();
3460: XP_SYS_OK(kq);
3461:
3462: fd = OPEN(devaudio, openmode);
3463: REQUIRED_SYS_OK(fd);
3464:
3465: /*
3466: * Check whether the specified filter can be set.
3467: * Any filters can always be set, even if pointless combination.
3468: * For example, EVFILT_READ can be set on O_WRONLY descriptor
3469: * though it will never raise.
3470: * I will not mention about good or bad of this behavior here.
3471: */
3472: EV_SET(&kev, fd, filt, EV_ADD, 0, 0, 0);
3473: r = KEVENT_SET(kq, &kev, 1);
3474: XP_SYS_EQ(0, r);
3475:
3476: if (r == 0) {
3477: /* If the filter can be set, try kevent(poll) */
3478: r = KEVENT_POLL(kq, &kev, 1, &ts);
3479: XP_SYS_EQ(expected, r);
3480:
3481: /* Delete it */
3482: EV_SET(&kev, fd, filt, EV_DELETE, 0, 0, 0);
3483: r = KEVENT_SET(kq, &kev, 1);
3484: XP_SYS_EQ(0, r);
3485: }
3486:
3487: r = CLOSE(fd);
3488: XP_SYS_EQ(0, r);
3489: r = CLOSE(kq);
3490: XP_SYS_EQ(0, r);
3491: }
3492: DEF(kqueue_mode_RDONLY_READ) {
3493: /* Should not raise yet (NetBSD7 has bugs?) */
3494: int expected = (netbsd < 8) ? 1 : 0;
3495: test_kqueue_mode(O_RDONLY, EVFILT_READ, expected);
3496: }
3497: DEF(kqueue_mode_RDONLY_WRITE) {
3498: /* Should never raise (NetBSD7 has bugs) */
3499: int expected = (netbsd < 8) ? 1 : 0;
3500: test_kqueue_mode(O_RDONLY, EVFILT_WRITE, expected);
3501: }
3502: DEF(kqueue_mode_WRONLY_READ) {
3503: /* Should never raise */
3504: test_kqueue_mode(O_WRONLY, EVFILT_READ, 0);
3505: }
3506: DEF(kqueue_mode_WRONLY_WRITE) {
3507: /* Should raise */
3508: test_kqueue_mode(O_WRONLY, EVFILT_WRITE, 1);
3509: }
3510: DEF(kqueue_mode_RDWR_READ) {
3511: /* Should not raise yet (NetBSD7 is something strange) */
3512: int expected = (netbsd < 8 && hw_fulldup()) ? 1 : 0;
3513: test_kqueue_mode(O_RDWR, EVFILT_READ, expected);
3514: }
3515: DEF(kqueue_mode_RDWR_WRITE) {
3516: /* Should raise */
3517: test_kqueue_mode(O_RDWR, EVFILT_WRITE, 1);
3518: }
3519:
3520: /*
3521: * kqueue(2) when buffer is empty.
3522: */
3523: DEF(kqueue_empty)
3524: {
3525: struct audio_info ai;
3526: struct kevent kev;
3527: struct timespec ts;
3528: int kq;
3529: int fd;
3530: int r;
3531:
3532: TEST("kqueue_empty");
3533:
3534: fd = OPEN(devaudio, O_WRONLY);
3535: REQUIRED_SYS_OK(fd);
3536:
3537: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3538: XP_SYS_EQ(0, r);
3539:
3540: kq = KQUEUE();
3541: XP_SYS_OK(kq);
3542:
3543: EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0);
3544: r = KEVENT_SET(kq, &kev, 1);
3545: XP_SYS_EQ(0, r);
3546:
3547: /* When the buffer is empty, it should succeed even if timeout == 0 */
3548: memset(&ts, 0, sizeof(ts));
3549: r = KEVENT_POLL(kq, &kev, 1, &ts);
3550: XP_SYS_EQ(1, r);
3551: XP_EQ(fd, kev.ident);
3552: /*
3553: * XXX According to kqueue(2) manpage, returned kev.data contains
3554: * "the amount of space remaining in the write buffer".
3555: * NetBSD7 returns buffer_size. Shouldn't it be blocksize * hiwat?
3556: */
3557: /* XP_EQ(ai.blocksize * ai.hiwat, kev.data); */
3558: XP_EQ(ai.play.buffer_size, kev.data);
3559:
3560: r = CLOSE(fd);
3561: XP_SYS_EQ(0, r);
3562: r = CLOSE(kq);
3563: XP_SYS_EQ(0, r);
3564: }
3565:
3566: /*
3567: * kqueue(2) when buffer is full.
3568: */
3569: DEF(kqueue_full)
3570: {
3571: struct audio_info ai;
3572: struct kevent kev;
3573: struct timespec ts;
3574: int kq;
3575: int fd;
3576: int r;
3577: char *buf;
3578: int buflen;
3579:
3580: TEST("kqueue_full");
3581:
3582: fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3583: REQUIRED_SYS_OK(fd);
3584:
3585: /* Pause */
3586: AUDIO_INITINFO(&ai);
3587: ai.play.pause = 1;
3588: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
3589: XP_SYS_EQ(0, r);
3590:
3591: /* Get buffer size */
3592: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3593: XP_SYS_EQ(0, r);
3594:
3595: /* Write until full */
3596: buflen = ai.play.buffer_size;
3597: buf = (char *)malloc(buflen);
3598: REQUIRED_IF(buf != NULL);
3599: memset(buf, 0xff, buflen);
3600: do {
3601: r = WRITE(fd, buf, buflen);
3602: } while (r == buflen);
3603: if (r == -1) {
3604: XP_SYS_NG(EAGAIN, r);
3605: }
3606:
3607: kq = KQUEUE();
3608: XP_SYS_OK(kq);
3609:
3610: EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0);
3611: r = KEVENT_SET(kq, &kev, 1);
3612: XP_SYS_EQ(0, r);
3613:
3614: /* kevent() should not raise */
3615: ts.tv_sec = 0;
3616: ts.tv_nsec = 100L * 1000 * 1000; /* 100msec */
3617: r = KEVENT_POLL(kq, &kev, 1, &ts);
3618: XP_SYS_EQ(0, r);
3619: if (r > 0) {
3620: XP_EQ(fd, kev.ident);
3621: XP_EQ(0, kev.data);
3622: }
3623:
3624: r = CLOSE(fd);
3625: XP_SYS_EQ(0, r);
3626: r = CLOSE(kq);
3627: XP_SYS_EQ(0, r);
3628: free(buf);
3629: }
3630:
3631: /*
3632: * kqueue(2) when buffer is full but hiwat sets lower than full.
3633: */
3634: DEF(kqueue_hiwat)
3635: {
3636: struct audio_info ai;
3637: struct kevent kev;
3638: struct timespec ts;
3639: int kq;
3640: int fd;
3641: int r;
3642: char *buf;
3643: int buflen;
3644: int newhiwat;
3645:
3646: TEST("kqueue_hiwat");
3647:
3648: fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3649: REQUIRED_SYS_OK(fd);
3650:
3651: /* Get buffer size and hiwat */
3652: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "hiwat");
3653: XP_SYS_EQ(0, r);
3654: /* Change hiwat some different value */
3655: newhiwat = ai.hiwat - 1;
3656:
3657: /* Set pause and hiwat */
3658: AUDIO_INITINFO(&ai);
3659: ai.play.pause = 1;
3660: ai.hiwat = newhiwat;
3661: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1;hiwat");
3662: XP_SYS_EQ(0, r);
3663:
3664: /* Get the set parameters again */
3665: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3666: XP_SYS_EQ(0, r);
3667: XP_EQ(1, ai.play.pause);
3668: XP_EQ(newhiwat, ai.hiwat);
3669:
3670: /* Write until full */
3671: buflen = ai.blocksize * ai.hiwat;
3672: buf = (char *)malloc(buflen);
3673: REQUIRED_IF(buf != NULL);
3674: memset(buf, 0xff, buflen);
3675: do {
3676: r = WRITE(fd, buf, buflen);
3677: } while (r == buflen);
3678: if (r == -1) {
3679: XP_SYS_NG(EAGAIN, r);
3680: }
3681:
3682: kq = KQUEUE();
3683: XP_SYS_OK(kq);
3684:
3685: EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0);
3686: r = KEVENT_SET(kq, &kev, 1);
3687: XP_SYS_EQ(0, r);
3688:
3689: /* Should not raise because it's not possible to write */
3690: ts.tv_sec = 0;
3691: ts.tv_nsec = 100L * 1000 * 1000; /* 100msec */
3692: r = KEVENT_POLL(kq, &kev, 1, &ts);
3693: if (r > 0)
3694: DEBUG_KEV("kev", &kev);
3695: XP_SYS_EQ(0, r);
3696:
3697: r = CLOSE(fd);
3698: XP_SYS_EQ(0, r);
3699: r = CLOSE(kq);
3700: XP_SYS_EQ(0, r);
3701: free(buf);
3702: }
3703:
3704: /*
3705: * Unpause from buffer full, kevent() should raise.
3706: */
3707: DEF(kqueue_unpause)
3708: {
3709: struct audio_info ai;
3710: struct kevent kev;
3711: struct timespec ts;
3712: int fd;
3713: int r;
3714: int kq;
3715: char *buf;
3716: int buflen;
3717: u_int blocksize;
3718: int hiwat;
3719: int lowat;
3720:
3721: TEST("kqueue_unpause");
3722:
3723: /* Non-blocking open */
3724: fd = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3725: REQUIRED_SYS_OK(fd);
3726:
3727: /* Adjust block size and hiwat/lowat to make the test time 1sec */
3728: blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */
3729: hiwat = 12; /* 1.5sec */
3730: lowat = 4; /* 0.5sec */
3731: AUDIO_INITINFO(&ai);
3732: ai.blocksize = blocksize;
3733: ai.hiwat = hiwat;
3734: ai.lowat = lowat;
3735: /* and also set encoding */
3736: /*
3737: * XXX NetBSD7 has different results depending on whether the input
3738: * encoding is emulated (AUDIO_ENCODINGFLAG_EMULATED) or not. It's
3739: * not easy to ensure this situation on all hardware environment.
3740: * On NetBSD9, the result is the same regardless of input encoding.
3741: */
3742: r = IOCTL(fd, AUDIO_SETINFO, &ai, "blocksize=%d", blocksize);
3743: XP_SYS_EQ(0, r);
3744: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3745: if (ai.blocksize != blocksize) {
3746: /*
3747: * NetBSD9 can not change the blocksize. Then,
3748: * adjust using hiwat/lowat.
3749: */
3750: blocksize = ai.blocksize;
3751: hiwat = howmany(8000 * 1.5, blocksize);
3752: lowat = howmany(8000 * 0.5, blocksize);
3753: }
3754: /* Anyway, set the parameters */
3755: AUDIO_INITINFO(&ai);
3756: ai.blocksize = blocksize;
3757: ai.hiwat = hiwat;
3758: ai.lowat = lowat;
3759: ai.play.pause = 1;
3760: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1");
3761: XP_SYS_EQ(0, r);
3762:
3763: /* Get the set parameters again */
3764: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
3765: XP_SYS_EQ(0, r);
3766: DPRINTF(" > blocksize=%d hiwat=%d lowat=%d buffer_size=%d\n",
3767: ai.blocksize, ai.hiwat, ai.lowat, ai.play.buffer_size);
3768:
3769: /* Write until full */
3770: buflen = ai.blocksize * ai.hiwat;
3771: buf = (char *)malloc(buflen);
3772: REQUIRED_IF(buf != NULL);
3773: memset(buf, 0xff, buflen);
3774: do {
3775: r = WRITE(fd, buf, buflen);
3776: } while (r == buflen);
3777: if (r == -1) {
3778: XP_SYS_NG(EAGAIN, r);
3779: }
3780:
3781: kq = KQUEUE();
3782: XP_SYS_OK(kq);
3783:
3784: EV_SET(&kev, fd, EV_ADD, EVFILT_WRITE, 0, 0, 0);
3785: r = KEVENT_SET(kq, &kev, 1);
3786: XP_SYS_EQ(0, r);
3787:
3788: /* Unpause */
3789: AUDIO_INITINFO(&ai);
3790: ai.play.pause = 0;
3791: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=0");
3792: XP_SYS_EQ(0, r);
3793:
3794: /* Check kevent() up to 2sec */
3795: ts.tv_sec = 2;
3796: ts.tv_nsec = 0;
3797: r = KEVENT_POLL(kq, &kev, 1, &ts);
3798: if (r >= 1)
3799: DEBUG_KEV("kev", &kev);
3800: if (netbsd < 8) {
3801: /*
3802: * NetBSD7 with EMULATED_FLAG unset has bugs. Unpausing
3803: * unintentionally clears buffer (and therefore it becomes
3804: * writable) but it doesn't raise EVFILT_WRITE.
3805: */
3806: } else {
3807: XP_SYS_EQ(1, r);
3808: }
3809:
3810: /* Flush it because there is no need to play it */
3811: r = IOCTL(fd, AUDIO_FLUSH, NULL, "");
3812: XP_SYS_EQ(0, r);
3813:
3814: r = CLOSE(fd);
3815: XP_SYS_EQ(0, r);
3816: r = CLOSE(kq);
3817: XP_SYS_EQ(0, r);
3818: free(buf);
3819: }
3820:
3821: /*
3822: * kevent(2) must not be affected by other audio descriptors.
3823: */
3824: DEF(kqueue_simul)
3825: {
3826: struct audio_info ai;
3827: struct audio_info ai2;
3828: struct kevent kev[2];
3829: struct timespec ts;
3830: int fd[2];
3831: int r;
3832: int kq;
3833: u_int blocksize;
3834: int hiwat;
3835: int lowat;
3836: char *buf;
3837: int buflen;
3838:
3839: TEST("kqueue_simul");
3840: if (netbsd < 8) {
3841: XP_SKIP("Multiple open is not supported");
3842: return;
3843: }
3844:
3845: memset(&ts, 0, sizeof(ts));
3846:
3847: /* Make sure that it's not affected by descriptor order */
3848: for (int i = 0; i < 2; i++) {
3849: int a = i;
3850: int b = 1 - i;
3851:
3852: fd[0] = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3853: REQUIRED_SYS_OK(fd[0]);
3854: fd[1] = OPEN(devaudio, O_WRONLY | O_NONBLOCK);
3855: REQUIRED_SYS_OK(fd[1]);
3856:
3857: /*
3858: * Adjust block size and hiwat/lowat.
3859: * I want to choice suitable blocksize (if possible).
3860: */
3861: blocksize = 1000; /* 1/8 sec in mulaw,1ch,8000Hz */
3862: hiwat = 12; /* 1.5sec */
3863: lowat = 4; /* 0.5sec */
3864: AUDIO_INITINFO(&ai);
3865: ai.blocksize = blocksize;
3866: ai.hiwat = hiwat;
3867: ai.lowat = lowat;
3868: r = IOCTL(fd[0], AUDIO_SETINFO, &ai, "blocksize=1000");
3869: XP_SYS_EQ(0, r);
3870: r = IOCTL(fd[0], AUDIO_GETBUFINFO, &ai, "read back blocksize");
3871: if (ai.blocksize != blocksize) {
3872: /*
3873: * NetBSD9 can not change the blocksize. Then,
3874: * adjust using hiwat/lowat.
3875: */
3876: blocksize = ai.blocksize;
3877: hiwat = howmany(8000 * 1.5, blocksize);
3878: lowat = howmany(8000 * 0.5, blocksize);
3879: }
3880: /* Anyway, set the parameters to both */
3881: AUDIO_INITINFO(&ai);
3882: ai.blocksize = blocksize;
3883: ai.hiwat = hiwat;
3884: ai.lowat = lowat;
3885: ai.play.pause = 1;
3886: r = IOCTL(fd[a], AUDIO_SETINFO, &ai, "pause=1");
3887: XP_SYS_EQ(0, r);
3888: r = IOCTL(fd[b], AUDIO_SETINFO, &ai, "pause=1");
3889: XP_SYS_EQ(0, r);
3890:
3891: /* Write both until full */
3892: buflen = ai.blocksize * ai.hiwat;
3893: buf = (char *)malloc(buflen);
3894: REQUIRED_IF(buf != NULL);
3895: memset(buf, 0xff, buflen);
3896: /* Write fdA */
3897: do {
3898: r = WRITE(fd[a], buf, buflen);
3899: } while (r == buflen);
3900: if (r == -1) {
3901: XP_SYS_NG(EAGAIN, r);
3902: }
3903: /* Write fdB */
3904: do {
3905: r = WRITE(fd[b], buf, buflen);
3906: } while (r == buflen);
3907: if (r == -1) {
3908: XP_SYS_NG(EAGAIN, r);
3909: }
3910:
3911: /* Get fdB's initial seek for later */
3912: r = IOCTL(fd[b], AUDIO_GETBUFINFO, &ai2, "");
3913: XP_SYS_EQ(0, r);
3914:
3915: kq = KQUEUE();
3916: XP_SYS_OK(kq);
3917:
3918: /* Both aren't raised at this point */
3919: EV_SET(&kev[0], fd[a], EV_ADD, EVFILT_WRITE, 0, 0, 0);
3920: EV_SET(&kev[1], fd[b], EV_ADD, EVFILT_WRITE, 0, 0, 0);
3921: r = KEVENT_SET(kq, kev, 2);
3922: XP_SYS_EQ(0, r);
3923:
3924: /* Unpause only fdA */
3925: AUDIO_INITINFO(&ai);
3926: ai.play.pause = 0;
3927: r = IOCTL(fd[a], AUDIO_SETINFO, &ai, "pause=0");
3928: XP_SYS_EQ(0, r);
3929:
3930: /* kevent() up to 2sec */
3931: ts.tv_sec = 2;
3932: ts.tv_nsec = 0;
3933: r = KEVENT_POLL(kq, &kev[0], 1, &ts);
3934: if (r >= 1)
3935: DEBUG_KEV("kev", &kev[0]);
3936: /* fdA should raise */
3937: XP_SYS_EQ(1, r);
3938: XP_EQ(fd[a], kev[0].ident);
3939:
3940: /* Make sure that fdB keeps whole data */
3941: r = IOCTL(fd[b], AUDIO_GETBUFINFO, &ai, "");
3942: XP_EQ(ai2.play.seek, ai.play.seek);
3943:
3944: /* Flush it because there is no need to play it */
3945: r = IOCTL(fd[0], AUDIO_FLUSH, NULL, "");
3946: XP_SYS_EQ(0, r);
3947: r = IOCTL(fd[1], AUDIO_FLUSH, NULL, "");
3948: XP_SYS_EQ(0, r);
3949:
3950: r = CLOSE(fd[0]);
3951: XP_SYS_EQ(0, r);
3952: r = CLOSE(fd[1]);
3953: XP_SYS_EQ(0, r);
3954: r = CLOSE(kq);
3955: XP_SYS_EQ(0, r);
3956: free(buf);
3957:
3958: xxx_close_wait();
3959: }
3960: }
3961:
3962: /* Shared data between threads for ioctl_while_write */
3963: struct ioctl_while_write_data {
3964: int fd;
3965: struct timeval start;
3966: int terminated;
3967: };
3968:
3969: /* Test thread for ioctl_while_write */
3970: void *thread_ioctl_while_write(void *);
3971: void *
3972: thread_ioctl_while_write(void *arg)
3973: {
3974: struct ioctl_while_write_data *data = arg;
3975: struct timeval now, res;
3976: struct audio_info ai;
3977: int r;
3978:
3979: /* If 0.5 seconds have elapsed since writing, assume it's blocked */
3980: do {
3981: usleep(100);
3982: gettimeofday(&now, NULL);
3983: timersub(&now, &data->start, &res);
3984: } while (res.tv_usec < 500000);
3985:
3986: /* Then, do ioctl() */
3987: r = IOCTL(data->fd, AUDIO_GETBUFINFO, &ai, "");
3988: XP_SYS_EQ(0, r);
3989:
3990: /* Terminate */
3991: data->terminated = 1;
3992:
3993: /* Resume write() by unpause */
3994: AUDIO_INITINFO(&ai);
3995: if (netbsd < 8) {
3996: /*
3997: * XXX NetBSD7 has bugs and it cannot be unpaused.
3998: * However, it also has another bug and it clears buffer
3999: * when encoding is changed. I use it. :-P
4000: */
4001: ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
4002: }
4003: ai.play.pause = 0;
4004: r = IOCTL(data->fd, AUDIO_SETINFO, &ai, "pause=0");
4005: XP_SYS_EQ(0, r);
4006:
4007: return NULL;
4008: }
4009:
4010: /*
4011: * ioctl(2) can be issued while write(2)-ing.
4012: */
4013: DEF(ioctl_while_write)
4014: {
4015: struct audio_info ai;
4016: struct ioctl_while_write_data data0, *data;
4017: char buf[8000]; /* 1sec in mulaw,1ch,8000Hz */
4018: pthread_t tid;
4019: int r;
4020:
4021: TEST("ioctl_while_write");
4022:
4023: data = &data0;
4024: memset(data, 0, sizeof(*data));
4025: memset(buf, 0xff, sizeof(buf));
4026:
4027: data->fd = OPEN(devaudio, O_WRONLY);
4028: REQUIRED_SYS_OK(data->fd);
4029:
4030: /* Pause to block write(2)ing */
4031: AUDIO_INITINFO(&ai);
4032: ai.play.pause = 1;
4033: r = IOCTL(data->fd, AUDIO_SETINFO, &ai, "pause=1");
4034: XP_SYS_EQ(0, r);
4035:
4036: gettimeofday(&data->start, NULL);
4037:
4038: pthread_create(&tid, NULL, thread_ioctl_while_write, data);
4039:
4040: /* Write until blocking */
4041: for (;;) {
4042: r = WRITE(data->fd, buf, sizeof(buf));
4043: if (data->terminated)
4044: break;
4045: XP_SYS_EQ(sizeof(buf), r);
4046:
4047: /* Update written time */
4048: gettimeofday(&data->start, NULL);
4049: }
4050:
4051: pthread_join(tid, NULL);
4052:
4053: /* Flush */
4054: r = IOCTL(data->fd, AUDIO_FLUSH, NULL, "");
4055: XP_SYS_EQ(0, r);
4056: r = CLOSE(data->fd);
4057: XP_SYS_EQ(0, r);
4058: }
4059:
4060: volatile int sigio_caught;
4061: void
4062: signal_FIOASYNC(int signo)
4063: {
4064: if (signo == SIGIO) {
4065: sigio_caught = 1;
4066: DPRINTF(" > %d: pid %d got SIGIO\n", __LINE__, (int)getpid());
4067: }
4068: }
4069:
4070: /*
4071: * FIOASYNC between two descriptors should be splitted.
4072: */
4073: DEF(FIOASYNC_reset)
4074: {
4075: int fd0, fd1;
4076: int r;
4077: int val;
4078:
4079: TEST("FIOASYNC_reset");
4080: if (netbsd < 8) {
4081: XP_SKIP("Multiple open is not supported");
4082: return;
4083: }
4084:
4085: /* The first one opens */
4086: fd0 = OPEN(devaudio, O_WRONLY);
4087: REQUIRED_SYS_OK(fd0);
4088:
4089: /* The second one opens, enables ASYNC, and closes */
4090: fd1 = OPEN(devaudio, O_WRONLY);
4091: REQUIRED_SYS_OK(fd1);
4092: val = 1;
4093: r = IOCTL(fd1, FIOASYNC, &val, "on");
4094: XP_SYS_EQ(0, r);
4095: r = CLOSE(fd1);
4096: XP_SYS_EQ(0, r);
4097:
4098: /* Again, the second one opens and enables ASYNC */
4099: fd1 = OPEN(devaudio, O_WRONLY);
4100: REQUIRED_SYS_OK(fd1);
4101: val = 1;
4102: r = IOCTL(fd1, FIOASYNC, &val, "on");
4103: XP_SYS_EQ(0, r); /* NetBSD8 fails */
4104: r = CLOSE(fd1);
4105: XP_SYS_EQ(0, r);
4106: r = CLOSE(fd0);
4107: XP_SYS_EQ(0, r);
4108: }
4109:
4110: /*
4111: * Whether SIGIO is emitted on plyaback.
4112: * XXX I don't understand conditions that NetBSD7 emits signal.
4113: */
4114: DEF(FIOASYNC_play_signal)
4115: {
4116: struct audio_info ai;
4117: int r;
4118: int fd;
4119: int val;
4120: char *data;
4121: int i;
4122:
4123: TEST("FIOASYNC_play_signal");
4124: if (hw_canplay() == 0) {
4125: XP_SKIP("This test is only for playable device");
4126: return;
4127: }
4128:
4129: signal(SIGIO, signal_FIOASYNC);
4130: sigio_caught = 0;
4131:
4132: fd = OPEN(devaudio, O_WRONLY);
4133: REQUIRED_SYS_OK(fd);
4134:
4135: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4136: REQUIRED_SYS_EQ(0, r);
4137: REQUIRED_IF(ai.blocksize != 0);
4138: data = (char *)malloc(ai.blocksize);
4139: REQUIRED_IF(data != NULL);
4140: memset(data, 0xff, ai.blocksize);
4141:
4142: val = 1;
4143: r = IOCTL(fd, FIOASYNC, &val, "on");
4144: XP_SYS_EQ(0, r);
4145:
4146: r = WRITE(fd, data, ai.blocksize);
4147: XP_SYS_EQ(ai.blocksize, r);
4148:
4149: /* Waits signal until 1sec */
4150: for (i = 0; i < 100 && sigio_caught == 0; i++) {
4151: usleep(10000);
4152: }
4153: signal(SIGIO, SIG_IGN);
4154: XP_EQ(1, sigio_caught);
4155:
4156: r = CLOSE(fd);
4157: XP_SYS_EQ(0, r);
4158:
4159: free(data);
4160: signal(SIGIO, SIG_IGN);
4161: sigio_caught = 0;
4162: }
4163:
4164: /*
4165: * Whether SIGIO is emitted on recording.
4166: */
4167: DEF(FIOASYNC_rec_signal)
4168: {
4169: char buf[10];
4170: int r;
4171: int fd;
4172: int val;
4173: int i;
4174:
4175: TEST("FIOASYNC_rec_signal");
4176: if (hw_canrec() == 0) {
4177: XP_SKIP("This test is only for recordable device");
4178: return;
4179: }
4180:
4181: signal(SIGIO, signal_FIOASYNC);
4182: sigio_caught = 0;
4183:
4184: fd = OPEN(devaudio, O_RDONLY);
4185: REQUIRED_SYS_OK(fd);
4186:
4187: val = 1;
4188: r = IOCTL(fd, FIOASYNC, &val, "on");
4189: XP_SYS_EQ(0, r);
4190:
4191: r = READ(fd, buf, sizeof(buf));
4192: XP_SYS_EQ(sizeof(buf), r);
4193:
4194: /* Wait signal until 1sec */
4195: for (i = 0; i < 100 && sigio_caught == 0; i++) {
4196: usleep(10000);
4197: }
4198: signal(SIGIO, SIG_IGN);
4199: XP_EQ(1, sigio_caught);
4200:
4201: r = CLOSE(fd);
4202: XP_SYS_EQ(0, r);
4203:
4204: signal(SIGIO, SIG_IGN);
4205: sigio_caught = 0;
4206: }
4207:
4208: /*
4209: * FIOASYNC doesn't affect other descriptor.
4210: * For simplify, test only for playback...
4211: */
4212: DEF(FIOASYNC_multi)
4213: {
4214: struct audio_info ai;
4215: char *buf;
4216: char pipebuf[1];
4217: int r;
4218: int i;
4219: int fd1;
4220: int fd2;
4221: int pd[2];
4222: int val;
4223: pid_t pid;
4224: int status;
4225:
4226: TEST("FIOASYNC_multi");
4227: if (netbsd < 8) {
4228: XP_SKIP("Multiple open is not supported");
4229: return;
4230: }
4231: if (hw_canplay() == 0) {
4232: XP_SKIP("This test is only for playable device");
4233: return;
4234: }
4235:
4236: /* Pipe used between parent and child */
4237: r = pipe(pd);
4238: REQUIRED_SYS_EQ(0, r);
4239:
4240: fd1 = OPEN(devaudio, O_WRONLY);
4241: REQUIRED_SYS_OK(fd1);
4242: fd2 = OPEN(devaudio, O_WRONLY);
4243: REQUIRED_SYS_OK(fd2);
4244:
4245: /* Pause fd2 */
4246: AUDIO_INITINFO(&ai);
4247: ai.play.pause = 1;
4248: r = IOCTL(fd2, AUDIO_SETINFO, &ai, "pause");
4249: REQUIRED_SYS_EQ(0, r);
4250:
4251: /* Fill both */
4252: r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, "");
4253: REQUIRED_SYS_EQ(0, r);
4254: REQUIRED_IF(ai.blocksize != 0);
4255: buf = (char *)malloc(ai.blocksize);
4256: REQUIRED_IF(buf != NULL);
4257: memset(buf, 0xff, ai.blocksize);
4258: r = WRITE(fd1, buf, ai.blocksize);
4259: XP_SYS_EQ(ai.blocksize, r);
4260:
4261: sigio_caught = 0;
4262: val = 1;
4263:
4264: fflush(stdout);
4265: fflush(stderr);
4266: pid = fork();
4267: if (pid == -1) {
4268: REQUIRED_SYS_OK(pid);
4269: }
4270: if (pid == 0) {
4271: /* Child */
4272: close(fd1);
4273:
4274: /* Child enables ASYNC on fd2 */
4275: signal(SIGIO, signal_FIOASYNC);
4276: r = IOCTL(fd2, FIOASYNC, &val, "on");
4277: /* It cannot count errors because here is a child process */
4278: /* XP_SYS_EQ(0, r); */
4279:
4280: /*
4281: * Waits signal until 1sec.
4282: * But fd2 is paused so it should never raise.
4283: */
4284: for (i = 0; i < 100 && sigio_caught == 0; i++) {
4285: usleep(10000);
4286: }
4287: signal(SIGIO, SIG_IGN);
4288: pipebuf[0] = sigio_caught;
4289: /* This is not WRITE() macro here */
4290: write(pd[1], pipebuf, sizeof(pipebuf));
4291:
4292: /* XXX? */
4293: close(fd2);
4294: sleep(1);
4295: exit(0);
4296: } else {
4297: /* Parent */
4298: DPRINTF(" > fork() = %d\n", (int)pid);
4299:
4300: /* Parent enables ASYNC on fd1 */
4301: signal(SIGIO, signal_FIOASYNC);
4302: r = IOCTL(fd1, FIOASYNC, &val, "on");
4303: XP_SYS_EQ(0, r);
4304:
4305: /* Waits signal until 1sec */
4306: for (i = 0; i < 100 && sigio_caught == 0; i++) {
4307: usleep(10000);
4308: }
4309: signal(SIGIO, SIG_IGN);
4310: XP_EQ(1, sigio_caught);
4311:
4312: /* Then read child's result from pipe */
4313: r = read(pd[0], pipebuf, sizeof(pipebuf));
4314: if (r != 1) {
4315: XP_FAIL("reading from child failed");
4316: }
4317: DPRINTF(" > child's sigio_cauht = %d\n", pipebuf[0]);
4318: XP_EQ(0, pipebuf[0]);
4319:
4320: waitpid(pid, &status, 0);
4321: }
4322:
4323: r = CLOSE(fd1);
4324: XP_SYS_EQ(0, r);
4325: r = CLOSE(fd2);
4326: XP_SYS_EQ(0, r);
4327:
4328: signal(SIGIO, SIG_IGN);
4329: sigio_caught = 0;
4330: free(buf);
4331: }
4332:
4333: /*
4334: * Check AUDIO_WSEEK behavior.
4335: */
4336: DEF(AUDIO_WSEEK)
4337: {
4338: char buf[4];
4339: struct audio_info ai;
4340: int r;
4341: int fd;
4342: int n;
4343:
4344: TEST("AUDIO_WSEEK");
4345:
4346: fd = OPEN(devaudio, O_WRONLY);
4347: REQUIRED_SYS_OK(fd);
4348:
4349: /* Pause to count sample data */
4350: AUDIO_INITINFO(&ai);
4351: ai.play.pause = 1;
4352: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause=1");
4353: REQUIRED_SYS_EQ(0, r);
4354:
4355: /* On the initial state, it should be 0 bytes */
4356: n = 0;
4357: r = IOCTL(fd, AUDIO_WSEEK, &n, "");
4358: XP_SYS_EQ(0, r);
4359: XP_EQ(0, n);
4360:
4361: /* When writing 4 bytes, it should be 4 bytes */
4362: memset(buf, 0xff, sizeof(buf));
4363: r = WRITE(fd, buf, sizeof(buf));
4364: REQUIRED_EQ(sizeof(buf), r);
4365: r = IOCTL(fd, AUDIO_WSEEK, &n, "");
4366: XP_SYS_EQ(0, r);
4367: if (netbsd < 9) {
4368: /*
4369: * On NetBSD7, it will return 0.
4370: * Perhaps, WSEEK returns the number of pustream bytes but
4371: * data has already advanced...
4372: */
4373: XP_EQ(0, n);
4374: } else {
4375: /* Data less than one block remains here */
4376: XP_EQ(4, n);
4377: }
4378:
4379: r = CLOSE(fd);
4380: XP_SYS_EQ(0, r);
4381: }
4382:
4383: /*
4384: * Check AUDIO_SETFD behavior for O_*ONLY descriptor.
4385: * On NetBSD7, SETFD modify audio layer's state (and MD driver's state)
4386: * regardless of open mode. GETFD obtains audio layer's duplex.
4387: * On NetBSD9, SETFD is obsoleted. GETFD obtains hardware's duplex.
4388: */
4389: void
4390: test_AUDIO_SETFD_xxONLY(int openmode)
4391: {
4392: struct audio_info ai;
4393: int r;
4394: int fd;
4395: int n;
4396:
4397: TEST("AUDIO_SETFD_%s", openmode_str[openmode] + 2);
4398: if (openmode == O_RDONLY && hw_canrec() == 0) {
4399: XP_SKIP("This test is for recordable device");
4400: return;
4401: }
4402: if (openmode == O_WRONLY && hw_canplay() == 0) {
4403: XP_SKIP("This test is for playable device");
4404: return;
4405: }
4406:
4407: fd = OPEN(devaudio, openmode);
4408: REQUIRED_SYS_OK(fd);
4409:
4410: /*
4411: * Just after open(2),
4412: * - On NetBSD7, it's always half-duplex.
4413: * - On NetBSD9, it's the same as hardware one regardless of openmode.
4414: */
4415: n = 0;
4416: r = IOCTL(fd, AUDIO_GETFD, &n, "");
4417: XP_SYS_EQ(0, r);
4418: if (netbsd < 9) {
4419: XP_EQ(0, n);
4420: } else {
4421: XP_EQ(hw_fulldup(), n);
4422: }
4423:
4424: /*
4425: * When trying to set to full-duplex,
4426: * - On NetBSD7, it will succeed if the hardware is full-duplex, or
4427: * will fail if the hardware is half-duplex.
4428: * - On NetBSD9, it will always succeed but will not be modified.
4429: */
4430: n = 1;
4431: r = IOCTL(fd, AUDIO_SETFD, &n, "on");
4432: if (netbsd < 8) {
4433: if (hw_fulldup()) {
4434: XP_SYS_EQ(0, r);
4435: } else {
4436: XP_SYS_NG(ENOTTY, r);
4437: }
4438: } else if (netbsd == 8) {
4439: XP_FAIL("expected result is unknown");
4440: } else {
4441: XP_SYS_EQ(0, r);
4442: }
4443:
4444: /*
4445: * When obtain it,
4446: * - On NetBSD7, it will be 1 if the hardware is full-duplex or
4447: * 0 if half-duplex.
4448: * - On NetBSD9, it will never be changed because it's the hardware
4449: * property.
4450: */
4451: n = 0;
4452: r = IOCTL(fd, AUDIO_GETFD, &n, "");
4453: XP_SYS_EQ(0, r);
4454: if (netbsd < 8) {
4455: XP_EQ(hw_fulldup(), n);
4456: } else if (netbsd == 8) {
4457: XP_FAIL("expected result is unknown");
4458: } else {
4459: XP_EQ(hw_fulldup(), n);
4460: }
4461:
4462: /* Some track parameters like ai.*.open should not change */
4463: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4464: XP_SYS_EQ(0, r);
4465: XP_EQ(mode2play(openmode), ai.play.open);
4466: XP_EQ(mode2rec(openmode), ai.record.open);
4467:
4468: /*
4469: * When trying to set to half-duplex,
4470: * - On NetBSD7, it will succeed if the hardware is full-duplex, or
4471: * it will succeed with nothing happens.
4472: * - On NetBSD9, it will always succeed but nothing happens.
4473: */
4474: n = 0;
4475: r = IOCTL(fd, AUDIO_SETFD, &n, "off");
4476: XP_SYS_EQ(0, r);
4477:
4478: /*
4479: * When obtain it again,
4480: * - On NetBSD7, it will be 0 if the hardware is full-duplex, or
4481: * still 0 if half-duplex.
4482: * - On NetBSD9, it should not change.
4483: */
4484: n = 0;
4485: r = IOCTL(fd, AUDIO_GETFD, &n, "");
4486: XP_SYS_EQ(0, r);
4487: if (netbsd < 9) {
4488: XP_EQ(0, n);
4489: } else {
4490: XP_EQ(hw_fulldup(), n);
4491: }
4492:
4493: /* Some track parameters like ai.*.open should not change */
4494: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4495: XP_SYS_EQ(0, r);
4496: XP_EQ(mode2play(openmode), ai.play.open);
4497: XP_EQ(mode2rec(openmode), ai.record.open);
4498:
4499: r = CLOSE(fd);
4500: XP_SYS_EQ(0, r);
4501: }
4502: DEF(AUDIO_SETFD_RDONLY) { test_AUDIO_SETFD_xxONLY(O_RDONLY); }
4503: DEF(AUDIO_SETFD_WRONLY) { test_AUDIO_SETFD_xxONLY(O_WRONLY); }
4504:
4505: /*
4506: * Check AUDIO_SETFD behavior for O_RDWR descriptor.
4507: */
4508: DEF(AUDIO_SETFD_RDWR)
4509: {
4510: struct audio_info ai;
4511: int r;
4512: int fd;
4513: int n;
4514:
4515: TEST("AUDIO_SETFD_RDWR");
4516: if (!hw_fulldup()) {
4517: XP_SKIP("This test is only for full-duplex device");
4518: return;
4519: }
4520:
4521: fd = OPEN(devaudio, O_RDWR);
4522: REQUIRED_SYS_OK(fd);
4523:
4524: /*
4525: * - audio(4) manpage until NetBSD7 said "If a full-duplex capable
4526: * audio device is opened for both reading and writing it will
4527: * start in half-duplex play mode", but implementation doesn't
4528: * seem to follow it. It returns full-duplex.
4529: * - On NetBSD9, it should return full-duplex on full-duplex, or
4530: * half-duplex on half-duplex.
4531: */
4532: n = 0;
4533: r = IOCTL(fd, AUDIO_GETFD, &n, "");
4534: XP_SYS_EQ(0, r);
4535: XP_EQ(hw_fulldup(), n);
4536:
4537: /*
4538: * When trying to set to full-duplex,
4539: * - On NetBSD7, it will succeed with nothing happens if full-duplex,
4540: * or will fail if half-duplex.
4541: * - On NetBSD9, it will always succeed with nothing happens.
4542: */
4543: n = 1;
4544: r = IOCTL(fd, AUDIO_SETFD, &n, "on");
4545: if (netbsd < 9) {
4546: if (hw_fulldup()) {
4547: XP_SYS_EQ(0, r);
4548: } else {
4549: XP_SYS_NG(ENOTTY, r);
4550: }
4551: } else {
4552: XP_SYS_EQ(0, r);
4553: }
4554:
4555: /* When obtains it, it retuns half/full-duplex as is */
4556: n = 0;
4557: r = IOCTL(fd, AUDIO_GETFD, &n, "");
4558: XP_SYS_EQ(0, r);
4559: XP_EQ(hw_fulldup(), n);
4560:
4561: /* Some track parameters like ai.*.open should not change */
4562: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4563: XP_SYS_EQ(0, r);
4564: XP_EQ(1, ai.play.open);
4565: XP_EQ(mode2rec(O_RDWR), ai.record.open);
4566:
4567: /*
4568: * When trying to set to half-duplex,
4569: * - On NetBSD7, it will succeed if the hardware is full-duplex, or
4570: * it will succeed with nothing happens.
4571: * - On NetBSD9, it will always succeed but nothing happens.
4572: */
4573: n = 0;
4574: r = IOCTL(fd, AUDIO_SETFD, &n, "off");
4575: if (netbsd < 8) {
4576: XP_SYS_EQ(0, r);
4577: } else if (netbsd == 8) {
4578: XP_FAIL("expected result is unknown");
4579: } else {
4580: XP_SYS_EQ(0, r);
4581: }
4582:
4583: /*
4584: * When obtain it again,
4585: * - On NetBSD7, it will be 0 if the hardware is full-duplex, or
4586: * still 0 if half-duplex.
4587: * - On NetBSD9, it should be 1 if the hardware is full-duplex, or
4588: * 0 if half-duplex.
4589: */
4590: n = 0;
4591: r = IOCTL(fd, AUDIO_GETFD, &n, "");
4592: XP_SYS_EQ(0, r);
4593: if (netbsd < 8) {
4594: XP_EQ(0, n);
4595: } else if (netbsd == 8) {
4596: XP_FAIL("expected result is unknown");
4597: } else {
4598: XP_EQ(hw_fulldup(), n);
4599: }
4600:
4601: /* Some track parameters like ai.*.open should not change */
4602: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4603: XP_SYS_EQ(0, r);
4604: XP_EQ(1, ai.play.open);
4605: XP_EQ(mode2rec(O_RDWR), ai.record.open);
4606:
4607: r = CLOSE(fd);
4608: XP_SYS_EQ(0, r);
4609: }
4610:
4611: /*
4612: * Check AUDIO_GETINFO.eof behavior.
4613: */
4614: DEF(AUDIO_GETINFO_eof)
4615: {
4616: struct audio_info ai;
4617: char buf[4];
4618: int r;
4619: int fd, fd1;
4620:
4621: TEST("AUDIO_GETINFO_eof");
4622: if (hw_canplay() == 0) {
4623: XP_SKIP("This test is for playable device");
4624: return;
4625: }
4626:
4627: fd = OPEN(devaudio, O_RDWR);
4628: REQUIRED_SYS_OK(fd);
4629:
4630: /* Pause to make no sound */
4631: AUDIO_INITINFO(&ai);
4632: ai.play.pause = 1;
4633: r = IOCTL(fd, AUDIO_SETINFO, &ai, "pause");
4634: REQUIRED_SYS_EQ(0, r);
4635:
4636: /* It should be 0 initially */
4637: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4638: XP_SYS_EQ(0, r);
4639: XP_EQ(0, ai.play.eof);
4640: XP_EQ(0, ai.record.eof);
4641:
4642: /* Writing zero bytes should increment it */
4643: r = WRITE(fd, &r, 0);
4644: REQUIRED_SYS_OK(r);
4645: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4646: XP_SYS_EQ(0, r);
4647: XP_EQ(1, ai.play.eof);
4648: XP_EQ(0, ai.record.eof);
4649:
4650: /* Writing one ore more bytes should noto increment it */
4651: memset(buf, 0xff, sizeof(buf));
4652: r = WRITE(fd, buf, sizeof(buf));
4653: REQUIRED_SYS_OK(r);
4654: memset(&ai, 0, sizeof(ai));
4655: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4656: XP_SYS_EQ(0, r);
4657: XP_EQ(1, ai.play.eof);
4658: XP_EQ(0, ai.record.eof);
4659:
4660: /* Writing zero bytes again should increment it */
4661: r = WRITE(fd, buf, 0);
4662: REQUIRED_SYS_OK(r);
4663: memset(&ai, 0, sizeof(ai));
4664: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4665: XP_SYS_EQ(0, r);
4666: XP_EQ(2, ai.play.eof);
4667: XP_EQ(0, ai.record.eof);
4668:
4669: /* Reading zero bytes should not increment it */
4670: if (hw_fulldup()) {
4671: r = READ(fd, buf, 0);
4672: REQUIRED_SYS_OK(r);
4673: memset(&ai, 0, sizeof(ai));
4674: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4675: XP_SYS_EQ(0, r);
4676: XP_EQ(2, ai.play.eof);
4677: XP_EQ(0, ai.record.eof);
4678: }
4679:
4680: /* should not interfere with other descriptor */
4681: if (netbsd >= 8) {
4682: fd1 = OPEN(devaudio, O_RDWR);
4683: REQUIRED_SYS_OK(fd1);
4684: memset(&ai, 0, sizeof(ai));
4685: r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, "");
4686: XP_SYS_EQ(0, r);
4687: XP_EQ(0, ai.play.eof);
4688: XP_EQ(0, ai.record.eof);
4689: r = CLOSE(fd1);
4690: XP_SYS_EQ(0, r);
4691: }
4692:
4693: r = CLOSE(fd);
4694: XP_SYS_EQ(0, r);
4695:
4696: xxx_close_wait();
4697:
4698: /* When reopen, it should reset the counter */
4699: fd = OPEN(devaudio, O_RDWR);
4700: REQUIRED_SYS_OK(fd);
4701:
4702: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4703: XP_SYS_EQ(0, r);
4704: XP_EQ(0, ai.play.eof);
4705: XP_EQ(0, ai.record.eof);
4706:
4707: r = CLOSE(fd);
4708: XP_SYS_EQ(0, r);
4709: }
4710:
4711: /*
4712: * Check relationship between openmode and mode set by AUDIO_SETINFO.
4713: */
4714: void
4715: test_AUDIO_SETINFO_mode(int openmode, int index, int setmode, int expected)
4716: {
4717: struct audio_info ai;
4718: char buf[10];
4719: int inimode;
4720: int r;
4721: int fd;
4722: bool canwrite;
4723: bool canread;
4724:
4725: /* index was passed only for displaying here */
4726: TEST("AUDIO_SETINFO_mode_%s_%d", openmode_str[openmode] + 2, index);
4727: if (mode2aumode(openmode) == 0) {
4728: XP_SKIP("Operation not allowed on this hardware property");
4729: return;
4730: }
4731:
4732: inimode = mode2aumode(openmode);
4733:
4734: fd = OPEN(devaudio, openmode);
4735: REQUIRED_SYS_OK(fd);
4736:
4737: /* When just after opening */
4738: memset(&ai, 0, sizeof(ai));
4739: r = IOCTL(fd, AUDIO_GETINFO, &ai, "");
4740: REQUIRED_SYS_EQ(0, r);
4741: XP_EQ(inimode, ai.mode);
4742: XP_EQ(mode2play(openmode), ai.play.open);
4743: XP_EQ(mode2rec(openmode), ai.record.open);
1.7 isaki 4744: XP_NE(0, ai.play.buffer_size);
4745: XP_NE(0, ai.record.buffer_size);
1.1 isaki 4746:
4747: /* Change mode (and pause here) */
4748: ai.mode = setmode;
4749: ai.play.pause = 1;
4750: ai.record.pause = 1;
4751: r = IOCTL(fd, AUDIO_SETINFO, &ai, "mode");
4752: XP_SYS_EQ(0, r);
4753: if (r == 0) {
4754: r = IOCTL(fd, AUDIO_GETINFO, &ai, "");
4755: XP_SYS_EQ(0, r);
4756: XP_EQ(expected, ai.mode);
4757:
4758: /* It seems to keep the initial openmode regardless of mode */
4759: XP_EQ(mode2play(openmode), ai.play.open);
4760: XP_EQ(mode2rec(openmode), ai.record.open);
1.7 isaki 4761: XP_NE(0, ai.play.buffer_size);
4762: XP_NE(0, ai.record.buffer_size);
1.1 isaki 4763: }
4764:
4765: /*
4766: * On NetBSD7, whether writable depends openmode when open.
4767: * On NetBSD9, whether writable should depend inimode when open.
4768: * Modifying after open should not affect this mode.
4769: */
4770: if (netbsd < 9) {
4771: canwrite = (openmode != O_RDONLY);
4772: } else {
4773: canwrite = ((inimode & AUMODE_PLAY) != 0);
4774: }
4775: r = WRITE(fd, buf, 0);
4776: if (canwrite) {
4777: XP_SYS_EQ(0, r);
4778: } else {
4779: XP_SYS_NG(EBADF, r);
4780: }
4781:
4782: /*
4783: * On NetBSD7, whether readable depends openmode when open.
4784: * On NetBSD9, whether readable should depend inimode when open.
4785: * Modifying after open should not affect this mode.
4786: */
4787: if (netbsd < 9) {
4788: canread = (openmode != O_WRONLY);
4789: } else {
4790: canread = ((inimode & AUMODE_RECORD) != 0);
4791: }
4792: r = READ(fd, buf, 0);
4793: if (canread) {
4794: XP_SYS_EQ(0, r);
4795: } else {
4796: XP_SYS_NG(EBADF, r);
4797: }
4798:
4799: r = CLOSE(fd);
4800: XP_SYS_EQ(0, r);
4801: }
4802: /*
4803: * XXX hmm... it's too complex
4804: */
4805: /* shortcut for table form */
4806: #define P AUMODE_PLAY
4807: #define A AUMODE_PLAY_ALL
4808: #define R AUMODE_RECORD
4809: struct setinfo_mode_t {
4810: int setmode; /* mode used in SETINFO */
4811: int expmode7; /* expected mode on NetBSD7 */
4812: int expmode9; /* expected mode on NetBSD9 */
4813: };
4814: /*
4815: * The following tables show this operation on NetBSD7 is almost 'undefined'.
4816: * In contrast, NetBSD9 never changes mode by AUDIO_SETINFO except
4817: * AUMODE_PLAY_ALL.
4818: *
4819: * setmode == 0 and 8 are out of range and invalid input samples.
4820: * But NetBSD7 seems to accept it as is.
4821: */
4822: struct setinfo_mode_t table_SETINFO_mode_O_RDONLY[] = {
4823: /* setmode expmode7 expmode9 */
4824: { 0, 0, R },
4825: { P, P, R },
4826: { A , A|P, R },
4827: { A|P, A|P, R },
4828: { R , R , R },
4829: { R| P, P, R },
4830: { R|A , A|P, R },
4831: { R|A|P, A|P, R },
4832: { 8, 8, R },
4833: };
4834: struct setinfo_mode_t table_SETINFO_mode_O_WRONLY[] = {
4835: /* setmode expmode7 expmode9 */
4836: { 0, 0, P },
4837: { P, P, P },
4838: { A , A|P, A|P },
4839: { A|P, A|P, A|P },
4840: { R , R , P },
4841: { R| P, P, P },
4842: { R|A , A|P, A|P },
4843: { R|A|P, A|P, A|P },
4844: { 8, 8, P },
4845: };
4846: #define f(openmode, index) do { \
4847: struct setinfo_mode_t *table = table_SETINFO_mode_##openmode; \
4848: int setmode = table[index].setmode; \
4849: int expected = (netbsd < 9) \
4850: ? table[index].expmode7 \
4851: : table[index].expmode9; \
4852: test_AUDIO_SETINFO_mode(openmode, index, setmode, expected); \
4853: } while (0)
4854: DEF(AUDIO_SETINFO_mode_RDONLY_0) { f(O_RDONLY, 0); }
4855: DEF(AUDIO_SETINFO_mode_RDONLY_1) { f(O_RDONLY, 1); }
4856: DEF(AUDIO_SETINFO_mode_RDONLY_2) { f(O_RDONLY, 2); }
4857: DEF(AUDIO_SETINFO_mode_RDONLY_3) { f(O_RDONLY, 3); }
4858: DEF(AUDIO_SETINFO_mode_RDONLY_4) { f(O_RDONLY, 4); }
4859: DEF(AUDIO_SETINFO_mode_RDONLY_5) { f(O_RDONLY, 5); }
4860: DEF(AUDIO_SETINFO_mode_RDONLY_6) { f(O_RDONLY, 6); }
4861: DEF(AUDIO_SETINFO_mode_RDONLY_7) { f(O_RDONLY, 7); }
4862: DEF(AUDIO_SETINFO_mode_RDONLY_8) { f(O_RDONLY, 8); }
4863: DEF(AUDIO_SETINFO_mode_WRONLY_0) { f(O_WRONLY, 0); }
4864: DEF(AUDIO_SETINFO_mode_WRONLY_1) { f(O_WRONLY, 1); }
4865: DEF(AUDIO_SETINFO_mode_WRONLY_2) { f(O_WRONLY, 2); }
4866: DEF(AUDIO_SETINFO_mode_WRONLY_3) { f(O_WRONLY, 3); }
4867: DEF(AUDIO_SETINFO_mode_WRONLY_4) { f(O_WRONLY, 4); }
4868: DEF(AUDIO_SETINFO_mode_WRONLY_5) { f(O_WRONLY, 5); }
4869: DEF(AUDIO_SETINFO_mode_WRONLY_6) { f(O_WRONLY, 6); }
4870: DEF(AUDIO_SETINFO_mode_WRONLY_7) { f(O_WRONLY, 7); }
4871: DEF(AUDIO_SETINFO_mode_WRONLY_8) { f(O_WRONLY, 8); }
4872: #undef f
4873: /*
4874: * The following tables also show that NetBSD7's behavior is almost
4875: * 'undefined'.
4876: */
4877: struct setinfo_mode_t table_SETINFO_mode_O_RDWR_full[] = {
4878: /* setmode expmode7 expmode9 */
4879: { 0, 0, R| P },
4880: { P, P, R| P },
4881: { A , A|P, R|A|P },
4882: { A|P, A|P, R|A|P },
4883: { R , R , R| P },
4884: { R| P, R| P, R| P },
4885: { R|A , R|A|P, R|A|P },
4886: { R|A|P, R|A|P, R|A|P },
4887: { 8, 8, R| P },
4888: };
4889: struct setinfo_mode_t table_SETINFO_mode_O_RDWR_half[] = {
4890: /* setmode expmode7 expmode9 */
4891: { 0, 0, P },
4892: { P, P, P },
4893: { A , A|P, A|P },
4894: { A|P, A|P, A|P },
4895: { R , R , P },
4896: { R| P, P, P },
4897: { R|A , A|P, A|P },
4898: { R|A|P, A|P, A|P },
4899: { 8, 8, P },
4900: };
4901: #define f(index) do { \
4902: struct setinfo_mode_t *table = (hw_fulldup()) \
4903: ? table_SETINFO_mode_O_RDWR_full \
4904: : table_SETINFO_mode_O_RDWR_half; \
4905: int setmode = table[index].setmode; \
4906: int expected = (netbsd < 9) \
4907: ? table[index].expmode7 \
4908: : table[index].expmode9; \
4909: test_AUDIO_SETINFO_mode(O_RDWR, index, setmode, expected); \
4910: } while (0)
4911: DEF(AUDIO_SETINFO_mode_RDWR_0) { f(0); }
4912: DEF(AUDIO_SETINFO_mode_RDWR_1) { f(1); }
4913: DEF(AUDIO_SETINFO_mode_RDWR_2) { f(2); }
4914: DEF(AUDIO_SETINFO_mode_RDWR_3) { f(3); }
4915: DEF(AUDIO_SETINFO_mode_RDWR_4) { f(4); }
4916: DEF(AUDIO_SETINFO_mode_RDWR_5) { f(5); }
4917: DEF(AUDIO_SETINFO_mode_RDWR_6) { f(6); }
4918: DEF(AUDIO_SETINFO_mode_RDWR_7) { f(7); }
4919: DEF(AUDIO_SETINFO_mode_RDWR_8) { f(8); }
4920: #undef f
4921: #undef P
4922: #undef A
4923: #undef R
4924:
4925: /*
4926: * Check whether encoding params can be set.
4927: */
4928: void
4929: test_AUDIO_SETINFO_params_set(int openmode, int aimode, int pause)
4930: {
4931: struct audio_info ai;
4932: int r;
4933: int fd;
4934:
4935: /*
4936: * aimode is bool value that indicates whether to change ai.mode.
4937: * pause is bool value that indicates whether to change ai.*.pause.
4938: */
4939:
4940: TEST("AUDIO_SETINFO_params_%s_%d_%d",
4941: openmode_str[openmode] + 2, aimode, pause);
4942: if (mode2aumode(openmode) == 0) {
4943: XP_SKIP("Operation not allowed on this hardware property");
4944: return;
4945: }
4946:
4947: /* On half-duplex, O_RDWR is the same as O_WRONLY, so skip it */
4948: if (!hw_fulldup() && openmode == O_RDWR) {
4949: XP_SKIP("This is the same with O_WRONLY on half-duplex");
4950: return;
4951: }
4952:
4953: fd = OPEN(devaudio, openmode);
4954: REQUIRED_SYS_OK(fd);
4955:
4956: AUDIO_INITINFO(&ai);
4957: /*
4958: * It takes time and effort to check all parameters independently,
4959: * so that use sample_rate as a representative.
4960: */
4961: ai.play.sample_rate = 11025;
4962: ai.record.sample_rate = 11025;
4963: if (aimode)
4964: ai.mode = mode2aumode(openmode) & ~AUMODE_PLAY_ALL;
4965: if (pause) {
4966: ai.play.pause = 1;
4967: ai.record.pause = 1;
4968: }
4969:
4970: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
4971: XP_SYS_EQ(0, r);
4972:
4973: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
4974: XP_SYS_EQ(0, r);
4975: int expmode = (aimode)
4976: ? (mode2aumode(openmode) & ~AUMODE_PLAY_ALL)
4977: : mode2aumode(openmode);
4978: XP_EQ(expmode, ai.mode);
1.7 isaki 4979: XP_EQ(11025, ai.play.sample_rate);
4980: XP_EQ(pause, ai.play.pause);
4981: XP_EQ(11025, ai.record.sample_rate);
4982: XP_EQ(pause, ai.record.pause);
1.1 isaki 4983:
4984: r = CLOSE(fd);
4985: XP_SYS_EQ(0, r);
4986: }
4987: #define f(a,b,c) test_AUDIO_SETINFO_params_set(a, b, c)
4988: DEF(AUDIO_SETINFO_params_set_RDONLY_0) { f(O_RDONLY, 0, 0); }
4989: DEF(AUDIO_SETINFO_params_set_RDONLY_1) { f(O_RDONLY, 0, 1); }
4990: /* On RDONLY, ai.mode is not changable
4991: * AUDIO_SETINFO_params_set_RDONLY_2) { f(O_RDONLY, 1, 0); }
4992: * AUDIO_SETINFO_params_set_RDONLY_3) { f(O_RDONLY, 1, 1); }
4993: */
4994: DEF(AUDIO_SETINFO_params_set_WRONLY_0) { f(O_WRONLY, 0, 0); }
4995: DEF(AUDIO_SETINFO_params_set_WRONLY_1) { f(O_WRONLY, 0, 1); }
4996: DEF(AUDIO_SETINFO_params_set_WRONLY_2) { f(O_WRONLY, 1, 0); }
4997: DEF(AUDIO_SETINFO_params_set_WRONLY_3) { f(O_WRONLY, 1, 1); }
4998: DEF(AUDIO_SETINFO_params_set_RDWR_0) { f(O_RDWR, 0, 0); }
4999: DEF(AUDIO_SETINFO_params_set_RDWR_1) { f(O_RDWR, 0, 1); }
5000: DEF(AUDIO_SETINFO_params_set_RDWR_2) { f(O_RDWR, 1, 0); }
5001: DEF(AUDIO_SETINFO_params_set_RDWR_3) { f(O_RDWR, 1, 1); }
5002: #undef f
5003:
5004: /*
1.7 isaki 5005: * AUDIO_SETINFO for existing track should not be interfered by other
5006: * descriptor.
5007: * AUDIO_SETINFO for non-existing track affects/is affected sticky parameters
5008: * for backward compatibility.
1.1 isaki 5009: */
5010: DEF(AUDIO_SETINFO_params_simul)
5011: {
5012: struct audio_info ai;
5013: int fd0;
5014: int fd1;
5015: int r;
5016:
5017: TEST("AUDIO_SETINFO_params_simul");
5018: if (netbsd < 8) {
5019: XP_SKIP("Multiple open is not supported");
5020: return;
5021: }
1.7 isaki 5022: if (hw_canplay() == 0) {
5023: XP_SKIP("This test is for playable device");
5024: return;
5025: }
1.1 isaki 5026:
5027: /* Open the 1st one as playback only */
5028: fd0 = OPEN(devaudio, O_WRONLY);
5029: REQUIRED_SYS_OK(fd0);
5030:
5031: /* Open the 2nd one as both of playback and recording */
5032: fd1 = OPEN(devaudio, O_RDWR);
5033: REQUIRED_SYS_OK(fd1);
5034:
5035: /* Change some parameters of both track on the 2nd one */
5036: AUDIO_INITINFO(&ai);
5037: ai.play.sample_rate = 11025;
5038: ai.record.sample_rate = 11025;
5039: r = IOCTL(fd1, AUDIO_SETINFO, &ai, "");
5040: XP_SYS_EQ(0, r);
5041:
1.7 isaki 5042: /*
5043: * The 1st one doesn't have recording track so that only recording
5044: * parameter is affected by sticky parameter.
5045: */
1.1 isaki 5046: memset(&ai, 0, sizeof(ai));
1.7 isaki 5047: r = IOCTL(fd0, AUDIO_GETBUFINFO, &ai, "");
1.1 isaki 5048: XP_SYS_EQ(0, r);
5049: XP_EQ(8000, ai.play.sample_rate);
1.7 isaki 5050: XP_EQ(11025, ai.record.sample_rate);
5051:
5052: /* Next, change some parameters of both track on the 1st one */
5053: AUDIO_INITINFO(&ai);
5054: ai.play.sample_rate = 16000;
5055: ai.record.sample_rate = 16000;
5056: r = IOCTL(fd0, AUDIO_SETINFO, &ai, "");
5057: XP_SYS_EQ(0, r);
5058:
5059: /*
5060: * On bi-directional device, the 2nd one has both track so that
5061: * both track are not affected by sticky parameter.
5062: * On uni-directional device, the 2nd one has only playback track
5063: * so that playback track is not affected by sticky parameter.
5064: */
5065: memset(&ai, 0, sizeof(ai));
5066: r = IOCTL(fd1, AUDIO_GETBUFINFO, &ai, "");
5067: XP_SYS_EQ(0, r);
5068: XP_EQ(11025, ai.play.sample_rate);
5069: if (hw_bidir()) {
5070: XP_EQ(11025, ai.record.sample_rate);
5071: } else {
5072: XP_EQ(16000, ai.record.sample_rate);
5073: }
1.1 isaki 5074:
5075: r = CLOSE(fd0);
5076: XP_SYS_EQ(0, r);
5077: r = CLOSE(fd1);
5078: XP_SYS_EQ(0, r);
5079: }
5080:
5081: /*
1.5 isaki 5082: * AUDIO_SETINFO(encoding/precision) is tested in AUDIO_GETENC_range below.
5083: */
5084:
5085: /*
5086: * Check whether the number of channels can be set.
5087: */
5088: DEF(AUDIO_SETINFO_channels)
5089: {
1.6 isaki 5090: struct audio_info hwinfo;
1.5 isaki 5091: struct audio_info ai;
5092: int mode;
5093: int r;
5094: int fd;
5095: int i;
1.6 isaki 5096: unsigned int ch;
1.5 isaki 5097: struct {
5098: int ch;
5099: bool expected;
5100: } table[] = {
5101: { 0, false },
5102: { 1, true }, /* monaural */
5103: { 2, true }, /* stereo */
5104: };
5105:
5106: TEST("AUDIO_SETINFO_channels");
5107: if (netbsd < 8) {
5108: /*
5109: * On NetBSD7, the result depends the hardware and there is
5110: * no way to know it.
5111: */
5112: XP_SKIP("The test doesn't make sense on NetBSD7");
5113: return;
5114: }
5115:
5116: mode = openable_mode();
5117: fd = OPEN(devaudio, mode);
5118: REQUIRED_SYS_OK(fd);
5119:
1.6 isaki 5120: /*
5121: * The audio layer always supports monaural and stereo regardless of
5122: * the hardware capability.
5123: */
1.5 isaki 5124: for (i = 0; i < (int)__arraycount(table); i++) {
1.6 isaki 5125: ch = table[i].ch;
1.5 isaki 5126: bool expected = table[i].expected;
5127:
5128: AUDIO_INITINFO(&ai);
5129: if (mode != O_RDONLY)
5130: ai.play.channels = ch;
5131: if (mode != O_WRONLY)
5132: ai.record.channels = ch;
5133: r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch);
5134: if (expected) {
5135: /* Expects to succeed */
5136: XP_SYS_EQ(0, r);
5137:
5138: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
5139: XP_SYS_EQ(0, r);
5140: if (mode != O_RDONLY)
5141: XP_EQ(ch, ai.play.channels);
5142: if (mode != O_WRONLY)
5143: XP_EQ(ch, ai.record.channels);
5144: } else {
5145: /* Expects to fail */
5146: XP_SYS_NG(EINVAL, r);
5147: }
5148: }
5149:
1.6 isaki 5150: /*
5151: * The maximum number of supported channels depends the hardware.
5152: */
5153: /* Get the number of channels that the hardware supports */
5154: r = IOCTL(fd, AUDIO_GETFORMAT, &hwinfo, "");
5155: REQUIRED_SYS_EQ(0, r);
5156:
5157: if ((hwinfo.mode & AUMODE_PLAY)) {
5158: DPRINTF(" > hwinfo.play.channels = %d\n",
5159: hwinfo.play.channels);
5160: for (ch = 3; ch <= hwinfo.play.channels; ch++) {
5161: AUDIO_INITINFO(&ai);
5162: ai.play.channels = ch;
5163: r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch);
5164: XP_SYS_EQ(0, r);
5165:
5166: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
5167: XP_SYS_EQ(0, r);
5168: XP_EQ(ch, ai.play.channels);
5169: }
5170:
5171: AUDIO_INITINFO(&ai);
5172: ai.play.channels = ch;
5173: r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch);
5174: XP_SYS_NG(EINVAL, r);
5175: }
5176: if ((hwinfo.mode & AUMODE_RECORD)) {
5177: DPRINTF(" > hwinfo.record.channels = %d\n",
5178: hwinfo.record.channels);
5179: for (ch = 3; ch <= hwinfo.record.channels; ch++) {
5180: AUDIO_INITINFO(&ai);
5181: ai.record.channels = ch;
5182: r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch);
5183: XP_SYS_EQ(0, r);
5184:
5185: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
5186: XP_SYS_EQ(0, r);
5187: XP_EQ(ch, ai.record.channels);
5188: }
5189:
5190: AUDIO_INITINFO(&ai);
5191: ai.record.channels = ch;
5192: r = IOCTL(fd, AUDIO_SETINFO, &ai, "channels=%d", ch);
5193: XP_SYS_NG(EINVAL, r);
5194: }
5195:
1.5 isaki 5196: r = CLOSE(fd);
5197: XP_SYS_EQ(0, r);
5198: }
5199:
5200: /*
5201: * Check whether the sample rate can be set.
5202: */
5203: DEF(AUDIO_SETINFO_sample_rate)
5204: {
5205: struct audio_info ai;
5206: int mode;
5207: int r;
5208: int fd;
5209: int i;
5210: struct {
5211: int freq;
5212: bool expected;
5213: } table[] = {
5214: { 999, false },
5215: { 1000, true }, /* lower limit */
5216: { 48000, true },
5217: { 192000, true }, /* upper limit */
5218: { 192001, false },
5219: };
5220:
5221: TEST("AUDIO_SETINFO_sample_rate");
5222: if (netbsd < 8) {
5223: /*
5224: * On NetBSD7, the result depends the hardware and there is
5225: * no way to know it.
5226: */
5227: XP_SKIP("The test doesn't make sense on NetBSD7");
5228: return;
5229: }
5230:
5231: mode = openable_mode();
5232: fd = OPEN(devaudio, mode);
5233: REQUIRED_SYS_OK(fd);
5234:
5235: for (i = 0; i < (int)__arraycount(table); i++) {
5236: int freq = table[i].freq;
5237: bool expected = table[i].expected;
5238:
5239: AUDIO_INITINFO(&ai);
5240: if (mode != O_RDONLY)
5241: ai.play.sample_rate = freq;
5242: if (mode != O_WRONLY)
5243: ai.record.sample_rate = freq;
5244: r = IOCTL(fd, AUDIO_SETINFO, &ai, "sample_rate=%d", freq);
5245: if (expected) {
5246: /* Expects to succeed */
5247: XP_SYS_EQ(0, r);
5248:
5249: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
5250: XP_SYS_EQ(0, r);
5251: if (mode != O_RDONLY)
5252: XP_EQ(freq, ai.play.sample_rate);
5253: if (mode != O_WRONLY)
5254: XP_EQ(freq, ai.record.sample_rate);
5255: } else {
5256: /* Expects to fail */
5257: XP_SYS_NG(EINVAL, r);
5258: }
5259: }
5260:
5261: r = CLOSE(fd);
5262: XP_SYS_EQ(0, r);
5263: }
5264:
5265: /*
5266: * SETINFO(sample_rate = 0) should fail correctly.
5267: */
5268: DEF(AUDIO_SETINFO_sample_rate_0)
5269: {
5270: struct audio_info ai;
5271: int mode;
5272: int r;
5273: int fd;
5274:
5275: TEST("AUDIO_SETINFO_sample_rate_0");
5276: if (netbsd < 9) {
5277: /*
5278: * On NetBSD7,8 this will block system call and you will not
5279: * even be able to shutdown...
5280: */
5281: XP_SKIP("This will cause an infinate loop in the kernel");
5282: return;
5283: }
5284:
5285: mode = openable_mode();
5286: fd = OPEN(devaudio, mode);
5287: REQUIRED_SYS_OK(fd);
5288:
5289: AUDIO_INITINFO(&ai);
5290: ai.play.sample_rate = 0;
5291: ai.record.sample_rate = 0;
5292: r = IOCTL(fd, AUDIO_SETINFO, &ai, "sample_rate=0");
5293: /* Expects to fail */
5294: XP_SYS_NG(EINVAL, r);
5295:
5296: r = CLOSE(fd);
5297: XP_SYS_EQ(0, r);
5298: }
5299:
5300: /*
1.1 isaki 5301: * Check whether the pause/unpause works.
5302: */
5303: void
5304: test_AUDIO_SETINFO_pause(int openmode, int aimode, int param)
5305: {
5306: struct audio_info ai;
5307: int r;
5308: int fd;
5309:
5310: /*
5311: * aimode is bool value that indicates whether to change ai.mode.
5312: * param is bool value that indicates whether to change encoding
5313: * parameters of ai.{play,record}.*.
5314: */
5315:
5316: TEST("AUDIO_SETINFO_pause_%s_%d_%d",
5317: openmode_str[openmode] + 2, aimode, param);
5318: if (mode2aumode(openmode) == 0) {
5319: XP_SKIP("Operation not allowed on this hardware property");
5320: return;
5321: }
5322:
5323: /* On half-duplex, O_RDWR is the same as O_WRONLY, so skip it */
5324: if (!hw_fulldup() && openmode == O_RDWR) {
5325: XP_SKIP("This is the same with O_WRONLY on half-duplex");
5326: return;
5327: }
5328:
5329: fd = OPEN(devaudio, openmode);
5330: REQUIRED_SYS_OK(fd);
5331:
5332: /* Set pause */
5333: AUDIO_INITINFO(&ai);
5334: ai.play.pause = 1;
5335: ai.record.pause = 1;
5336: if (aimode)
5337: ai.mode = mode2aumode(openmode) & ~AUMODE_PLAY_ALL;
5338: if (param) {
5339: ai.play.sample_rate = 11025;
5340: ai.record.sample_rate = 11025;
5341: }
5342:
5343: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
5344: XP_SYS_EQ(0, r);
5345:
5346: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
5347: XP_SYS_EQ(0, r);
5348: int expmode = (aimode)
5349: ? (mode2aumode(openmode) & ~AUMODE_PLAY_ALL)
5350: : mode2aumode(openmode);
5351: XP_EQ(expmode, ai.mode);
1.7 isaki 5352: XP_EQ(1, ai.play.pause);
5353: XP_EQ(param ? 11025 : 8000, ai.play.sample_rate);
5354: XP_EQ(1, ai.record.pause);
5355: XP_EQ(param ? 11025 : 8000, ai.record.sample_rate);
1.1 isaki 5356:
5357: /* Set unpause (?) */
5358: AUDIO_INITINFO(&ai);
5359: ai.play.pause = 0;
5360: ai.record.pause = 0;
5361: if (aimode)
5362: ai.mode = mode2aumode(openmode);
5363: if (param) {
5364: ai.play.sample_rate = 16000;
5365: ai.record.sample_rate = 16000;
5366: }
5367:
5368: r = IOCTL(fd, AUDIO_SETINFO, &ai, "");
5369: XP_SYS_EQ(0, r);
5370:
5371: r = IOCTL(fd, AUDIO_GETBUFINFO, &ai, "");
5372: XP_SYS_EQ(0, r);
5373: XP_EQ(mode2aumode(openmode), ai.mode);
5374: XP_EQ(0, ai.play.pause);
5375: XP_EQ(0, ai.record.pause);
5376: if (openmode != O_RDONLY)
5377: XP_EQ(param ? 16000 : 8000, ai.play.sample_rate);
5378: if (openmode != O_WRONLY)
5379: XP_EQ(param ? 16000 : 8000, ai.record.sample_rate);
5380:
5381: r = CLOSE(fd);
5382: XP_SYS_EQ(0, r);
5383: }
5384: DEF(AUDIO_SETINFO_pause_RDONLY_0) { test_AUDIO_SETINFO_pause(O_RDONLY, 0, 0); }
5385: DEF(AUDIO_SETINFO_pause_RDONLY_1) { test_AUDIO_SETINFO_pause(O_RDONLY, 0, 1); }
5386: /* On RDONLY, ai.mode is not changable
5387: * AUDIO_SETINFO_pause_RDONLY_2) { test_AUDIO_SETINFO_pause(O_RDONLY, 1, 0); }
5388: * AUDIO_SETINFO_pause_RDONLY_3) { test_AUDIO_SETINFO_pause(O_RDONLY, 1, 1); }
5389: */
5390: DEF(AUDIO_SETINFO_pause_WRONLY_0) { test_AUDIO_SETINFO_pause(O_WRONLY, 0, 0); }
5391: DEF(AUDIO_SETINFO_pause_WRONLY_1) { test_AUDIO_SETINFO_pause(O_WRONLY, 0, 1); }
5392: DEF(AUDIO_SETINFO_pause_WRONLY_2) { test_AUDIO_SETINFO_pause(O_WRONLY, 1, 0); }
5393: DEF(AUDIO_SETINFO_pause_WRONLY_3) { test_AUDIO_SETINFO_pause(O_WRONLY, 1, 1); }
5394: DEF(AUDIO_SETINFO_pause_RDWR_0) { test_AUDIO_SETINFO_pause(O_RDWR, 0, 0); }
5395: DEF(AUDIO_SETINFO_pause_RDWR_1) { test_AUDIO_SETINFO_pause(O_RDWR, 0, 1); }
5396: DEF(AUDIO_SETINFO_pause_RDWR_2) { test_AUDIO_SETINFO_pause(O_RDWR, 1, 0); }
5397: DEF(AUDIO_SETINFO_pause_RDWR_3) { test_AUDIO_SETINFO_pause(O_RDWR, 1, 1); }
5398:
5399: /*
5400: * Check whether gain can be obtained/set.
5401: * And the gain should work with rich mixer.
5402: * PR kern/52781
5403: */
5404: DEF(AUDIO_SETINFO_gain)
5405: {
5406: struct audio_info ai;
5407: mixer_ctrl_t m;
5408: int index;
5409: int master;
5410: int master_backup;
5411: int gain;
5412: int fd;
5413: int mixerfd;
5414: int r;
5415:
5416: TEST("AUDIO_SETINFO_gain");
5417:
5418: /* Open /dev/mixer */
5419: mixerfd = OPEN(devmixer, O_RDWR);
5420: REQUIRED_SYS_OK(mixerfd);
5421: index = mixer_get_outputs_master(mixerfd);
5422: if (index == -1) {
5423: XP_SKIP("Hardware has no outputs.master");
5424: CLOSE(mixerfd);
5425: return;
5426: }
5427:
5428: /*
5429: * Get current outputs.master.
5430: * auich(4) requires class type (m.type) and number of channels
5431: * (un.value.num_channels) in addition to the index (m.dev)...
5432: * What is the index...?
5433: */
5434: memset(&m, 0, sizeof(m));
5435: m.dev = index;
5436: m.type = AUDIO_MIXER_VALUE;
5437: m.un.value.num_channels = 1; /* dummy */
5438: r = IOCTL(mixerfd, AUDIO_MIXER_READ, &m, "m.dev=%d", m.dev);
5439: REQUIRED_SYS_EQ(0, r);
5440: master = m.un.value.level[0];
5441: DPRINTF(" > outputs.master = %d\n", master);
5442: master_backup = master;
5443:
5444: /* Open /dev/audio */
5445: fd = OPEN(devaudio, O_WRONLY);
5446: REQUIRED_SYS_OK(fd);
5447:
5448: /* Check ai.play.gain */
5449: r = IOCTL(fd, AUDIO_GETINFO, &ai, "");
5450: XP_SYS_EQ(0, r);
5451: XP_EQ(master, ai.play.gain);
5452:
5453: /* Change it some different value */
5454: AUDIO_INITINFO(&ai);
5455: if (master == 0)
5456: gain = 255;
5457: else
5458: gain = 0;
5459: ai.play.gain = gain;
5460: r = IOCTL(fd, AUDIO_SETINFO, &ai, "play.gain=%d", ai.play.gain);
5461: XP_SYS_EQ(0, r);
5462:
5463: /* Check gain has changed */
5464: r = IOCTL(fd, AUDIO_GETINFO, &ai, "play.gain");
5465: XP_SYS_EQ(0, r);
5466: XP_NE(master, ai.play.gain);
5467:
5468: /* Check whether outputs.master work with gain */
5469: r = IOCTL(mixerfd, AUDIO_MIXER_READ, &m, "");
5470: XP_SYS_EQ(0, r);
5471: XP_EQ(ai.play.gain, m.un.value.level[0]);
5472:
5473: /* Restore outputs.master */
5474: AUDIO_INITINFO(&ai);
5475: ai.play.gain = master_backup;
5476: r = IOCTL(fd, AUDIO_SETINFO, &ai, "play.gain=%d", ai.play.gain);
5477: XP_SYS_EQ(0, r);
5478:
5479: r = CLOSE(fd);
5480: XP_SYS_EQ(0, r);
5481: r = CLOSE(mixerfd);
5482: XP_SYS_EQ(0, r);
5483: }
5484:
5485: #define NENC (AUDIO_ENCODING_AC3 + 1)
5486: #define NPREC (5)
5487: /*
5488: * Make table of encoding+precision supported by this device.
5489: * Return last used index .
5490: * This function is called from test_AUDIO_GETENC_*()
5491: */
5492: int
5493: getenc_make_table(int fd, int expected[][5])
5494: {
5495: audio_encoding_t ae;
5496: int idx;
5497: int p;
5498: int r;
5499:
5500: /*
5501: * expected[][] is two dimensional table.
5502: * encoding \ precision| 4 8 16 24 32
5503: * --------------------+-----------------
5504: * AUDIO_ENCODING_NONE |
5505: * AUDIO_ENCODING_ULAW |
5506: * :
5507: *
5508: * Each cell has expected behavior.
5509: * 0: the hardware doesn't support this encoding/precision.
5510: * 1: the hardware supports this encoding/precision.
5511: * 2: the hardware doesn't support this encoding/precision but
5512: * audio layer will respond as supported for compatibility.
5513: */
5514: for (idx = 0; ; idx++) {
5515: memset(&ae, 0, sizeof(ae));
5516: ae.index = idx;
5517: r = IOCTL(fd, AUDIO_GETENC, &ae, "index=%d", idx);
5518: if (r != 0) {
5519: XP_SYS_NG(EINVAL, r);
5520: break;
5521: }
5522:
5523: XP_EQ(idx, ae.index);
5524: if (0 <= ae.encoding && ae.encoding <= AUDIO_ENCODING_AC3) {
5525: XP_EQ_STR(encoding_names[ae.encoding], ae.name);
5526: } else {
5527: XP_FAIL("ae.encoding %d", ae.encoding);
5528: }
5529:
5530: if (ae.precision != 4 &&
5531: ae.precision != 8 &&
5532: ae.precision != 16 &&
5533: ae.precision != 24 &&
5534: ae.precision != 32)
5535: {
5536: XP_FAIL("ae.precision %d", ae.precision);
5537: }
5538: /* Other bits should not be set */
5539: XP_EQ(0, (ae.flags & ~AUDIO_ENCODINGFLAG_EMULATED));
5540:
5541: expected[ae.encoding][ae.precision / 8] = 1;
5542: DPRINTF(" > encoding=%s precision=%d\n",
5543: encoding_names[ae.encoding], ae.precision);
5544: }
5545:
5546: /*
5547: * Backward compatibility bandaid.
5548: *
5549: * - Some encoding/precision pairs are obviously inconsistent
5550: * (e.g., encoding=AUDIO_ENCODING_PCM8, precision=16) but
5551: * it's due to historical reasons.
5552: * - It's incomplete for NetBSD7 and NetBSD8. I don't really
5553: * understand thier rule... This is just memo, not specification.
5554: */
5555: #define SET(x) do { \
5556: if ((x) == 0) \
5557: x = 2; \
5558: } while (0)
5559: #define p4 (0)
5560: #define p8 (1)
5561: #define p16 (2)
5562: #define p24 (3)
5563: #define p32 (4)
5564:
5565: if (expected[AUDIO_ENCODING_SLINEAR][p8]) {
5566: SET(expected[AUDIO_ENCODING_SLINEAR_LE][p8]);
5567: SET(expected[AUDIO_ENCODING_SLINEAR_BE][p8]);
5568: }
5569: if (expected[AUDIO_ENCODING_ULINEAR][p8]) {
5570: SET(expected[AUDIO_ENCODING_ULINEAR_LE][p8]);
5571: SET(expected[AUDIO_ENCODING_ULINEAR_BE][p8]);
5572: SET(expected[AUDIO_ENCODING_PCM8][p8]);
5573: SET(expected[AUDIO_ENCODING_PCM16][p8]);
5574: }
5575: for (p = p16; p <= p32; p++) {
5576: #if !defined(AUDIO_SUPPORT_LINEAR24)
5577: if (p == p24)
5578: continue;
5579: #endif
5580: if (expected[AUDIO_ENCODING_SLINEAR_NE][p]) {
5581: SET(expected[AUDIO_ENCODING_SLINEAR][p]);
5582: SET(expected[AUDIO_ENCODING_PCM16][p]);
5583: }
5584: if (expected[AUDIO_ENCODING_ULINEAR_NE][p]) {
5585: SET(expected[AUDIO_ENCODING_ULINEAR][p]);
5586: }
5587: }
5588:
5589: if (netbsd < 9) {
5590: if (expected[AUDIO_ENCODING_SLINEAR_LE][p16] ||
5591: expected[AUDIO_ENCODING_SLINEAR_BE][p16] ||
5592: expected[AUDIO_ENCODING_ULINEAR_LE][p16] ||
5593: expected[AUDIO_ENCODING_ULINEAR_BE][p16])
5594: {
5595: SET(expected[AUDIO_ENCODING_PCM8][p8]);
5596: SET(expected[AUDIO_ENCODING_PCM16][p8]);
5597: SET(expected[AUDIO_ENCODING_SLINEAR_LE][p8]);
5598: SET(expected[AUDIO_ENCODING_SLINEAR_BE][p8]);
5599: SET(expected[AUDIO_ENCODING_ULINEAR_LE][p8]);
5600: SET(expected[AUDIO_ENCODING_ULINEAR_BE][p8]);
5601: SET(expected[AUDIO_ENCODING_SLINEAR][p8]);
5602: SET(expected[AUDIO_ENCODING_ULINEAR][p8]);
5603: }
5604: }
5605:
5606: /* Return last used index */
5607: return idx;
5608: #undef SET
5609: #undef p4
5610: #undef p8
5611: #undef p16
5612: #undef p24
5613: #undef p32
5614: }
5615:
5616: /*
5617: * This function is called from test_AUDIO_GETENC below.
5618: */
5619: void
5620: xp_getenc(int expected[][5], int enc, int j, int r, struct audio_prinfo *pr)
5621: {
5622: int prec = (j == 0) ? 4 : j * 8;
5623:
5624: if (expected[enc][j]) {
5625: /* expect to succeed */
5626: XP_SYS_EQ(0, r);
5627:
5628: XP_EQ(enc, pr->encoding);
5629: XP_EQ(prec, pr->precision);
5630: } else {
5631: /* expect to fail */
5632: XP_SYS_NG(EINVAL, r);
5633: }
5634: }
5635:
5636: /*
5637: * This function is called from test_AUDIO_GETENC below.
5638: */
5639: void
5640: getenc_check_encodings(int openmode, int expected[][5])
5641: {
5642: struct audio_info ai;
5643: int fd;
5644: int i, j;
5645: int r;
5646:
5647: fd = OPEN(devaudio, openmode);
5648: REQUIRED_SYS_OK(fd);
5649:
5650: for (i = 0; i < NENC; i++) {
5651: for (j = 0; j < NPREC; j++) {
5652: /* precisions are 4 and 8, 16, 24, 32 */
5653: int prec = (j == 0) ? 4 : j * 8;
5654:
5655: /*
5656: * AUDIO_GETENC has no way to know range of
5657: * supported channels and sample_rate.
5658: */
5659: AUDIO_INITINFO(&ai);
5660: ai.play.encoding = i;
5661: ai.play.precision = prec;
5662: ai.record.encoding = i;
5663: ai.record.precision = prec;
5664:
5665: r = IOCTL(fd, AUDIO_SETINFO, &ai, "%s:%d",
5666: encoding_names[i], prec);
5667: if (mode2play(openmode))
5668: xp_getenc(expected, i, j, r, &ai.play);
5669: if (mode2rec(openmode))
5670: xp_getenc(expected, i, j, r, &ai.record);
5671: }
5672: }
5673: r = CLOSE(fd);
5674: XP_SYS_EQ(0, r);
5675: }
5676:
5677: /*
5678: * Check whether encoding+precision obtained by AUDIO_GETENC can be set.
5679: */
5680: DEF(AUDIO_GETENC_range)
5681: {
5682: audio_encoding_t ae;
5683: int fd;
5684: int r;
5685: int expected[NENC][NPREC];
5686: int i, j;
5687:
5688: TEST("AUDIO_GETENC_range");
5689:
5690: fd = OPEN(devaudio, openable_mode());
5691: REQUIRED_SYS_OK(fd);
5692:
5693: memset(&expected, 0, sizeof(expected));
5694: i = getenc_make_table(fd, expected);
5695:
5696: /* When error has occured, the next index should also occur error */
5697: ae.index = i + 1;
5698: r = IOCTL(fd, AUDIO_GETENC, &ae, "index=%d", ae.index);
5699: XP_SYS_NG(EINVAL, r);
5700:
5701: r = CLOSE(fd);
5702: XP_SYS_EQ(0, r);
5703:
5704: /* For debug */
5705: if (debug) {
5706: for (i = 0; i < NENC; i++) {
5707: printf("expected[%2d] %15s", i, encoding_names[i]);
5708: for (j = 0; j < NPREC; j++) {
5709: printf(" %d", expected[i][j]);
5710: }
5711: printf("\n");
5712: }
5713: }
5714:
5715: /* Whether obtained encodings can be actually set */
5716: if (hw_fulldup()) {
5717: /* Test both R/W at once using single descriptor */
5718: getenc_check_encodings(O_RDWR, expected);
5719: } else {
5720: /* Test playback and recording if available */
5721: if (hw_canplay()) {
5722: getenc_check_encodings(O_WRONLY, expected);
5723: }
5724: if (hw_canplay() && hw_canrec()) {
5725: xxx_close_wait();
5726: }
5727: if (hw_canrec()) {
5728: getenc_check_encodings(O_RDONLY, expected);
5729: }
5730: }
5731: }
5732: #undef NENC
5733: #undef NPREC
5734:
5735: /*
5736: * Check AUDIO_GETENC out of range.
5737: */
5738: DEF(AUDIO_GETENC_error)
5739: {
5740: audio_encoding_t e;
5741: int fd;
5742: int r;
5743:
5744: TEST("AUDIO_GETENC_error");
5745:
5746: fd = OPEN(devaudio, openable_mode());
5747: REQUIRED_SYS_OK(fd);
5748:
5749: memset(&e, 0, sizeof(e));
5750: e.index = -1;
5751: r = IOCTL(fd, AUDIO_GETENC, &e, "index=-1");
5752: /* NetBSD7 may not fail depending on hardware driver */
5753: XP_SYS_NG(EINVAL, r);
5754:
5755: r = CLOSE(fd);
5756: XP_SYS_EQ(0, r);
5757: }
5758:
5759: /*
5760: * AUDIO_[PR]ERROR should be zero on the initial state even on non-existent
5761: * track.
5762: */
5763: void
5764: test_AUDIO_ERROR(int openmode)
5765: {
5766: int fd;
5767: int r;
5768: int errors;
5769:
5770: TEST("AUDIO_ERROR_%s", openmode_str[openmode] + 2);
5771: if (mode2aumode(openmode) == 0) {
5772: XP_SKIP("Operation not allowed on this hardware property");
5773: return;
5774: }
5775:
5776: fd = OPEN(devaudio, openmode);
5777: REQUIRED_SYS_OK(fd);
5778:
5779: /* Check PERROR */
5780: errors = 0xdeadbeef;
5781: r = IOCTL(fd, AUDIO_PERROR, &errors, "");
5782: XP_SYS_EQ(0, r);
5783: XP_EQ(0, errors);
5784:
5785: /* Check RERROR */
5786: errors = 0xdeadbeef;
5787: r = IOCTL(fd, AUDIO_RERROR, &errors, "");
5788: XP_SYS_EQ(0, r);
5789: XP_EQ(0, errors);
5790:
5791: r = CLOSE(fd);
5792: XP_SYS_EQ(0, r);
5793: }
5794: DEF(AUDIO_ERROR_RDONLY) { test_AUDIO_ERROR(O_RDONLY); }
5795: DEF(AUDIO_ERROR_WRONLY) { test_AUDIO_ERROR(O_WRONLY); }
5796: DEF(AUDIO_ERROR_RDWR) { test_AUDIO_ERROR(O_RDWR); }
5797:
5798: /*
5799: * /dev/audioctl can always be opened while /dev/audio is open.
5800: */
5801: void
5802: test_audioctl_open_1(int fmode, int cmode)
5803: {
5804: int fd;
5805: int ctl;
5806: int r;
5807:
5808: TEST("audioctl_open_1_%s_%s",
5809: openmode_str[fmode] + 2, openmode_str[cmode] + 2);
5810: if (hw_canplay() == 0 && fmode == O_WRONLY) {
5811: XP_SKIP("This test is for playable device");
5812: return;
5813: }
5814: if (hw_canrec() == 0 && fmode == O_RDONLY) {
5815: XP_SKIP("This test is for recordable device");
5816: return;
5817: }
5818:
5819: fd = OPEN(devaudio, fmode);
5820: REQUIRED_SYS_OK(fd);
5821:
5822: ctl = OPEN(devaudioctl, cmode);
5823: XP_SYS_OK(ctl);
5824:
5825: r = CLOSE(ctl);
5826: XP_SYS_EQ(0, r);
5827:
5828: r = CLOSE(fd);
5829: XP_SYS_EQ(0, r);
5830: }
5831: DEF(audioctl_open_1_RDONLY_RDONLY) { test_audioctl_open_1(O_RDONLY, O_RDONLY); }
5832: DEF(audioctl_open_1_RDONLY_RWONLY) { test_audioctl_open_1(O_RDONLY, O_WRONLY); }
5833: DEF(audioctl_open_1_RDONLY_RDWR) { test_audioctl_open_1(O_RDONLY, O_RDWR); }
5834: DEF(audioctl_open_1_WRONLY_RDONLY) { test_audioctl_open_1(O_WRONLY, O_RDONLY); }
5835: DEF(audioctl_open_1_WRONLY_RWONLY) { test_audioctl_open_1(O_WRONLY, O_WRONLY); }
5836: DEF(audioctl_open_1_WRONLY_RDWR) { test_audioctl_open_1(O_WRONLY, O_RDWR); }
5837: DEF(audioctl_open_1_RDWR_RDONLY) { test_audioctl_open_1(O_RDWR, O_RDONLY); }
5838: DEF(audioctl_open_1_RDWR_RWONLY) { test_audioctl_open_1(O_RDWR, O_WRONLY); }
5839: DEF(audioctl_open_1_RDWR_RDWR) { test_audioctl_open_1(O_RDWR, O_RDWR); }
5840:
5841: /*
5842: * /dev/audio can always be opened while /dev/audioctl is open.
5843: */
5844: void
5845: test_audioctl_open_2(int fmode, int cmode)
5846: {
5847: int fd;
5848: int ctl;
5849: int r;
5850:
5851: TEST("audioctl_open_2_%s_%s",
5852: openmode_str[fmode] + 2, openmode_str[cmode] + 2);
5853: if (hw_canplay() == 0 && fmode == O_WRONLY) {
5854: XP_SKIP("This test is for playable device");
5855: return;
5856: }
5857: if (hw_canrec() == 0 && fmode == O_RDONLY) {
5858: XP_SKIP("This test is for recordable device");
5859: return;
5860: }
5861:
5862: ctl = OPEN(devaudioctl, cmode);
5863: REQUIRED_SYS_OK(ctl);
5864:
5865: fd = OPEN(devaudio, fmode);
5866: XP_SYS_OK(fd);
5867:
5868: r = CLOSE(fd);
5869: XP_SYS_EQ(0, r);
5870:
5871: r = CLOSE(ctl);
5872: XP_SYS_EQ(0, r);
5873: }
5874: DEF(audioctl_open_2_RDONLY_RDONLY) { test_audioctl_open_2(O_RDONLY, O_RDONLY); }
5875: DEF(audioctl_open_2_RDONLY_RWONLY) { test_audioctl_open_2(O_RDONLY, O_WRONLY); }
5876: DEF(audioctl_open_2_RDONLY_RDWR) { test_audioctl_open_2(O_RDONLY, O_RDWR); }
5877: DEF(audioctl_open_2_WRONLY_RDONLY) { test_audioctl_open_2(O_WRONLY, O_RDONLY); }
5878: DEF(audioctl_open_2_WRONLY_RWONLY) { test_audioctl_open_2(O_WRONLY, O_WRONLY); }
5879: DEF(audioctl_open_2_WRONLY_RDWR) { test_audioctl_open_2(O_WRONLY, O_RDWR); }
5880: DEF(audioctl_open_2_RDWR_RDONLY) { test_audioctl_open_2(O_RDWR, O_RDONLY); }
5881: DEF(audioctl_open_2_RDWR_RWONLY) { test_audioctl_open_2(O_RDWR, O_WRONLY); }
5882: DEF(audioctl_open_2_RDWR_RDWR) { test_audioctl_open_2(O_RDWR, O_RDWR); }
5883:
5884: /*
5885: * Open multiple /dev/audioctl.
5886: */
5887: DEF(audioctl_open_simul)
5888: {
5889: int ctl0;
5890: int ctl1;
5891: int r;
5892:
5893: TEST("audioctl_open_simul");
5894:
5895: ctl0 = OPEN(devaudioctl, O_RDWR);
5896: REQUIRED_SYS_OK(ctl0);
5897:
5898: ctl1 = OPEN(devaudioctl, O_RDWR);
5899: XP_SYS_OK(ctl1);
5900:
5901: r = CLOSE(ctl0);
5902: XP_SYS_EQ(0, r);
5903:
5904: r = CLOSE(ctl1);
5905: XP_SYS_EQ(0, r);
5906: }
5907:
5908: /*
1.4 isaki 5909: * /dev/audioctl can be opened by other user who opens /dev/audioctl,
5910: * /dev/audioctl can be opened by other user who opens /dev/audio,
5911: * /dev/audio can be opened by other user who opens /dev/audioctl,
5912: * regardless of multiuser mode.
1.1 isaki 5913: */
5914: void
1.4 isaki 5915: try_audioctl_open_multiuser(const char *dev1, const char *dev2)
1.1 isaki 5916: {
5917: int fd1;
5918: int fd2;
5919: int r;
5920: uid_t ouid;
5921:
5922: /*
5923: * At first, open dev1 as root.
5924: * And then open dev2 as unprivileged user.
5925: */
5926:
5927: fd1 = OPEN(dev1, O_RDWR);
5928: REQUIRED_SYS_OK(fd1);
5929:
5930: ouid = GETUID();
5931: r = SETEUID(1);
5932: REQUIRED_SYS_EQ(0, r);
5933:
5934: fd2 = OPEN(dev2, O_RDWR);
5935: XP_SYS_OK(fd2);
5936:
5937: /* Close */
5938: r = CLOSE(fd2);
5939: XP_SYS_EQ(0, r);
5940:
5941: r = SETEUID(ouid);
5942: REQUIRED_SYS_EQ(0, r);
5943:
5944: r = CLOSE(fd1);
5945: XP_SYS_EQ(0, r);
5946: }
5947: /*
5948: * This is a wrapper for audioctl_open_multiuser.
5949: * XXX XP_* macros are not compatible with on-error-goto, we need try-catch...
5950: */
5951: void
1.4 isaki 5952: test_audioctl_open_multiuser(bool multiuser,
5953: const char *dev1, const char *dev2)
1.1 isaki 5954: {
5955: char mibname[32];
5956: bool oldval;
5957: size_t oldlen;
5958: int r;
5959:
5960: if (netbsd < 8 && multiuser == 1) {
5961: XP_SKIP("multiuser is not supported");
5962: return;
5963: }
5964: if (netbsd < 9) {
5965: /* NetBSD8 has no way (difficult) to determine device name */
5966: XP_SKIP("NetBSD8 cannot determine device name");
5967: return;
5968: }
5969: if (geteuid() != 0) {
5970: XP_SKIP("This test must be priviledged user");
5971: return;
5972: }
5973:
5974: /* Get current multiuser mode (and save it) */
5975: snprintf(mibname, sizeof(mibname), "hw.%s.multiuser", devicename);
5976: oldlen = sizeof(oldval);
5977: r = SYSCTLBYNAME(mibname, &oldval, &oldlen, NULL, 0);
5978: REQUIRED_SYS_EQ(0, r);
5979: DPRINTF(" > multiuser=%d\n", oldval);
5980:
5981: /* Change if necessary */
5982: if (oldval != multiuser) {
1.4 isaki 5983: r = SYSCTLBYNAME(mibname, NULL, NULL, &multiuser,
5984: sizeof(multiuser));
1.1 isaki 5985: REQUIRED_SYS_EQ(0, r);
5986: DPRINTF(" > new multiuser=%d\n", multiuser);
5987: }
5988:
5989: /* Do test */
1.4 isaki 5990: try_audioctl_open_multiuser(dev1, dev2);
1.1 isaki 5991:
5992: /* Restore multiuser mode */
1.4 isaki 5993: if (oldval != multiuser) {
1.1 isaki 5994: DPRINTF(" > restore multiuser to %d\n", oldval);
5995: r = SYSCTLBYNAME(mibname, NULL, NULL, &oldval, sizeof(oldval));
5996: XP_SYS_EQ(0, r);
5997: }
5998: }
5999: DEF(audioctl_open_multiuser0_audio1) {
6000: TEST("audioctl_open_multiuser0_audio1");
1.4 isaki 6001: test_audioctl_open_multiuser(false, devaudio, devaudioctl);
1.1 isaki 6002: }
6003: DEF(audioctl_open_multiuser1_audio1) {
6004: TEST("audioctl_open_multiuser1_audio1");
1.4 isaki 6005: test_audioctl_open_multiuser(true, devaudio, devaudioctl);
1.1 isaki 6006: }
6007: DEF(audioctl_open_multiuser0_audio2) {
6008: TEST("audioctl_open_multiuser0_audio2");
1.4 isaki 6009: test_audioctl_open_multiuser(false, devaudioctl, devaudio);
1.1 isaki 6010: }
6011: DEF(audioctl_open_multiuser1_audio2) {
6012: TEST("audioctl_open_multiuser1_audio2");
1.4 isaki 6013: test_audioctl_open_multiuser(true, devaudioctl, devaudio);
1.1 isaki 6014: }
6015: DEF(audioctl_open_multiuser0_audioctl) {
6016: TEST("audioctl_open_multiuser0_audioctl");
1.4 isaki 6017: test_audioctl_open_multiuser(false, devaudioctl, devaudioctl);
1.1 isaki 6018: }
6019: DEF(audioctl_open_multiuser1_audioctl) {
6020: TEST("audioctl_open_multiuser1_audioctl");
1.4 isaki 6021: test_audioctl_open_multiuser(true, devaudioctl, devaudioctl);
1.1 isaki 6022: }
6023:
6024: /*
6025: * /dev/audioctl cannot be read/written regardless of its open mode.
6026: */
6027: void
6028: test_audioctl_rw(int openmode)
6029: {
6030: char buf[1];
6031: int fd;
6032: int r;
6033:
6034: TEST("audioctl_rw_%s", openmode_str[openmode] + 2);
6035:
6036: fd = OPEN(devaudioctl, openmode);
6037: REQUIRED_SYS_OK(fd);
6038:
6039: if (mode2play(openmode)) {
6040: r = WRITE(fd, buf, sizeof(buf));
6041: XP_SYS_NG(ENODEV, r);
6042: }
6043:
6044: if (mode2rec(openmode)) {
6045: r = READ(fd, buf, sizeof(buf));
6046: XP_SYS_NG(ENODEV, r);
6047: }
6048:
6049: r = CLOSE(fd);
6050: XP_SYS_EQ(0, r);
6051: }
6052: DEF(audioctl_rw_RDONLY) { test_audioctl_rw(O_RDONLY); }
6053: DEF(audioctl_rw_WRONLY) { test_audioctl_rw(O_WRONLY); }
6054: DEF(audioctl_rw_RDWR) { test_audioctl_rw(O_RDWR); }
6055:
6056: /*
6057: * poll(2) for /dev/audioctl should never raise.
6058: * I'm not sure about consistency between poll(2) and kqueue(2) but
6059: * anyway I follow it.
6060: * XXX Omit checking each openmode
6061: */
6062: DEF(audioctl_poll)
6063: {
6064: struct pollfd pfd;
6065: int fd;
6066: int r;
6067:
6068: TEST("audioctl_poll");
6069:
6070: fd = OPEN(devaudioctl, O_WRONLY);
6071: REQUIRED_SYS_OK(fd);
6072:
6073: pfd.fd = fd;
6074: pfd.events = POLLOUT;
6075: r = POLL(&pfd, 1, 100);
6076: XP_SYS_EQ(0, r);
6077: XP_EQ(0, pfd.revents);
6078:
6079: r = CLOSE(fd);
6080: XP_SYS_EQ(0, r);
6081: }
6082:
6083: /*
6084: * kqueue(2) for /dev/audioctl fails.
6085: * I'm not sure about consistency between poll(2) and kqueue(2) but
6086: * anyway I follow it.
6087: * XXX Omit checking each openmode
6088: */
6089: DEF(audioctl_kqueue)
6090: {
6091: struct kevent kev;
6092: int fd;
6093: int kq;
6094: int r;
6095:
6096: TEST("audioctl_kqueue");
6097:
6098: fd = OPEN(devaudioctl, O_WRONLY);
6099: REQUIRED_SYS_OK(fd);
6100:
6101: kq = KQUEUE();
6102: XP_SYS_OK(kq);
6103:
6104: EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
6105: r = KEVENT_SET(kq, &kev, 1);
6106: /*
6107: * NetBSD7 has a bug. It looks to wanted to treat it as successful
6108: * but returned 1(== EPERM).
6109: * On NetBSD9, I decided to return ENODEV.
6110: */
6111: if (netbsd < 8) {
6112: XP_SYS_NG(1/*EPERM*/, r);
6113: } else {
6114: XP_SYS_NG(ENODEV, r);
6115: }
6116:
6117: r = CLOSE(fd);
6118: XP_SYS_EQ(0, r);
6119: }
6120:
6121:
6122: /*
6123: * This table is processed by t_audio.awk!
6124: * Keep /^\tENT(testname),/ format in order to add to atf.
6125: */
6126: #define ENT(x) { #x, test__ ## x }
6127: struct testentry testtable[] = {
6128: ENT(open_mode_RDONLY),
6129: ENT(open_mode_WRONLY),
6130: ENT(open_mode_RDWR),
6131: ENT(open_audio_RDONLY),
6132: ENT(open_audio_WRONLY),
6133: ENT(open_audio_RDWR),
6134: ENT(open_sound_RDONLY),
6135: ENT(open_sound_WRONLY),
6136: ENT(open_sound_RDWR),
6137: ENT(open_audioctl_RDONLY),
6138: ENT(open_audioctl_WRONLY),
6139: ENT(open_audioctl_RDWR),
6140: ENT(open_sound_sticky),
6141: ENT(open_audioctl_sticky),
6142: ENT(open_simul_RDONLY_RDONLY),
6143: ENT(open_simul_RDONLY_WRONLY),
6144: ENT(open_simul_RDONLY_RDWR),
6145: ENT(open_simul_WRONLY_RDONLY),
6146: ENT(open_simul_WRONLY_WRONLY),
6147: ENT(open_simul_WRONLY_RDWR),
6148: ENT(open_simul_RDWR_RDONLY),
6149: ENT(open_simul_RDWR_WRONLY),
6150: ENT(open_simul_RDWR_RDWR),
6151: /**/ ENT(open_multiuser_0), // XXX TODO sysctl
6152: /**/ ENT(open_multiuser_1), // XXX TODO sysctl
6153: ENT(write_PLAY_ALL),
6154: ENT(write_PLAY),
6155: ENT(read),
6156: ENT(rept_write),
6157: ENT(rept_read),
6158: ENT(rdwr_fallback_RDONLY),
6159: ENT(rdwr_fallback_WRONLY),
6160: ENT(rdwr_fallback_RDWR),
6161: ENT(rdwr_two_RDONLY_RDONLY),
6162: ENT(rdwr_two_RDONLY_WRONLY),
6163: ENT(rdwr_two_RDONLY_RDWR),
6164: ENT(rdwr_two_WRONLY_RDONLY),
6165: ENT(rdwr_two_WRONLY_WRONLY),
6166: ENT(rdwr_two_WRONLY_RDWR),
6167: ENT(rdwr_two_RDWR_RDONLY),
6168: ENT(rdwr_two_RDWR_WRONLY),
6169: ENT(rdwr_two_RDWR_RDWR),
6170: ENT(rdwr_simul),
6171: ENT(drain_incomplete),
6172: ENT(drain_pause),
6173: ENT(drain_onrec),
6174: /**/ ENT(mmap_mode_RDONLY_NONE), // XXX rump doesn't supprot mmap
6175: /**/ ENT(mmap_mode_RDONLY_READ), // XXX rump doesn't supprot mmap
6176: /**/ ENT(mmap_mode_RDONLY_WRITE), // XXX rump doesn't supprot mmap
6177: /**/ ENT(mmap_mode_RDONLY_READWRITE),// XXX rump doesn't supprot mmap
6178: /**/ ENT(mmap_mode_WRONLY_NONE), // XXX rump doesn't supprot mmap
6179: /**/ ENT(mmap_mode_WRONLY_READ), // XXX rump doesn't supprot mmap
6180: /**/ ENT(mmap_mode_WRONLY_WRITE), // XXX rump doesn't supprot mmap
6181: /**/ ENT(mmap_mode_WRONLY_READWRITE),// XXX rump doesn't supprot mmap
6182: /**/ ENT(mmap_mode_RDWR_NONE), // XXX rump doesn't supprot mmap
6183: /**/ ENT(mmap_mode_RDWR_READ), // XXX rump doesn't supprot mmap
6184: /**/ ENT(mmap_mode_RDWR_WRITE), // XXX rump doesn't supprot mmap
6185: /**/ ENT(mmap_mode_RDWR_READWRITE), // XXX rump doesn't supprot mmap
6186: /**/ ENT(mmap_len), // XXX rump doesn't supprot mmap
6187: /**/ ENT(mmap_twice), // XXX rump doesn't supprot mmap
6188: /**/ ENT(mmap_multi), // XXX rump doesn't supprot mmap
6189: ENT(poll_mode_RDONLY_IN),
6190: ENT(poll_mode_RDONLY_OUT),
6191: ENT(poll_mode_RDONLY_INOUT),
6192: ENT(poll_mode_WRONLY_IN),
6193: ENT(poll_mode_WRONLY_OUT),
6194: ENT(poll_mode_WRONLY_INOUT),
6195: ENT(poll_mode_RDWR_IN),
6196: ENT(poll_mode_RDWR_OUT),
6197: ENT(poll_mode_RDWR_INOUT),
6198: ENT(poll_out_empty),
6199: ENT(poll_out_full),
6200: ENT(poll_out_hiwat),
6201: /**/ ENT(poll_out_unpause), // XXX does not seem to work on rump
6202: /**/ ENT(poll_out_simul), // XXX does not seem to work on rump
6203: ENT(poll_in_simul),
6204: ENT(kqueue_mode_RDONLY_READ),
6205: ENT(kqueue_mode_RDONLY_WRITE),
6206: ENT(kqueue_mode_WRONLY_READ),
6207: ENT(kqueue_mode_WRONLY_WRITE),
6208: ENT(kqueue_mode_RDWR_READ),
6209: ENT(kqueue_mode_RDWR_WRITE),
6210: ENT(kqueue_empty),
6211: ENT(kqueue_full),
6212: ENT(kqueue_hiwat),
6213: /**/ ENT(kqueue_unpause), // XXX does not seem to work on rump
6214: /**/ ENT(kqueue_simul), // XXX does not seem to work on rump
6215: ENT(ioctl_while_write),
6216: ENT(FIOASYNC_reset),
6217: ENT(FIOASYNC_play_signal),
6218: ENT(FIOASYNC_rec_signal),
6219: /**/ ENT(FIOASYNC_multi), // XXX does not seem to work on rump
6220: ENT(AUDIO_WSEEK),
6221: ENT(AUDIO_SETFD_RDONLY),
6222: ENT(AUDIO_SETFD_WRONLY),
6223: ENT(AUDIO_SETFD_RDWR),
6224: ENT(AUDIO_GETINFO_eof),
6225: ENT(AUDIO_SETINFO_mode_RDONLY_0),
6226: ENT(AUDIO_SETINFO_mode_RDONLY_1),
6227: ENT(AUDIO_SETINFO_mode_RDONLY_2),
6228: ENT(AUDIO_SETINFO_mode_RDONLY_3),
6229: ENT(AUDIO_SETINFO_mode_RDONLY_4),
6230: ENT(AUDIO_SETINFO_mode_RDONLY_5),
6231: ENT(AUDIO_SETINFO_mode_RDONLY_6),
6232: ENT(AUDIO_SETINFO_mode_RDONLY_7),
6233: ENT(AUDIO_SETINFO_mode_RDONLY_8),
6234: ENT(AUDIO_SETINFO_mode_WRONLY_0),
6235: ENT(AUDIO_SETINFO_mode_WRONLY_1),
6236: ENT(AUDIO_SETINFO_mode_WRONLY_2),
6237: ENT(AUDIO_SETINFO_mode_WRONLY_3),
6238: ENT(AUDIO_SETINFO_mode_WRONLY_4),
6239: ENT(AUDIO_SETINFO_mode_WRONLY_5),
6240: ENT(AUDIO_SETINFO_mode_WRONLY_6),
6241: ENT(AUDIO_SETINFO_mode_WRONLY_7),
6242: ENT(AUDIO_SETINFO_mode_WRONLY_8),
6243: ENT(AUDIO_SETINFO_mode_RDWR_0),
6244: ENT(AUDIO_SETINFO_mode_RDWR_1),
6245: ENT(AUDIO_SETINFO_mode_RDWR_2),
6246: ENT(AUDIO_SETINFO_mode_RDWR_3),
6247: ENT(AUDIO_SETINFO_mode_RDWR_4),
6248: ENT(AUDIO_SETINFO_mode_RDWR_5),
6249: ENT(AUDIO_SETINFO_mode_RDWR_6),
6250: ENT(AUDIO_SETINFO_mode_RDWR_7),
6251: ENT(AUDIO_SETINFO_mode_RDWR_8),
6252: ENT(AUDIO_SETINFO_params_set_RDONLY_0),
6253: ENT(AUDIO_SETINFO_params_set_RDONLY_1),
6254: ENT(AUDIO_SETINFO_params_set_WRONLY_0),
6255: ENT(AUDIO_SETINFO_params_set_WRONLY_1),
6256: ENT(AUDIO_SETINFO_params_set_WRONLY_2),
6257: ENT(AUDIO_SETINFO_params_set_WRONLY_3),
6258: ENT(AUDIO_SETINFO_params_set_RDWR_0),
6259: ENT(AUDIO_SETINFO_params_set_RDWR_1),
6260: ENT(AUDIO_SETINFO_params_set_RDWR_2),
6261: ENT(AUDIO_SETINFO_params_set_RDWR_3),
6262: ENT(AUDIO_SETINFO_params_simul),
1.5 isaki 6263: ENT(AUDIO_SETINFO_channels),
6264: ENT(AUDIO_SETINFO_sample_rate),
6265: ENT(AUDIO_SETINFO_sample_rate_0),
1.1 isaki 6266: ENT(AUDIO_SETINFO_pause_RDONLY_0),
6267: ENT(AUDIO_SETINFO_pause_RDONLY_1),
6268: ENT(AUDIO_SETINFO_pause_WRONLY_0),
6269: ENT(AUDIO_SETINFO_pause_WRONLY_1),
6270: ENT(AUDIO_SETINFO_pause_WRONLY_2),
6271: ENT(AUDIO_SETINFO_pause_WRONLY_3),
6272: ENT(AUDIO_SETINFO_pause_RDWR_0),
6273: ENT(AUDIO_SETINFO_pause_RDWR_1),
6274: ENT(AUDIO_SETINFO_pause_RDWR_2),
6275: ENT(AUDIO_SETINFO_pause_RDWR_3),
6276: ENT(AUDIO_SETINFO_gain),
6277: ENT(AUDIO_GETENC_range),
6278: ENT(AUDIO_GETENC_error),
6279: ENT(AUDIO_ERROR_RDONLY),
6280: ENT(AUDIO_ERROR_WRONLY),
6281: ENT(AUDIO_ERROR_RDWR),
6282: ENT(audioctl_open_1_RDONLY_RDONLY),
6283: ENT(audioctl_open_1_RDONLY_RWONLY),
6284: ENT(audioctl_open_1_RDONLY_RDWR),
6285: ENT(audioctl_open_1_WRONLY_RDONLY),
6286: ENT(audioctl_open_1_WRONLY_RWONLY),
6287: ENT(audioctl_open_1_WRONLY_RDWR),
6288: ENT(audioctl_open_1_RDWR_RDONLY),
6289: ENT(audioctl_open_1_RDWR_RWONLY),
6290: ENT(audioctl_open_1_RDWR_RDWR),
6291: ENT(audioctl_open_2_RDONLY_RDONLY),
6292: ENT(audioctl_open_2_RDONLY_RWONLY),
6293: ENT(audioctl_open_2_RDONLY_RDWR),
6294: ENT(audioctl_open_2_WRONLY_RDONLY),
6295: ENT(audioctl_open_2_WRONLY_RWONLY),
6296: ENT(audioctl_open_2_WRONLY_RDWR),
6297: ENT(audioctl_open_2_RDWR_RDONLY),
6298: ENT(audioctl_open_2_RDWR_RWONLY),
6299: ENT(audioctl_open_2_RDWR_RDWR),
6300: ENT(audioctl_open_simul),
6301: /**/ ENT(audioctl_open_multiuser0_audio1), // XXX TODO sysctl
6302: /**/ ENT(audioctl_open_multiuser1_audio1), // XXX TODO sysctl
6303: /**/ ENT(audioctl_open_multiuser0_audio2), // XXX TODO sysctl
6304: /**/ ENT(audioctl_open_multiuser1_audio2), // XXX TODO sysctl
6305: /**/ ENT(audioctl_open_multiuser0_audioctl), // XXX TODO sysctl
6306: /**/ ENT(audioctl_open_multiuser1_audioctl), // XXX TODO sysctl
6307: ENT(audioctl_rw_RDONLY),
6308: ENT(audioctl_rw_WRONLY),
6309: ENT(audioctl_rw_RDWR),
6310: ENT(audioctl_poll),
6311: ENT(audioctl_kqueue),
1.2 martin 6312: {.name = NULL},
1.1 isaki 6313: };
CVSweb <webmaster@jp.NetBSD.org>