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