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