diff --git a/tests/sys/Makefile b/tests/sys/Makefile --- a/tests/sys/Makefile +++ b/tests/sys/Makefile @@ -31,6 +31,7 @@ TESTS_SUBDIRS+= opencrypto TESTS_SUBDIRS+= posixshm TESTS_SUBDIRS+= ses +TESTS_SUBDIRS+= sound TESTS_SUBDIRS+= sys TESTS_SUBDIRS+= vfs TESTS_SUBDIRS+= vm diff --git a/tests/sys/sound/Makefile b/tests/sys/sound/Makefile new file mode 100644 --- /dev/null +++ b/tests/sys/sound/Makefile @@ -0,0 +1,9 @@ +PACKAGE= tests + +TESTSDIR= ${TESTSBASE}/sys/sound + +ATF_TESTS_C+= sndstat + +LDFLAGS+= -lnv + +.include diff --git a/tests/sys/sound/sndstat.c b/tests/sys/sound/sndstat.c new file mode 100644 --- /dev/null +++ b/tests/sys/sound/sndstat.c @@ -0,0 +1,156 @@ +#include +#include + +#include +#include +#include +#include + +ATF_TC(sndstat_nv); +ATF_TC_HEAD(sndstat_nv, tc) +{ + atf_tc_set_md_var(tc, "descr", "/dev/sndstat nvlist test"); +} + +ATF_TC_BODY(sndstat_nv, tc) +{ + nvlist_t *nvl; + const nvlist_t * const *di; + const nvlist_t * const *cdi; + struct sndstioc_nv_arg arg; + size_t nitems, nchans, i, j; + int fd, rc; + int pchan, rchan; + + fd = open("/dev/sndstat", O_RDONLY); + ATF_REQUIRE_MSG(fd >= 0, "/dev/sndstat not found, load sound(4)"); + + rc = ioctl(fd, SNDSTIOC_REFRESH_DEVS, NULL); + ATF_REQUIRE_EQ(rc, 0); + + arg.nbytes = 0; + arg.buf = NULL; + rc = ioctl(fd, SNDSTIOC_GET_DEVS, &arg); + ATF_REQUIRE_EQ_MSG(rc, 0, "ioctl(SNDSTIOC_GET_DEVS#1) failed"); + + arg.buf = malloc(arg.nbytes); + ATF_REQUIRE(arg.buf != NULL); + + rc = ioctl(fd, SNDSTIOC_GET_DEVS, &arg); + ATF_REQUIRE_EQ_MSG(rc, 0, "ioctl(SNDSTIOC_GET_DEVS#2) failed"); + + nvl = nvlist_unpack(arg.buf, arg.nbytes, 0); + ATF_REQUIRE(nvl != NULL); + + if (nvlist_empty(nvl) || !nvlist_exists(nvl, SNDST_DSPS)) + atf_tc_skip("no soundcards attached"); + + di = nvlist_get_nvlist_array(nvl, SNDST_DSPS, &nitems); + for (i = 0; i < nitems; i++) { + nvlist_get_string(di[i], SNDST_DSPS_NAMEUNIT); + nvlist_get_bool(di[i], SNDST_DSPS_FROM_USER); + nvlist_get_string(di[i], SNDST_DSPS_DEVNODE); + nvlist_get_string(di[i], SNDST_DSPS_DESC); + nvlist_get_string(di[i], SNDST_DSPS_PROVIDER); + + pchan = nvlist_get_number(di[i], SNDST_DSPS_PCHAN); + rchan = nvlist_get_number(di[i], SNDST_DSPS_RCHAN); + + if (pchan && !nvlist_exists(di[i], SNDST_DSPS_INFO_PLAY)) + atf_tc_fail("playback channel list empty"); + if (rchan && !nvlist_exists(di[i], SNDST_DSPS_INFO_REC)) + atf_tc_fail("recording channel list empty"); + + if (pchan) { + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_PLAY), SNDST_DSPS_INFO_MIN_RATE); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_PLAY), SNDST_DSPS_INFO_MAX_RATE); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_PLAY), SNDST_DSPS_INFO_FORMATS); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_PLAY), SNDST_DSPS_INFO_MIN_CHN); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_PLAY), SNDST_DSPS_INFO_MAX_CHN); + } + if (rchan) { + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_REC), SNDST_DSPS_INFO_MIN_RATE); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_REC), SNDST_DSPS_INFO_MAX_RATE); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_REC), SNDST_DSPS_INFO_FORMATS); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_REC), SNDST_DSPS_INFO_MIN_CHN); + nvlist_get_number(nvlist_get_nvlist(di[i], + SNDST_DSPS_INFO_REC), SNDST_DSPS_INFO_MAX_CHN); + } + + /* XXX Do we need to skip the TC? userdevs won't have this list */ + if (!nvlist_exists(di[i], SNDST_DSPS_PROVIDER_INFO)) + continue; + + nvlist_get_number( + nvlist_get_nvlist(di[i], SNDST_DSPS_PROVIDER_INFO), + SNDST_DSPS_SOUND4_UNIT); + nvlist_get_bool( + nvlist_get_nvlist(di[i], SNDST_DSPS_PROVIDER_INFO), + SNDST_DSPS_SOUND4_BITPERFECT); + nvlist_get_number( + nvlist_get_nvlist(di[i], SNDST_DSPS_PROVIDER_INFO), + SNDST_DSPS_SOUND4_PVCHAN); + nvlist_get_number( + nvlist_get_nvlist(di[i], SNDST_DSPS_PROVIDER_INFO), + SNDST_DSPS_SOUND4_RVCHAN); + + if (!nvlist_exists(nvlist_get_nvlist(di[i], + SNDST_DSPS_PROVIDER_INFO), SNDST_DSPS_SOUND4_CHAN_INFO)) + atf_tc_fail("channel info list empty"); + + cdi = nvlist_get_nvlist_array( + nvlist_get_nvlist(di[i], SNDST_DSPS_PROVIDER_INFO), + SNDST_DSPS_SOUND4_CHAN_INFO, &nchans); + for (j = 0; j < nchans; j++) { +#define NV(type, item) \ + nvlist_get_ ## type (cdi[j], SNDST_DSPS_SOUND4_CHAN_ ## item) + NV(string, NAME); + NV(string, PARENTCHAN); + NV(number, UNIT); + NV(number, LATENCY); + NV(number, RATE); + NV(number, FORMAT); + NV(number, PID); + NV(string, COMM); + NV(number, INTR); + NV(number, XRUNS); + NV(number, FEEDCNT); + NV(number, LEFTVOL); + NV(number, RIGHTVOL); + NV(number, HWBUF_FORMAT); + NV(number, HWBUF_SIZE); + NV(number, HWBUF_BLKSZ); + NV(number, HWBUF_BLKCNT); + NV(number, HWBUF_FREE); + NV(number, HWBUF_READY); + NV(number, SWBUF_FORMAT); + NV(number, SWBUF_SIZE); + NV(number, SWBUF_BLKSZ); + NV(number, SWBUF_BLKCNT); + NV(number, SWBUF_FREE); + NV(number, SWBUF_READY); + NV(string, FEEDERCHAIN); +#undef NV + } + } + + free(arg.buf); + nvlist_destroy(nvl); + close(fd); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, sndstat_nv); + + return (atf_no_error()); +}