1*dd81b19eSChristos Margiolis /*- 2*dd81b19eSChristos Margiolis * SPDX-License-Identifier: BSD-2-Clause 3*dd81b19eSChristos Margiolis * 4*dd81b19eSChristos Margiolis * Copyright (c) 2025 The FreeBSD Foundation 5*dd81b19eSChristos Margiolis * 6*dd81b19eSChristos Margiolis * This software was developed by Christos Margiolis <christos@FreeBSD.org> 7*dd81b19eSChristos Margiolis * under sponsorship from the FreeBSD Foundation. 8*dd81b19eSChristos Margiolis * 9*dd81b19eSChristos Margiolis * Redistribution and use in source and binary forms, with or without 10*dd81b19eSChristos Margiolis * modification, are permitted provided that the following conditions 11*dd81b19eSChristos Margiolis * are met: 12*dd81b19eSChristos Margiolis * 1. Redistributions of source code must retain the above copyright 13*dd81b19eSChristos Margiolis * notice, this list of conditions and the following disclaimer. 14*dd81b19eSChristos Margiolis * 2. Redistributions in binary form must reproduce the above copyright 15*dd81b19eSChristos Margiolis * notice, this list of conditions and the following disclaimer in the 16*dd81b19eSChristos Margiolis * documentation and/or other materials provided with the distribution. 17*dd81b19eSChristos Margiolis * 18*dd81b19eSChristos Margiolis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*dd81b19eSChristos Margiolis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*dd81b19eSChristos Margiolis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*dd81b19eSChristos Margiolis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*dd81b19eSChristos Margiolis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*dd81b19eSChristos Margiolis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*dd81b19eSChristos Margiolis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*dd81b19eSChristos Margiolis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*dd81b19eSChristos Margiolis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*dd81b19eSChristos Margiolis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*dd81b19eSChristos Margiolis * SUCH DAMAGE. 29*dd81b19eSChristos Margiolis */ 30*dd81b19eSChristos Margiolis 31*dd81b19eSChristos Margiolis #include <sys/event.h> 32*dd81b19eSChristos Margiolis #include <sys/soundcard.h> 33*dd81b19eSChristos Margiolis 34*dd81b19eSChristos Margiolis #include <atf-c.h> 35*dd81b19eSChristos Margiolis #include <errno.h> 36*dd81b19eSChristos Margiolis #include <fcntl.h> 37*dd81b19eSChristos Margiolis #include <poll.h> 38*dd81b19eSChristos Margiolis #include <unistd.h> 39*dd81b19eSChristos Margiolis 40*dd81b19eSChristos Margiolis #define FMT_ERR(s) s ": %s", strerror(errno) 41*dd81b19eSChristos Margiolis 42*dd81b19eSChristos Margiolis static int 43*dd81b19eSChristos Margiolis oss_init(void) 44*dd81b19eSChristos Margiolis { 45*dd81b19eSChristos Margiolis int fd, tmp, rc; 46*dd81b19eSChristos Margiolis 47*dd81b19eSChristos Margiolis fd = open("/dev/dsp.dummy", O_RDWR); 48*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open")); 49*dd81b19eSChristos Margiolis 50*dd81b19eSChristos Margiolis tmp = 2; 51*dd81b19eSChristos Margiolis rc = ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp); 52*dd81b19eSChristos Margiolis ATF_REQUIRE_EQ_MSG(rc, 0, FMT_ERR("ioctl")); 53*dd81b19eSChristos Margiolis 54*dd81b19eSChristos Margiolis tmp = AFMT_S16_LE; 55*dd81b19eSChristos Margiolis rc = ioctl(fd, SNDCTL_DSP_SETFMT, &tmp); 56*dd81b19eSChristos Margiolis ATF_REQUIRE_EQ_MSG(rc, 0, FMT_ERR("ioctl")); 57*dd81b19eSChristos Margiolis 58*dd81b19eSChristos Margiolis tmp = 48000; 59*dd81b19eSChristos Margiolis rc = ioctl(fd, SNDCTL_DSP_SPEED, &tmp); 60*dd81b19eSChristos Margiolis ATF_REQUIRE_EQ_MSG(rc, 0, FMT_ERR("ioctl")); 61*dd81b19eSChristos Margiolis 62*dd81b19eSChristos Margiolis /* 63*dd81b19eSChristos Margiolis * See http://manuals.opensound.com/developer/SNDCTL_DSP_SETTRIGGER.html 64*dd81b19eSChristos Margiolis */ 65*dd81b19eSChristos Margiolis tmp = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT; 66*dd81b19eSChristos Margiolis rc = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp); 67*dd81b19eSChristos Margiolis ATF_REQUIRE_EQ_MSG(rc, 0, FMT_ERR("ioctl")); 68*dd81b19eSChristos Margiolis 69*dd81b19eSChristos Margiolis return (fd); 70*dd81b19eSChristos Margiolis } 71*dd81b19eSChristos Margiolis 72*dd81b19eSChristos Margiolis ATF_TC(poll_kqueue); 73*dd81b19eSChristos Margiolis ATF_TC_HEAD(poll_kqueue, tc) 74*dd81b19eSChristos Margiolis { 75*dd81b19eSChristos Margiolis atf_tc_set_md_var(tc, "descr", "kqueue(2) test"); 76*dd81b19eSChristos Margiolis atf_tc_set_md_var(tc, "require.kmods", "snd_dummy"); 77*dd81b19eSChristos Margiolis } 78*dd81b19eSChristos Margiolis 79*dd81b19eSChristos Margiolis ATF_TC_BODY(poll_kqueue, tc) 80*dd81b19eSChristos Margiolis { 81*dd81b19eSChristos Margiolis struct kevent ev; 82*dd81b19eSChristos Margiolis int16_t buf[32]; 83*dd81b19eSChristos Margiolis int fd, kq; 84*dd81b19eSChristos Margiolis 85*dd81b19eSChristos Margiolis fd = oss_init(); 86*dd81b19eSChristos Margiolis 87*dd81b19eSChristos Margiolis kq = kqueue(); 88*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue")); 89*dd81b19eSChristos Margiolis EV_SET(&ev, fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0); 90*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0, 91*dd81b19eSChristos Margiolis FMT_ERR("kevent")); 92*dd81b19eSChristos Margiolis 93*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1, 94*dd81b19eSChristos Margiolis FMT_ERR("kevent")); 95*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG((ev.flags & EV_ERROR) == 0, "EV_ERROR is set"); 96*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(ev.data != 0, "data is %ld", ev.data); 97*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(read(fd, buf, sizeof(buf)) > 0, FMT_ERR("read")); 98*dd81b19eSChristos Margiolis 99*dd81b19eSChristos Margiolis EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); 100*dd81b19eSChristos Margiolis close(kq); 101*dd81b19eSChristos Margiolis 102*dd81b19eSChristos Margiolis kq = kqueue(); 103*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue")); 104*dd81b19eSChristos Margiolis EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0); 105*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0, 106*dd81b19eSChristos Margiolis FMT_ERR("kevent")); 107*dd81b19eSChristos Margiolis 108*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1, 109*dd81b19eSChristos Margiolis FMT_ERR("kevent")); 110*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG((ev.flags & EV_ERROR) == 0, "EV_ERROR is set"); 111*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(ev.data != 0, "data is %ld", ev.data); 112*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) > 0, FMT_ERR("write")); 113*dd81b19eSChristos Margiolis 114*dd81b19eSChristos Margiolis EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); 115*dd81b19eSChristos Margiolis close(kq); 116*dd81b19eSChristos Margiolis 117*dd81b19eSChristos Margiolis close(fd); 118*dd81b19eSChristos Margiolis } 119*dd81b19eSChristos Margiolis 120*dd81b19eSChristos Margiolis ATF_TC(poll_poll); 121*dd81b19eSChristos Margiolis ATF_TC_HEAD(poll_poll, tc) 122*dd81b19eSChristos Margiolis { 123*dd81b19eSChristos Margiolis atf_tc_set_md_var(tc, "descr", "poll(2) test"); 124*dd81b19eSChristos Margiolis atf_tc_set_md_var(tc, "require.kmods", "snd_dummy"); 125*dd81b19eSChristos Margiolis } 126*dd81b19eSChristos Margiolis 127*dd81b19eSChristos Margiolis ATF_TC_BODY(poll_poll, tc) 128*dd81b19eSChristos Margiolis { 129*dd81b19eSChristos Margiolis struct pollfd pfd[2]; 130*dd81b19eSChristos Margiolis int16_t buf[32]; 131*dd81b19eSChristos Margiolis int fd; 132*dd81b19eSChristos Margiolis bool rd = false; 133*dd81b19eSChristos Margiolis bool wr = false; 134*dd81b19eSChristos Margiolis 135*dd81b19eSChristos Margiolis fd = oss_init(); 136*dd81b19eSChristos Margiolis 137*dd81b19eSChristos Margiolis while (!rd || !wr) { 138*dd81b19eSChristos Margiolis pfd[0].fd = fd; 139*dd81b19eSChristos Margiolis pfd[0].events = POLLIN; 140*dd81b19eSChristos Margiolis pfd[1].fd = fd; 141*dd81b19eSChristos Margiolis pfd[1].events = POLLOUT; 142*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(poll(pfd, sizeof(pfd) / sizeof(struct pollfd), 143*dd81b19eSChristos Margiolis -1) > 0, FMT_ERR("poll")); 144*dd81b19eSChristos Margiolis 145*dd81b19eSChristos Margiolis if (pfd[0].revents) { 146*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(read(fd, buf, sizeof(buf)) > 0, 147*dd81b19eSChristos Margiolis FMT_ERR("read")); 148*dd81b19eSChristos Margiolis rd = true; 149*dd81b19eSChristos Margiolis } 150*dd81b19eSChristos Margiolis if (pfd[1].revents) { 151*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) > 0, 152*dd81b19eSChristos Margiolis FMT_ERR("write")); 153*dd81b19eSChristos Margiolis wr = true; 154*dd81b19eSChristos Margiolis } 155*dd81b19eSChristos Margiolis } 156*dd81b19eSChristos Margiolis close(fd); 157*dd81b19eSChristos Margiolis } 158*dd81b19eSChristos Margiolis 159*dd81b19eSChristos Margiolis ATF_TC(poll_select); 160*dd81b19eSChristos Margiolis ATF_TC_HEAD(poll_select, tc) 161*dd81b19eSChristos Margiolis { 162*dd81b19eSChristos Margiolis atf_tc_set_md_var(tc, "descr", "select(2) test"); 163*dd81b19eSChristos Margiolis atf_tc_set_md_var(tc, "require.kmods", "snd_dummy"); 164*dd81b19eSChristos Margiolis } 165*dd81b19eSChristos Margiolis 166*dd81b19eSChristos Margiolis ATF_TC_BODY(poll_select, tc) 167*dd81b19eSChristos Margiolis { 168*dd81b19eSChristos Margiolis fd_set fds[2]; 169*dd81b19eSChristos Margiolis int16_t buf[32]; 170*dd81b19eSChristos Margiolis int fd; 171*dd81b19eSChristos Margiolis bool rd = false; 172*dd81b19eSChristos Margiolis bool wr = false; 173*dd81b19eSChristos Margiolis 174*dd81b19eSChristos Margiolis fd = oss_init(); 175*dd81b19eSChristos Margiolis 176*dd81b19eSChristos Margiolis while (!rd || !wr) { 177*dd81b19eSChristos Margiolis FD_ZERO(&fds[0]); 178*dd81b19eSChristos Margiolis FD_ZERO(&fds[1]); 179*dd81b19eSChristos Margiolis FD_SET(fd, &fds[0]); 180*dd81b19eSChristos Margiolis FD_SET(fd, &fds[1]); 181*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(select(fd + 1, &fds[0], &fds[1], NULL, NULL) > 0, 182*dd81b19eSChristos Margiolis FMT_ERR("select")); 183*dd81b19eSChristos Margiolis if (FD_ISSET(fd, &fds[0])) { 184*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(read(fd, buf, sizeof(buf)) > 0, 185*dd81b19eSChristos Margiolis FMT_ERR("read")); 186*dd81b19eSChristos Margiolis rd = true; 187*dd81b19eSChristos Margiolis } 188*dd81b19eSChristos Margiolis if (FD_ISSET(fd, &fds[1])) { 189*dd81b19eSChristos Margiolis ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) > 0, 190*dd81b19eSChristos Margiolis FMT_ERR("write")); 191*dd81b19eSChristos Margiolis wr = true; 192*dd81b19eSChristos Margiolis } 193*dd81b19eSChristos Margiolis } 194*dd81b19eSChristos Margiolis close(fd); 195*dd81b19eSChristos Margiolis } 196*dd81b19eSChristos Margiolis 197*dd81b19eSChristos Margiolis ATF_TP_ADD_TCS(tp) 198*dd81b19eSChristos Margiolis { 199*dd81b19eSChristos Margiolis ATF_TP_ADD_TC(tp, poll_kqueue); 200*dd81b19eSChristos Margiolis ATF_TP_ADD_TC(tp, poll_poll); 201*dd81b19eSChristos Margiolis ATF_TP_ADD_TC(tp, poll_select); 202*dd81b19eSChristos Margiolis 203*dd81b19eSChristos Margiolis return (atf_no_error()); 204*dd81b19eSChristos Margiolis } 205