xref: /freebsd/sys/dev/sound/pcm/feeder.c (revision 98cd27c8e13418fa517a02844641f390f9389987)
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