1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
5 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
6 * All rights reserved.
7 * Copyright (c) 2024-2025 The FreeBSD Foundation
8 *
9 * Portions of this software were developed by Christos Margiolis
10 * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifdef HAVE_KERNEL_OPTION_HEADERS
35 #include "opt_snd.h"
36 #endif
37
38 #include <dev/sound/pcm/sound.h>
39
40 #include "feeder_if.h"
41
42 static MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder");
43
44 static SLIST_HEAD(, feeder_class) feedertab = SLIST_HEAD_INITIALIZER(feedertab);
45
46 void
feeder_register(void * p)47 feeder_register(void *p)
48 {
49 struct feeder_class *fc = p;
50
51 SLIST_INSERT_HEAD(&feedertab, fc, link);
52 }
53
54 static void
feeder_unregisterall(void * p __unused)55 feeder_unregisterall(void *p __unused)
56 {
57 SLIST_INIT(&feedertab);
58 }
59
60 static void
feeder_destroy(struct pcm_feeder * f)61 feeder_destroy(struct pcm_feeder *f)
62 {
63 FEEDER_FREE(f);
64 kobj_delete((kobj_t)f, M_FEEDER);
65 }
66
67 static struct pcm_feeder *
feeder_create(struct feeder_class * fc,struct pcm_feederdesc * desc)68 feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc)
69 {
70 struct pcm_feeder *f;
71 int err;
72
73 f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO);
74 if (f == NULL)
75 return NULL;
76
77 f->class = fc;
78 if (desc != NULL)
79 f->desc = *desc;
80
81 err = FEEDER_INIT(f);
82 if (err) {
83 printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err);
84 feeder_destroy(f);
85
86 return NULL;
87 }
88
89 return f;
90 }
91
92 struct feeder_class *
feeder_getclass(u_int32_t type)93 feeder_getclass(u_int32_t type)
94 {
95 struct feeder_class *fc;
96
97 SLIST_FOREACH(fc, &feedertab, link) {
98 if (fc->type == type)
99 return (fc);
100 }
101 return (NULL);
102 }
103
104 int
feeder_add(struct pcm_channel * c,struct feeder_class * fc,struct pcm_feederdesc * desc)105 feeder_add(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc)
106 {
107 struct pcm_feeder *nf;
108
109 nf = feeder_create(fc, desc);
110 if (nf == NULL)
111 return ENOSPC;
112
113 nf->source = c->feeder;
114
115 if (c->feeder != NULL)
116 c->feeder->parent = nf;
117 c->feeder = nf;
118
119 return 0;
120 }
121
122 void
feeder_remove(struct pcm_channel * c)123 feeder_remove(struct pcm_channel *c)
124 {
125 struct pcm_feeder *f;
126
127 while (c->feeder != NULL) {
128 f = c->feeder;
129 c->feeder = c->feeder->source;
130 feeder_destroy(f);
131 }
132 }
133
134 struct pcm_feeder *
feeder_find(struct pcm_channel * c,u_int32_t type)135 feeder_find(struct pcm_channel *c, u_int32_t type)
136 {
137 struct pcm_feeder *f;
138
139 f = c->feeder;
140 while (f != NULL) {
141 if (f->class->type == type)
142 return f;
143 f = f->source;
144 }
145
146 return NULL;
147 }
148
149 /*
150 * 14bit format scoring
151 * --------------------
152 *
153 * 13 12 11 10 9 8 2 1 0 offset
154 * +---+---+---+---+---+---+-------------+---+---+
155 * | X | X | X | X | X | X | X X X X X X | X | X |
156 * +---+---+---+---+---+---+-------------+---+---+
157 * | | | | | | | | |
158 * | | | | | | | | +--> signed?
159 * | | | | | | | |
160 * | | | | | | | +------> bigendian?
161 * | | | | | | |
162 * | | | | | | +---------------> total channels
163 * | | | | | |
164 * | | | | | +------------------------> AFMT_A_LAW
165 * | | | | |
166 * | | | | +----------------------------> AFMT_MU_LAW
167 * | | | |
168 * | | | +--------------------------------> AFMT_8BIT
169 * | | |
170 * | | +------------------------------------> AFMT_16BIT
171 * | |
172 * | +----------------------------------------> AFMT_24BIT
173 * |
174 * +--------------------------------------------> AFMT_32BIT
175 */
176 #define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1))
177 #define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2))
178 #define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc))
179 #define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc))
180 #define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc))
181 #define score_val(s1) ((s1) & 0x3f00)
182 #define score_cse(s1) ((s1) & 0x7f)
183
184 u_int32_t
snd_fmtscore(u_int32_t fmt)185 snd_fmtscore(u_int32_t fmt)
186 {
187 u_int32_t ret;
188
189 ret = 0;
190 if (fmt & AFMT_SIGNED)
191 ret |= 1 << 0;
192 if (fmt & AFMT_BIGENDIAN)
193 ret |= 1 << 1;
194 /*if (fmt & AFMT_STEREO)
195 ret |= (2 & 0x3f) << 2;
196 else
197 ret |= (1 & 0x3f) << 2;*/
198 ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2;
199 if (fmt & AFMT_A_LAW)
200 ret |= 1 << 8;
201 else if (fmt & AFMT_MU_LAW)
202 ret |= 1 << 9;
203 else if (fmt & AFMT_8BIT)
204 ret |= 1 << 10;
205 else if (fmt & AFMT_16BIT)
206 ret |= 1 << 11;
207 else if (fmt & AFMT_24BIT)
208 ret |= 1 << 12;
209 else if (fmt & AFMT_32BIT)
210 ret |= 1 << 13;
211
212 return ret;
213 }
214
215 static u_int32_t
snd_fmtbestfunc(u_int32_t fmt,u_int32_t * fmts,int cheq)216 snd_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq)
217 {
218 u_int32_t best, score, score2, oldscore;
219 int i;
220
221 if (fmt == 0 || fmts == NULL || fmts[0] == 0)
222 return 0;
223
224 if (snd_fmtvalid(fmt, fmts))
225 return fmt;
226
227 best = 0;
228 score = snd_fmtscore(fmt);
229 oldscore = 0;
230 for (i = 0; fmts[i] != 0; i++) {
231 score2 = snd_fmtscore(fmts[i]);
232 if (cheq && !score_cheq(score, score2) &&
233 (score_chlt(score2, score) ||
234 (oldscore != 0 && score_chgt(score2, oldscore))))
235 continue;
236 if (oldscore == 0 ||
237 (score_val(score2) == score_val(score)) ||
238 (score_val(score2) == score_val(oldscore)) ||
239 (score_val(score2) > score_val(oldscore) &&
240 score_val(score2) < score_val(score)) ||
241 (score_val(score2) < score_val(oldscore) &&
242 score_val(score2) > score_val(score)) ||
243 (score_val(oldscore) < score_val(score) &&
244 score_val(score2) > score_val(oldscore))) {
245 if (score_val(oldscore) != score_val(score2) ||
246 score_cse(score) == score_cse(score2) ||
247 ((score_cse(oldscore) != score_cse(score) &&
248 !score_endianeq(score, oldscore) &&
249 (score_endianeq(score, score2) ||
250 (!score_signeq(score, oldscore) &&
251 score_signeq(score, score2)))))) {
252 best = fmts[i];
253 oldscore = score2;
254 }
255 }
256 }
257 return best;
258 }
259
260 u_int32_t
snd_fmtbestbit(u_int32_t fmt,u_int32_t * fmts)261 snd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts)
262 {
263 return snd_fmtbestfunc(fmt, fmts, 0);
264 }
265
266 u_int32_t
snd_fmtbestchannel(u_int32_t fmt,u_int32_t * fmts)267 snd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts)
268 {
269 return snd_fmtbestfunc(fmt, fmts, 1);
270 }
271
272 u_int32_t
snd_fmtbest(u_int32_t fmt,u_int32_t * fmts)273 snd_fmtbest(u_int32_t fmt, u_int32_t *fmts)
274 {
275 u_int32_t best1, best2;
276 u_int32_t score, score1, score2;
277
278 if (snd_fmtvalid(fmt, fmts))
279 return fmt;
280
281 best1 = snd_fmtbestchannel(fmt, fmts);
282 best2 = snd_fmtbestbit(fmt, fmts);
283
284 if (best1 != 0 && best2 != 0 && best1 != best2) {
285 /*if (fmt & AFMT_STEREO)*/
286 if (AFMT_CHANNEL(fmt) > 1)
287 return best1;
288 else {
289 score = score_val(snd_fmtscore(fmt));
290 score1 = score_val(snd_fmtscore(best1));
291 score2 = score_val(snd_fmtscore(best2));
292 if (score1 == score2 || score1 == score)
293 return best1;
294 else if (score2 == score)
295 return best2;
296 else if (score1 > score2)
297 return best1;
298 return best2;
299 }
300 } else if (best2 == 0)
301 return best1;
302 else
303 return best2;
304 }
305
306 static int
feed_root(struct pcm_feeder * feeder,struct pcm_channel * ch,u_int8_t * buffer,u_int32_t count,void * source)307 feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source)
308 {
309 struct snd_dbuf *src = source;
310 int l, offset;
311
312 KASSERT(count > 0, ("feed_root: count == 0"));
313
314 if (++ch->feedcount == 0)
315 ch->feedcount = 2;
316
317 l = min(count, sndbuf_getready(src));
318
319 /* When recording only return as much data as available */
320 if (ch->direction == PCMDIR_REC) {
321 sndbuf_dispose(src, buffer, l);
322 return l;
323 }
324
325 offset = count - l;
326
327 if (offset > 0) {
328 if (snd_verbose > 3)
329 printf("%s: (%s) %spending %d bytes "
330 "(count=%d l=%d feed=%d)\n",
331 __func__,
332 (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
333 (ch->feedcount == 1) ? "pre" : "ap",
334 offset, count, l, ch->feedcount);
335
336 if (ch->feedcount == 1) {
337 memset(buffer, sndbuf_zerodata(src->fmt), offset);
338 if (l > 0)
339 sndbuf_dispose(src, buffer + offset, l);
340 else
341 ch->feedcount--;
342 } else {
343 if (l > 0)
344 sndbuf_dispose(src, buffer, l);
345 memset(buffer + l, sndbuf_zerodata(src->fmt), offset);
346 if (!(ch->flags & CHN_F_CLOSING))
347 ch->xruns++;
348 }
349 } else if (l > 0)
350 sndbuf_dispose(src, buffer, l);
351
352 return count;
353 }
354
355 static kobj_method_t feeder_root_methods[] = {
356 KOBJMETHOD(feeder_feed, feed_root),
357 KOBJMETHOD_END
358 };
359 static struct feeder_class feeder_root_class = {
360 .name = "feeder_root",
361 .methods = feeder_root_methods,
362 .size = sizeof(struct pcm_feeder),
363 .type = FEEDER_ROOT,
364 };
365 /*
366 * Register the root feeder first so that pcm_addchan() and subsequent
367 * functions can use it.
368 */
369 SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register,
370 &feeder_root_class);
371 SYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL);
372