feeder.c revision 170884
1139749Simp/*-
2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
350724Scg * All rights reserved.
450724Scg *
550724Scg * Redistribution and use in source and binary forms, with or without
650724Scg * modification, are permitted provided that the following conditions
750724Scg * are met:
850724Scg * 1. Redistributions of source code must retain the above copyright
950724Scg *    notice, this list of conditions and the following disclaimer.
1050724Scg * 2. Redistributions in binary form must reproduce the above copyright
1150724Scg *    notice, this list of conditions and the following disclaimer in the
1250724Scg *    documentation and/or other materials provided with the distribution.
1350724Scg *
1450724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750724Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450724Scg * SUCH DAMAGE.
2550724Scg */
2650724Scg
2753465Scg#include <dev/sound/pcm/sound.h>
2850724Scg
2970134Scg#include "feeder_if.h"
3070134Scg
3182180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/feeder.c 170884 2007-06-17 15:53:11Z ariff $");
3282180Scg
3370134ScgMALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder");
3470134Scg
3566308Scg#define MAXFEEDERS 	256
3665645Scg#undef FEEDER_DEBUG
3750724Scg
38164614Sariffint feeder_buffersize = FEEDBUFSZ;
39164614SariffTUNABLE_INT("hw.snd.feeder_buffersize", &feeder_buffersize);
40167644Sariff
41167644Sariff#ifdef SND_DEBUG
42167644Sariffstatic int
43167644Sariffsysctl_hw_snd_feeder_buffersize(SYSCTL_HANDLER_ARGS)
44167644Sariff{
45167644Sariff	int i, err, val;
46167644Sariff
47167644Sariff	val = feeder_buffersize;
48170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
49167644Sariff
50167644Sariff	if (err != 0 || req->newptr == NULL)
51167644Sariff		return err;
52167644Sariff
53167644Sariff	if (val < FEEDBUFSZ_MIN || val > FEEDBUFSZ_MAX)
54167644Sariff		return EINVAL;
55167644Sariff
56167644Sariff	i = 0;
57167644Sariff	while (val >> i)
58167644Sariff		i++;
59167644Sariff	i = 1 << i;
60167644Sariff	if (i > val && (i >> 1) > 0 && (i >> 1) >= ((val * 3) >> 2))
61167644Sariff		i >>= 1;
62167644Sariff
63167644Sariff	feeder_buffersize = i;
64167644Sariff
65167644Sariff	return err;
66167644Sariff}
67167644SariffSYSCTL_PROC(_hw_snd, OID_AUTO, feeder_buffersize, CTLTYPE_INT | CTLFLAG_RW,
68167644Sariff	0, sizeof(int), sysctl_hw_snd_feeder_buffersize, "I",
69167644Sariff	"feeder buffer size");
70167644Sariff#else
71164614SariffSYSCTL_INT(_hw_snd, OID_AUTO, feeder_buffersize, CTLFLAG_RD,
72164614Sariff	&feeder_buffersize, FEEDBUFSZ, "feeder buffer size");
73167644Sariff#endif
74164614Sariff
7564881Scgstruct feedertab_entry {
7664881Scg	SLIST_ENTRY(feedertab_entry) link;
7770134Scg	struct feeder_class *feederclass;
7864881Scg	struct pcm_feederdesc *desc;
7964881Scg
8064881Scg	int idx;
8164881Scg};
8264881Scgstatic SLIST_HEAD(, feedertab_entry) feedertab;
8364881Scg
8450724Scg/*****************************************************************************/
8550724Scg
8664881Scgvoid
8764881Scgfeeder_register(void *p)
8864881Scg{
8989834Scg	static int feedercnt = 0;
9089834Scg
9170134Scg	struct feeder_class *fc = p;
9264881Scg	struct feedertab_entry *fte;
9364881Scg	int i;
9464881Scg
9564881Scg	if (feedercnt == 0) {
9689834Scg		KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name));
9789834Scg
9864881Scg		SLIST_INIT(&feedertab);
99111909Sorion		fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO);
10089834Scg		if (fte == NULL) {
10197274Sbde			printf("can't allocate memory for root feeder: %s\n",
10297274Sbde			    fc->name);
10389834Scg
10489834Scg			return;
10589834Scg		}
10670134Scg		fte->feederclass = fc;
10764881Scg		fte->desc = NULL;
10864881Scg		fte->idx = feedercnt;
10964881Scg		SLIST_INSERT_HEAD(&feedertab, fte, link);
11064881Scg		feedercnt++;
11189834Scg
112164614Sariff		/* initialize global variables */
113164614Sariff
114170161Sariff		if (snd_verbose < 0 || snd_verbose > 4)
115164614Sariff			snd_verbose = 1;
116164614Sariff
117170161Sariff		/* initialize unit numbering */
118170161Sariff		snd_unit_init();
119170161Sariff		if (snd_unit < 0 || snd_unit > PCMMAXUNIT)
120170884Sariff			snd_unit = -1;
121164614Sariff
122164614Sariff		if (snd_maxautovchans < 0 ||
123164614Sariff		    snd_maxautovchans > SND_MAXVCHANS)
124164614Sariff			snd_maxautovchans = 0;
125164614Sariff
126164614Sariff		if (chn_latency < CHN_LATENCY_MIN ||
127164614Sariff		    chn_latency > CHN_LATENCY_MAX)
128164614Sariff			chn_latency = CHN_LATENCY_DEFAULT;
129164614Sariff
130164614Sariff		if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN ||
131164614Sariff		    chn_latency_profile > CHN_LATENCY_PROFILE_MAX)
132164614Sariff			chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT;
133164614Sariff
134164614Sariff		if (feeder_buffersize < FEEDBUFSZ_MIN ||
135164614Sariff		    	    feeder_buffersize > FEEDBUFSZ_MAX)
136164614Sariff			feeder_buffersize = FEEDBUFSZ;
137164614Sariff
138164614Sariff		if (feeder_rate_min < FEEDRATE_MIN ||
139164614Sariff			    feeder_rate_max < FEEDRATE_MIN ||
140164614Sariff			    feeder_rate_min > FEEDRATE_MAX ||
141164614Sariff			    feeder_rate_max > FEEDRATE_MAX ||
142164614Sariff			    !(feeder_rate_min < feeder_rate_max)) {
143164614Sariff			feeder_rate_min = FEEDRATE_RATEMIN;
144164614Sariff			feeder_rate_max = FEEDRATE_RATEMAX;
145164614Sariff		}
146164614Sariff
147164614Sariff		if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN ||
148164614Sariff		    	    feeder_rate_round > FEEDRATE_ROUNDHZ_MAX)
149164614Sariff			feeder_rate_round = FEEDRATE_ROUNDHZ;
150164614Sariff
151164614Sariff		if (bootverbose)
152164614Sariff			printf("%s: snd_unit=%d snd_maxautovchans=%d "
153164614Sariff			    "latency=%d feeder_buffersize=%d "
154164614Sariff			    "feeder_rate_min=%d feeder_rate_max=%d "
155164614Sariff			    "feeder_rate_round=%d\n",
156164614Sariff			    __func__, snd_unit, snd_maxautovchans,
157164614Sariff			    chn_latency, feeder_buffersize,
158164614Sariff			    feeder_rate_min, feeder_rate_max,
159164614Sariff			    feeder_rate_round);
160164614Sariff
16189834Scg		/* we've got our root feeder so don't veto pcm loading anymore */
16289834Scg		pcm_veto_load = 0;
16389834Scg
16464881Scg		return;
16564881Scg	}
16664881Scg
16789834Scg	KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name));
16889834Scg
16989834Scg	/* beyond this point failure is non-fatal but may result in some translations being unavailable */
17064881Scg	i = 0;
17170134Scg	while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) {
17275355Scg		/* printf("adding feeder %s, %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); */
173111909Sorion		fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO);
17489834Scg		if (fte == NULL) {
17589834Scg			printf("can't allocate memory for feeder '%s', %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out);
17689834Scg
17789834Scg			return;
17889834Scg		}
17970134Scg		fte->feederclass = fc;
18070134Scg		fte->desc = &fc->desc[i];
18164881Scg		fte->idx = feedercnt;
18264881Scg		fte->desc->idx = feedercnt;
18364881Scg		SLIST_INSERT_HEAD(&feedertab, fte, link);
18464881Scg		i++;
18564881Scg	}
18664881Scg	feedercnt++;
18764881Scg	if (feedercnt >= MAXFEEDERS)
18889834Scg		printf("MAXFEEDERS (%d >= %d) exceeded\n", feedercnt, MAXFEEDERS);
18964881Scg}
19064881Scg
19174363Scgstatic void
19274363Scgfeeder_unregisterall(void *p)
19374363Scg{
19474363Scg	struct feedertab_entry *fte, *next;
19574363Scg
19674363Scg	next = SLIST_FIRST(&feedertab);
19774363Scg	while (next != NULL) {
19874363Scg		fte = next;
19974363Scg		next = SLIST_NEXT(fte, link);
20074363Scg		free(fte, M_FEEDER);
20174363Scg	}
20274363Scg}
20374363Scg
20450724Scgstatic int
20564881Scgcmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m)
20650724Scg{
20766308Scg	return ((n->type == m->type) &&
20866308Scg		((n->in == 0) || (n->in == m->in)) &&
20966308Scg		((n->out == 0) || (n->out == m->out)) &&
21066308Scg		(n->flags == m->flags));
21150724Scg}
21250724Scg
21370134Scgstatic void
21474763Scgfeeder_destroy(struct pcm_feeder *f)
21550724Scg{
21670134Scg	FEEDER_FREE(f);
21770134Scg	kobj_delete((kobj_t)f, M_FEEDER);
21870134Scg}
21964881Scg
22074763Scgstatic struct pcm_feeder *
22170134Scgfeeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc)
22270134Scg{
22374763Scg	struct pcm_feeder *f;
22470134Scg	int err;
22570134Scg
226111909Sorion	f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO);
22789834Scg	if (f == NULL)
22889834Scg		return NULL;
22989834Scg
23070134Scg	f->align = fc->align;
23189834Scg	f->data = fc->data;
23289834Scg	f->source = NULL;
23389834Scg	f->parent = NULL;
23489834Scg	f->class = fc;
23589834Scg	f->desc = &(f->desc_static);
23689834Scg
23789834Scg	if (desc) {
23870134Scg		*(f->desc) = *desc;
23989834Scg	} else {
24070134Scg		f->desc->type = FEEDER_ROOT;
24170134Scg		f->desc->in = 0;
24270134Scg		f->desc->out = 0;
24370134Scg		f->desc->flags = 0;
24470134Scg		f->desc->idx = 0;
24564881Scg	}
24689834Scg
24770134Scg	err = FEEDER_INIT(f);
24870134Scg	if (err) {
24975319Scg		printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err);
25070134Scg		feeder_destroy(f);
25189834Scg
25270134Scg		return NULL;
25389834Scg	}
25489834Scg
25589834Scg	return f;
25650724Scg}
25750724Scg
25870134Scgstruct feeder_class *
25970134Scgfeeder_getclass(struct pcm_feederdesc *desc)
26050724Scg{
26164881Scg	struct feedertab_entry *fte;
26250724Scg
26364881Scg	SLIST_FOREACH(fte, &feedertab, link) {
26470134Scg		if ((desc == NULL) && (fte->desc == NULL))
26570134Scg			return fte->feederclass;
26670134Scg		if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc))
26770134Scg			return fte->feederclass;
26864881Scg	}
26964881Scg	return NULL;
27050724Scg}
27150724Scg
27250724Scgint
27374763Scgchn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc)
27466308Scg{
27574763Scg	struct pcm_feeder *nf;
27670134Scg
27770134Scg	nf = feeder_create(fc, desc);
27870134Scg	if (nf == NULL)
27989834Scg		return ENOSPC;
28066308Scg
28170134Scg	nf->source = c->feeder;
28266308Scg
283117307Scg	/* XXX we should use the lowest common denominator for align */
28466308Scg	if (nf->align > 0)
28566308Scg		c->align += nf->align;
28666308Scg	else if (nf->align < 0 && c->align < -nf->align)
28766308Scg		c->align = -nf->align;
288117307Scg	if (c->feeder != NULL)
289117307Scg		c->feeder->parent = nf;
29066308Scg	c->feeder = nf;
29166308Scg
29266308Scg	return 0;
29366308Scg}
29466308Scg
29566308Scgint
29674763Scgchn_removefeeder(struct pcm_channel *c)
29750724Scg{
29874763Scg	struct pcm_feeder *f;
29950724Scg
30070134Scg	if (c->feeder == NULL)
30164881Scg		return -1;
30270134Scg	f = c->feeder;
30370134Scg	c->feeder = c->feeder->source;
30470134Scg	feeder_destroy(f);
30589834Scg
30664881Scg	return 0;
30750724Scg}
30850724Scg
30974763Scgstruct pcm_feeder *
31074763Scgchn_findfeeder(struct pcm_channel *c, u_int32_t type)
31166308Scg{
31274763Scg	struct pcm_feeder *f;
31366308Scg
31466308Scg	f = c->feeder;
31566308Scg	while (f != NULL) {
31666308Scg		if (f->desc->type == type)
31766308Scg			return f;
31866308Scg		f = f->source;
31966308Scg	}
32089834Scg
32166308Scg	return NULL;
32266308Scg}
32366308Scg
32450724Scgstatic int
32574763Scgchainok(struct pcm_feeder *test, struct pcm_feeder *stop)
32650724Scg{
32764881Scg	u_int32_t visited[MAXFEEDERS / 32];
32864881Scg	u_int32_t idx, mask;
32964881Scg
33064881Scg	bzero(visited, sizeof(visited));
33164881Scg	while (test && (test != stop)) {
33264881Scg		idx = test->desc->idx;
33364881Scg		if (idx < 0)
33464881Scg			panic("bad idx %d", idx);
33564881Scg		if (idx >= MAXFEEDERS)
33664881Scg			panic("bad idx %d", idx);
33764881Scg		mask = 1 << (idx & 31);
33864881Scg		idx >>= 5;
33964881Scg		if (visited[idx] & mask)
34064881Scg			return 0;
34164881Scg		visited[idx] |= mask;
34264881Scg		test = test->source;
34364881Scg	}
34489834Scg
34564881Scg	return 1;
34650724Scg}
34750724Scg
348164614Sariff/*
349170161Sariff * See feeder_fmtchain() for the mumbo-jumbo ridiculous explanation
350164614Sariff * of what the heck is this FMT_Q_*
351164614Sariff */
352164614Sariff#define FMT_Q_UP	1
353164614Sariff#define FMT_Q_DOWN	2
354164614Sariff#define FMT_Q_EQ	3
355164614Sariff#define FMT_Q_MULTI	4
35664881Scg
357164614Sariff/*
358164614Sariff * 14bit format scoring
359164614Sariff * --------------------
360164614Sariff *
361164614Sariff *  13  12  11  10   9   8        2        1   0    offset
362164614Sariff * +---+---+---+---+---+---+-------------+---+---+
363164614Sariff * | X | X | X | X | X | X | X X X X X X | X | X |
364164614Sariff * +---+---+---+---+---+---+-------------+---+---+
365164614Sariff *   |   |   |   |   |   |        |        |   |
366164614Sariff *   |   |   |   |   |   |        |        |   +--> signed?
367164614Sariff *   |   |   |   |   |   |        |        |
368164614Sariff *   |   |   |   |   |   |        |        +------> bigendian?
369164614Sariff *   |   |   |   |   |   |        |
370164614Sariff *   |   |   |   |   |   |        +---------------> total channels
371164614Sariff *   |   |   |   |   |   |
372164614Sariff *   |   |   |   |   |   +------------------------> AFMT_A_LAW
373164614Sariff *   |   |   |   |   |
374164614Sariff *   |   |   |   |   +----------------------------> AFMT_MU_LAW
375164614Sariff *   |   |   |   |
376164614Sariff *   |   |   |   +--------------------------------> AFMT_8BIT
377164614Sariff *   |   |   |
378164614Sariff *   |   |   +------------------------------------> AFMT_16BIT
379164614Sariff *   |   |
380164614Sariff *   |   +----------------------------------------> AFMT_24BIT
381164614Sariff *   |
382164614Sariff *   +--------------------------------------------> AFMT_32BIT
383164614Sariff */
384164614Sariff#define score_signeq(s1, s2)	(((s1) & 0x1) == ((s2) & 0x1))
385164614Sariff#define score_endianeq(s1, s2)	(((s1) & 0x2) == ((s2) & 0x2))
386164614Sariff#define score_cheq(s1, s2)	(((s1) & 0xfc) == ((s2) & 0xfc))
387164614Sariff#define score_val(s1)		((s1) & 0x3f00)
388164614Sariff#define score_cse(s1)		((s1) & 0x7f)
38964881Scg
390164614Sariffu_int32_t
391154684Sariffchn_fmtscore(u_int32_t fmt)
392154684Sariff{
393164614Sariff	u_int32_t ret;
394164614Sariff
395164614Sariff	ret = 0;
396164614Sariff	if (fmt & AFMT_SIGNED)
397164614Sariff		ret |= 1 << 0;
398164614Sariff	if (fmt & AFMT_BIGENDIAN)
399164614Sariff		ret |= 1 << 1;
400164614Sariff	if (fmt & AFMT_STEREO)
401164614Sariff		ret |= (2 & 0x3f) << 2;
402164614Sariff	else
403164614Sariff		ret |= (1 & 0x3f) << 2;
404154969Sariff	if (fmt & AFMT_A_LAW)
405164614Sariff		ret |= 1 << 8;
406164614Sariff	else if (fmt & AFMT_MU_LAW)
407164614Sariff		ret |= 1 << 9;
408164614Sariff	else if (fmt & AFMT_8BIT)
409164614Sariff		ret |= 1 << 10;
410164614Sariff	else if (fmt & AFMT_16BIT)
411164614Sariff		ret |= 1 << 11;
412164614Sariff	else if (fmt & AFMT_24BIT)
413164614Sariff		ret |= 1 << 12;
414164614Sariff	else if (fmt & AFMT_32BIT)
415164614Sariff		ret |= 1 << 13;
416164614Sariff
417164614Sariff	return ret;
418154684Sariff}
419154684Sariff
420164614Sariffstatic u_int32_t
421164614Sariffchn_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq)
422154684Sariff{
423164614Sariff	u_int32_t best, score, score2, oldscore;
424164614Sariff	int i;
425154684Sariff
426164614Sariff	if (fmt == 0 || fmts == NULL || fmts[0] == 0)
427164614Sariff		return 0;
428164614Sariff
429164614Sariff	if (fmtvalid(fmt, fmts))
430164614Sariff		return fmt;
431164614Sariff
432154684Sariff	best = 0;
433154684Sariff	score = chn_fmtscore(fmt);
434154684Sariff	oldscore = 0;
435154684Sariff	for (i = 0; fmts[i] != 0; i++) {
436154684Sariff		score2 = chn_fmtscore(fmts[i]);
437164614Sariff		if (cheq && !score_cheq(score, score2))
438164614Sariff			continue;
439164614Sariff		if (oldscore == 0 ||
440164614Sariff			    (score_val(score2) == score_val(score)) ||
441164614Sariff			    (score_val(score2) == score_val(oldscore)) ||
442164614Sariff			    (score_val(score2) > score_val(oldscore) &&
443164614Sariff			    score_val(score2) < score_val(score)) ||
444164614Sariff			    (score_val(score2) < score_val(oldscore) &&
445164614Sariff			    score_val(score2) > score_val(score)) ||
446164614Sariff			    (score_val(oldscore) < score_val(score) &&
447164614Sariff			    score_val(score2) > score_val(oldscore))) {
448164614Sariff			if (score_val(oldscore) != score_val(score2) ||
449164614Sariff				    score_cse(score) == score_cse(score2) ||
450164614Sariff				    ((score_cse(oldscore) != score_cse(score) &&
451164614Sariff				    !score_endianeq(score, oldscore) &&
452164614Sariff				    (score_endianeq(score, score2) ||
453164614Sariff				    (!score_signeq(score, oldscore) &&
454164614Sariff				    score_signeq(score, score2)))))) {
455164614Sariff				best = fmts[i];
456164614Sariff				oldscore = score2;
457164614Sariff			}
458154684Sariff		}
459154684Sariff	}
460154684Sariff	return best;
461154684Sariff}
462154684Sariff
463154684Sariffu_int32_t
464164614Sariffchn_fmtbestbit(u_int32_t fmt, u_int32_t *fmts)
465164614Sariff{
466164614Sariff	return chn_fmtbestfunc(fmt, fmts, 0);
467164614Sariff}
468164614Sariff
469164614Sariffu_int32_t
470154684Sariffchn_fmtbeststereo(u_int32_t fmt, u_int32_t *fmts)
471154684Sariff{
472164614Sariff	return chn_fmtbestfunc(fmt, fmts, 1);
473154684Sariff}
474154684Sariff
475154684Sariffu_int32_t
476154684Sariffchn_fmtbest(u_int32_t fmt, u_int32_t *fmts)
477154684Sariff{
478154684Sariff	u_int32_t best1, best2;
479164614Sariff	u_int32_t score, score1, score2;
480154684Sariff
481164614Sariff	if (fmtvalid(fmt, fmts))
482164614Sariff		return fmt;
483164614Sariff
484154684Sariff	best1 = chn_fmtbeststereo(fmt, fmts);
485154684Sariff	best2 = chn_fmtbestbit(fmt, fmts);
486154684Sariff
487164614Sariff	if (best1 != 0 && best2 != 0 && best1 != best2) {
488154684Sariff		if (fmt & AFMT_STEREO)
489154684Sariff			return best1;
490154684Sariff		else {
491164614Sariff			score = score_val(chn_fmtscore(fmt));
492164614Sariff			score1 = score_val(chn_fmtscore(best1));
493164614Sariff			score2 = score_val(chn_fmtscore(best2));
494154969Sariff			if (score1 == score2 || score1 == score)
495154969Sariff				return best1;
496154969Sariff			else if (score2 == score)
497154684Sariff				return best2;
498154969Sariff			else if (score1 > score2)
499154684Sariff				return best1;
500154684Sariff			return best2;
501154684Sariff		}
502154684Sariff	} else if (best2 == 0)
503154684Sariff		return best1;
504155958Sjhb	else
505154684Sariff		return best2;
506154684Sariff}
507154684Sariff
508164614Sariffstatic struct pcm_feeder *
509164614Sarifffeeder_fmtchain(u_int32_t *to, struct pcm_feeder *source, struct pcm_feeder *stop, int maxdepth)
510164614Sariff{
511164614Sariff	struct feedertab_entry *fte, *ftebest;
512164614Sariff	struct pcm_feeder *try, *ret;
513164614Sariff	uint32_t fl, qout, qsrc, qdst;
514164614Sariff	int qtype;
515164614Sariff
516164614Sariff	if (to == NULL || to[0] == 0)
517164614Sariff		return NULL;
518164614Sariff
519164614Sariff	DEB(printf("trying %s (0x%08x -> 0x%08x)...\n", source->class->name, source->desc->in, source->desc->out));
520164614Sariff	if (fmtvalid(source->desc->out, to)) {
521164614Sariff		DEB(printf("got it\n"));
522164614Sariff		return source;
523164614Sariff	}
524164614Sariff
525164614Sariff	if (maxdepth < 0)
526164614Sariff		return NULL;
527164614Sariff
528164614Sariff	/*
529164614Sariff	 * WARNING: THIS IS _NOT_ FOR THE FAINT HEART
530164614Sariff	 * Disclaimer: I don't expect anybody could understand this
531164614Sariff	 *             without deep logical and mathematical analysis
532164614Sariff	 *             involving various unnamed probability theorem.
533164614Sariff	 *
534164614Sariff	 * This "Best Fit Random Chain Selection" (BLEHBLEHWHATEVER) algorithm
535164614Sariff	 * is **extremely** difficult to digest especially when applied to
536164614Sariff	 * large sets / numbers of random chains (feeders), each with
537164614Sariff	 * unique characteristic providing different sets of in/out format.
538164614Sariff	 *
539164614Sariff	 * Basically, our FEEDER_FMT (see feeder_fmt.c) chains characteristic:
540164614Sariff	 * 1) Format chains
541164614Sariff	 *    1.1 "8bit to any, not to 8bit"
542164614Sariff	 *      1.1.1 sign can remain consistent, e.g: u8 -> u16[le|be]
543164614Sariff	 *      1.1.2 sign can be changed, e.g: u8 -> s16[le|be]
544164614Sariff	 *      1.1.3 endian can be changed, e.g: u8 -> u16[le|be]
545164614Sariff	 *      1.1.4 both can be changed, e.g: u8 -> [u|s]16[le|be]
546164614Sariff	 *    1.2 "Any to 8bit, not from 8bit"
547164614Sariff	 *      1.2.1 sign can remain consistent, e.g: s16le -> s8
548164614Sariff	 *      1.2.2 sign can be changed, e.g: s16le -> u8
549164614Sariff	 *      1.2.3 source endian can be anything e.g: s16[le|be] -> s8
550164614Sariff	 *      1.2.4 source endian / sign can be anything e.g: [u|s]16[le|be] -> u8
551164614Sariff	 *    1.3 "Any to any where BOTH input and output either 8bit or non-8bit"
552164614Sariff	 *      1.3.1 endian MUST remain consistent
553164614Sariff	 *      1.3.2 sign CAN be changed
554164614Sariff	 *    1.4 "Long jump" is allowed, e.g: from 16bit to 32bit, excluding
555164614Sariff	 *        16bit to 24bit .
556164614Sariff	 * 2) Channel chains (mono <-> stereo)
557164614Sariff	 *    2.1 Both endian and sign MUST remain consistent
558164614Sariff	 * 3) Endian chains (big endian <-> little endian)
559164614Sariff	 *    3.1 Channels and sign MUST remain consistent
560164614Sariff	 * 4) Sign chains (signed <-> unsigned)
561164614Sariff	 *    4.1 Channels and endian MUST remain consistent
562164614Sariff	 *
563164614Sariff	 * .. and the mother of all chaining rules:
564164614Sariff	 *
565164614Sariff	 * Rules 0: Source and destination MUST not contain multiple selections.
566164614Sariff	 *          (qtype != FMT_Q_MULTI)
567164614Sariff	 *
568164614Sariff	 * First of all, our caller ( chn_fmtchain() ) will reduce the possible
569164614Sariff	 * multiple from/to formats to a single best format using chn_fmtbest().
570164614Sariff	 * Then, using chn_fmtscore(), we determine the chaining characteristic.
571164614Sariff	 * Our main goal is to narrow it down until it reach FMT_Q_EQ chaining
572164614Sariff	 * type while still adhering above chaining rules.
573164614Sariff	 *
574164614Sariff	 * The need for this complicated chaining procedures is inevitable,
575164614Sariff	 * since currently we have more than 200 different types of FEEDER_FMT
576164614Sariff	 * doing various unique format conversion. Without this (the old way),
577164614Sariff	 * it is possible to generate broken chain since it doesn't do any
578164614Sariff	 * sanity checking to ensure that the output format is "properly aligned"
579164614Sariff	 * with the direction of conversion (quality up/down/equal).
580164614Sariff	 *
581164614Sariff	 *   Conversion: s24le to s32le
582164614Sariff	 *   Possible chain: 1) s24le -> s32le (correct, optimized)
583164614Sariff	 *                   2) s24le -> s16le -> s32le
584164614Sariff	 *                      (since we have feeder_24to16 and feeder_16to32)
585164614Sariff	 *                      +-- obviously broken!
586164614Sariff	 *
587164614Sariff	 * Using scoring mechanisme, this will ensure that the chaining
588164614Sariff	 * process do the right thing, or at least, give the best chain
589164614Sariff	 * possible without causing quality (the 'Q') degradation.
590164614Sariff	 */
591164614Sariff
592164614Sariff	qdst = chn_fmtscore(to[0]);
593164614Sariff	qsrc = chn_fmtscore(source->desc->out);
594164614Sariff
595164614Sariff#define score_q(s1)			score_val(s1)
596164614Sariff#define score_8bit(s1)			((s1) & 0x700)
597164614Sariff#define score_non8bit(s1)		(!score_8bit(s1))
598164614Sariff#define score_across8bit(s1, s2)	((score_8bit(s1) && score_non8bit(s2)) || \
599164614Sariff					(score_8bit(s2) && score_non8bit(s1)))
600164614Sariff
601164614Sariff#define FMT_CHAIN_Q_UP(s1, s2)		(score_q(s1) < score_q(s2))
602164614Sariff#define FMT_CHAIN_Q_DOWN(s1, s2)	(score_q(s1) > score_q(s2))
603164614Sariff#define FMT_CHAIN_Q_EQ(s1, s2)		(score_q(s1) == score_q(s2))
604164614Sariff#define FMT_Q_DOWN_FLAGS(s1, s2)	(0x1 | (score_across8bit(s1, s2) ? \
605164614Sariff						0x2 : 0x0))
606164614Sariff#define FMT_Q_UP_FLAGS(s1, s2)		FMT_Q_DOWN_FLAGS(s1, s2)
607164614Sariff#define FMT_Q_EQ_FLAGS(s1, s2)		(0x3ffc | \
608164614Sariff					((score_cheq(s1, s2) && \
609164614Sariff						score_endianeq(s1, s2)) ? \
610164614Sariff						0x1 : 0x0) | \
611164614Sariff					((score_cheq(s1, s2) && \
612164614Sariff						score_signeq(s1, s2)) ? \
613164614Sariff						0x2 : 0x0))
614164614Sariff
615164614Sariff	/* Determine chaining direction and set matching flag */
616164614Sariff	fl = 0x3fff;
617164614Sariff	if (to[1] != 0) {
618164614Sariff		qtype = FMT_Q_MULTI;
619164614Sariff		printf("%s: WARNING: FMT_Q_MULTI chaining. Expect the unexpected.\n", __func__);
620164614Sariff	} else if (FMT_CHAIN_Q_DOWN(qsrc, qdst)) {
621164614Sariff		qtype = FMT_Q_DOWN;
622164614Sariff		fl = FMT_Q_DOWN_FLAGS(qsrc, qdst);
623164614Sariff	} else if (FMT_CHAIN_Q_UP(qsrc, qdst)) {
624164614Sariff		qtype = FMT_Q_UP;
625164614Sariff		fl = FMT_Q_UP_FLAGS(qsrc, qdst);
626164614Sariff	} else {
627164614Sariff		qtype = FMT_Q_EQ;
628164614Sariff		fl = FMT_Q_EQ_FLAGS(qsrc, qdst);
629164614Sariff	}
630164614Sariff
631164614Sariff	ftebest = NULL;
632164614Sariff
633164614Sariff	SLIST_FOREACH(fte, &feedertab, link) {
634164614Sariff		if (fte->desc == NULL)
635164614Sariff			continue;
636164614Sariff		if (fte->desc->type != FEEDER_FMT)
637164614Sariff			continue;
638164614Sariff		qout = chn_fmtscore(fte->desc->out);
639164614Sariff#define FMT_Q_MULTI_VALIDATE(qt)		((qt) == FMT_Q_MULTI)
640164614Sariff#define FMT_Q_FL_MATCH(qfl, s1, s2)		(((s1) & (qfl)) == ((s2) & (qfl)))
641164614Sariff#define FMT_Q_UP_VALIDATE(qt, s1, s2, s3)	((qt) == FMT_Q_UP && \
642164614Sariff						score_q(s3) >= score_q(s1) && \
643164614Sariff						score_q(s3) <= score_q(s2))
644164614Sariff#define FMT_Q_DOWN_VALIDATE(qt, s1, s2, s3)	((qt) == FMT_Q_DOWN && \
645164614Sariff						score_q(s3) <= score_q(s1) && \
646164614Sariff						score_q(s3) >= score_q(s2))
647164614Sariff#define FMT_Q_EQ_VALIDATE(qt, s1, s2)		((qt) == FMT_Q_EQ && \
648164614Sariff						score_q(s1) == score_q(s2))
649164614Sariff		if (fte->desc->in == source->desc->out &&
650164614Sariff			    (FMT_Q_MULTI_VALIDATE(qtype) ||
651164614Sariff			    (FMT_Q_FL_MATCH(fl, qout, qdst) &&
652164614Sariff			    (FMT_Q_UP_VALIDATE(qtype, qsrc, qdst, qout) ||
653164614Sariff			    FMT_Q_DOWN_VALIDATE(qtype, qsrc, qdst, qout) ||
654164614Sariff			    FMT_Q_EQ_VALIDATE(qtype, qdst, qout))))) {
655164614Sariff			try = feeder_create(fte->feederclass, fte->desc);
656164614Sariff			if (try) {
657164614Sariff				try->source = source;
658164614Sariff				ret = chainok(try, stop) ? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL;
659164614Sariff				if (ret != NULL)
660164614Sariff					return ret;
661164614Sariff				feeder_destroy(try);
662164614Sariff			}
663164614Sariff		} else if (fte->desc->in == source->desc->out) {
664164614Sariff			/* XXX quality must be considered! */
665164614Sariff			if (ftebest == NULL)
666164614Sariff				ftebest = fte;
667164614Sariff		}
668164614Sariff	}
669164614Sariff
670164614Sariff	if (ftebest != NULL) {
671164614Sariff		try = feeder_create(ftebest->feederclass, ftebest->desc);
672164614Sariff		if (try) {
673164614Sariff			try->source = source;
674164614Sariff			ret = chainok(try, stop) ? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL;
675164614Sariff			if (ret != NULL)
676164614Sariff				return ret;
677164614Sariff			feeder_destroy(try);
678164614Sariff		}
679164614Sariff	}
680164614Sariff
681164614Sariff	/* printf("giving up %s...\n", source->class->name); */
682164614Sariff
683164614Sariff	return NULL;
684164614Sariff}
685164614Sariff
686154684Sariffu_int32_t
68774763Scgchn_fmtchain(struct pcm_channel *c, u_int32_t *to)
68864881Scg{
68989686Scg	struct pcm_feeder *try, *del, *stop;
690154684Sariff	u_int32_t tmpfrom[2], tmpto[2], best, *from;
69189686Scg	int i, max, bestmax;
69264881Scg
69389686Scg	KASSERT(c != NULL, ("c == NULL"));
69489686Scg	KASSERT(c->feeder != NULL, ("c->feeder == NULL"));
69589686Scg	KASSERT(to != NULL, ("to == NULL"));
69689686Scg	KASSERT(to[0] != 0, ("to[0] == 0"));
69789686Scg
698164614Sariff	if (c == NULL || c->feeder == NULL || to == NULL || to[0] == 0)
699164614Sariff		return 0;
700164614Sariff
70164881Scg	stop = c->feeder;
702164614Sariff	best = 0;
70389686Scg
70489686Scg	if (c->direction == PCMDIR_REC && c->feeder->desc->type == FEEDER_ROOT) {
70589686Scg		from = chn_getcaps(c)->fmtlist;
706164614Sariff		if (from[1] != 0) {
707154684Sariff			best = chn_fmtbest(to[0], from);
708154684Sariff			if (best != 0) {
709154684Sariff				tmpfrom[0] = best;
710154684Sariff				tmpfrom[1] = 0;
711154684Sariff				from = tmpfrom;
712154684Sariff			}
713154684Sariff		}
71489686Scg	} else {
71589686Scg		tmpfrom[0] = c->feeder->desc->out;
71689686Scg		tmpfrom[1] = 0;
71789686Scg		from = tmpfrom;
718154684Sariff		if (to[1] != 0) {
719164614Sariff			best = chn_fmtbest(from[0], to);
720164614Sariff			if (best != 0) {
721164614Sariff				tmpto[0] = best;
722154684Sariff				tmpto[1] = 0;
723154684Sariff				to = tmpto;
724154684Sariff			}
725154684Sariff		}
72665645Scg	}
72789686Scg
728164614Sariff#define FEEDER_FMTCHAIN_MAXDEPTH	8
729164614Sariff
730164614Sariff	try = NULL;
731164614Sariff
732164614Sariff	if (to[0] != 0 && from[0] != 0 &&
733164614Sariff		    to[1] == 0 && from[1] == 0) {
73489686Scg		max = 0;
735164614Sariff		best = from[0];
736164614Sariff		c->feeder->desc->out = best;
737164614Sariff		do {
73889686Scg			try = feeder_fmtchain(to, c->feeder, stop, max);
739164614Sariff			DEB(if (try != NULL) {
740164614Sariff				printf("%s: 0x%08x -> 0x%08x (maxdepth: %d)\n",
741165835Snetchild					__func__, from[0], to[0], max);
742164614Sariff			});
743164614Sariff		} while (try == NULL && max++ < FEEDER_FMTCHAIN_MAXDEPTH);
744164614Sariff	} else {
745164614Sariff		printf("%s: Using the old-way format chaining!\n", __func__);
746164614Sariff		i = 0;
747164614Sariff		best = 0;
748164614Sariff		bestmax = 100;
749164614Sariff		while (from[i] != 0) {
750164614Sariff			c->feeder->desc->out = from[i];
751164614Sariff			try = NULL;
752164614Sariff			max = 0;
753164614Sariff			do {
754164614Sariff				try = feeder_fmtchain(to, c->feeder, stop, max);
755164614Sariff			} while (try == NULL && max++ < FEEDER_FMTCHAIN_MAXDEPTH);
756164614Sariff			if (try != NULL && max < bestmax) {
757164614Sariff				bestmax = max;
758164614Sariff				best = from[i];
759164614Sariff			}
760164614Sariff			while (try != NULL && try != stop) {
761164614Sariff				del = try;
762164614Sariff				try = try->source;
763164614Sariff				feeder_destroy(del);
764164614Sariff			}
765164614Sariff			i++;
76689686Scg		}
767164614Sariff		if (best == 0)
768164614Sariff			return 0;
769164614Sariff
770164614Sariff		c->feeder->desc->out = best;
771164614Sariff		try = feeder_fmtchain(to, c->feeder, stop, bestmax);
77289686Scg	}
77364881Scg	if (try == NULL)
77464881Scg		return 0;
77589686Scg
77664881Scg	c->feeder = try;
77764881Scg	c->align = 0;
77865645Scg#ifdef FEEDER_DEBUG
77989686Scg	printf("\n\nchain: ");
78065645Scg#endif
78164881Scg	while (try && (try != stop)) {
78265645Scg#ifdef FEEDER_DEBUG
78375319Scg		printf("%s [%d]", try->class->name, try->desc->idx);
78465645Scg		if (try->source)
78565645Scg			printf(" -> ");
78665645Scg#endif
78789686Scg		if (try->source)
78889686Scg			try->source->parent = try;
78964881Scg		if (try->align > 0)
79064881Scg			c->align += try->align;
79164881Scg		else if (try->align < 0 && c->align < -try->align)
79264881Scg			c->align = -try->align;
79364881Scg		try = try->source;
79464881Scg	}
79565645Scg#ifdef FEEDER_DEBUG
79675319Scg	printf("%s [%d]\n", try->class->name, try->desc->idx);
79765645Scg#endif
79889834Scg
799149950Snetchild	if (c->direction == PCMDIR_REC) {
800149950Snetchild		try = c->feeder;
801149950Snetchild		while (try != NULL) {
802149950Snetchild			if (try->desc->type == FEEDER_ROOT)
803149950Snetchild				return try->desc->out;
804149950Snetchild			try = try->source;
805149950Snetchild		}
806149950Snetchild		return best;
807149950Snetchild	} else
808149950Snetchild		return c->feeder->desc->out;
80964881Scg}
81066308Scg
811117307Scgvoid
812117307Scgfeeder_printchain(struct pcm_feeder *head)
813117307Scg{
814117307Scg	struct pcm_feeder *f;
815117307Scg
816117307Scg	printf("feeder chain (head @%p)\n", head);
817117307Scg	f = head;
818117307Scg	while (f != NULL) {
819117307Scg		printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f);
820117307Scg		f = f->source;
821117307Scg	}
822117307Scg	printf("[end]\n\n");
823117307Scg}
824117307Scg
82566308Scg/*****************************************************************************/
82666308Scg
82766308Scgstatic int
82874763Scgfeed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source)
82966308Scg{
83074763Scg	struct snd_dbuf *src = source;
831164614Sariff	int l, offset;
83266308Scg
83374763Scg	KASSERT(count > 0, ("feed_root: count == 0"));
83474763Scg	/* count &= ~((1 << ch->align) - 1); */
83574763Scg	KASSERT(count > 0, ("feed_root: aligned count == 0 (align = %d)", ch->align));
83666308Scg
837164614Sariff	if (++ch->feedcount == 0)
838164614Sariff		ch->feedcount = 2;
839164614Sariff
84074763Scg	l = min(count, sndbuf_getready(src));
84166308Scg
842110287Sorion	/* When recording only return as much data as available */
843164614Sariff	if (ch->direction == PCMDIR_REC) {
844164614Sariff		sndbuf_dispose(src, buffer, l);
845110287Sorion		return l;
846164614Sariff	}
847110287Sorion
84874763Scg
849164614Sariff	offset = count - l;
85074763Scg
851164614Sariff	if (offset > 0) {
852164614Sariff		if (snd_verbose > 3)
853164614Sariff			printf("%s: (%s) %spending %d bytes "
854164614Sariff			    "(count=%d l=%d feed=%d)\n",
855164614Sariff			    __func__,
856164614Sariff			    (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
857164614Sariff			    (ch->feedcount == 1) ? "pre" : "ap",
858164614Sariff			    offset, count, l, ch->feedcount);
859164614Sariff
860164614Sariff		if (ch->feedcount == 1) {
861167644Sariff			memset(buffer,
862167644Sariff			    sndbuf_zerodata(sndbuf_getfmt(src)),
863167644Sariff			    offset);
864164614Sariff			if (l > 0)
865164614Sariff				sndbuf_dispose(src, buffer + offset, l);
866164614Sariff			else
867164614Sariff				ch->feedcount--;
868164614Sariff		} else {
869164614Sariff			if (l > 0)
870164614Sariff				sndbuf_dispose(src, buffer, l);
871167644Sariff			memset(buffer + l,
872167644Sariff			    sndbuf_zerodata(sndbuf_getfmt(src)),
873167644Sariff			    offset);
874167644Sariff			if (!(ch->flags & CHN_F_CLOSING))
875167644Sariff				ch->xruns++;
876164614Sariff		}
877164614Sariff	} else if (l > 0)
878164614Sariff		sndbuf_dispose(src, buffer, l);
879164614Sariff
88066308Scg	return count;
88166308Scg}
88270134Scg
88370134Scgstatic kobj_method_t feeder_root_methods[] = {
88470134Scg    	KOBJMETHOD(feeder_feed,		feed_root),
88570134Scg	{ 0, 0 }
88666308Scg};
88770134Scgstatic struct feeder_class feeder_root_class = {
888118473Sdds	.name =		"feeder_root",
889118473Sdds	.methods =	feeder_root_methods,
890118473Sdds	.size =		sizeof(struct pcm_feeder),
891118473Sdds	.align =	0,
892118473Sdds	.desc =		NULL,
893118473Sdds	.data =		NULL,
89470134Scg};
89570134ScgSYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class);
89674363ScgSYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL);
897