1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <dev/sound/pcm/sound.h> 28 29 #include "feeder_if.h" 30 31 SND_DECLARE_FILE("$FreeBSD$"); 32 33 MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder"); 34 35 #define MAXFEEDERS 256 36 #undef FEEDER_DEBUG 37 38 int feeder_buffersize = FEEDBUFSZ; 39 TUNABLE_INT("hw.snd.feeder_buffersize", &feeder_buffersize); 40 SYSCTL_INT(_hw_snd, OID_AUTO, feeder_buffersize, CTLFLAG_RD, 41 &feeder_buffersize, FEEDBUFSZ, "feeder buffer size"); 42 43 struct feedertab_entry { 44 SLIST_ENTRY(feedertab_entry) link; 45 struct feeder_class *feederclass; 46 struct pcm_feederdesc *desc; 47 48 int idx; 49 }; 50 static SLIST_HEAD(, feedertab_entry) feedertab; 51 52 /*****************************************************************************/ 53 54 void 55 feeder_register(void *p) 56 { 57 static int feedercnt = 0; 58 59 struct feeder_class *fc = p; 60 struct feedertab_entry *fte; 61 int i; 62 63 if (feedercnt == 0) { 64 KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name)); 65 66 SLIST_INIT(&feedertab); 67 fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 68 if (fte == NULL) { 69 printf("can't allocate memory for root feeder: %s\n", 70 fc->name); 71 72 return; 73 } 74 fte->feederclass = fc; 75 fte->desc = NULL; 76 fte->idx = feedercnt; 77 SLIST_INSERT_HEAD(&feedertab, fte, link); 78 feedercnt++; 79 80 /* initialize global variables */ 81 82 if (snd_verbose < 0 || snd_verbose > 3) 83 snd_verbose = 1; 84 85 if (snd_unit < 0 || snd_unit > PCMMAXDEV) 86 snd_unit = 0; 87 88 if (snd_maxautovchans < 0 || 89 snd_maxautovchans > SND_MAXVCHANS) 90 snd_maxautovchans = 0; 91 92 if (chn_latency < CHN_LATENCY_MIN || 93 chn_latency > CHN_LATENCY_MAX) 94 chn_latency = CHN_LATENCY_DEFAULT; 95 96 if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN || 97 chn_latency_profile > CHN_LATENCY_PROFILE_MAX) 98 chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; 99 100 if (feeder_buffersize < FEEDBUFSZ_MIN || 101 feeder_buffersize > FEEDBUFSZ_MAX) 102 feeder_buffersize = FEEDBUFSZ; 103 104 if (feeder_rate_min < FEEDRATE_MIN || 105 feeder_rate_max < FEEDRATE_MIN || 106 feeder_rate_min > FEEDRATE_MAX || 107 feeder_rate_max > FEEDRATE_MAX || 108 !(feeder_rate_min < feeder_rate_max)) { 109 feeder_rate_min = FEEDRATE_RATEMIN; 110 feeder_rate_max = FEEDRATE_RATEMAX; 111 } 112 113 if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN || 114 feeder_rate_round > FEEDRATE_ROUNDHZ_MAX) 115 feeder_rate_round = FEEDRATE_ROUNDHZ; 116 117 if (bootverbose) 118 printf("%s: snd_unit=%d snd_maxautovchans=%d " 119 "latency=%d feeder_buffersize=%d " 120 "feeder_rate_min=%d feeder_rate_max=%d " 121 "feeder_rate_round=%d\n", 122 __func__, snd_unit, snd_maxautovchans, 123 chn_latency, feeder_buffersize, 124 feeder_rate_min, feeder_rate_max, 125 feeder_rate_round); 126 127 /* we've got our root feeder so don't veto pcm loading anymore */ 128 pcm_veto_load = 0; 129 130 return; 131 } 132 133 KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name)); 134 135 /* beyond this point failure is non-fatal but may result in some translations being unavailable */ 136 i = 0; 137 while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) { 138 /* printf("adding feeder %s, %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); */ 139 fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 140 if (fte == NULL) { 141 printf("can't allocate memory for feeder '%s', %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); 142 143 return; 144 } 145 fte->feederclass = fc; 146 fte->desc = &fc->desc[i]; 147 fte->idx = feedercnt; 148 fte->desc->idx = feedercnt; 149 SLIST_INSERT_HEAD(&feedertab, fte, link); 150 i++; 151 } 152 feedercnt++; 153 if (feedercnt >= MAXFEEDERS) 154 printf("MAXFEEDERS (%d >= %d) exceeded\n", feedercnt, MAXFEEDERS); 155 } 156 157 static void 158 feeder_unregisterall(void *p) 159 { 160 struct feedertab_entry *fte, *next; 161 162 next = SLIST_FIRST(&feedertab); 163 while (next != NULL) { 164 fte = next; 165 next = SLIST_NEXT(fte, link); 166 free(fte, M_FEEDER); 167 } 168 } 169 170 static int 171 cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 172 { 173 return ((n->type == m->type) && 174 ((n->in == 0) || (n->in == m->in)) && 175 ((n->out == 0) || (n->out == m->out)) && 176 (n->flags == m->flags)); 177 } 178 179 static void 180 feeder_destroy(struct pcm_feeder *f) 181 { 182 FEEDER_FREE(f); 183 kobj_delete((kobj_t)f, M_FEEDER); 184 } 185 186 static struct pcm_feeder * 187 feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc) 188 { 189 struct pcm_feeder *f; 190 int err; 191 192 f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO); 193 if (f == NULL) 194 return NULL; 195 196 f->align = fc->align; 197 f->data = fc->data; 198 f->source = NULL; 199 f->parent = NULL; 200 f->class = fc; 201 f->desc = &(f->desc_static); 202 203 if (desc) { 204 *(f->desc) = *desc; 205 } else { 206 f->desc->type = FEEDER_ROOT; 207 f->desc->in = 0; 208 f->desc->out = 0; 209 f->desc->flags = 0; 210 f->desc->idx = 0; 211 } 212 213 err = FEEDER_INIT(f); 214 if (err) { 215 printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err); 216 feeder_destroy(f); 217 218 return NULL; 219 } 220 221 return f; 222 } 223 224 struct feeder_class * 225 feeder_getclass(struct pcm_feederdesc *desc) 226 { 227 struct feedertab_entry *fte; 228 229 SLIST_FOREACH(fte, &feedertab, link) { 230 if ((desc == NULL) && (fte->desc == NULL)) 231 return fte->feederclass; 232 if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc)) 233 return fte->feederclass; 234 } 235 return NULL; 236 } 237 238 int 239 chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) 240 { 241 struct pcm_feeder *nf; 242 243 nf = feeder_create(fc, desc); 244 if (nf == NULL) 245 return ENOSPC; 246 247 nf->source = c->feeder; 248 249 /* XXX we should use the lowest common denominator for align */ 250 if (nf->align > 0) 251 c->align += nf->align; 252 else if (nf->align < 0 && c->align < -nf->align) 253 c->align = -nf->align; 254 if (c->feeder != NULL) 255 c->feeder->parent = nf; 256 c->feeder = nf; 257 258 return 0; 259 } 260 261 int 262 chn_removefeeder(struct pcm_channel *c) 263 { 264 struct pcm_feeder *f; 265 266 if (c->feeder == NULL) 267 return -1; 268 f = c->feeder; 269 c->feeder = c->feeder->source; 270 feeder_destroy(f); 271 272 return 0; 273 } 274 275 struct pcm_feeder * 276 chn_findfeeder(struct pcm_channel *c, u_int32_t type) 277 { 278 struct pcm_feeder *f; 279 280 f = c->feeder; 281 while (f != NULL) { 282 if (f->desc->type == type) 283 return f; 284 f = f->source; 285 } 286 287 return NULL; 288 } 289 290 static int 291 chainok(struct pcm_feeder *test, struct pcm_feeder *stop) 292 { 293 u_int32_t visited[MAXFEEDERS / 32]; 294 u_int32_t idx, mask; 295 296 bzero(visited, sizeof(visited)); 297 while (test && (test != stop)) { 298 idx = test->desc->idx; 299 if (idx < 0) 300 panic("bad idx %d", idx); 301 if (idx >= MAXFEEDERS) 302 panic("bad idx %d", idx); 303 mask = 1 << (idx & 31); 304 idx >>= 5; 305 if (visited[idx] & mask) 306 return 0; 307 visited[idx] |= mask; 308 test = test->source; 309 } 310 311 return 1; 312 } 313 314 /* 315 * See feeder_fmtchain() for the mumbo-jumbo ridiculous explaination 316 * of what the heck is this FMT_Q_* 317 */ 318 #define FMT_Q_UP 1 319 #define FMT_Q_DOWN 2 320 #define FMT_Q_EQ 3 321 #define FMT_Q_MULTI 4 322 323 /* 324 * 14bit format scoring 325 * -------------------- 326 * 327 * 13 12 11 10 9 8 2 1 0 offset 328 * +---+---+---+---+---+---+-------------+---+---+ 329 * | X | X | X | X | X | X | X X X X X X | X | X | 330 * +---+---+---+---+---+---+-------------+---+---+ 331 * | | | | | | | | | 332 * | | | | | | | | +--> signed? 333 * | | | | | | | | 334 * | | | | | | | +------> bigendian? 335 * | | | | | | | 336 * | | | | | | +---------------> total channels 337 * | | | | | | 338 * | | | | | +------------------------> AFMT_A_LAW 339 * | | | | | 340 * | | | | +----------------------------> AFMT_MU_LAW 341 * | | | | 342 * | | | +--------------------------------> AFMT_8BIT 343 * | | | 344 * | | +------------------------------------> AFMT_16BIT 345 * | | 346 * | +----------------------------------------> AFMT_24BIT 347 * | 348 * +--------------------------------------------> AFMT_32BIT 349 */ 350 #define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1)) 351 #define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2)) 352 #define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc)) 353 #define score_val(s1) ((s1) & 0x3f00) 354 #define score_cse(s1) ((s1) & 0x7f) 355 356 u_int32_t 357 chn_fmtscore(u_int32_t fmt) 358 { 359 u_int32_t ret; 360 361 ret = 0; 362 if (fmt & AFMT_SIGNED) 363 ret |= 1 << 0; 364 if (fmt & AFMT_BIGENDIAN) 365 ret |= 1 << 1; 366 if (fmt & AFMT_STEREO) 367 ret |= (2 & 0x3f) << 2; 368 else 369 ret |= (1 & 0x3f) << 2; 370 if (fmt & AFMT_A_LAW) 371 ret |= 1 << 8; 372 else if (fmt & AFMT_MU_LAW) 373 ret |= 1 << 9; 374 else if (fmt & AFMT_8BIT) 375 ret |= 1 << 10; 376 else if (fmt & AFMT_16BIT) 377 ret |= 1 << 11; 378 else if (fmt & AFMT_24BIT) 379 ret |= 1 << 12; 380 else if (fmt & AFMT_32BIT) 381 ret |= 1 << 13; 382 383 return ret; 384 } 385 386 static u_int32_t 387 chn_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq) 388 { 389 u_int32_t best, score, score2, oldscore; 390 int i; 391 392 if (fmt == 0 || fmts == NULL || fmts[0] == 0) 393 return 0; 394 395 if (fmtvalid(fmt, fmts)) 396 return fmt; 397 398 best = 0; 399 score = chn_fmtscore(fmt); 400 oldscore = 0; 401 for (i = 0; fmts[i] != 0; i++) { 402 score2 = chn_fmtscore(fmts[i]); 403 if (cheq && !score_cheq(score, score2)) 404 continue; 405 if (oldscore == 0 || 406 (score_val(score2) == score_val(score)) || 407 (score_val(score2) == score_val(oldscore)) || 408 (score_val(score2) > score_val(oldscore) && 409 score_val(score2) < score_val(score)) || 410 (score_val(score2) < score_val(oldscore) && 411 score_val(score2) > score_val(score)) || 412 (score_val(oldscore) < score_val(score) && 413 score_val(score2) > score_val(oldscore))) { 414 if (score_val(oldscore) != score_val(score2) || 415 score_cse(score) == score_cse(score2) || 416 ((score_cse(oldscore) != score_cse(score) && 417 !score_endianeq(score, oldscore) && 418 (score_endianeq(score, score2) || 419 (!score_signeq(score, oldscore) && 420 score_signeq(score, score2)))))) { 421 best = fmts[i]; 422 oldscore = score2; 423 } 424 } 425 } 426 return best; 427 } 428 429 u_int32_t 430 chn_fmtbestbit(u_int32_t fmt, u_int32_t *fmts) 431 { 432 return chn_fmtbestfunc(fmt, fmts, 0); 433 } 434 435 u_int32_t 436 chn_fmtbeststereo(u_int32_t fmt, u_int32_t *fmts) 437 { 438 return chn_fmtbestfunc(fmt, fmts, 1); 439 } 440 441 u_int32_t 442 chn_fmtbest(u_int32_t fmt, u_int32_t *fmts) 443 { 444 u_int32_t best1, best2; 445 u_int32_t score, score1, score2; 446 447 if (fmtvalid(fmt, fmts)) 448 return fmt; 449 450 best1 = chn_fmtbeststereo(fmt, fmts); 451 best2 = chn_fmtbestbit(fmt, fmts); 452 453 if (best1 != 0 && best2 != 0 && best1 != best2) { 454 if (fmt & AFMT_STEREO) 455 return best1; 456 else { 457 score = score_val(chn_fmtscore(fmt)); 458 score1 = score_val(chn_fmtscore(best1)); 459 score2 = score_val(chn_fmtscore(best2)); 460 if (score1 == score2 || score1 == score) 461 return best1; 462 else if (score2 == score) 463 return best2; 464 else if (score1 > score2) 465 return best1; 466 return best2; 467 } 468 } else if (best2 == 0) 469 return best1; 470 else 471 return best2; 472 } 473 474 static struct pcm_feeder * 475 feeder_fmtchain(u_int32_t *to, struct pcm_feeder *source, struct pcm_feeder *stop, int maxdepth) 476 { 477 struct feedertab_entry *fte, *ftebest; 478 struct pcm_feeder *try, *ret; 479 uint32_t fl, qout, qsrc, qdst; 480 int qtype; 481 482 if (to == NULL || to[0] == 0) 483 return NULL; 484 485 DEB(printf("trying %s (0x%08x -> 0x%08x)...\n", source->class->name, source->desc->in, source->desc->out)); 486 if (fmtvalid(source->desc->out, to)) { 487 DEB(printf("got it\n")); 488 return source; 489 } 490 491 if (maxdepth < 0) 492 return NULL; 493 494 /* 495 * WARNING: THIS IS _NOT_ FOR THE FAINT HEART 496 * Disclaimer: I don't expect anybody could understand this 497 * without deep logical and mathematical analysis 498 * involving various unnamed probability theorem. 499 * 500 * This "Best Fit Random Chain Selection" (BLEHBLEHWHATEVER) algorithm 501 * is **extremely** difficult to digest especially when applied to 502 * large sets / numbers of random chains (feeders), each with 503 * unique characteristic providing different sets of in/out format. 504 * 505 * Basically, our FEEDER_FMT (see feeder_fmt.c) chains characteristic: 506 * 1) Format chains 507 * 1.1 "8bit to any, not to 8bit" 508 * 1.1.1 sign can remain consistent, e.g: u8 -> u16[le|be] 509 * 1.1.2 sign can be changed, e.g: u8 -> s16[le|be] 510 * 1.1.3 endian can be changed, e.g: u8 -> u16[le|be] 511 * 1.1.4 both can be changed, e.g: u8 -> [u|s]16[le|be] 512 * 1.2 "Any to 8bit, not from 8bit" 513 * 1.2.1 sign can remain consistent, e.g: s16le -> s8 514 * 1.2.2 sign can be changed, e.g: s16le -> u8 515 * 1.2.3 source endian can be anything e.g: s16[le|be] -> s8 516 * 1.2.4 source endian / sign can be anything e.g: [u|s]16[le|be] -> u8 517 * 1.3 "Any to any where BOTH input and output either 8bit or non-8bit" 518 * 1.3.1 endian MUST remain consistent 519 * 1.3.2 sign CAN be changed 520 * 1.4 "Long jump" is allowed, e.g: from 16bit to 32bit, excluding 521 * 16bit to 24bit . 522 * 2) Channel chains (mono <-> stereo) 523 * 2.1 Both endian and sign MUST remain consistent 524 * 3) Endian chains (big endian <-> little endian) 525 * 3.1 Channels and sign MUST remain consistent 526 * 4) Sign chains (signed <-> unsigned) 527 * 4.1 Channels and endian MUST remain consistent 528 * 529 * .. and the mother of all chaining rules: 530 * 531 * Rules 0: Source and destination MUST not contain multiple selections. 532 * (qtype != FMT_Q_MULTI) 533 * 534 * First of all, our caller ( chn_fmtchain() ) will reduce the possible 535 * multiple from/to formats to a single best format using chn_fmtbest(). 536 * Then, using chn_fmtscore(), we determine the chaining characteristic. 537 * Our main goal is to narrow it down until it reach FMT_Q_EQ chaining 538 * type while still adhering above chaining rules. 539 * 540 * The need for this complicated chaining procedures is inevitable, 541 * since currently we have more than 200 different types of FEEDER_FMT 542 * doing various unique format conversion. Without this (the old way), 543 * it is possible to generate broken chain since it doesn't do any 544 * sanity checking to ensure that the output format is "properly aligned" 545 * with the direction of conversion (quality up/down/equal). 546 * 547 * Conversion: s24le to s32le 548 * Possible chain: 1) s24le -> s32le (correct, optimized) 549 * 2) s24le -> s16le -> s32le 550 * (since we have feeder_24to16 and feeder_16to32) 551 * +-- obviously broken! 552 * 553 * Using scoring mechanisme, this will ensure that the chaining 554 * process do the right thing, or at least, give the best chain 555 * possible without causing quality (the 'Q') degradation. 556 */ 557 558 qdst = chn_fmtscore(to[0]); 559 qsrc = chn_fmtscore(source->desc->out); 560 561 #define score_q(s1) score_val(s1) 562 #define score_8bit(s1) ((s1) & 0x700) 563 #define score_non8bit(s1) (!score_8bit(s1)) 564 #define score_across8bit(s1, s2) ((score_8bit(s1) && score_non8bit(s2)) || \ 565 (score_8bit(s2) && score_non8bit(s1))) 566 567 #define FMT_CHAIN_Q_UP(s1, s2) (score_q(s1) < score_q(s2)) 568 #define FMT_CHAIN_Q_DOWN(s1, s2) (score_q(s1) > score_q(s2)) 569 #define FMT_CHAIN_Q_EQ(s1, s2) (score_q(s1) == score_q(s2)) 570 #define FMT_Q_DOWN_FLAGS(s1, s2) (0x1 | (score_across8bit(s1, s2) ? \ 571 0x2 : 0x0)) 572 #define FMT_Q_UP_FLAGS(s1, s2) FMT_Q_DOWN_FLAGS(s1, s2) 573 #define FMT_Q_EQ_FLAGS(s1, s2) (0x3ffc | \ 574 ((score_cheq(s1, s2) && \ 575 score_endianeq(s1, s2)) ? \ 576 0x1 : 0x0) | \ 577 ((score_cheq(s1, s2) && \ 578 score_signeq(s1, s2)) ? \ 579 0x2 : 0x0)) 580 581 /* Determine chaining direction and set matching flag */ 582 fl = 0x3fff; 583 if (to[1] != 0) { 584 qtype = FMT_Q_MULTI; 585 printf("%s: WARNING: FMT_Q_MULTI chaining. Expect the unexpected.\n", __func__); 586 } else if (FMT_CHAIN_Q_DOWN(qsrc, qdst)) { 587 qtype = FMT_Q_DOWN; 588 fl = FMT_Q_DOWN_FLAGS(qsrc, qdst); 589 } else if (FMT_CHAIN_Q_UP(qsrc, qdst)) { 590 qtype = FMT_Q_UP; 591 fl = FMT_Q_UP_FLAGS(qsrc, qdst); 592 } else { 593 qtype = FMT_Q_EQ; 594 fl = FMT_Q_EQ_FLAGS(qsrc, qdst); 595 } 596 597 ftebest = NULL; 598 599 SLIST_FOREACH(fte, &feedertab, link) { 600 if (fte->desc == NULL) 601 continue; 602 if (fte->desc->type != FEEDER_FMT) 603 continue; 604 qout = chn_fmtscore(fte->desc->out); 605 #define FMT_Q_MULTI_VALIDATE(qt) ((qt) == FMT_Q_MULTI) 606 #define FMT_Q_FL_MATCH(qfl, s1, s2) (((s1) & (qfl)) == ((s2) & (qfl))) 607 #define FMT_Q_UP_VALIDATE(qt, s1, s2, s3) ((qt) == FMT_Q_UP && \ 608 score_q(s3) >= score_q(s1) && \ 609 score_q(s3) <= score_q(s2)) 610 #define FMT_Q_DOWN_VALIDATE(qt, s1, s2, s3) ((qt) == FMT_Q_DOWN && \ 611 score_q(s3) <= score_q(s1) && \ 612 score_q(s3) >= score_q(s2)) 613 #define FMT_Q_EQ_VALIDATE(qt, s1, s2) ((qt) == FMT_Q_EQ && \ 614 score_q(s1) == score_q(s2)) 615 if (fte->desc->in == source->desc->out && 616 (FMT_Q_MULTI_VALIDATE(qtype) || 617 (FMT_Q_FL_MATCH(fl, qout, qdst) && 618 (FMT_Q_UP_VALIDATE(qtype, qsrc, qdst, qout) || 619 FMT_Q_DOWN_VALIDATE(qtype, qsrc, qdst, qout) || 620 FMT_Q_EQ_VALIDATE(qtype, qdst, qout))))) { 621 try = feeder_create(fte->feederclass, fte->desc); 622 if (try) { 623 try->source = source; 624 ret = chainok(try, stop) ? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL; 625 if (ret != NULL) 626 return ret; 627 feeder_destroy(try); 628 } 629 } else if (fte->desc->in == source->desc->out) { 630 /* XXX quality must be considered! */ 631 if (ftebest == NULL) 632 ftebest = fte; 633 } 634 } 635 636 if (ftebest != NULL) { 637 try = feeder_create(ftebest->feederclass, ftebest->desc); 638 if (try) { 639 try->source = source; 640 ret = chainok(try, stop) ? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL; 641 if (ret != NULL) 642 return ret; 643 feeder_destroy(try); 644 } 645 } 646 647 /* printf("giving up %s...\n", source->class->name); */ 648 649 return NULL; 650 } 651 652 u_int32_t 653 chn_fmtchain(struct pcm_channel *c, u_int32_t *to) 654 { 655 struct pcm_feeder *try, *del, *stop; 656 u_int32_t tmpfrom[2], tmpto[2], best, *from; 657 int i, max, bestmax; 658 659 KASSERT(c != NULL, ("c == NULL")); 660 KASSERT(c->feeder != NULL, ("c->feeder == NULL")); 661 KASSERT(to != NULL, ("to == NULL")); 662 KASSERT(to[0] != 0, ("to[0] == 0")); 663 664 if (c == NULL || c->feeder == NULL || to == NULL || to[0] == 0) 665 return 0; 666 667 stop = c->feeder; 668 best = 0; 669 670 if (c->direction == PCMDIR_REC && c->feeder->desc->type == FEEDER_ROOT) { 671 from = chn_getcaps(c)->fmtlist; 672 if (from[1] != 0) { 673 best = chn_fmtbest(to[0], from); 674 if (best != 0) { 675 tmpfrom[0] = best; 676 tmpfrom[1] = 0; 677 from = tmpfrom; 678 } 679 } 680 } else { 681 tmpfrom[0] = c->feeder->desc->out; 682 tmpfrom[1] = 0; 683 from = tmpfrom; 684 if (to[1] != 0) { 685 best = chn_fmtbest(from[0], to); 686 if (best != 0) { 687 tmpto[0] = best; 688 tmpto[1] = 0; 689 to = tmpto; 690 } 691 } 692 } 693 694 #define FEEDER_FMTCHAIN_MAXDEPTH 8 695 696 try = NULL; 697 698 if (to[0] != 0 && from[0] != 0 && 699 to[1] == 0 && from[1] == 0) { 700 max = 0; 701 best = from[0]; 702 c->feeder->desc->out = best; 703 do { 704 try = feeder_fmtchain(to, c->feeder, stop, max); 705 DEB(if (try != NULL) { 706 printf("%s: 0x%08x -> 0x%08x (maxdepth: %d)\n", 707 __func__, from[0], to[0], max); 708 }); 709 } while (try == NULL && max++ < FEEDER_FMTCHAIN_MAXDEPTH); 710 } else { 711 printf("%s: Using the old-way format chaining!\n", __func__); 712 i = 0; 713 best = 0; 714 bestmax = 100; 715 while (from[i] != 0) { 716 c->feeder->desc->out = from[i]; 717 try = NULL; 718 max = 0; 719 do { 720 try = feeder_fmtchain(to, c->feeder, stop, max); 721 } while (try == NULL && max++ < FEEDER_FMTCHAIN_MAXDEPTH); 722 if (try != NULL && max < bestmax) { 723 bestmax = max; 724 best = from[i]; 725 } 726 while (try != NULL && try != stop) { 727 del = try; 728 try = try->source; 729 feeder_destroy(del); 730 } 731 i++; 732 } 733 if (best == 0) 734 return 0; 735 736 c->feeder->desc->out = best; 737 try = feeder_fmtchain(to, c->feeder, stop, bestmax); 738 } 739 if (try == NULL) 740 return 0; 741 742 c->feeder = try; 743 c->align = 0; 744 #ifdef FEEDER_DEBUG 745 printf("\n\nchain: "); 746 #endif 747 while (try && (try != stop)) { 748 #ifdef FEEDER_DEBUG 749 printf("%s [%d]", try->class->name, try->desc->idx); 750 if (try->source) 751 printf(" -> "); 752 #endif 753 if (try->source) 754 try->source->parent = try; 755 if (try->align > 0) 756 c->align += try->align; 757 else if (try->align < 0 && c->align < -try->align) 758 c->align = -try->align; 759 try = try->source; 760 } 761 #ifdef FEEDER_DEBUG 762 printf("%s [%d]\n", try->class->name, try->desc->idx); 763 #endif 764 765 if (c->direction == PCMDIR_REC) { 766 try = c->feeder; 767 while (try != NULL) { 768 if (try->desc->type == FEEDER_ROOT) 769 return try->desc->out; 770 try = try->source; 771 } 772 return best; 773 } else 774 return c->feeder->desc->out; 775 } 776 777 void 778 feeder_printchain(struct pcm_feeder *head) 779 { 780 struct pcm_feeder *f; 781 782 printf("feeder chain (head @%p)\n", head); 783 f = head; 784 while (f != NULL) { 785 printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f); 786 f = f->source; 787 } 788 printf("[end]\n\n"); 789 } 790 791 /*****************************************************************************/ 792 793 static int 794 feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source) 795 { 796 struct snd_dbuf *src = source; 797 int l, offset; 798 799 KASSERT(count > 0, ("feed_root: count == 0")); 800 /* count &= ~((1 << ch->align) - 1); */ 801 KASSERT(count > 0, ("feed_root: aligned count == 0 (align = %d)", ch->align)); 802 803 if (++ch->feedcount == 0) 804 ch->feedcount = 2; 805 806 l = min(count, sndbuf_getready(src)); 807 808 /* When recording only return as much data as available */ 809 if (ch->direction == PCMDIR_REC) { 810 sndbuf_dispose(src, buffer, l); 811 return l; 812 } 813 814 815 offset = count - l; 816 817 if (offset > 0) { 818 if (snd_verbose > 3) 819 printf("%s: (%s) %spending %d bytes " 820 "(count=%d l=%d feed=%d)\n", 821 __func__, 822 (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware", 823 (ch->feedcount == 1) ? "pre" : "ap", 824 offset, count, l, ch->feedcount); 825 826 if (ch->feedcount == 1) { 827 if (offset > 0) 828 memset(buffer, 829 sndbuf_zerodata(sndbuf_getfmt(src)), 830 offset); 831 if (l > 0) 832 sndbuf_dispose(src, buffer + offset, l); 833 else 834 ch->feedcount--; 835 } else { 836 if (l > 0) 837 sndbuf_dispose(src, buffer, l); 838 if (offset > 0) { 839 #if 1 840 memset(buffer + l, 841 sndbuf_zerodata(sndbuf_getfmt(src)), 842 offset); 843 if (!(ch->flags & CHN_F_CLOSING)) 844 ch->xruns++; 845 #else 846 if (l < 1 || (ch->flags & CHN_F_CLOSING)) { 847 memset(buffer + l, 848 sndbuf_zerodata(sndbuf_getfmt(src)), 849 offset); 850 if (!(ch->flags & CHN_F_CLOSING)) 851 ch->xruns++; 852 } else { 853 int cp, tgt; 854 855 tgt = l; 856 while (offset > 0) { 857 cp = min(l, offset); 858 memcpy(buffer + tgt, buffer, cp); 859 offset -= cp; 860 tgt += cp; 861 } 862 ch->xruns++; 863 } 864 #endif 865 } 866 } 867 } else if (l > 0) 868 sndbuf_dispose(src, buffer, l); 869 870 return count; 871 } 872 873 static kobj_method_t feeder_root_methods[] = { 874 KOBJMETHOD(feeder_feed, feed_root), 875 { 0, 0 } 876 }; 877 static struct feeder_class feeder_root_class = { 878 .name = "feeder_root", 879 .methods = feeder_root_methods, 880 .size = sizeof(struct pcm_feeder), 881 .align = 0, 882 .desc = NULL, 883 .data = NULL, 884 }; 885 SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class); 886 SYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL); 887