1098ca2bdSWarner Losh /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
490da2b28SAriff Abdullah * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
590da2b28SAriff Abdullah * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
6987e5972SCameron Grant * All rights reserved.
7987e5972SCameron Grant *
8987e5972SCameron Grant * Redistribution and use in source and binary forms, with or without
9987e5972SCameron Grant * modification, are permitted provided that the following conditions
10987e5972SCameron Grant * are met:
11987e5972SCameron Grant * 1. Redistributions of source code must retain the above copyright
12987e5972SCameron Grant * notice, this list of conditions and the following disclaimer.
13987e5972SCameron Grant * 2. Redistributions in binary form must reproduce the above copyright
14987e5972SCameron Grant * notice, this list of conditions and the following disclaimer in the
15987e5972SCameron Grant * documentation and/or other materials provided with the distribution.
16987e5972SCameron Grant *
17987e5972SCameron Grant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18987e5972SCameron Grant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19987e5972SCameron Grant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20987e5972SCameron Grant * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21987e5972SCameron Grant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22987e5972SCameron Grant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23987e5972SCameron Grant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24987e5972SCameron Grant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25987e5972SCameron Grant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26987e5972SCameron Grant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27987e5972SCameron Grant * SUCH DAMAGE.
28987e5972SCameron Grant */
29987e5972SCameron Grant
3090da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS
3190da2b28SAriff Abdullah #include "opt_snd.h"
3290da2b28SAriff Abdullah #endif
3390da2b28SAriff Abdullah
34ef9308b1SCameron Grant #include <dev/sound/pcm/sound.h>
357ad5f383SChristos Margiolis #include <dev/sound/pcm/vchan.h>
36987e5972SCameron Grant
370f55ac6cSCameron Grant #include "feeder_if.h"
380f55ac6cSCameron Grant
39d745c852SEd Schouten static MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder");
400f55ac6cSCameron Grant
41c9c6ba09SCameron Grant #define MAXFEEDERS 256
42987e5972SCameron Grant
43513693beSCameron Grant struct feedertab_entry {
44513693beSCameron Grant SLIST_ENTRY(feedertab_entry) link;
450f55ac6cSCameron Grant struct feeder_class *feederclass;
46513693beSCameron Grant struct pcm_feederdesc *desc;
47513693beSCameron Grant
48513693beSCameron Grant int idx;
49513693beSCameron Grant };
50513693beSCameron Grant static SLIST_HEAD(, feedertab_entry) feedertab;
5197570db0SChristos Margiolis static int feedercnt = 0;
52513693beSCameron Grant
53513693beSCameron Grant /*****************************************************************************/
54513693beSCameron Grant
5597570db0SChristos Margiolis static void
feeder_register_root(void * p)5697570db0SChristos Margiolis feeder_register_root(void *p)
57513693beSCameron Grant {
580f55ac6cSCameron Grant struct feeder_class *fc = p;
59513693beSCameron Grant struct feedertab_entry *fte;
60513693beSCameron Grant
6197570db0SChristos Margiolis MPASS(feedercnt == 0);
62b8a36395SCameron Grant KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name));
63b8a36395SCameron Grant
64513693beSCameron Grant SLIST_INIT(&feedertab);
655e33eca8SChristos Margiolis fte = malloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO);
660f55ac6cSCameron Grant fte->feederclass = fc;
67513693beSCameron Grant fte->desc = NULL;
68513693beSCameron Grant fte->idx = feedercnt;
69513693beSCameron Grant SLIST_INSERT_HEAD(&feedertab, fte, link);
70513693beSCameron Grant feedercnt++;
71513693beSCameron Grant }
72513693beSCameron Grant
7397570db0SChristos Margiolis void
feeder_register(void * p)7497570db0SChristos Margiolis feeder_register(void *p)
7597570db0SChristos Margiolis {
7697570db0SChristos Margiolis struct feeder_class *fc = p;
7797570db0SChristos Margiolis struct feedertab_entry *fte;
7897570db0SChristos Margiolis int i;
7997570db0SChristos Margiolis
80b8a36395SCameron Grant KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name));
81b8a36395SCameron Grant
8297570db0SChristos Margiolis /*
8397570db0SChristos Margiolis * beyond this point failure is non-fatal but may result in some
8497570db0SChristos Margiolis * translations being unavailable
8597570db0SChristos Margiolis */
86513693beSCameron Grant i = 0;
870f55ac6cSCameron Grant while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) {
885e33eca8SChristos Margiolis fte = malloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO);
890f55ac6cSCameron Grant fte->feederclass = fc;
900f55ac6cSCameron Grant fte->desc = &fc->desc[i];
91513693beSCameron Grant fte->idx = feedercnt;
92513693beSCameron Grant fte->desc->idx = feedercnt;
93513693beSCameron Grant SLIST_INSERT_HEAD(&feedertab, fte, link);
94513693beSCameron Grant i++;
95513693beSCameron Grant }
96513693beSCameron Grant feedercnt++;
9797570db0SChristos Margiolis if (feedercnt >= MAXFEEDERS) {
9897570db0SChristos Margiolis printf("MAXFEEDERS (%d >= %d) exceeded\n",
9997570db0SChristos Margiolis feedercnt, MAXFEEDERS);
10097570db0SChristos Margiolis }
101513693beSCameron Grant }
102513693beSCameron Grant
103effbadb7SCameron Grant static void
feeder_unregisterall(void * p)104effbadb7SCameron Grant feeder_unregisterall(void *p)
105effbadb7SCameron Grant {
106effbadb7SCameron Grant struct feedertab_entry *fte, *next;
107effbadb7SCameron Grant
108effbadb7SCameron Grant next = SLIST_FIRST(&feedertab);
109effbadb7SCameron Grant while (next != NULL) {
110effbadb7SCameron Grant fte = next;
111effbadb7SCameron Grant next = SLIST_NEXT(fte, link);
112effbadb7SCameron Grant free(fte, M_FEEDER);
113effbadb7SCameron Grant }
114effbadb7SCameron Grant }
115effbadb7SCameron Grant
116987e5972SCameron Grant static int
cmpdesc(struct pcm_feederdesc * n,struct pcm_feederdesc * m)117513693beSCameron Grant cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m)
118987e5972SCameron Grant {
119c9c6ba09SCameron Grant return ((n->type == m->type) &&
120c9c6ba09SCameron Grant ((n->in == 0) || (n->in == m->in)) &&
121c9c6ba09SCameron Grant ((n->out == 0) || (n->out == m->out)) &&
122c9c6ba09SCameron Grant (n->flags == m->flags));
123987e5972SCameron Grant }
124987e5972SCameron Grant
1250f55ac6cSCameron Grant static void
feeder_destroy(struct pcm_feeder * f)12666ef8af5SCameron Grant feeder_destroy(struct pcm_feeder *f)
127987e5972SCameron Grant {
1280f55ac6cSCameron Grant FEEDER_FREE(f);
1290f55ac6cSCameron Grant kobj_delete((kobj_t)f, M_FEEDER);
130513693beSCameron Grant }
1310f55ac6cSCameron Grant
13266ef8af5SCameron Grant static struct pcm_feeder *
feeder_create(struct feeder_class * fc,struct pcm_feederdesc * desc)1330f55ac6cSCameron Grant feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc)
1340f55ac6cSCameron Grant {
13566ef8af5SCameron Grant struct pcm_feeder *f;
1360f55ac6cSCameron Grant int err;
1370f55ac6cSCameron Grant
138a7576e2eSOrion Hodson f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO);
139b8a36395SCameron Grant if (f == NULL)
140b8a36395SCameron Grant return NULL;
141b8a36395SCameron Grant
142b8a36395SCameron Grant f->data = fc->data;
143b8a36395SCameron Grant f->source = NULL;
144b8a36395SCameron Grant f->parent = NULL;
145b8a36395SCameron Grant f->class = fc;
146b8a36395SCameron Grant f->desc = &(f->desc_static);
147b8a36395SCameron Grant
148b8a36395SCameron Grant if (desc) {
1490f55ac6cSCameron Grant *(f->desc) = *desc;
150b8a36395SCameron Grant } else {
1510f55ac6cSCameron Grant f->desc->type = FEEDER_ROOT;
1520f55ac6cSCameron Grant f->desc->in = 0;
1530f55ac6cSCameron Grant f->desc->out = 0;
1540f55ac6cSCameron Grant f->desc->flags = 0;
1550f55ac6cSCameron Grant f->desc->idx = 0;
1560f55ac6cSCameron Grant }
157b8a36395SCameron Grant
1580f55ac6cSCameron Grant err = FEEDER_INIT(f);
1590f55ac6cSCameron Grant if (err) {
16066a3addbSCameron Grant printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err);
1610f55ac6cSCameron Grant feeder_destroy(f);
162b8a36395SCameron Grant
163513693beSCameron Grant return NULL;
164b8a36395SCameron Grant }
165b8a36395SCameron Grant
1660f55ac6cSCameron Grant return f;
167987e5972SCameron Grant }
168987e5972SCameron Grant
1690f55ac6cSCameron Grant struct feeder_class *
feeder_getclass(struct pcm_feederdesc * desc)1700f55ac6cSCameron Grant feeder_getclass(struct pcm_feederdesc *desc)
171987e5972SCameron Grant {
172513693beSCameron Grant struct feedertab_entry *fte;
173987e5972SCameron Grant
174513693beSCameron Grant SLIST_FOREACH(fte, &feedertab, link) {
1750f55ac6cSCameron Grant if ((desc == NULL) && (fte->desc == NULL))
1760f55ac6cSCameron Grant return fte->feederclass;
1770f55ac6cSCameron Grant if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc))
1780f55ac6cSCameron Grant return fte->feederclass;
179513693beSCameron Grant }
180513693beSCameron Grant return NULL;
181987e5972SCameron Grant }
182987e5972SCameron Grant
183987e5972SCameron Grant int
feeder_add(struct pcm_channel * c,struct feeder_class * fc,struct pcm_feederdesc * desc)18429ff7b08SChristos Margiolis feeder_add(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc)
185c9c6ba09SCameron Grant {
18666ef8af5SCameron Grant struct pcm_feeder *nf;
187c9c6ba09SCameron Grant
1880f55ac6cSCameron Grant nf = feeder_create(fc, desc);
1890f55ac6cSCameron Grant if (nf == NULL)
190b8a36395SCameron Grant return ENOSPC;
1910f55ac6cSCameron Grant
192c9c6ba09SCameron Grant nf->source = c->feeder;
1930f55ac6cSCameron Grant
194eaa69ee9SCameron Grant if (c->feeder != NULL)
195eaa69ee9SCameron Grant c->feeder->parent = nf;
196c9c6ba09SCameron Grant c->feeder = nf;
197c9c6ba09SCameron Grant
198c9c6ba09SCameron Grant return 0;
199c9c6ba09SCameron Grant }
200c9c6ba09SCameron Grant
20100172d20SChristos Margiolis void
feeder_remove(struct pcm_channel * c)20229ff7b08SChristos Margiolis feeder_remove(struct pcm_channel *c)
203987e5972SCameron Grant {
20466ef8af5SCameron Grant struct pcm_feeder *f;
205513693beSCameron Grant
20600172d20SChristos Margiolis while (c->feeder != NULL) {
2070f55ac6cSCameron Grant f = c->feeder;
2080f55ac6cSCameron Grant c->feeder = c->feeder->source;
2090f55ac6cSCameron Grant feeder_destroy(f);
21000172d20SChristos Margiolis }
211987e5972SCameron Grant }
212987e5972SCameron Grant
21366ef8af5SCameron Grant struct pcm_feeder *
feeder_find(struct pcm_channel * c,u_int32_t type)21429ff7b08SChristos Margiolis feeder_find(struct pcm_channel *c, u_int32_t type)
215c9c6ba09SCameron Grant {
21666ef8af5SCameron Grant struct pcm_feeder *f;
217c9c6ba09SCameron Grant
218c9c6ba09SCameron Grant f = c->feeder;
219c9c6ba09SCameron Grant while (f != NULL) {
220c9c6ba09SCameron Grant if (f->desc->type == type)
221c9c6ba09SCameron Grant return f;
222c9c6ba09SCameron Grant f = f->source;
223c9c6ba09SCameron Grant }
224b8a36395SCameron Grant
225c9c6ba09SCameron Grant return NULL;
226c9c6ba09SCameron Grant }
227c9c6ba09SCameron Grant
228a580b31aSAriff Abdullah /*
229a580b31aSAriff Abdullah * 14bit format scoring
230a580b31aSAriff Abdullah * --------------------
231a580b31aSAriff Abdullah *
232a580b31aSAriff Abdullah * 13 12 11 10 9 8 2 1 0 offset
233a580b31aSAriff Abdullah * +---+---+---+---+---+---+-------------+---+---+
234a580b31aSAriff Abdullah * | X | X | X | X | X | X | X X X X X X | X | X |
235a580b31aSAriff Abdullah * +---+---+---+---+---+---+-------------+---+---+
236a580b31aSAriff Abdullah * | | | | | | | | |
237a580b31aSAriff Abdullah * | | | | | | | | +--> signed?
238a580b31aSAriff Abdullah * | | | | | | | |
239a580b31aSAriff Abdullah * | | | | | | | +------> bigendian?
240a580b31aSAriff Abdullah * | | | | | | |
241a580b31aSAriff Abdullah * | | | | | | +---------------> total channels
242a580b31aSAriff Abdullah * | | | | | |
243a580b31aSAriff Abdullah * | | | | | +------------------------> AFMT_A_LAW
244a580b31aSAriff Abdullah * | | | | |
245a580b31aSAriff Abdullah * | | | | +----------------------------> AFMT_MU_LAW
246a580b31aSAriff Abdullah * | | | |
247a580b31aSAriff Abdullah * | | | +--------------------------------> AFMT_8BIT
248a580b31aSAriff Abdullah * | | |
249a580b31aSAriff Abdullah * | | +------------------------------------> AFMT_16BIT
250a580b31aSAriff Abdullah * | |
251a580b31aSAriff Abdullah * | +----------------------------------------> AFMT_24BIT
252a580b31aSAriff Abdullah * |
253a580b31aSAriff Abdullah * +--------------------------------------------> AFMT_32BIT
254a580b31aSAriff Abdullah */
255a580b31aSAriff Abdullah #define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1))
256a580b31aSAriff Abdullah #define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2))
257a580b31aSAriff Abdullah #define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc))
25890da2b28SAriff Abdullah #define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc))
25990da2b28SAriff Abdullah #define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc))
260a580b31aSAriff Abdullah #define score_val(s1) ((s1) & 0x3f00)
261a580b31aSAriff Abdullah #define score_cse(s1) ((s1) & 0x7f)
262513693beSCameron Grant
263a580b31aSAriff Abdullah u_int32_t
snd_fmtscore(u_int32_t fmt)26490da2b28SAriff Abdullah snd_fmtscore(u_int32_t fmt)
265d9bd8445SAriff Abdullah {
266a580b31aSAriff Abdullah u_int32_t ret;
267a580b31aSAriff Abdullah
268a580b31aSAriff Abdullah ret = 0;
269a580b31aSAriff Abdullah if (fmt & AFMT_SIGNED)
270a580b31aSAriff Abdullah ret |= 1 << 0;
271a580b31aSAriff Abdullah if (fmt & AFMT_BIGENDIAN)
272a580b31aSAriff Abdullah ret |= 1 << 1;
27390da2b28SAriff Abdullah /*if (fmt & AFMT_STEREO)
274a580b31aSAriff Abdullah ret |= (2 & 0x3f) << 2;
275a580b31aSAriff Abdullah else
27690da2b28SAriff Abdullah ret |= (1 & 0x3f) << 2;*/
27790da2b28SAriff Abdullah ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2;
2784a193ac9SAriff Abdullah if (fmt & AFMT_A_LAW)
279a580b31aSAriff Abdullah ret |= 1 << 8;
280a580b31aSAriff Abdullah else if (fmt & AFMT_MU_LAW)
281a580b31aSAriff Abdullah ret |= 1 << 9;
282a580b31aSAriff Abdullah else if (fmt & AFMT_8BIT)
283a580b31aSAriff Abdullah ret |= 1 << 10;
284a580b31aSAriff Abdullah else if (fmt & AFMT_16BIT)
285a580b31aSAriff Abdullah ret |= 1 << 11;
286a580b31aSAriff Abdullah else if (fmt & AFMT_24BIT)
287a580b31aSAriff Abdullah ret |= 1 << 12;
288a580b31aSAriff Abdullah else if (fmt & AFMT_32BIT)
289a580b31aSAriff Abdullah ret |= 1 << 13;
290a580b31aSAriff Abdullah
291a580b31aSAriff Abdullah return ret;
292a580b31aSAriff Abdullah }
293a580b31aSAriff Abdullah
294a580b31aSAriff Abdullah static u_int32_t
snd_fmtbestfunc(u_int32_t fmt,u_int32_t * fmts,int cheq)29590da2b28SAriff Abdullah snd_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq)
296a580b31aSAriff Abdullah {
297a580b31aSAriff Abdullah u_int32_t best, score, score2, oldscore;
298a580b31aSAriff Abdullah int i;
299a580b31aSAriff Abdullah
300a580b31aSAriff Abdullah if (fmt == 0 || fmts == NULL || fmts[0] == 0)
3014a193ac9SAriff Abdullah return 0;
302a580b31aSAriff Abdullah
30390da2b28SAriff Abdullah if (snd_fmtvalid(fmt, fmts))
304a580b31aSAriff Abdullah return fmt;
305a580b31aSAriff Abdullah
306a580b31aSAriff Abdullah best = 0;
30790da2b28SAriff Abdullah score = snd_fmtscore(fmt);
308a580b31aSAriff Abdullah oldscore = 0;
309a580b31aSAriff Abdullah for (i = 0; fmts[i] != 0; i++) {
31090da2b28SAriff Abdullah score2 = snd_fmtscore(fmts[i]);
31190da2b28SAriff Abdullah if (cheq && !score_cheq(score, score2) &&
31290da2b28SAriff Abdullah (score_chlt(score2, score) ||
31390da2b28SAriff Abdullah (oldscore != 0 && score_chgt(score2, oldscore))))
314a580b31aSAriff Abdullah continue;
315a580b31aSAriff Abdullah if (oldscore == 0 ||
316a580b31aSAriff Abdullah (score_val(score2) == score_val(score)) ||
317a580b31aSAriff Abdullah (score_val(score2) == score_val(oldscore)) ||
318a580b31aSAriff Abdullah (score_val(score2) > score_val(oldscore) &&
319a580b31aSAriff Abdullah score_val(score2) < score_val(score)) ||
320a580b31aSAriff Abdullah (score_val(score2) < score_val(oldscore) &&
321a580b31aSAriff Abdullah score_val(score2) > score_val(score)) ||
322a580b31aSAriff Abdullah (score_val(oldscore) < score_val(score) &&
323a580b31aSAriff Abdullah score_val(score2) > score_val(oldscore))) {
324a580b31aSAriff Abdullah if (score_val(oldscore) != score_val(score2) ||
325a580b31aSAriff Abdullah score_cse(score) == score_cse(score2) ||
326a580b31aSAriff Abdullah ((score_cse(oldscore) != score_cse(score) &&
327a580b31aSAriff Abdullah !score_endianeq(score, oldscore) &&
328a580b31aSAriff Abdullah (score_endianeq(score, score2) ||
329a580b31aSAriff Abdullah (!score_signeq(score, oldscore) &&
330a580b31aSAriff Abdullah score_signeq(score, score2)))))) {
331a580b31aSAriff Abdullah best = fmts[i];
332a580b31aSAriff Abdullah oldscore = score2;
333a580b31aSAriff Abdullah }
334a580b31aSAriff Abdullah }
335a580b31aSAriff Abdullah }
336a580b31aSAriff Abdullah return best;
337d9bd8445SAriff Abdullah }
338d9bd8445SAriff Abdullah
339d9bd8445SAriff Abdullah u_int32_t
snd_fmtbestbit(u_int32_t fmt,u_int32_t * fmts)34090da2b28SAriff Abdullah snd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts)
341d9bd8445SAriff Abdullah {
34290da2b28SAriff Abdullah return snd_fmtbestfunc(fmt, fmts, 0);
343d9bd8445SAriff Abdullah }
344d9bd8445SAriff Abdullah
345d9bd8445SAriff Abdullah u_int32_t
snd_fmtbestchannel(u_int32_t fmt,u_int32_t * fmts)34690da2b28SAriff Abdullah snd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts)
347d9bd8445SAriff Abdullah {
34890da2b28SAriff Abdullah return snd_fmtbestfunc(fmt, fmts, 1);
349d9bd8445SAriff Abdullah }
350d9bd8445SAriff Abdullah
351d9bd8445SAriff Abdullah u_int32_t
snd_fmtbest(u_int32_t fmt,u_int32_t * fmts)35290da2b28SAriff Abdullah snd_fmtbest(u_int32_t fmt, u_int32_t *fmts)
353d9bd8445SAriff Abdullah {
354d9bd8445SAriff Abdullah u_int32_t best1, best2;
355a580b31aSAriff Abdullah u_int32_t score, score1, score2;
356a580b31aSAriff Abdullah
35790da2b28SAriff Abdullah if (snd_fmtvalid(fmt, fmts))
358a580b31aSAriff Abdullah return fmt;
359d9bd8445SAriff Abdullah
36090da2b28SAriff Abdullah best1 = snd_fmtbestchannel(fmt, fmts);
36190da2b28SAriff Abdullah best2 = snd_fmtbestbit(fmt, fmts);
362d9bd8445SAriff Abdullah
363a580b31aSAriff Abdullah if (best1 != 0 && best2 != 0 && best1 != best2) {
36490da2b28SAriff Abdullah /*if (fmt & AFMT_STEREO)*/
36590da2b28SAriff Abdullah if (AFMT_CHANNEL(fmt) > 1)
366d9bd8445SAriff Abdullah return best1;
367d9bd8445SAriff Abdullah else {
36890da2b28SAriff Abdullah score = score_val(snd_fmtscore(fmt));
36990da2b28SAriff Abdullah score1 = score_val(snd_fmtscore(best1));
37090da2b28SAriff Abdullah score2 = score_val(snd_fmtscore(best2));
3714a193ac9SAriff Abdullah if (score1 == score2 || score1 == score)
3724a193ac9SAriff Abdullah return best1;
3734a193ac9SAriff Abdullah else if (score2 == score)
374d9bd8445SAriff Abdullah return best2;
3754a193ac9SAriff Abdullah else if (score1 > score2)
376d9bd8445SAriff Abdullah return best1;
377d9bd8445SAriff Abdullah return best2;
378d9bd8445SAriff Abdullah }
379d9bd8445SAriff Abdullah } else if (best2 == 0)
380d9bd8445SAriff Abdullah return best1;
381de49f325SJohn Baldwin else
382d9bd8445SAriff Abdullah return best2;
383d9bd8445SAriff Abdullah }
384d9bd8445SAriff Abdullah
385eaa69ee9SCameron Grant void
feeder_printchain(struct pcm_feeder * head)386eaa69ee9SCameron Grant feeder_printchain(struct pcm_feeder *head)
387eaa69ee9SCameron Grant {
388eaa69ee9SCameron Grant struct pcm_feeder *f;
389eaa69ee9SCameron Grant
390eaa69ee9SCameron Grant printf("feeder chain (head @%p)\n", head);
391eaa69ee9SCameron Grant f = head;
392eaa69ee9SCameron Grant while (f != NULL) {
393eaa69ee9SCameron Grant printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f);
394eaa69ee9SCameron Grant f = f->source;
395eaa69ee9SCameron Grant }
396eaa69ee9SCameron Grant printf("[end]\n\n");
397eaa69ee9SCameron Grant }
398eaa69ee9SCameron Grant
399c9c6ba09SCameron Grant /*****************************************************************************/
400c9c6ba09SCameron Grant
401c9c6ba09SCameron Grant static int
feed_root(struct pcm_feeder * feeder,struct pcm_channel * ch,u_int8_t * buffer,u_int32_t count,void * source)40266ef8af5SCameron Grant feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source)
403c9c6ba09SCameron Grant {
40466ef8af5SCameron Grant struct snd_dbuf *src = source;
405a580b31aSAriff Abdullah int l, offset;
406c9c6ba09SCameron Grant
40766ef8af5SCameron Grant KASSERT(count > 0, ("feed_root: count == 0"));
408c9c6ba09SCameron Grant
409a580b31aSAriff Abdullah if (++ch->feedcount == 0)
410a580b31aSAriff Abdullah ch->feedcount = 2;
411a580b31aSAriff Abdullah
41266ef8af5SCameron Grant l = min(count, sndbuf_getready(src));
41366ef8af5SCameron Grant
414faea6799SOrion Hodson /* When recording only return as much data as available */
415a580b31aSAriff Abdullah if (ch->direction == PCMDIR_REC) {
416a580b31aSAriff Abdullah sndbuf_dispose(src, buffer, l);
417faea6799SOrion Hodson return l;
418a580b31aSAriff Abdullah }
419faea6799SOrion Hodson
420a580b31aSAriff Abdullah offset = count - l;
421a580b31aSAriff Abdullah
422a580b31aSAriff Abdullah if (offset > 0) {
423a580b31aSAriff Abdullah if (snd_verbose > 3)
424a580b31aSAriff Abdullah printf("%s: (%s) %spending %d bytes "
425a580b31aSAriff Abdullah "(count=%d l=%d feed=%d)\n",
426a580b31aSAriff Abdullah __func__,
427a580b31aSAriff Abdullah (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
428a580b31aSAriff Abdullah (ch->feedcount == 1) ? "pre" : "ap",
429a580b31aSAriff Abdullah offset, count, l, ch->feedcount);
430a580b31aSAriff Abdullah
431a580b31aSAriff Abdullah if (ch->feedcount == 1) {
432a580b31aSAriff Abdullah memset(buffer,
433a580b31aSAriff Abdullah sndbuf_zerodata(sndbuf_getfmt(src)),
434a580b31aSAriff Abdullah offset);
435a580b31aSAriff Abdullah if (l > 0)
436a580b31aSAriff Abdullah sndbuf_dispose(src, buffer + offset, l);
437a580b31aSAriff Abdullah else
438a580b31aSAriff Abdullah ch->feedcount--;
439a580b31aSAriff Abdullah } else {
440a580b31aSAriff Abdullah if (l > 0)
441a580b31aSAriff Abdullah sndbuf_dispose(src, buffer, l);
442a580b31aSAriff Abdullah memset(buffer + l,
443a580b31aSAriff Abdullah sndbuf_zerodata(sndbuf_getfmt(src)),
444a580b31aSAriff Abdullah offset);
445a580b31aSAriff Abdullah if (!(ch->flags & CHN_F_CLOSING))
446a580b31aSAriff Abdullah ch->xruns++;
447a580b31aSAriff Abdullah }
448a580b31aSAriff Abdullah } else if (l > 0)
449a580b31aSAriff Abdullah sndbuf_dispose(src, buffer, l);
450c9c6ba09SCameron Grant
451c9c6ba09SCameron Grant return count;
452c9c6ba09SCameron Grant }
4530f55ac6cSCameron Grant
4540f55ac6cSCameron Grant static kobj_method_t feeder_root_methods[] = {
4550f55ac6cSCameron Grant KOBJMETHOD(feeder_feed, feed_root),
45690da2b28SAriff Abdullah KOBJMETHOD_END
457c9c6ba09SCameron Grant };
4580f55ac6cSCameron Grant static struct feeder_class feeder_root_class = {
45959873565SDiomidis Spinellis .name = "feeder_root",
46059873565SDiomidis Spinellis .methods = feeder_root_methods,
46159873565SDiomidis Spinellis .size = sizeof(struct pcm_feeder),
46259873565SDiomidis Spinellis .desc = NULL,
46359873565SDiomidis Spinellis .data = NULL,
4640f55ac6cSCameron Grant };
465*98cd27c8SChristos Margiolis /*
466*98cd27c8SChristos Margiolis * Register the root feeder first so that pcm_addchan() and subsequent
467*98cd27c8SChristos Margiolis * functions can use it.
468*98cd27c8SChristos Margiolis */
46997570db0SChristos Margiolis SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register_root,
47097570db0SChristos Margiolis &feeder_root_class);
471effbadb7SCameron Grant SYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL);
472