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 #include <dev/sound/pcm/vchan.h>
40
41 #include "feeder_if.h"
42
43 static MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder");
44
45 #define MAXFEEDERS 256
46
47 struct feedertab_entry {
48 SLIST_ENTRY(feedertab_entry) link;
49 struct feeder_class *feederclass;
50 struct pcm_feederdesc *desc;
51
52 int idx;
53 };
54 static SLIST_HEAD(, feedertab_entry) feedertab;
55 static int feedercnt = 0;
56
57 /*****************************************************************************/
58
59 static void
feeder_register_root(void * p)60 feeder_register_root(void *p)
61 {
62 struct feeder_class *fc = p;
63 struct feedertab_entry *fte;
64
65 MPASS(feedercnt == 0);
66 KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name));
67
68 SLIST_INIT(&feedertab);
69 fte = malloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO);
70 fte->feederclass = fc;
71 fte->desc = NULL;
72 fte->idx = feedercnt;
73 SLIST_INSERT_HEAD(&feedertab, fte, link);
74 feedercnt++;
75 }
76
77 void
feeder_register(void * p)78 feeder_register(void *p)
79 {
80 struct feeder_class *fc = p;
81 struct feedertab_entry *fte;
82 int i;
83
84 KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name));
85
86 /*
87 * beyond this point failure is non-fatal but may result in some
88 * translations being unavailable
89 */
90 i = 0;
91 while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) {
92 fte = malloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO);
93 fte->feederclass = fc;
94 fte->desc = &fc->desc[i];
95 fte->idx = feedercnt;
96 fte->desc->idx = feedercnt;
97 SLIST_INSERT_HEAD(&feedertab, fte, link);
98 i++;
99 }
100 feedercnt++;
101 if (feedercnt >= MAXFEEDERS) {
102 printf("MAXFEEDERS (%d >= %d) exceeded\n",
103 feedercnt, MAXFEEDERS);
104 }
105 }
106
107 static void
feeder_unregisterall(void * p)108 feeder_unregisterall(void *p)
109 {
110 struct feedertab_entry *fte, *next;
111
112 next = SLIST_FIRST(&feedertab);
113 while (next != NULL) {
114 fte = next;
115 next = SLIST_NEXT(fte, link);
116 free(fte, M_FEEDER);
117 }
118 }
119
120 static int
cmpdesc(struct pcm_feederdesc * n,struct pcm_feederdesc * m)121 cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m)
122 {
123 return ((n->type == m->type) &&
124 ((n->in == 0) || (n->in == m->in)) &&
125 ((n->out == 0) || (n->out == m->out)) &&
126 (n->flags == m->flags));
127 }
128
129 static void
feeder_destroy(struct pcm_feeder * f)130 feeder_destroy(struct pcm_feeder *f)
131 {
132 FEEDER_FREE(f);
133 kobj_delete((kobj_t)f, M_FEEDER);
134 }
135
136 static struct pcm_feeder *
feeder_create(struct feeder_class * fc,struct pcm_feederdesc * desc)137 feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc)
138 {
139 struct pcm_feeder *f;
140 int err;
141
142 f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO);
143 if (f == NULL)
144 return NULL;
145
146 f->data = fc->data;
147 f->source = NULL;
148 f->parent = NULL;
149 f->class = fc;
150 f->desc = &(f->desc_static);
151
152 if (desc) {
153 *(f->desc) = *desc;
154 } else {
155 f->desc->type = FEEDER_ROOT;
156 f->desc->in = 0;
157 f->desc->out = 0;
158 f->desc->flags = 0;
159 f->desc->idx = 0;
160 }
161
162 err = FEEDER_INIT(f);
163 if (err) {
164 printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err);
165 feeder_destroy(f);
166
167 return NULL;
168 }
169
170 return f;
171 }
172
173 struct feeder_class *
feeder_getclass(struct pcm_feederdesc * desc)174 feeder_getclass(struct pcm_feederdesc *desc)
175 {
176 struct feedertab_entry *fte;
177
178 SLIST_FOREACH(fte, &feedertab, link) {
179 if ((desc == NULL) && (fte->desc == NULL))
180 return fte->feederclass;
181 if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc))
182 return fte->feederclass;
183 }
184 return NULL;
185 }
186
187 int
feeder_add(struct pcm_channel * c,struct feeder_class * fc,struct pcm_feederdesc * desc)188 feeder_add(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc)
189 {
190 struct pcm_feeder *nf;
191
192 nf = feeder_create(fc, desc);
193 if (nf == NULL)
194 return ENOSPC;
195
196 nf->source = c->feeder;
197
198 if (c->feeder != NULL)
199 c->feeder->parent = nf;
200 c->feeder = nf;
201
202 return 0;
203 }
204
205 void
feeder_remove(struct pcm_channel * c)206 feeder_remove(struct pcm_channel *c)
207 {
208 struct pcm_feeder *f;
209
210 while (c->feeder != NULL) {
211 f = c->feeder;
212 c->feeder = c->feeder->source;
213 feeder_destroy(f);
214 }
215 }
216
217 struct pcm_feeder *
feeder_find(struct pcm_channel * c,u_int32_t type)218 feeder_find(struct pcm_channel *c, u_int32_t type)
219 {
220 struct pcm_feeder *f;
221
222 f = c->feeder;
223 while (f != NULL) {
224 if (f->desc->type == type)
225 return f;
226 f = f->source;
227 }
228
229 return NULL;
230 }
231
232 /*
233 * 14bit format scoring
234 * --------------------
235 *
236 * 13 12 11 10 9 8 2 1 0 offset
237 * +---+---+---+---+---+---+-------------+---+---+
238 * | X | X | X | X | X | X | X X X X X X | X | X |
239 * +---+---+---+---+---+---+-------------+---+---+
240 * | | | | | | | | |
241 * | | | | | | | | +--> signed?
242 * | | | | | | | |
243 * | | | | | | | +------> bigendian?
244 * | | | | | | |
245 * | | | | | | +---------------> total channels
246 * | | | | | |
247 * | | | | | +------------------------> AFMT_A_LAW
248 * | | | | |
249 * | | | | +----------------------------> AFMT_MU_LAW
250 * | | | |
251 * | | | +--------------------------------> AFMT_8BIT
252 * | | |
253 * | | +------------------------------------> AFMT_16BIT
254 * | |
255 * | +----------------------------------------> AFMT_24BIT
256 * |
257 * +--------------------------------------------> AFMT_32BIT
258 */
259 #define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1))
260 #define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2))
261 #define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc))
262 #define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc))
263 #define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc))
264 #define score_val(s1) ((s1) & 0x3f00)
265 #define score_cse(s1) ((s1) & 0x7f)
266
267 u_int32_t
snd_fmtscore(u_int32_t fmt)268 snd_fmtscore(u_int32_t fmt)
269 {
270 u_int32_t ret;
271
272 ret = 0;
273 if (fmt & AFMT_SIGNED)
274 ret |= 1 << 0;
275 if (fmt & AFMT_BIGENDIAN)
276 ret |= 1 << 1;
277 /*if (fmt & AFMT_STEREO)
278 ret |= (2 & 0x3f) << 2;
279 else
280 ret |= (1 & 0x3f) << 2;*/
281 ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2;
282 if (fmt & AFMT_A_LAW)
283 ret |= 1 << 8;
284 else if (fmt & AFMT_MU_LAW)
285 ret |= 1 << 9;
286 else if (fmt & AFMT_8BIT)
287 ret |= 1 << 10;
288 else if (fmt & AFMT_16BIT)
289 ret |= 1 << 11;
290 else if (fmt & AFMT_24BIT)
291 ret |= 1 << 12;
292 else if (fmt & AFMT_32BIT)
293 ret |= 1 << 13;
294
295 return ret;
296 }
297
298 static u_int32_t
snd_fmtbestfunc(u_int32_t fmt,u_int32_t * fmts,int cheq)299 snd_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq)
300 {
301 u_int32_t best, score, score2, oldscore;
302 int i;
303
304 if (fmt == 0 || fmts == NULL || fmts[0] == 0)
305 return 0;
306
307 if (snd_fmtvalid(fmt, fmts))
308 return fmt;
309
310 best = 0;
311 score = snd_fmtscore(fmt);
312 oldscore = 0;
313 for (i = 0; fmts[i] != 0; i++) {
314 score2 = snd_fmtscore(fmts[i]);
315 if (cheq && !score_cheq(score, score2) &&
316 (score_chlt(score2, score) ||
317 (oldscore != 0 && score_chgt(score2, oldscore))))
318 continue;
319 if (oldscore == 0 ||
320 (score_val(score2) == score_val(score)) ||
321 (score_val(score2) == score_val(oldscore)) ||
322 (score_val(score2) > score_val(oldscore) &&
323 score_val(score2) < score_val(score)) ||
324 (score_val(score2) < score_val(oldscore) &&
325 score_val(score2) > score_val(score)) ||
326 (score_val(oldscore) < score_val(score) &&
327 score_val(score2) > score_val(oldscore))) {
328 if (score_val(oldscore) != score_val(score2) ||
329 score_cse(score) == score_cse(score2) ||
330 ((score_cse(oldscore) != score_cse(score) &&
331 !score_endianeq(score, oldscore) &&
332 (score_endianeq(score, score2) ||
333 (!score_signeq(score, oldscore) &&
334 score_signeq(score, score2)))))) {
335 best = fmts[i];
336 oldscore = score2;
337 }
338 }
339 }
340 return best;
341 }
342
343 u_int32_t
snd_fmtbestbit(u_int32_t fmt,u_int32_t * fmts)344 snd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts)
345 {
346 return snd_fmtbestfunc(fmt, fmts, 0);
347 }
348
349 u_int32_t
snd_fmtbestchannel(u_int32_t fmt,u_int32_t * fmts)350 snd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts)
351 {
352 return snd_fmtbestfunc(fmt, fmts, 1);
353 }
354
355 u_int32_t
snd_fmtbest(u_int32_t fmt,u_int32_t * fmts)356 snd_fmtbest(u_int32_t fmt, u_int32_t *fmts)
357 {
358 u_int32_t best1, best2;
359 u_int32_t score, score1, score2;
360
361 if (snd_fmtvalid(fmt, fmts))
362 return fmt;
363
364 best1 = snd_fmtbestchannel(fmt, fmts);
365 best2 = snd_fmtbestbit(fmt, fmts);
366
367 if (best1 != 0 && best2 != 0 && best1 != best2) {
368 /*if (fmt & AFMT_STEREO)*/
369 if (AFMT_CHANNEL(fmt) > 1)
370 return best1;
371 else {
372 score = score_val(snd_fmtscore(fmt));
373 score1 = score_val(snd_fmtscore(best1));
374 score2 = score_val(snd_fmtscore(best2));
375 if (score1 == score2 || score1 == score)
376 return best1;
377 else if (score2 == score)
378 return best2;
379 else if (score1 > score2)
380 return best1;
381 return best2;
382 }
383 } else if (best2 == 0)
384 return best1;
385 else
386 return best2;
387 }
388
389 void
feeder_printchain(struct pcm_feeder * head)390 feeder_printchain(struct pcm_feeder *head)
391 {
392 struct pcm_feeder *f;
393
394 printf("feeder chain (head @%p)\n", head);
395 f = head;
396 while (f != NULL) {
397 printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f);
398 f = f->source;
399 }
400 printf("[end]\n\n");
401 }
402
403 /*****************************************************************************/
404
405 static int
feed_root(struct pcm_feeder * feeder,struct pcm_channel * ch,u_int8_t * buffer,u_int32_t count,void * source)406 feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source)
407 {
408 struct snd_dbuf *src = source;
409 int l, offset;
410
411 KASSERT(count > 0, ("feed_root: count == 0"));
412
413 if (++ch->feedcount == 0)
414 ch->feedcount = 2;
415
416 l = min(count, sndbuf_getready(src));
417
418 /* When recording only return as much data as available */
419 if (ch->direction == PCMDIR_REC) {
420 sndbuf_dispose(src, buffer, l);
421 return l;
422 }
423
424 offset = count - l;
425
426 if (offset > 0) {
427 if (snd_verbose > 3)
428 printf("%s: (%s) %spending %d bytes "
429 "(count=%d l=%d feed=%d)\n",
430 __func__,
431 (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
432 (ch->feedcount == 1) ? "pre" : "ap",
433 offset, count, l, ch->feedcount);
434
435 if (ch->feedcount == 1) {
436 memset(buffer,
437 sndbuf_zerodata(sndbuf_getfmt(src)),
438 offset);
439 if (l > 0)
440 sndbuf_dispose(src, buffer + offset, l);
441 else
442 ch->feedcount--;
443 } else {
444 if (l > 0)
445 sndbuf_dispose(src, buffer, l);
446 memset(buffer + l,
447 sndbuf_zerodata(sndbuf_getfmt(src)),
448 offset);
449 if (!(ch->flags & CHN_F_CLOSING))
450 ch->xruns++;
451 }
452 } else if (l > 0)
453 sndbuf_dispose(src, buffer, l);
454
455 return count;
456 }
457
458 static kobj_method_t feeder_root_methods[] = {
459 KOBJMETHOD(feeder_feed, feed_root),
460 KOBJMETHOD_END
461 };
462 static struct feeder_class feeder_root_class = {
463 .name = "feeder_root",
464 .methods = feeder_root_methods,
465 .size = sizeof(struct pcm_feeder),
466 .desc = NULL,
467 .data = NULL,
468 };
469 /*
470 * Register the root feeder first so that pcm_addchan() and subsequent
471 * functions can use it.
472 */
473 SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register_root,
474 &feeder_root_class);
475 SYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL);
476