1098ca2bdSWarner Losh /*- 2*4d846d26SWarner 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> 35987e5972SCameron Grant 360f55ac6cSCameron Grant #include "feeder_if.h" 370f55ac6cSCameron Grant 3867b1dce3SCameron Grant SND_DECLARE_FILE("$FreeBSD$"); 3967b1dce3SCameron Grant 40d745c852SEd Schouten static MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder"); 410f55ac6cSCameron Grant 42c9c6ba09SCameron Grant #define MAXFEEDERS 256 4358359dc5SCameron Grant #undef FEEDER_DEBUG 44987e5972SCameron Grant 45513693beSCameron Grant struct feedertab_entry { 46513693beSCameron Grant SLIST_ENTRY(feedertab_entry) link; 470f55ac6cSCameron Grant struct feeder_class *feederclass; 48513693beSCameron Grant struct pcm_feederdesc *desc; 49513693beSCameron Grant 50513693beSCameron Grant int idx; 51513693beSCameron Grant }; 52513693beSCameron Grant static SLIST_HEAD(, feedertab_entry) feedertab; 53513693beSCameron Grant 54513693beSCameron Grant /*****************************************************************************/ 55513693beSCameron Grant 56513693beSCameron Grant void 57513693beSCameron Grant feeder_register(void *p) 58513693beSCameron Grant { 59b8a36395SCameron Grant static int feedercnt = 0; 60b8a36395SCameron Grant 610f55ac6cSCameron Grant struct feeder_class *fc = p; 62513693beSCameron Grant struct feedertab_entry *fte; 63513693beSCameron Grant int i; 64513693beSCameron Grant 65513693beSCameron Grant if (feedercnt == 0) { 66b8a36395SCameron Grant KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name)); 67b8a36395SCameron Grant 68513693beSCameron Grant SLIST_INIT(&feedertab); 69a7576e2eSOrion Hodson fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 70b8a36395SCameron Grant if (fte == NULL) { 71e788f796SBruce Evans printf("can't allocate memory for root feeder: %s\n", 72e788f796SBruce Evans fc->name); 73b8a36395SCameron Grant 74b8a36395SCameron Grant return; 75b8a36395SCameron Grant } 760f55ac6cSCameron Grant fte->feederclass = fc; 77513693beSCameron Grant fte->desc = NULL; 78513693beSCameron Grant fte->idx = feedercnt; 79513693beSCameron Grant SLIST_INSERT_HEAD(&feedertab, fte, link); 80513693beSCameron Grant feedercnt++; 81b8a36395SCameron Grant 82a580b31aSAriff Abdullah /* initialize global variables */ 83a580b31aSAriff Abdullah 84bba4862cSAriff Abdullah if (snd_verbose < 0 || snd_verbose > 4) 85a580b31aSAriff Abdullah snd_verbose = 1; 86a580b31aSAriff Abdullah 87bba4862cSAriff Abdullah /* initialize unit numbering */ 88bba4862cSAriff Abdullah snd_unit_init(); 89bba4862cSAriff Abdullah if (snd_unit < 0 || snd_unit > PCMMAXUNIT) 90f3685841SAriff Abdullah snd_unit = -1; 91a580b31aSAriff Abdullah 92a580b31aSAriff Abdullah if (snd_maxautovchans < 0 || 93a580b31aSAriff Abdullah snd_maxautovchans > SND_MAXVCHANS) 94a580b31aSAriff Abdullah snd_maxautovchans = 0; 95a580b31aSAriff Abdullah 96a580b31aSAriff Abdullah if (chn_latency < CHN_LATENCY_MIN || 97a580b31aSAriff Abdullah chn_latency > CHN_LATENCY_MAX) 98a580b31aSAriff Abdullah chn_latency = CHN_LATENCY_DEFAULT; 99a580b31aSAriff Abdullah 100a580b31aSAriff Abdullah if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN || 101a580b31aSAriff Abdullah chn_latency_profile > CHN_LATENCY_PROFILE_MAX) 102a580b31aSAriff Abdullah chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; 103a580b31aSAriff Abdullah 104a580b31aSAriff Abdullah if (feeder_rate_min < FEEDRATE_MIN || 105a580b31aSAriff Abdullah feeder_rate_max < FEEDRATE_MIN || 106a580b31aSAriff Abdullah feeder_rate_min > FEEDRATE_MAX || 107a580b31aSAriff Abdullah feeder_rate_max > FEEDRATE_MAX || 108a580b31aSAriff Abdullah !(feeder_rate_min < feeder_rate_max)) { 109a580b31aSAriff Abdullah feeder_rate_min = FEEDRATE_RATEMIN; 110a580b31aSAriff Abdullah feeder_rate_max = FEEDRATE_RATEMAX; 111a580b31aSAriff Abdullah } 112a580b31aSAriff Abdullah 113a580b31aSAriff Abdullah if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN || 114a580b31aSAriff Abdullah feeder_rate_round > FEEDRATE_ROUNDHZ_MAX) 115a580b31aSAriff Abdullah feeder_rate_round = FEEDRATE_ROUNDHZ; 116a580b31aSAriff Abdullah 117a580b31aSAriff Abdullah if (bootverbose) 118a580b31aSAriff Abdullah printf("%s: snd_unit=%d snd_maxautovchans=%d " 11990da2b28SAriff Abdullah "latency=%d " 120a580b31aSAriff Abdullah "feeder_rate_min=%d feeder_rate_max=%d " 121a580b31aSAriff Abdullah "feeder_rate_round=%d\n", 122a580b31aSAriff Abdullah __func__, snd_unit, snd_maxautovchans, 12390da2b28SAriff Abdullah chn_latency, 124a580b31aSAriff Abdullah feeder_rate_min, feeder_rate_max, 125a580b31aSAriff Abdullah feeder_rate_round); 126a580b31aSAriff Abdullah 127b8a36395SCameron Grant /* we've got our root feeder so don't veto pcm loading anymore */ 128b8a36395SCameron Grant pcm_veto_load = 0; 129b8a36395SCameron Grant 130513693beSCameron Grant return; 131513693beSCameron Grant } 132513693beSCameron Grant 133b8a36395SCameron Grant KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name)); 134b8a36395SCameron Grant 135b8a36395SCameron Grant /* beyond this point failure is non-fatal but may result in some translations being unavailable */ 136513693beSCameron Grant i = 0; 1370f55ac6cSCameron Grant while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) { 138941431caSCameron Grant /* printf("adding feeder %s, %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); */ 139a7576e2eSOrion Hodson fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 140b8a36395SCameron Grant if (fte == NULL) { 141b8a36395SCameron Grant printf("can't allocate memory for feeder '%s', %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); 142b8a36395SCameron Grant 143b8a36395SCameron Grant return; 144b8a36395SCameron Grant } 1450f55ac6cSCameron Grant fte->feederclass = fc; 1460f55ac6cSCameron Grant fte->desc = &fc->desc[i]; 147513693beSCameron Grant fte->idx = feedercnt; 148513693beSCameron Grant fte->desc->idx = feedercnt; 149513693beSCameron Grant SLIST_INSERT_HEAD(&feedertab, fte, link); 150513693beSCameron Grant i++; 151513693beSCameron Grant } 152513693beSCameron Grant feedercnt++; 153513693beSCameron Grant if (feedercnt >= MAXFEEDERS) 154b8a36395SCameron Grant printf("MAXFEEDERS (%d >= %d) exceeded\n", feedercnt, MAXFEEDERS); 155513693beSCameron Grant } 156513693beSCameron Grant 157effbadb7SCameron Grant static void 158effbadb7SCameron Grant feeder_unregisterall(void *p) 159effbadb7SCameron Grant { 160effbadb7SCameron Grant struct feedertab_entry *fte, *next; 161effbadb7SCameron Grant 162effbadb7SCameron Grant next = SLIST_FIRST(&feedertab); 163effbadb7SCameron Grant while (next != NULL) { 164effbadb7SCameron Grant fte = next; 165effbadb7SCameron Grant next = SLIST_NEXT(fte, link); 166effbadb7SCameron Grant free(fte, M_FEEDER); 167effbadb7SCameron Grant } 168effbadb7SCameron Grant } 169effbadb7SCameron Grant 170987e5972SCameron Grant static int 171513693beSCameron Grant cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 172987e5972SCameron Grant { 173c9c6ba09SCameron Grant return ((n->type == m->type) && 174c9c6ba09SCameron Grant ((n->in == 0) || (n->in == m->in)) && 175c9c6ba09SCameron Grant ((n->out == 0) || (n->out == m->out)) && 176c9c6ba09SCameron Grant (n->flags == m->flags)); 177987e5972SCameron Grant } 178987e5972SCameron Grant 1790f55ac6cSCameron Grant static void 18066ef8af5SCameron Grant feeder_destroy(struct pcm_feeder *f) 181987e5972SCameron Grant { 1820f55ac6cSCameron Grant FEEDER_FREE(f); 1830f55ac6cSCameron Grant kobj_delete((kobj_t)f, M_FEEDER); 184513693beSCameron Grant } 1850f55ac6cSCameron Grant 18666ef8af5SCameron Grant static struct pcm_feeder * 1870f55ac6cSCameron Grant feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc) 1880f55ac6cSCameron Grant { 18966ef8af5SCameron Grant struct pcm_feeder *f; 1900f55ac6cSCameron Grant int err; 1910f55ac6cSCameron Grant 192a7576e2eSOrion Hodson f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO); 193b8a36395SCameron Grant if (f == NULL) 194b8a36395SCameron Grant return NULL; 195b8a36395SCameron Grant 196b8a36395SCameron Grant f->data = fc->data; 197b8a36395SCameron Grant f->source = NULL; 198b8a36395SCameron Grant f->parent = NULL; 199b8a36395SCameron Grant f->class = fc; 200b8a36395SCameron Grant f->desc = &(f->desc_static); 201b8a36395SCameron Grant 202b8a36395SCameron Grant if (desc) { 2030f55ac6cSCameron Grant *(f->desc) = *desc; 204b8a36395SCameron Grant } else { 2050f55ac6cSCameron Grant f->desc->type = FEEDER_ROOT; 2060f55ac6cSCameron Grant f->desc->in = 0; 2070f55ac6cSCameron Grant f->desc->out = 0; 2080f55ac6cSCameron Grant f->desc->flags = 0; 2090f55ac6cSCameron Grant f->desc->idx = 0; 2100f55ac6cSCameron Grant } 211b8a36395SCameron Grant 2120f55ac6cSCameron Grant err = FEEDER_INIT(f); 2130f55ac6cSCameron Grant if (err) { 21466a3addbSCameron Grant printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err); 2150f55ac6cSCameron Grant feeder_destroy(f); 216b8a36395SCameron Grant 217513693beSCameron Grant return NULL; 218b8a36395SCameron Grant } 219b8a36395SCameron Grant 2200f55ac6cSCameron Grant return f; 221987e5972SCameron Grant } 222987e5972SCameron Grant 2230f55ac6cSCameron Grant struct feeder_class * 2240f55ac6cSCameron Grant feeder_getclass(struct pcm_feederdesc *desc) 225987e5972SCameron Grant { 226513693beSCameron Grant struct feedertab_entry *fte; 227987e5972SCameron Grant 228513693beSCameron Grant SLIST_FOREACH(fte, &feedertab, link) { 2290f55ac6cSCameron Grant if ((desc == NULL) && (fte->desc == NULL)) 2300f55ac6cSCameron Grant return fte->feederclass; 2310f55ac6cSCameron Grant if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc)) 2320f55ac6cSCameron Grant return fte->feederclass; 233513693beSCameron Grant } 234513693beSCameron Grant return NULL; 235987e5972SCameron Grant } 236987e5972SCameron Grant 237987e5972SCameron Grant int 23866ef8af5SCameron Grant chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) 239c9c6ba09SCameron Grant { 24066ef8af5SCameron Grant struct pcm_feeder *nf; 241c9c6ba09SCameron Grant 2420f55ac6cSCameron Grant nf = feeder_create(fc, desc); 2430f55ac6cSCameron Grant if (nf == NULL) 244b8a36395SCameron Grant return ENOSPC; 2450f55ac6cSCameron Grant 246c9c6ba09SCameron Grant nf->source = c->feeder; 2470f55ac6cSCameron Grant 248eaa69ee9SCameron Grant if (c->feeder != NULL) 249eaa69ee9SCameron Grant c->feeder->parent = nf; 250c9c6ba09SCameron Grant c->feeder = nf; 251c9c6ba09SCameron Grant 252c9c6ba09SCameron Grant return 0; 253c9c6ba09SCameron Grant } 254c9c6ba09SCameron Grant 255c9c6ba09SCameron Grant int 25666ef8af5SCameron Grant chn_removefeeder(struct pcm_channel *c) 257987e5972SCameron Grant { 25866ef8af5SCameron Grant struct pcm_feeder *f; 259513693beSCameron Grant 2600f55ac6cSCameron Grant if (c->feeder == NULL) 261513693beSCameron Grant return -1; 2620f55ac6cSCameron Grant f = c->feeder; 2630f55ac6cSCameron Grant c->feeder = c->feeder->source; 2640f55ac6cSCameron Grant feeder_destroy(f); 265b8a36395SCameron Grant 266987e5972SCameron Grant return 0; 267987e5972SCameron Grant } 268987e5972SCameron Grant 26966ef8af5SCameron Grant struct pcm_feeder * 27066ef8af5SCameron Grant chn_findfeeder(struct pcm_channel *c, u_int32_t type) 271c9c6ba09SCameron Grant { 27266ef8af5SCameron Grant struct pcm_feeder *f; 273c9c6ba09SCameron Grant 274c9c6ba09SCameron Grant f = c->feeder; 275c9c6ba09SCameron Grant while (f != NULL) { 276c9c6ba09SCameron Grant if (f->desc->type == type) 277c9c6ba09SCameron Grant return f; 278c9c6ba09SCameron Grant f = f->source; 279c9c6ba09SCameron Grant } 280b8a36395SCameron Grant 281c9c6ba09SCameron Grant return NULL; 282c9c6ba09SCameron Grant } 283c9c6ba09SCameron Grant 284a580b31aSAriff Abdullah /* 285a580b31aSAriff Abdullah * 14bit format scoring 286a580b31aSAriff Abdullah * -------------------- 287a580b31aSAriff Abdullah * 288a580b31aSAriff Abdullah * 13 12 11 10 9 8 2 1 0 offset 289a580b31aSAriff Abdullah * +---+---+---+---+---+---+-------------+---+---+ 290a580b31aSAriff Abdullah * | X | X | X | X | X | X | X X X X X X | X | X | 291a580b31aSAriff Abdullah * +---+---+---+---+---+---+-------------+---+---+ 292a580b31aSAriff Abdullah * | | | | | | | | | 293a580b31aSAriff Abdullah * | | | | | | | | +--> signed? 294a580b31aSAriff Abdullah * | | | | | | | | 295a580b31aSAriff Abdullah * | | | | | | | +------> bigendian? 296a580b31aSAriff Abdullah * | | | | | | | 297a580b31aSAriff Abdullah * | | | | | | +---------------> total channels 298a580b31aSAriff Abdullah * | | | | | | 299a580b31aSAriff Abdullah * | | | | | +------------------------> AFMT_A_LAW 300a580b31aSAriff Abdullah * | | | | | 301a580b31aSAriff Abdullah * | | | | +----------------------------> AFMT_MU_LAW 302a580b31aSAriff Abdullah * | | | | 303a580b31aSAriff Abdullah * | | | +--------------------------------> AFMT_8BIT 304a580b31aSAriff Abdullah * | | | 305a580b31aSAriff Abdullah * | | +------------------------------------> AFMT_16BIT 306a580b31aSAriff Abdullah * | | 307a580b31aSAriff Abdullah * | +----------------------------------------> AFMT_24BIT 308a580b31aSAriff Abdullah * | 309a580b31aSAriff Abdullah * +--------------------------------------------> AFMT_32BIT 310a580b31aSAriff Abdullah */ 311a580b31aSAriff Abdullah #define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1)) 312a580b31aSAriff Abdullah #define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2)) 313a580b31aSAriff Abdullah #define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc)) 31490da2b28SAriff Abdullah #define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc)) 31590da2b28SAriff Abdullah #define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc)) 316a580b31aSAriff Abdullah #define score_val(s1) ((s1) & 0x3f00) 317a580b31aSAriff Abdullah #define score_cse(s1) ((s1) & 0x7f) 318513693beSCameron Grant 319a580b31aSAriff Abdullah u_int32_t 32090da2b28SAriff Abdullah snd_fmtscore(u_int32_t fmt) 321d9bd8445SAriff Abdullah { 322a580b31aSAriff Abdullah u_int32_t ret; 323a580b31aSAriff Abdullah 324a580b31aSAriff Abdullah ret = 0; 325a580b31aSAriff Abdullah if (fmt & AFMT_SIGNED) 326a580b31aSAriff Abdullah ret |= 1 << 0; 327a580b31aSAriff Abdullah if (fmt & AFMT_BIGENDIAN) 328a580b31aSAriff Abdullah ret |= 1 << 1; 32990da2b28SAriff Abdullah /*if (fmt & AFMT_STEREO) 330a580b31aSAriff Abdullah ret |= (2 & 0x3f) << 2; 331a580b31aSAriff Abdullah else 33290da2b28SAriff Abdullah ret |= (1 & 0x3f) << 2;*/ 33390da2b28SAriff Abdullah ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2; 3344a193ac9SAriff Abdullah if (fmt & AFMT_A_LAW) 335a580b31aSAriff Abdullah ret |= 1 << 8; 336a580b31aSAriff Abdullah else if (fmt & AFMT_MU_LAW) 337a580b31aSAriff Abdullah ret |= 1 << 9; 338a580b31aSAriff Abdullah else if (fmt & AFMT_8BIT) 339a580b31aSAriff Abdullah ret |= 1 << 10; 340a580b31aSAriff Abdullah else if (fmt & AFMT_16BIT) 341a580b31aSAriff Abdullah ret |= 1 << 11; 342a580b31aSAriff Abdullah else if (fmt & AFMT_24BIT) 343a580b31aSAriff Abdullah ret |= 1 << 12; 344a580b31aSAriff Abdullah else if (fmt & AFMT_32BIT) 345a580b31aSAriff Abdullah ret |= 1 << 13; 346a580b31aSAriff Abdullah 347a580b31aSAriff Abdullah return ret; 348a580b31aSAriff Abdullah } 349a580b31aSAriff Abdullah 350a580b31aSAriff Abdullah static u_int32_t 35190da2b28SAriff Abdullah snd_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq) 352a580b31aSAriff Abdullah { 353a580b31aSAriff Abdullah u_int32_t best, score, score2, oldscore; 354a580b31aSAriff Abdullah int i; 355a580b31aSAriff Abdullah 356a580b31aSAriff Abdullah if (fmt == 0 || fmts == NULL || fmts[0] == 0) 3574a193ac9SAriff Abdullah return 0; 358a580b31aSAriff Abdullah 35990da2b28SAriff Abdullah if (snd_fmtvalid(fmt, fmts)) 360a580b31aSAriff Abdullah return fmt; 361a580b31aSAriff Abdullah 362a580b31aSAriff Abdullah best = 0; 36390da2b28SAriff Abdullah score = snd_fmtscore(fmt); 364a580b31aSAriff Abdullah oldscore = 0; 365a580b31aSAriff Abdullah for (i = 0; fmts[i] != 0; i++) { 36690da2b28SAriff Abdullah score2 = snd_fmtscore(fmts[i]); 36790da2b28SAriff Abdullah if (cheq && !score_cheq(score, score2) && 36890da2b28SAriff Abdullah (score_chlt(score2, score) || 36990da2b28SAriff Abdullah (oldscore != 0 && score_chgt(score2, oldscore)))) 370a580b31aSAriff Abdullah continue; 371a580b31aSAriff Abdullah if (oldscore == 0 || 372a580b31aSAriff Abdullah (score_val(score2) == score_val(score)) || 373a580b31aSAriff Abdullah (score_val(score2) == score_val(oldscore)) || 374a580b31aSAriff Abdullah (score_val(score2) > score_val(oldscore) && 375a580b31aSAriff Abdullah score_val(score2) < score_val(score)) || 376a580b31aSAriff Abdullah (score_val(score2) < score_val(oldscore) && 377a580b31aSAriff Abdullah score_val(score2) > score_val(score)) || 378a580b31aSAriff Abdullah (score_val(oldscore) < score_val(score) && 379a580b31aSAriff Abdullah score_val(score2) > score_val(oldscore))) { 380a580b31aSAriff Abdullah if (score_val(oldscore) != score_val(score2) || 381a580b31aSAriff Abdullah score_cse(score) == score_cse(score2) || 382a580b31aSAriff Abdullah ((score_cse(oldscore) != score_cse(score) && 383a580b31aSAriff Abdullah !score_endianeq(score, oldscore) && 384a580b31aSAriff Abdullah (score_endianeq(score, score2) || 385a580b31aSAriff Abdullah (!score_signeq(score, oldscore) && 386a580b31aSAriff Abdullah score_signeq(score, score2)))))) { 387a580b31aSAriff Abdullah best = fmts[i]; 388a580b31aSAriff Abdullah oldscore = score2; 389a580b31aSAriff Abdullah } 390a580b31aSAriff Abdullah } 391a580b31aSAriff Abdullah } 392a580b31aSAriff Abdullah return best; 393d9bd8445SAriff Abdullah } 394d9bd8445SAriff Abdullah 395d9bd8445SAriff Abdullah u_int32_t 39690da2b28SAriff Abdullah snd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts) 397d9bd8445SAriff Abdullah { 39890da2b28SAriff Abdullah return snd_fmtbestfunc(fmt, fmts, 0); 399d9bd8445SAriff Abdullah } 400d9bd8445SAriff Abdullah 401d9bd8445SAriff Abdullah u_int32_t 40290da2b28SAriff Abdullah snd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts) 403d9bd8445SAriff Abdullah { 40490da2b28SAriff Abdullah return snd_fmtbestfunc(fmt, fmts, 1); 405d9bd8445SAriff Abdullah } 406d9bd8445SAriff Abdullah 407d9bd8445SAriff Abdullah u_int32_t 40890da2b28SAriff Abdullah snd_fmtbest(u_int32_t fmt, u_int32_t *fmts) 409d9bd8445SAriff Abdullah { 410d9bd8445SAriff Abdullah u_int32_t best1, best2; 411a580b31aSAriff Abdullah u_int32_t score, score1, score2; 412a580b31aSAriff Abdullah 41390da2b28SAriff Abdullah if (snd_fmtvalid(fmt, fmts)) 414a580b31aSAriff Abdullah return fmt; 415d9bd8445SAriff Abdullah 41690da2b28SAriff Abdullah best1 = snd_fmtbestchannel(fmt, fmts); 41790da2b28SAriff Abdullah best2 = snd_fmtbestbit(fmt, fmts); 418d9bd8445SAriff Abdullah 419a580b31aSAriff Abdullah if (best1 != 0 && best2 != 0 && best1 != best2) { 42090da2b28SAriff Abdullah /*if (fmt & AFMT_STEREO)*/ 42190da2b28SAriff Abdullah if (AFMT_CHANNEL(fmt) > 1) 422d9bd8445SAriff Abdullah return best1; 423d9bd8445SAriff Abdullah else { 42490da2b28SAriff Abdullah score = score_val(snd_fmtscore(fmt)); 42590da2b28SAriff Abdullah score1 = score_val(snd_fmtscore(best1)); 42690da2b28SAriff Abdullah score2 = score_val(snd_fmtscore(best2)); 4274a193ac9SAriff Abdullah if (score1 == score2 || score1 == score) 4284a193ac9SAriff Abdullah return best1; 4294a193ac9SAriff Abdullah else if (score2 == score) 430d9bd8445SAriff Abdullah return best2; 4314a193ac9SAriff Abdullah else if (score1 > score2) 432d9bd8445SAriff Abdullah return best1; 433d9bd8445SAriff Abdullah return best2; 434d9bd8445SAriff Abdullah } 435d9bd8445SAriff Abdullah } else if (best2 == 0) 436d9bd8445SAriff Abdullah return best1; 437de49f325SJohn Baldwin else 438d9bd8445SAriff Abdullah return best2; 439d9bd8445SAriff Abdullah } 440d9bd8445SAriff Abdullah 441eaa69ee9SCameron Grant void 442eaa69ee9SCameron Grant feeder_printchain(struct pcm_feeder *head) 443eaa69ee9SCameron Grant { 444eaa69ee9SCameron Grant struct pcm_feeder *f; 445eaa69ee9SCameron Grant 446eaa69ee9SCameron Grant printf("feeder chain (head @%p)\n", head); 447eaa69ee9SCameron Grant f = head; 448eaa69ee9SCameron Grant while (f != NULL) { 449eaa69ee9SCameron Grant printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f); 450eaa69ee9SCameron Grant f = f->source; 451eaa69ee9SCameron Grant } 452eaa69ee9SCameron Grant printf("[end]\n\n"); 453eaa69ee9SCameron Grant } 454eaa69ee9SCameron Grant 455c9c6ba09SCameron Grant /*****************************************************************************/ 456c9c6ba09SCameron Grant 457c9c6ba09SCameron Grant static int 45866ef8af5SCameron Grant feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source) 459c9c6ba09SCameron Grant { 46066ef8af5SCameron Grant struct snd_dbuf *src = source; 461a580b31aSAriff Abdullah int l, offset; 462c9c6ba09SCameron Grant 46366ef8af5SCameron Grant KASSERT(count > 0, ("feed_root: count == 0")); 464c9c6ba09SCameron Grant 465a580b31aSAriff Abdullah if (++ch->feedcount == 0) 466a580b31aSAriff Abdullah ch->feedcount = 2; 467a580b31aSAriff Abdullah 46866ef8af5SCameron Grant l = min(count, sndbuf_getready(src)); 46966ef8af5SCameron Grant 470faea6799SOrion Hodson /* When recording only return as much data as available */ 471a580b31aSAriff Abdullah if (ch->direction == PCMDIR_REC) { 472a580b31aSAriff Abdullah sndbuf_dispose(src, buffer, l); 473faea6799SOrion Hodson return l; 474a580b31aSAriff Abdullah } 475faea6799SOrion Hodson 476a580b31aSAriff Abdullah offset = count - l; 477a580b31aSAriff Abdullah 478a580b31aSAriff Abdullah if (offset > 0) { 479a580b31aSAriff Abdullah if (snd_verbose > 3) 480a580b31aSAriff Abdullah printf("%s: (%s) %spending %d bytes " 481a580b31aSAriff Abdullah "(count=%d l=%d feed=%d)\n", 482a580b31aSAriff Abdullah __func__, 483a580b31aSAriff Abdullah (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware", 484a580b31aSAriff Abdullah (ch->feedcount == 1) ? "pre" : "ap", 485a580b31aSAriff Abdullah offset, count, l, ch->feedcount); 486a580b31aSAriff Abdullah 487a580b31aSAriff Abdullah if (ch->feedcount == 1) { 488a580b31aSAriff Abdullah memset(buffer, 489a580b31aSAriff Abdullah sndbuf_zerodata(sndbuf_getfmt(src)), 490a580b31aSAriff Abdullah offset); 491a580b31aSAriff Abdullah if (l > 0) 492a580b31aSAriff Abdullah sndbuf_dispose(src, buffer + offset, l); 493a580b31aSAriff Abdullah else 494a580b31aSAriff Abdullah ch->feedcount--; 495a580b31aSAriff Abdullah } else { 496a580b31aSAriff Abdullah if (l > 0) 497a580b31aSAriff Abdullah sndbuf_dispose(src, buffer, l); 498a580b31aSAriff Abdullah memset(buffer + l, 499a580b31aSAriff Abdullah sndbuf_zerodata(sndbuf_getfmt(src)), 500a580b31aSAriff Abdullah offset); 501a580b31aSAriff Abdullah if (!(ch->flags & CHN_F_CLOSING)) 502a580b31aSAriff Abdullah ch->xruns++; 503a580b31aSAriff Abdullah } 504a580b31aSAriff Abdullah } else if (l > 0) 505a580b31aSAriff Abdullah sndbuf_dispose(src, buffer, l); 506c9c6ba09SCameron Grant 507c9c6ba09SCameron Grant return count; 508c9c6ba09SCameron Grant } 5090f55ac6cSCameron Grant 5100f55ac6cSCameron Grant static kobj_method_t feeder_root_methods[] = { 5110f55ac6cSCameron Grant KOBJMETHOD(feeder_feed, feed_root), 51290da2b28SAriff Abdullah KOBJMETHOD_END 513c9c6ba09SCameron Grant }; 5140f55ac6cSCameron Grant static struct feeder_class feeder_root_class = { 51559873565SDiomidis Spinellis .name = "feeder_root", 51659873565SDiomidis Spinellis .methods = feeder_root_methods, 51759873565SDiomidis Spinellis .size = sizeof(struct pcm_feeder), 51859873565SDiomidis Spinellis .desc = NULL, 51959873565SDiomidis Spinellis .data = NULL, 5200f55ac6cSCameron Grant }; 5210f55ac6cSCameron Grant SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class); 522effbadb7SCameron Grant SYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL); 523