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 * $FreeBSD: src/sys/dev/sound/pcm/feeder.c,v 1.33.2.3 2006/03/07 15:51:19 jhb Exp $ 27 * $DragonFly: src/sys/dev/sound/pcm/feeder.c,v 1.6 2007/01/04 21:47:03 corecode Exp $ 28 */ 29 30 #include <dev/sound/pcm/sound.h> 31 32 #include "feeder_if.h" 33 34 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/feeder.c,v 1.6 2007/01/04 21:47:03 corecode Exp $"); 35 36 MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder"); 37 38 #define MAXFEEDERS 256 39 #undef FEEDER_DEBUG 40 41 struct feedertab_entry { 42 SLIST_ENTRY(feedertab_entry) link; 43 struct feeder_class *feederclass; 44 struct pcm_feederdesc *desc; 45 46 int idx; 47 }; 48 static SLIST_HEAD(, feedertab_entry) feedertab; 49 50 /*****************************************************************************/ 51 52 void 53 feeder_register(void *p) 54 { 55 static int feedercnt = 0; 56 57 struct feeder_class *fc = p; 58 struct feedertab_entry *fte; 59 int i; 60 61 if (feedercnt == 0) { 62 KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name)); 63 64 SLIST_INIT(&feedertab); 65 fte = kmalloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO); 66 if (fte == NULL) { 67 kprintf("can't allocate memory for root feeder: %s\n", 68 fc->name); 69 70 return; 71 } 72 fte->feederclass = fc; 73 fte->desc = NULL; 74 fte->idx = feedercnt; 75 SLIST_INSERT_HEAD(&feedertab, fte, link); 76 feedercnt++; 77 78 /* we've got our root feeder so don't veto pcm loading anymore */ 79 pcm_veto_load = 0; 80 81 return; 82 } 83 84 KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name)); 85 86 /* beyond this point failure is non-fatal but may result in some translations being unavailable */ 87 i = 0; 88 while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) { 89 /* kprintf("adding feeder %s, %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); */ 90 fte = kmalloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO); 91 if (fte == NULL) { 92 kprintf("can't allocate memory for feeder '%s', %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); 93 94 return; 95 } 96 fte->feederclass = fc; 97 fte->desc = &fc->desc[i]; 98 fte->idx = feedercnt; 99 fte->desc->idx = feedercnt; 100 SLIST_INSERT_HEAD(&feedertab, fte, link); 101 i++; 102 } 103 feedercnt++; 104 if (feedercnt >= MAXFEEDERS) 105 kprintf("MAXFEEDERS (%d >= %d) exceeded\n", feedercnt, MAXFEEDERS); 106 } 107 108 static void 109 feeder_unregisterall(void *p) 110 { 111 struct feedertab_entry *fte, *next; 112 113 next = SLIST_FIRST(&feedertab); 114 while (next != NULL) { 115 fte = next; 116 next = SLIST_NEXT(fte, link); 117 kfree(fte, M_FEEDER); 118 } 119 } 120 121 static int 122 cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 123 { 124 return ((n->type == m->type) && 125 ((n->in == 0) || (n->in == m->in)) && 126 ((n->out == 0) || (n->out == m->out)) && 127 (n->flags == m->flags)); 128 } 129 130 static void 131 feeder_destroy(struct pcm_feeder *f) 132 { 133 FEEDER_FREE(f); 134 kobj_delete((kobj_t)f, M_FEEDER); 135 } 136 137 static struct pcm_feeder * 138 feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc) 139 { 140 struct pcm_feeder *f; 141 int err; 142 143 f = (void *)kobj_create((kobj_class_t)fc, M_FEEDER, M_WAITOK | M_ZERO); 144 if (f == NULL) 145 return NULL; 146 147 f->align = fc->align; 148 f->data = fc->data; 149 f->source = NULL; 150 f->parent = NULL; 151 f->class = fc; 152 f->desc = &(f->desc_static); 153 154 if (desc) { 155 *(f->desc) = *desc; 156 } else { 157 f->desc->type = FEEDER_ROOT; 158 f->desc->in = 0; 159 f->desc->out = 0; 160 f->desc->flags = 0; 161 f->desc->idx = 0; 162 } 163 164 err = FEEDER_INIT(f); 165 if (err) { 166 kprintf("feeder_init(%p) on %s returned %d\n", f, fc->name, err); 167 feeder_destroy(f); 168 169 return NULL; 170 } 171 172 return f; 173 } 174 175 struct feeder_class * 176 feeder_getclass(struct pcm_feederdesc *desc) 177 { 178 struct feedertab_entry *fte; 179 180 SLIST_FOREACH(fte, &feedertab, link) { 181 if ((desc == NULL) && (fte->desc == NULL)) 182 return fte->feederclass; 183 if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc)) 184 return fte->feederclass; 185 } 186 return NULL; 187 } 188 189 int 190 chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) 191 { 192 struct pcm_feeder *nf; 193 194 nf = feeder_create(fc, desc); 195 if (nf == NULL) 196 return ENOSPC; 197 198 nf->source = c->feeder; 199 200 /* XXX we should use the lowest common denominator for align */ 201 if (nf->align > 0) 202 c->align += nf->align; 203 else if (nf->align < 0 && c->align < -nf->align) 204 c->align = -nf->align; 205 if (c->feeder != NULL) 206 c->feeder->parent = nf; 207 c->feeder = nf; 208 209 return 0; 210 } 211 212 int 213 chn_removefeeder(struct pcm_channel *c) 214 { 215 struct pcm_feeder *f; 216 217 if (c->feeder == NULL) 218 return -1; 219 f = c->feeder; 220 c->feeder = c->feeder->source; 221 feeder_destroy(f); 222 223 return 0; 224 } 225 226 struct pcm_feeder * 227 chn_findfeeder(struct pcm_channel *c, u_int32_t type) 228 { 229 struct pcm_feeder *f; 230 231 f = c->feeder; 232 while (f != NULL) { 233 if (f->desc->type == type) 234 return f; 235 f = f->source; 236 } 237 238 return NULL; 239 } 240 241 static int 242 chainok(struct pcm_feeder *test, struct pcm_feeder *stop) 243 { 244 u_int32_t visited[MAXFEEDERS / 32]; 245 u_int32_t idx, mask; 246 247 bzero(visited, sizeof(visited)); 248 while (test && (test != stop)) { 249 idx = test->desc->idx; 250 if (idx < 0) 251 panic("bad idx %d", idx); 252 if (idx >= MAXFEEDERS) 253 panic("bad idx %d", idx); 254 mask = 1 << (idx & 31); 255 idx >>= 5; 256 if (visited[idx] & mask) 257 return 0; 258 visited[idx] |= mask; 259 test = test->source; 260 } 261 262 return 1; 263 } 264 265 static struct pcm_feeder * 266 feeder_fmtchain(u_int32_t *to, struct pcm_feeder *source, struct pcm_feeder *stop, int maxdepth) 267 { 268 struct feedertab_entry *fte; 269 struct pcm_feeder *try, *ret; 270 271 DEB(kprintf("trying %s (0x%08x -> 0x%08x)...\n", source->class->name, source->desc->in, source->desc->out)); 272 if (fmtvalid(source->desc->out, to)) { 273 DEB(kprintf("got it\n")); 274 return source; 275 } 276 277 if (maxdepth < 0) 278 return NULL; 279 280 SLIST_FOREACH(fte, &feedertab, link) { 281 if (fte->desc == NULL) 282 continue; 283 if (fte->desc->type != FEEDER_FMT) 284 continue; 285 if (fte->desc->in == source->desc->out) { 286 try = feeder_create(fte->feederclass, fte->desc); 287 if (try) { 288 try->source = source; 289 ret = chainok(try, stop)? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL; 290 if (ret != NULL) 291 return ret; 292 feeder_destroy(try); 293 } 294 } 295 } 296 /* kprintf("giving up %s...\n", source->class->name); */ 297 298 return NULL; 299 } 300 301 int 302 chn_fmtscore(u_int32_t fmt) 303 { 304 if (fmt & AFMT_32BIT) 305 return 60; 306 if (fmt & AFMT_24BIT) 307 return 50; 308 if (fmt & AFMT_16BIT) 309 return 40; 310 if (fmt & (AFMT_U8|AFMT_S8)) 311 return 30; 312 if (fmt & AFMT_MU_LAW) 313 return 20; 314 if (fmt & AFMT_A_LAW) 315 return 10; 316 return 0; 317 } 318 319 u_int32_t 320 chn_fmtbestbit(u_int32_t fmt, u_int32_t *fmts) 321 { 322 u_int32_t best; 323 int i, score, score2, oldscore; 324 325 best = 0; 326 score = chn_fmtscore(fmt); 327 oldscore = 0; 328 for (i = 0; fmts[i] != 0; i++) { 329 score2 = chn_fmtscore(fmts[i]); 330 if (oldscore == 0 || (score2 == score) || 331 (score2 > oldscore && score2 < score) || 332 (score2 < oldscore && score2 > score) || 333 (oldscore < score && score2 > oldscore)) { 334 best = fmts[i]; 335 oldscore = score2; 336 } 337 } 338 return best; 339 } 340 341 u_int32_t 342 chn_fmtbeststereo(u_int32_t fmt, u_int32_t *fmts) 343 { 344 u_int32_t best; 345 int i, score, score2, oldscore; 346 347 best = 0; 348 score = chn_fmtscore(fmt); 349 oldscore = 0; 350 for (i = 0; fmts[i] != 0; i++) { 351 if ((fmt & AFMT_STEREO) == (fmts[i] & AFMT_STEREO)) { 352 score2 = chn_fmtscore(fmts[i]); 353 if (oldscore == 0 || (score2 == score) || 354 (score2 > oldscore && score2 < score) || 355 (score2 < oldscore && score2 > score) || 356 (oldscore < score && score2 > oldscore)) { 357 best = fmts[i]; 358 oldscore = score2; 359 } 360 } 361 } 362 return best; 363 } 364 365 u_int32_t 366 chn_fmtbest(u_int32_t fmt, u_int32_t *fmts) 367 { 368 u_int32_t best1, best2; 369 int score, score1, score2; 370 371 best1 = chn_fmtbeststereo(fmt, fmts); 372 best2 = chn_fmtbestbit(fmt, fmts); 373 374 if (best1 != 0 && best2 != 0) { 375 if (fmt & AFMT_STEREO) 376 return best1; 377 else { 378 score = chn_fmtscore(fmt); 379 score1 = chn_fmtscore(best1); 380 score2 = chn_fmtscore(best2); 381 if (score1 == score2 || score1 == score) 382 return best1; 383 else if (score2 == score) 384 return best2; 385 else if (score1 > score2) 386 return best1; 387 return best2; 388 } 389 } else if (best2 == 0) 390 return best1; 391 else 392 return best2; 393 } 394 395 u_int32_t 396 chn_fmtchain(struct pcm_channel *c, u_int32_t *to) 397 { 398 struct pcm_feeder *try, *del, *stop; 399 u_int32_t tmpfrom[2], tmpto[2], best, *from; 400 int i, max, bestmax; 401 402 KASSERT(c != NULL, ("c == NULL")); 403 KASSERT(c->feeder != NULL, ("c->feeder == NULL")); 404 KASSERT(to != NULL, ("to == NULL")); 405 KASSERT(to[0] != 0, ("to[0] == 0")); 406 407 stop = c->feeder; 408 409 if (c->direction == PCMDIR_REC && c->feeder->desc->type == FEEDER_ROOT) { 410 from = chn_getcaps(c)->fmtlist; 411 if (fmtvalid(to[0], from)) 412 from = to; 413 else { 414 best = chn_fmtbest(to[0], from); 415 if (best != 0) { 416 tmpfrom[0] = best; 417 tmpfrom[1] = 0; 418 from = tmpfrom; 419 } 420 } 421 } else { 422 tmpfrom[0] = c->feeder->desc->out; 423 tmpfrom[1] = 0; 424 from = tmpfrom; 425 if (to[1] != 0) { 426 if (fmtvalid(tmpfrom[0], to)) { 427 tmpto[0] = tmpfrom[0]; 428 tmpto[1] = 0; 429 to = tmpto; 430 } else { 431 best = chn_fmtbest(tmpfrom[0], to); 432 if (best != 0) { 433 tmpto[0] = best; 434 tmpto[1] = 0; 435 to = tmpto; 436 } 437 } 438 } 439 } 440 441 i = 0; 442 best = 0; 443 bestmax = 100; 444 while (from[i] != 0) { 445 c->feeder->desc->out = from[i]; 446 try = NULL; 447 max = 0; 448 while (try == NULL && max < 8) { 449 try = feeder_fmtchain(to, c->feeder, stop, max); 450 if (try == NULL) 451 max++; 452 } 453 if (try != NULL && max < bestmax) { 454 bestmax = max; 455 best = from[i]; 456 } 457 while (try != NULL && try != stop) { 458 del = try; 459 try = try->source; 460 feeder_destroy(del); 461 } 462 i++; 463 } 464 if (best == 0) 465 return 0; 466 467 c->feeder->desc->out = best; 468 try = feeder_fmtchain(to, c->feeder, stop, bestmax); 469 if (try == NULL) 470 return 0; 471 472 c->feeder = try; 473 c->align = 0; 474 #ifdef FEEDER_DEBUG 475 kprintf("\n\nchain: "); 476 #endif 477 while (try && (try != stop)) { 478 #ifdef FEEDER_DEBUG 479 kprintf("%s [%d]", try->class->name, try->desc->idx); 480 if (try->source) 481 kprintf(" -> "); 482 #endif 483 if (try->source) 484 try->source->parent = try; 485 if (try->align > 0) 486 c->align += try->align; 487 else if (try->align < 0 && c->align < -try->align) 488 c->align = -try->align; 489 try = try->source; 490 } 491 #ifdef FEEDER_DEBUG 492 kprintf("%s [%d]\n", try->class->name, try->desc->idx); 493 #endif 494 495 if (c->direction == PCMDIR_REC) { 496 try = c->feeder; 497 while (try != NULL) { 498 if (try->desc->type == FEEDER_ROOT) 499 return try->desc->out; 500 try = try->source; 501 } 502 return best; 503 } else 504 return c->feeder->desc->out; 505 } 506 507 void 508 feeder_printchain(struct pcm_feeder *head) 509 { 510 struct pcm_feeder *f; 511 512 kprintf("feeder chain (head @%p)\n", head); 513 f = head; 514 while (f != NULL) { 515 kprintf("%s/%d @ %p\n", f->class->name, f->desc->idx, f); 516 f = f->source; 517 } 518 kprintf("[end]\n\n"); 519 } 520 521 /*****************************************************************************/ 522 523 static int 524 feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source) 525 { 526 struct snd_dbuf *src = source; 527 int l; 528 u_int8_t x; 529 530 KASSERT(count > 0, ("feed_root: count == 0")); 531 /* count &= ~((1 << ch->align) - 1); */ 532 KASSERT(count > 0, ("feed_root: aligned count == 0 (align = %d)", ch->align)); 533 534 l = min(count, sndbuf_getready(src)); 535 sndbuf_dispose(src, buffer, l); 536 537 /* When recording only return as much data as available */ 538 if (ch->direction == PCMDIR_REC) 539 return l; 540 541 /* 542 if (l < count) 543 kprintf("appending %d bytes\n", count - l); 544 */ 545 546 x = (sndbuf_getfmt(src) & AFMT_SIGNED)? 0 : 0x80; 547 while (l < count) 548 buffer[l++] = x; 549 550 return count; 551 } 552 553 static kobj_method_t feeder_root_methods[] = { 554 KOBJMETHOD(feeder_feed, feed_root), 555 { 0, 0 } 556 }; 557 static struct feeder_class feeder_root_class = { 558 .name = "feeder_root", 559 .methods = feeder_root_methods, 560 .size = sizeof(struct pcm_feeder), 561 .align = 0, 562 .desc = NULL, 563 .data = NULL, 564 }; 565 SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class); 566 SYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL); 567 568 569 570 571 572