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