feeder.c revision 155958
1145256Sjkoshy/*- 2177107Sjkoshy * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3145256Sjkoshy * All rights reserved. 4145256Sjkoshy * 5145256Sjkoshy * Redistribution and use in source and binary forms, with or without 6145256Sjkoshy * modification, are permitted provided that the following conditions 7145256Sjkoshy * are met: 8145256Sjkoshy * 1. Redistributions of source code must retain the above copyright 9145256Sjkoshy * notice, this list of conditions and the following disclaimer. 10145256Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11145256Sjkoshy * notice, this list of conditions and the following disclaimer in the 12145256Sjkoshy * documentation and/or other materials provided with the distribution. 13145256Sjkoshy * 14145256Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15145256Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16145256Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17145256Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18145256Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19145256Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20145256Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21145256Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22145256Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23145256Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24145256Sjkoshy * SUCH DAMAGE. 25145256Sjkoshy */ 26145256Sjkoshy 27145256Sjkoshy#include <dev/sound/pcm/sound.h> 28145256Sjkoshy 29145256Sjkoshy#include "feeder_if.h" 30145256Sjkoshy 31145256SjkoshySND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/feeder.c 155958 2006-02-23 19:23:55Z jhb $"); 32145256Sjkoshy 33145256SjkoshyMALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder"); 34145256Sjkoshy 35145256Sjkoshy#define MAXFEEDERS 256 36145256Sjkoshy#undef FEEDER_DEBUG 37145256Sjkoshy 38145256Sjkoshystruct feedertab_entry { 39145256Sjkoshy SLIST_ENTRY(feedertab_entry) link; 40145256Sjkoshy struct feeder_class *feederclass; 41145256Sjkoshy struct pcm_feederdesc *desc; 42145256Sjkoshy 43145256Sjkoshy int idx; 44145256Sjkoshy}; 45145256Sjkoshystatic SLIST_HEAD(, feedertab_entry) feedertab; 46145340Smarcel 47145256Sjkoshy/*****************************************************************************/ 48145256Sjkoshy 49147191Sjkoshyvoid 50147759Sjkoshyfeeder_register(void *p) 51147191Sjkoshy{ 52145256Sjkoshy static int feedercnt = 0; 53147759Sjkoshy 54147759Sjkoshy struct feeder_class *fc = p; 55147191Sjkoshy struct feedertab_entry *fte; 56147191Sjkoshy int i; 57145256Sjkoshy 58145256Sjkoshy if (feedercnt == 0) { 59147191Sjkoshy KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name)); 60145256Sjkoshy 61145256Sjkoshy SLIST_INIT(&feedertab); 62145256Sjkoshy fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 63145256Sjkoshy if (fte == NULL) { 64145256Sjkoshy printf("can't allocate memory for root feeder: %s\n", 65145256Sjkoshy fc->name); 66145256Sjkoshy 67145256Sjkoshy return; 68145256Sjkoshy } 69145256Sjkoshy fte->feederclass = fc; 70145256Sjkoshy fte->desc = NULL; 71145256Sjkoshy fte->idx = feedercnt; 72145256Sjkoshy SLIST_INSERT_HEAD(&feedertab, fte, link); 73145256Sjkoshy feedercnt++; 74145256Sjkoshy 75145256Sjkoshy /* we've got our root feeder so don't veto pcm loading anymore */ 76145256Sjkoshy pcm_veto_load = 0; 77145256Sjkoshy 78145256Sjkoshy return; 79145256Sjkoshy } 80145256Sjkoshy 81145256Sjkoshy KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name)); 82145256Sjkoshy 83145256Sjkoshy /* beyond this point failure is non-fatal but may result in some translations being unavailable */ 84145256Sjkoshy i = 0; 85145256Sjkoshy while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) { 86145256Sjkoshy /* printf("adding feeder %s, %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); */ 87145256Sjkoshy fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 88145256Sjkoshy if (fte == NULL) { 89145256Sjkoshy printf("can't allocate memory for feeder '%s', %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); 90145256Sjkoshy 91145256Sjkoshy return; 92145256Sjkoshy } 93145256Sjkoshy fte->feederclass = fc; 94145256Sjkoshy fte->desc = &fc->desc[i]; 95145256Sjkoshy fte->idx = feedercnt; 96145256Sjkoshy fte->desc->idx = feedercnt; 97145256Sjkoshy SLIST_INSERT_HEAD(&feedertab, fte, link); 98145256Sjkoshy i++; 99145256Sjkoshy } 100145256Sjkoshy feedercnt++; 101145256Sjkoshy if (feedercnt >= MAXFEEDERS) 102145256Sjkoshy printf("MAXFEEDERS (%d >= %d) exceeded\n", feedercnt, MAXFEEDERS); 103145256Sjkoshy} 104145256Sjkoshy 105145256Sjkoshystatic void 106145256Sjkoshyfeeder_unregisterall(void *p) 107145256Sjkoshy{ 108145256Sjkoshy struct feedertab_entry *fte, *next; 109145256Sjkoshy 110145256Sjkoshy next = SLIST_FIRST(&feedertab); 111145256Sjkoshy while (next != NULL) { 112145256Sjkoshy fte = next; 113145256Sjkoshy next = SLIST_NEXT(fte, link); 114145256Sjkoshy free(fte, M_FEEDER); 115145256Sjkoshy } 116145256Sjkoshy} 117145256Sjkoshy 118145256Sjkoshystatic int 119145256Sjkoshycmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 120145256Sjkoshy{ 121145256Sjkoshy return ((n->type == m->type) && 122145256Sjkoshy ((n->in == 0) || (n->in == m->in)) && 123145256Sjkoshy ((n->out == 0) || (n->out == m->out)) && 124145256Sjkoshy (n->flags == m->flags)); 125145256Sjkoshy} 126145256Sjkoshy 127145256Sjkoshystatic void 128145256Sjkoshyfeeder_destroy(struct pcm_feeder *f) 129145256Sjkoshy{ 130145256Sjkoshy FEEDER_FREE(f); 131145256Sjkoshy kobj_delete((kobj_t)f, M_FEEDER); 132145256Sjkoshy} 133145256Sjkoshy 134145256Sjkoshystatic struct pcm_feeder * 135145256Sjkoshyfeeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc) 136145256Sjkoshy{ 137145256Sjkoshy struct pcm_feeder *f; 138145256Sjkoshy int err; 139145256Sjkoshy 140147219Sjkoshy f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO); 141145256Sjkoshy if (f == NULL) 142147219Sjkoshy return NULL; 143145256Sjkoshy 144145256Sjkoshy f->align = fc->align; 145145256Sjkoshy f->data = fc->data; 146145256Sjkoshy f->source = NULL; 147145256Sjkoshy f->parent = NULL; 148145256Sjkoshy f->class = fc; 149145256Sjkoshy f->desc = &(f->desc_static); 150145256Sjkoshy 151145256Sjkoshy if (desc) { 152145256Sjkoshy *(f->desc) = *desc; 153145256Sjkoshy } else { 154145256Sjkoshy f->desc->type = FEEDER_ROOT; 155147759Sjkoshy f->desc->in = 0; 156145256Sjkoshy f->desc->out = 0; 157145256Sjkoshy f->desc->flags = 0; 158145256Sjkoshy f->desc->idx = 0; 159145256Sjkoshy } 160145256Sjkoshy 161145256Sjkoshy err = FEEDER_INIT(f); 162145256Sjkoshy if (err) { 163145256Sjkoshy printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err); 164174406Sjkoshy feeder_destroy(f); 165145256Sjkoshy 166145256Sjkoshy return NULL; 167174406Sjkoshy } 168145256Sjkoshy 169145256Sjkoshy return f; 170145256Sjkoshy} 171145256Sjkoshy 172145256Sjkoshystruct feeder_class * 173174406Sjkoshyfeeder_getclass(struct pcm_feederdesc *desc) 174145256Sjkoshy{ 175145256Sjkoshy struct feedertab_entry *fte; 176145256Sjkoshy 177174406Sjkoshy SLIST_FOREACH(fte, &feedertab, link) { 178145256Sjkoshy if ((desc == NULL) && (fte->desc == NULL)) 179145340Smarcel return fte->feederclass; 180145256Sjkoshy if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc)) 181145256Sjkoshy return fte->feederclass; 182145256Sjkoshy } 183145256Sjkoshy return NULL; 184145256Sjkoshy} 185145340Smarcel 186145256Sjkoshyint 187145256Sjkoshychn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) 188145256Sjkoshy{ 189145256Sjkoshy struct pcm_feeder *nf; 190145256Sjkoshy 191145256Sjkoshy nf = feeder_create(fc, desc); 192145351Sjkoshy if (nf == NULL) 193145351Sjkoshy return ENOSPC; 194145351Sjkoshy 195145351Sjkoshy nf->source = c->feeder; 196145351Sjkoshy 197145351Sjkoshy /* XXX we should use the lowest common denominator for align */ 198145351Sjkoshy if (nf->align > 0) 199145351Sjkoshy c->align += nf->align; 200145256Sjkoshy else if (nf->align < 0 && c->align < -nf->align) 201145256Sjkoshy c->align = -nf->align; 202145256Sjkoshy if (c->feeder != NULL) 203145256Sjkoshy c->feeder->parent = nf; 204145256Sjkoshy c->feeder = nf; 205145256Sjkoshy 206145256Sjkoshy return 0; 207145256Sjkoshy} 208145256Sjkoshy 209145256Sjkoshyint 210145256Sjkoshychn_removefeeder(struct pcm_channel *c) 211145256Sjkoshy{ 212145256Sjkoshy struct pcm_feeder *f; 213145256Sjkoshy 214145256Sjkoshy if (c->feeder == NULL) 215145256Sjkoshy return -1; 216145256Sjkoshy f = c->feeder; 217147191Sjkoshy c->feeder = c->feeder->source; 218145256Sjkoshy feeder_destroy(f); 219145256Sjkoshy 220145256Sjkoshy return 0; 221145256Sjkoshy} 222145256Sjkoshy 223174406Sjkoshystruct pcm_feeder * 224174406Sjkoshychn_findfeeder(struct pcm_channel *c, u_int32_t type) 225145256Sjkoshy{ 226145256Sjkoshy struct pcm_feeder *f; 227145256Sjkoshy 228145256Sjkoshy f = c->feeder; 229145256Sjkoshy while (f != NULL) { 230145256Sjkoshy if (f->desc->type == type) 231147191Sjkoshy return f; 232145256Sjkoshy f = f->source; 233145256Sjkoshy } 234145256Sjkoshy 235145256Sjkoshy return NULL; 236145256Sjkoshy} 237145256Sjkoshy 238145256Sjkoshystatic int 239145256Sjkoshychainok(struct pcm_feeder *test, struct pcm_feeder *stop) 240145256Sjkoshy{ 241174406Sjkoshy u_int32_t visited[MAXFEEDERS / 32]; 242145256Sjkoshy u_int32_t idx, mask; 243145256Sjkoshy 244145256Sjkoshy bzero(visited, sizeof(visited)); 245174406Sjkoshy while (test && (test != stop)) { 246145256Sjkoshy idx = test->desc->idx; 247145256Sjkoshy if (idx < 0) 248147191Sjkoshy panic("bad idx %d", idx); 249147191Sjkoshy if (idx >= MAXFEEDERS) 250145256Sjkoshy panic("bad idx %d", idx); 251145256Sjkoshy mask = 1 << (idx & 31); 252145256Sjkoshy idx >>= 5; 253145256Sjkoshy if (visited[idx] & mask) 254145256Sjkoshy return 0; 255145256Sjkoshy visited[idx] |= mask; 256145256Sjkoshy test = test->source; 257145256Sjkoshy } 258145256Sjkoshy 259174406Sjkoshy return 1; 260145256Sjkoshy} 261145256Sjkoshy 262145256Sjkoshystatic struct pcm_feeder * 263174406Sjkoshyfeeder_fmtchain(u_int32_t *to, struct pcm_feeder *source, struct pcm_feeder *stop, int maxdepth) 264145256Sjkoshy{ 265145256Sjkoshy struct feedertab_entry *fte; 266145256Sjkoshy struct pcm_feeder *try, *ret; 267147191Sjkoshy 268145256Sjkoshy DEB(printf("trying %s (0x%08x -> 0x%08x)...\n", source->class->name, source->desc->in, source->desc->out)); 269147191Sjkoshy if (fmtvalid(source->desc->out, to)) { 270145256Sjkoshy DEB(printf("got it\n")); 271147191Sjkoshy return source; 272145256Sjkoshy } 273147191Sjkoshy 274145256Sjkoshy if (maxdepth < 0) 275147191Sjkoshy return NULL; 276145256Sjkoshy 277145256Sjkoshy SLIST_FOREACH(fte, &feedertab, link) { 278145256Sjkoshy if (fte->desc == NULL) 279174406Sjkoshy continue; 280145256Sjkoshy if (fte->desc->type != FEEDER_FMT) 281145256Sjkoshy continue; 282174406Sjkoshy if (fte->desc->in == source->desc->out) { 283145256Sjkoshy try = feeder_create(fte->feederclass, fte->desc); 284145256Sjkoshy if (try) { 285145256Sjkoshy try->source = source; 286145256Sjkoshy ret = chainok(try, stop)? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL; 287174406Sjkoshy if (ret != NULL) 288145256Sjkoshy return ret; 289145256Sjkoshy feeder_destroy(try); 290145256Sjkoshy } 291145256Sjkoshy } 292147191Sjkoshy } 293147191Sjkoshy /* printf("giving up %s...\n", source->class->name); */ 294145256Sjkoshy 295145256Sjkoshy return NULL; 296174406Sjkoshy} 297145256Sjkoshy 298145256Sjkoshyint 299145256Sjkoshychn_fmtscore(u_int32_t fmt) 300147191Sjkoshy{ 301147191Sjkoshy if (fmt & AFMT_32BIT) 302147759Sjkoshy return 60; 303147191Sjkoshy if (fmt & AFMT_24BIT) 304145256Sjkoshy return 50; 305147191Sjkoshy if (fmt & AFMT_16BIT) 306147191Sjkoshy return 40; 307147191Sjkoshy if (fmt & (AFMT_U8|AFMT_S8)) 308147191Sjkoshy return 30; 309147191Sjkoshy if (fmt & AFMT_MU_LAW) 310147191Sjkoshy return 20; 311147191Sjkoshy if (fmt & AFMT_A_LAW) 312147191Sjkoshy return 10; 313147191Sjkoshy return 0; 314147191Sjkoshy} 315147191Sjkoshy 316147191Sjkoshyu_int32_t 317147191Sjkoshychn_fmtbestbit(u_int32_t fmt, u_int32_t *fmts) 318147191Sjkoshy{ 319147191Sjkoshy u_int32_t best; 320155998Sjkoshy int i, score, score2, oldscore; 321147191Sjkoshy 322147191Sjkoshy best = 0; 323147191Sjkoshy score = chn_fmtscore(fmt); 324147191Sjkoshy oldscore = 0; 325147191Sjkoshy for (i = 0; fmts[i] != 0; i++) { 326147191Sjkoshy score2 = chn_fmtscore(fmts[i]); 327147191Sjkoshy if (oldscore == 0 || (score2 == score) || 328147191Sjkoshy (score2 > oldscore && score2 < score) || 329147191Sjkoshy (score2 < oldscore && score2 > score) || 330147191Sjkoshy (oldscore < score && score2 > oldscore)) { 331147191Sjkoshy best = fmts[i]; 332147191Sjkoshy oldscore = score2; 333147191Sjkoshy } 334147191Sjkoshy } 335147191Sjkoshy return best; 336147191Sjkoshy} 337147191Sjkoshy 338147191Sjkoshyu_int32_t 339147191Sjkoshychn_fmtbeststereo(u_int32_t fmt, u_int32_t *fmts) 340147191Sjkoshy{ 341147191Sjkoshy u_int32_t best; 342147191Sjkoshy int i, score, score2, oldscore; 343147191Sjkoshy 344147191Sjkoshy best = 0; 345147191Sjkoshy score = chn_fmtscore(fmt); 346147191Sjkoshy oldscore = 0; 347147191Sjkoshy for (i = 0; fmts[i] != 0; i++) { 348147191Sjkoshy if ((fmt & AFMT_STEREO) == (fmts[i] & AFMT_STEREO)) { 349147191Sjkoshy score2 = chn_fmtscore(fmts[i]); 350147191Sjkoshy if (oldscore == 0 || (score2 == score) || 351147191Sjkoshy (score2 > oldscore && score2 < score) || 352147191Sjkoshy (score2 < oldscore && score2 > score) || 353147191Sjkoshy (oldscore < score && score2 > oldscore)) { 354147191Sjkoshy best = fmts[i]; 355147191Sjkoshy oldscore = score2; 356147191Sjkoshy } 357147191Sjkoshy } 358147191Sjkoshy } 359147191Sjkoshy return best; 360147191Sjkoshy} 361147191Sjkoshy 362147191Sjkoshyu_int32_t 363147191Sjkoshychn_fmtbest(u_int32_t fmt, u_int32_t *fmts) 364147191Sjkoshy{ 365147191Sjkoshy u_int32_t best1, best2; 366147191Sjkoshy int score, score1, score2; 367147191Sjkoshy 368147191Sjkoshy best1 = chn_fmtbeststereo(fmt, fmts); 369147191Sjkoshy best2 = chn_fmtbestbit(fmt, fmts); 370147191Sjkoshy 371147191Sjkoshy if (best1 != 0 && best2 != 0) { 372147191Sjkoshy if (fmt & AFMT_STEREO) 373147191Sjkoshy return best1; 374147191Sjkoshy else { 375147191Sjkoshy score = chn_fmtscore(fmt); 376147191Sjkoshy score1 = chn_fmtscore(best1); 377147191Sjkoshy score2 = chn_fmtscore(best2); 378147191Sjkoshy if (score1 == score2 || score1 == score) 379147191Sjkoshy return best1; 380147191Sjkoshy else if (score2 == score) 381147191Sjkoshy return best2; 382147191Sjkoshy else if (score1 > score2) 383147191Sjkoshy return best1; 384147191Sjkoshy return best2; 385147191Sjkoshy } 386147191Sjkoshy } else if (best2 == 0) 387147191Sjkoshy return best1; 388147191Sjkoshy else 389147191Sjkoshy return best2; 390147191Sjkoshy} 391147191Sjkoshy 392147191Sjkoshyu_int32_t 393147191Sjkoshychn_fmtchain(struct pcm_channel *c, u_int32_t *to) 394147191Sjkoshy{ 395147191Sjkoshy struct pcm_feeder *try, *del, *stop; 396147191Sjkoshy u_int32_t tmpfrom[2], tmpto[2], best, *from; 397147191Sjkoshy int i, max, bestmax; 398147191Sjkoshy 399147191Sjkoshy KASSERT(c != NULL, ("c == NULL")); 400147191Sjkoshy KASSERT(c->feeder != NULL, ("c->feeder == NULL")); 401147191Sjkoshy KASSERT(to != NULL, ("to == NULL")); 402147191Sjkoshy KASSERT(to[0] != 0, ("to[0] == 0")); 403147191Sjkoshy 404147191Sjkoshy stop = c->feeder; 405147191Sjkoshy 406147191Sjkoshy if (c->direction == PCMDIR_REC && c->feeder->desc->type == FEEDER_ROOT) { 407147191Sjkoshy from = chn_getcaps(c)->fmtlist; 408147191Sjkoshy if (fmtvalid(to[0], from)) 409147191Sjkoshy from = to; 410147191Sjkoshy else { 411147191Sjkoshy best = chn_fmtbest(to[0], from); 412147191Sjkoshy if (best != 0) { 413147191Sjkoshy tmpfrom[0] = best; 414147191Sjkoshy tmpfrom[1] = 0; 415147191Sjkoshy from = tmpfrom; 416147191Sjkoshy } 417147191Sjkoshy } 418147191Sjkoshy } else { 419147191Sjkoshy tmpfrom[0] = c->feeder->desc->out; 420147191Sjkoshy tmpfrom[1] = 0; 421147191Sjkoshy from = tmpfrom; 422147191Sjkoshy if (to[1] != 0) { 423147191Sjkoshy if (fmtvalid(tmpfrom[0], to)) { 424147191Sjkoshy tmpto[0] = tmpfrom[0]; 425147191Sjkoshy tmpto[1] = 0; 426147191Sjkoshy to = tmpto; 427147191Sjkoshy } else { 428147191Sjkoshy best = chn_fmtbest(tmpfrom[0], to); 429147191Sjkoshy if (best != 0) { 430147191Sjkoshy tmpto[0] = best; 431147191Sjkoshy tmpto[1] = 0; 432147191Sjkoshy to = tmpto; 433147191Sjkoshy } 434147191Sjkoshy } 435147191Sjkoshy } 436147191Sjkoshy } 437147191Sjkoshy 438147191Sjkoshy i = 0; 439147191Sjkoshy best = 0; 440147191Sjkoshy bestmax = 100; 441147191Sjkoshy while (from[i] != 0) { 442147191Sjkoshy c->feeder->desc->out = from[i]; 443147191Sjkoshy try = NULL; 444147191Sjkoshy max = 0; 445147191Sjkoshy while (try == NULL && max < 8) { 446147191Sjkoshy try = feeder_fmtchain(to, c->feeder, stop, max); 447147191Sjkoshy if (try == NULL) 448147191Sjkoshy max++; 449147191Sjkoshy } 450147191Sjkoshy if (try != NULL && max < bestmax) { 451147191Sjkoshy bestmax = max; 452147191Sjkoshy best = from[i]; 453147191Sjkoshy } 454147191Sjkoshy while (try != NULL && try != stop) { 455147191Sjkoshy del = try; 456147191Sjkoshy try = try->source; 457147191Sjkoshy feeder_destroy(del); 458147191Sjkoshy } 459147191Sjkoshy i++; 460147191Sjkoshy } 461147191Sjkoshy if (best == 0) 462147191Sjkoshy return 0; 463147191Sjkoshy 464147191Sjkoshy c->feeder->desc->out = best; 465147191Sjkoshy try = feeder_fmtchain(to, c->feeder, stop, bestmax); 466147191Sjkoshy if (try == NULL) 467147191Sjkoshy return 0; 468147191Sjkoshy 469147191Sjkoshy c->feeder = try; 470147191Sjkoshy c->align = 0; 471147191Sjkoshy#ifdef FEEDER_DEBUG 472147191Sjkoshy printf("\n\nchain: "); 473147191Sjkoshy#endif 474147191Sjkoshy while (try && (try != stop)) { 475147191Sjkoshy#ifdef FEEDER_DEBUG 476147191Sjkoshy printf("%s [%d]", try->class->name, try->desc->idx); 477147191Sjkoshy if (try->source) 478147191Sjkoshy printf(" -> "); 479147191Sjkoshy#endif 480147191Sjkoshy if (try->source) 481147191Sjkoshy try->source->parent = try; 482147191Sjkoshy if (try->align > 0) 483147191Sjkoshy c->align += try->align; 484147191Sjkoshy else if (try->align < 0 && c->align < -try->align) 485147191Sjkoshy c->align = -try->align; 486147191Sjkoshy try = try->source; 487147191Sjkoshy } 488147191Sjkoshy#ifdef FEEDER_DEBUG 489147191Sjkoshy printf("%s [%d]\n", try->class->name, try->desc->idx); 490147191Sjkoshy#endif 491147191Sjkoshy 492147191Sjkoshy if (c->direction == PCMDIR_REC) { 493147191Sjkoshy try = c->feeder; 494147191Sjkoshy while (try != NULL) { 495147191Sjkoshy if (try->desc->type == FEEDER_ROOT) 496147191Sjkoshy return try->desc->out; 497147191Sjkoshy try = try->source; 498147191Sjkoshy } 499147191Sjkoshy return best; 500147191Sjkoshy } else 501147191Sjkoshy return c->feeder->desc->out; 502147191Sjkoshy} 503147191Sjkoshy 504147191Sjkoshyvoid 505147191Sjkoshyfeeder_printchain(struct pcm_feeder *head) 506147191Sjkoshy{ 507147191Sjkoshy struct pcm_feeder *f; 508147191Sjkoshy 509147191Sjkoshy printf("feeder chain (head @%p)\n", head); 510147191Sjkoshy f = head; 511147191Sjkoshy while (f != NULL) { 512147191Sjkoshy printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f); 513147191Sjkoshy f = f->source; 514147191Sjkoshy } 515147191Sjkoshy printf("[end]\n\n"); 516147191Sjkoshy} 517147191Sjkoshy 518147191Sjkoshy/*****************************************************************************/ 519147191Sjkoshy 520147191Sjkoshystatic int 521147191Sjkoshyfeed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source) 522147191Sjkoshy{ 523174406Sjkoshy struct snd_dbuf *src = source; 524174406Sjkoshy int l; 525147191Sjkoshy u_int8_t x; 526147191Sjkoshy 527147191Sjkoshy KASSERT(count > 0, ("feed_root: count == 0")); 528147191Sjkoshy /* count &= ~((1 << ch->align) - 1); */ 529147191Sjkoshy KASSERT(count > 0, ("feed_root: aligned count == 0 (align = %d)", ch->align)); 530147191Sjkoshy 531147191Sjkoshy l = min(count, sndbuf_getready(src)); 532147191Sjkoshy sndbuf_dispose(src, buffer, l); 533147191Sjkoshy 534147191Sjkoshy /* When recording only return as much data as available */ 535147191Sjkoshy if (ch->direction == PCMDIR_REC) 536147191Sjkoshy return l; 537147191Sjkoshy 538147191Sjkoshy/* 539147191Sjkoshy if (l < count) 540147191Sjkoshy printf("appending %d bytes\n", count - l); 541147191Sjkoshy*/ 542147191Sjkoshy 543147191Sjkoshy x = (sndbuf_getfmt(src) & AFMT_SIGNED)? 0 : 0x80; 544147191Sjkoshy while (l < count) 545147191Sjkoshy buffer[l++] = x; 546147191Sjkoshy 547147191Sjkoshy return count; 548147191Sjkoshy} 549147191Sjkoshy 550147191Sjkoshystatic kobj_method_t feeder_root_methods[] = { 551147191Sjkoshy KOBJMETHOD(feeder_feed, feed_root), 552147191Sjkoshy { 0, 0 } 553147191Sjkoshy}; 554147191Sjkoshystatic struct feeder_class feeder_root_class = { 555147191Sjkoshy .name = "feeder_root", 556147191Sjkoshy .methods = feeder_root_methods, 557147191Sjkoshy .size = sizeof(struct pcm_feeder), 558147191Sjkoshy .align = 0, 559147191Sjkoshy .desc = NULL, 560147191Sjkoshy .data = NULL, 561147191Sjkoshy}; 562147191SjkoshySYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class); 563147191SjkoshySYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL); 564147191Sjkoshy 565147191Sjkoshy 566147191Sjkoshy 567147191Sjkoshy 568147191Sjkoshy 569147191Sjkoshy