feeder.c revision 65645
1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 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: head/sys/dev/sound/pcm/feeder.c 65645 2000-09-09 21:24:03Z cg $ 27 */ 28 29#include <dev/sound/pcm/sound.h> 30 31#define FEEDBUFSZ 8192 32#undef FEEDER_DEBUG 33 34static unsigned char ulaw_to_u8[] = { 35 3, 7, 11, 15, 19, 23, 27, 31, 36 35, 39, 43, 47, 51, 55, 59, 63, 37 66, 68, 70, 72, 74, 76, 78, 80, 38 82, 84, 86, 88, 90, 92, 94, 96, 39 98, 99, 100, 101, 102, 103, 104, 105, 40 106, 107, 108, 109, 110, 111, 112, 113, 41 113, 114, 114, 115, 115, 116, 116, 117, 42 117, 118, 118, 119, 119, 120, 120, 121, 43 121, 121, 122, 122, 122, 122, 123, 123, 44 123, 123, 124, 124, 124, 124, 125, 125, 45 125, 125, 125, 125, 126, 126, 126, 126, 46 126, 126, 126, 126, 127, 127, 127, 127, 47 127, 127, 127, 127, 127, 127, 127, 127, 48 128, 128, 128, 128, 128, 128, 128, 128, 49 128, 128, 128, 128, 128, 128, 128, 128, 50 128, 128, 128, 128, 128, 128, 128, 128, 51 253, 249, 245, 241, 237, 233, 229, 225, 52 221, 217, 213, 209, 205, 201, 197, 193, 53 190, 188, 186, 184, 182, 180, 178, 176, 54 174, 172, 170, 168, 166, 164, 162, 160, 55 158, 157, 156, 155, 154, 153, 152, 151, 56 150, 149, 148, 147, 146, 145, 144, 143, 57 143, 142, 142, 141, 141, 140, 140, 139, 58 139, 138, 138, 137, 137, 136, 136, 135, 59 135, 135, 134, 134, 134, 134, 133, 133, 60 133, 133, 132, 132, 132, 132, 131, 131, 61 131, 131, 131, 131, 130, 130, 130, 130, 62 130, 130, 130, 130, 129, 129, 129, 129, 63 129, 129, 129, 129, 129, 129, 129, 129, 64 128, 128, 128, 128, 128, 128, 128, 128, 65 128, 128, 128, 128, 128, 128, 128, 128, 66 128, 128, 128, 128, 128, 128, 128, 128, 67}; 68 69static unsigned char u8_to_ulaw[] = { 70 0, 0, 0, 0, 0, 1, 1, 1, 71 1, 2, 2, 2, 2, 3, 3, 3, 72 3, 4, 4, 4, 4, 5, 5, 5, 73 5, 6, 6, 6, 6, 7, 7, 7, 74 7, 8, 8, 8, 8, 9, 9, 9, 75 9, 10, 10, 10, 10, 11, 11, 11, 76 11, 12, 12, 12, 12, 13, 13, 13, 77 13, 14, 14, 14, 14, 15, 15, 15, 78 15, 16, 16, 17, 17, 18, 18, 19, 79 19, 20, 20, 21, 21, 22, 22, 23, 80 23, 24, 24, 25, 25, 26, 26, 27, 81 27, 28, 28, 29, 29, 30, 30, 31, 82 31, 32, 33, 34, 35, 36, 37, 38, 83 39, 40, 41, 42, 43, 44, 45, 46, 84 47, 49, 51, 53, 55, 57, 59, 61, 85 63, 66, 70, 74, 78, 84, 92, 104, 86 254, 231, 219, 211, 205, 201, 197, 193, 87 190, 188, 186, 184, 182, 180, 178, 176, 88 175, 174, 173, 172, 171, 170, 169, 168, 89 167, 166, 165, 164, 163, 162, 161, 160, 90 159, 159, 158, 158, 157, 157, 156, 156, 91 155, 155, 154, 154, 153, 153, 152, 152, 92 151, 151, 150, 150, 149, 149, 148, 148, 93 147, 147, 146, 146, 145, 145, 144, 144, 94 143, 143, 143, 143, 142, 142, 142, 142, 95 141, 141, 141, 141, 140, 140, 140, 140, 96 139, 139, 139, 139, 138, 138, 138, 138, 97 137, 137, 137, 137, 136, 136, 136, 136, 98 135, 135, 135, 135, 134, 134, 134, 134, 99 133, 133, 133, 133, 132, 132, 132, 132, 100 131, 131, 131, 131, 130, 130, 130, 130, 101 129, 129, 129, 129, 128, 128, 128, 128, 102}; 103 104struct feedertab_entry { 105 SLIST_ENTRY(feedertab_entry) link; 106 pcm_feeder *feeder; 107 struct pcm_feederdesc *desc; 108 109 int idx; 110}; 111static SLIST_HEAD(, feedertab_entry) feedertab; 112 113/*****************************************************************************/ 114 115void 116feeder_register(void *p) 117{ 118 pcm_feeder *f = p; 119 struct feedertab_entry *fte; 120 static int feedercnt = 0; 121 int i; 122 123 if (feedercnt == 0) { 124 if (f->desc) 125 panic("FIRST FEEDER NOT ROOT: %s\n", f->name); 126 SLIST_INIT(&feedertab); 127 fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT); 128 fte->feeder = f; 129 fte->desc = NULL; 130 fte->idx = feedercnt; 131 SLIST_INSERT_HEAD(&feedertab, fte, link); 132 feedercnt++; 133 return; 134 } 135 /* printf("installing feeder: %s\n", f->name); */ 136 137 i = 0; 138 while ((feedercnt < MAXFEEDERS) && (f->desc[i].type > 0)) { 139 fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT); 140 fte->feeder = f; 141 fte->desc = &f->desc[i]; 142 fte->idx = feedercnt; 143 fte->desc->idx = feedercnt; 144 SLIST_INSERT_HEAD(&feedertab, fte, link); 145 i++; 146 } 147 feedercnt++; 148 if (feedercnt >= MAXFEEDERS) 149 printf("MAXFEEDERS exceeded\n"); 150} 151 152/*****************************************************************************/ 153 154static int 155feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream) 156{ 157 int ret, s; 158 159 KASSERT(count, ("feed_root: count == 0")); 160 count &= ~((1 << ch->align) - 1); 161 KASSERT(count, ("feed_root: aligned count == 0")); 162 163 s = spltty(); 164 count = min(count, stream->uio_resid); 165 if (count) { 166 ret = uiomove(buffer, count, stream); 167 KASSERT(ret == 0, ("feed_root: uiomove failed")); 168 } 169 splx(s); 170 171 return count; 172} 173static pcm_feeder feeder_root = { "root", 0, NULL, NULL, NULL, feed_root }; 174SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root); 175 176/*****************************************************************************/ 177 178static int 179feed_8to16le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 180{ 181 int i, j, k; 182 183 k = f->source->feed(f->source, c, b, count / 2, stream); 184 j = k - 1; 185 i = j * 2 + 1; 186 while (i > 0 && j >= 0) { 187 b[i--] = b[j--]; 188 b[i--] = 0; 189 } 190 return k * 2; 191} 192 193static struct pcm_feederdesc desc_8to16le[] = { 194 {FEEDER_FMT, AFMT_U8, AFMT_U16_LE, 0}, 195 {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, 196 {FEEDER_FMT, AFMT_S8, AFMT_S16_LE, 0}, 197 {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, 198 {0}, 199}; 200static pcm_feeder feeder_8to16le = 201 { "8to16le", 0, desc_8to16le, NULL, NULL, feed_8to16le }; 202SYSINIT(feeder_8to16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_8to16le); 203 204/*****************************************************************************/ 205 206static int 207feed_16to8_init(pcm_feeder *f) 208{ 209 f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 210 return (f->data == NULL); 211} 212 213static int 214feed_16to8_free(pcm_feeder *f) 215{ 216 if (f->data) free(f->data, M_DEVBUF); 217 f->data = NULL; 218 return 0; 219} 220 221static int 222feed_16leto8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 223{ 224 u_int32_t i = 0, toget = count * 2; 225 int j = 1, k; 226 227 k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 228 while (j < k) { 229 b[i++] = ((u_int8_t *)f->data)[j]; 230 j += 2; 231 } 232 return i; 233} 234 235static struct pcm_feederdesc desc_16leto8[] = { 236 {FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0}, 237 {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, 238 {FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0}, 239 {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, 240 {0}, 241}; 242static pcm_feeder feeder_16leto8 = 243 { "16leto8", 1, desc_16leto8, feed_16to8_init, feed_16to8_free, feed_16leto8 }; 244SYSINIT(feeder_16leto8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_16leto8); 245 246/*****************************************************************************/ 247 248static int 249feed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 250{ 251 int i, j, k = f->source->feed(f->source, c, b, count / 2, stream); 252 253 j = k - 1; 254 i = j * 2 + 1; 255 while (i > 0 && j >= 0) { 256 b[i--] = b[j]; 257 b[i--] = b[j]; 258 j--; 259 } 260 return k * 2; 261} 262 263static struct pcm_feederdesc desc_monotostereo8[] = { 264 {FEEDER_FMT, AFMT_U8, AFMT_U8 | AFMT_STEREO, 0}, 265 {FEEDER_FMT, AFMT_S8, AFMT_S8 | AFMT_STEREO, 0}, 266 {0}, 267}; 268static pcm_feeder feeder_monotostereo8 = 269 { "monotostereo8", 0, desc_monotostereo8, NULL, NULL, feed_monotostereo8 }; 270SYSINIT(feeder_monotostereo8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_monotostereo8); 271 272/*****************************************************************************/ 273 274static int 275feed_monotostereo16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 276{ 277 int i, j, k = f->source->feed(f->source, c, b, count / 2, stream); 278 u_int8_t x, y; 279 280 j = k - 1; 281 i = j * 2 + 1; 282 while (i > 3 && j >= 1) { 283 x = b[j--]; 284 y = b[j--]; 285 b[i--] = x; 286 b[i--] = y; 287 b[i--] = x; 288 b[i--] = y; 289 } 290 return k * 2; 291} 292 293static struct pcm_feederdesc desc_monotostereo16[] = { 294 {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE | AFMT_STEREO, 0}, 295 {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE | AFMT_STEREO, 0}, 296 {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE | AFMT_STEREO, 0}, 297 {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE | AFMT_STEREO, 0}, 298 {0}, 299}; 300static pcm_feeder feeder_monotostereo16 = 301 { "monotostereo16", 0, desc_monotostereo16, NULL, NULL, feed_monotostereo16 }; 302SYSINIT(feeder_monotostereo16, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_monotostereo16); 303 304/*****************************************************************************/ 305 306static int 307feed_stereotomono8_init(pcm_feeder *f) 308{ 309 f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 310 return (f->data == NULL); 311} 312 313static int 314feed_stereotomono8_free(pcm_feeder *f) 315{ 316 if (f->data) free(f->data, M_DEVBUF); 317 f->data = NULL; 318 return 0; 319} 320 321static int 322feed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 323{ 324 u_int32_t i = 0, toget = count * 2; 325 int j = 0, k; 326 327 k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 328 while (j < k) { 329 b[i++] = ((u_int8_t *)f->data)[j]; 330 j += 2; 331 } 332 return i; 333} 334 335static struct pcm_feederdesc desc_stereotomono8[] = { 336 {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U8, 0}, 337 {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S8, 0}, 338 {0}, 339}; 340static pcm_feeder feeder_stereotomono8 = 341 { "stereotomono8", 1, desc_stereotomono8, feed_stereotomono8_init, feed_stereotomono8_free, feed_stereotomono8 }; 342SYSINIT(feeder_stereotomono8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_stereotomono8); 343 344/*****************************************************************************/ 345 346static int 347feed_stereotomono16_init(pcm_feeder *f) 348{ 349 f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 350 return (f->data == NULL); 351} 352 353static int 354feed_stereotomono16_free(pcm_feeder *f) 355{ 356 if (f->data) free(f->data, M_DEVBUF); 357 f->data = NULL; 358 return 0; 359} 360 361static int 362feed_stereotomono16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 363{ 364 u_int32_t i = 0, toget = count * 2; 365 int j = 0, k; 366 367 k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 368 while (j < k) { 369 b[i++] = ((u_int8_t *)f->data)[j]; 370 b[i++] = ((u_int8_t *)f->data)[j + 1]; 371 j += 4; 372 } 373 return i; 374} 375 376static struct pcm_feederdesc desc_stereotomono16[] = { 377 {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE, 0}, 378 {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE, 0}, 379 {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE, 0}, 380 {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE, 0}, 381 {0}, 382}; 383static pcm_feeder feeder_stereotomono16 = 384 { "stereotomono16", 1, desc_stereotomono16, feed_stereotomono16_init, feed_stereotomono16_free, feed_stereotomono16 }; 385SYSINIT(feeder_stereotomono16, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_stereotomono16); 386 387/*****************************************************************************/ 388 389static int 390feed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 391{ 392 u_int8_t t; 393 int i = 0, j = f->source->feed(f->source, c, b, count, stream); 394 395 while (i < j) { 396 t = b[i]; 397 b[i] = b[i + 1]; 398 b[i + 1] = t; 399 i += 2; 400 } 401 return i; 402} 403 404static struct pcm_feederdesc desc_endian[] = { 405 {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_BE, 0}, 406 {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, 407 {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_BE, 0}, 408 {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, 409 {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_LE, 0}, 410 {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, 411 {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_LE, 0}, 412 {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, 413 {0}, 414}; 415static pcm_feeder feeder_endian = { "endian", -1, desc_endian, NULL, NULL, feed_endian }; 416SYSINIT(feeder_endian, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_endian); 417 418/*****************************************************************************/ 419 420static int 421feed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 422{ 423 int i = 0, j = f->source->feed(f->source, c, b, count, stream); 424 int ssz = (int)f->data, ofs = ssz - 1; 425 426 while (i < j) { 427 b[i + ofs] ^= 0x80; 428 i += ssz; 429 } 430 return i; 431} 432 433static struct pcm_feederdesc desc_sign8[] = { 434 {FEEDER_FMT, AFMT_U8, AFMT_S8, 0}, 435 {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, 436 {FEEDER_FMT, AFMT_S8, AFMT_U8, 0}, 437 {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, 438 {0}, 439}; 440static pcm_feeder feeder_sign8 = 441 { "sign8", 0, desc_sign8, NULL, NULL, feed_sign, (void *)1 }; 442SYSINIT(feeder_sign8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign8); 443 444static struct pcm_feederdesc desc_sign16le[] = { 445 {FEEDER_FMT, AFMT_U16_LE, AFMT_S16_LE, 0}, 446 {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, 447 {FEEDER_FMT, AFMT_S16_LE, AFMT_U16_LE, 0}, 448 {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, 449 {0}, 450}; 451static pcm_feeder feeder_sign16le = 452 { "sign16le", -1, desc_sign16le, NULL, NULL, feed_sign, (void *)2 }; 453SYSINIT(feeder_sign16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign16le); 454 455/*****************************************************************************/ 456 457static int 458feed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 459{ 460 int i = 0, j = f->source->feed(f->source, c, b, count, stream); 461 462 while (i < j) { 463 b[i] = ((u_int8_t *)f->data)[b[i]]; 464 i++; 465 } 466 return i; 467} 468 469static struct pcm_feederdesc desc_ulawtou8[] = { 470 {FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0}, 471 {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, 472 {0}, 473}; 474static pcm_feeder feeder_ulawtou8 = 475 { "ulawtou8", 0, desc_ulawtou8, NULL, NULL, feed_table, ulaw_to_u8 }; 476SYSINIT(feeder_ulawtou8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_ulawtou8); 477 478static struct pcm_feederdesc desc_u8toulaw[] = { 479 {FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0}, 480 {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0}, 481 {0}, 482}; 483static pcm_feeder feeder_u8toulaw = 484 { "u8toulaw", 0, desc_u8toulaw, NULL, NULL, feed_table, u8_to_ulaw }; 485SYSINIT(feeder_u8toulaw, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_u8toulaw); 486 487/*****************************************************************************/ 488 489static int 490cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 491{ 492 return ((n->type == m->type) && (n->in == m->in) && (n->out == m->out) && (n->flags == m->flags)); 493} 494 495pcm_feeder * 496feeder_get(struct pcm_feederdesc *desc) 497{ 498 struct feedertab_entry *fte; 499 500 SLIST_FOREACH(fte, &feedertab, link) { 501 if ((fte->desc != NULL) && cmpdesc(desc, fte->desc)) 502 return fte->feeder; 503 } 504 return NULL; 505} 506 507pcm_feeder * 508feeder_getroot() 509{ 510 struct feedertab_entry *fte; 511 512 SLIST_FOREACH(fte, &feedertab, link) { 513 if (fte->desc == NULL) 514 return fte->feeder; 515 } 516 return NULL; 517} 518 519int 520chn_removefeeder(pcm_channel *c) 521{ 522 pcm_feeder *f; 523 524 if (c->feeder->source == NULL) 525 return -1; 526 f = c->feeder->source; 527 if (c->feeder->free) 528 c->feeder->free(c->feeder); 529 free(c->feeder, M_DEVBUF); 530 c->feeder = f; 531 return 0; 532} 533 534static int 535chainok(pcm_feeder *test, pcm_feeder *stop) 536{ 537 u_int32_t visited[MAXFEEDERS / 32]; 538 u_int32_t idx, mask; 539 540 bzero(visited, sizeof(visited)); 541 while (test && (test != stop)) { 542 idx = test->desc->idx; 543 if (idx < 0) 544 panic("bad idx %d", idx); 545 if (idx >= MAXFEEDERS) 546 panic("bad idx %d", idx); 547 mask = 1 << (idx & 31); 548 idx >>= 5; 549 if (visited[idx] & mask) 550 return 0; 551 visited[idx] |= mask; 552 test = test->source; 553 } 554 return 1; 555} 556 557static pcm_feeder * 558feeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth) 559{ 560 struct feedertab_entry *fte; 561 pcm_feeder *try, *ret; 562 struct pcm_feederdesc *trydesc; 563 564 /* printf("trying %s...\n", source->name); */ 565 if (fmtvalid(source->desc->out, to)) { 566 /* printf("got it\n"); */ 567 return source; 568 } 569 570 if (maxdepth < 0) 571 return NULL; 572 573 try = malloc(sizeof(*try), M_DEVBUF, M_NOWAIT); 574 trydesc = malloc(sizeof(*trydesc), M_DEVBUF, M_NOWAIT); 575 trydesc->type = FEEDER_FMT; 576 trydesc->in = source->desc->out; 577 trydesc->out = 0; 578 trydesc->flags = 0; 579 trydesc->idx = -1; 580 581 SLIST_FOREACH(fte, &feedertab, link) { 582 if ((fte->desc) && (fte->desc->in == source->desc->out)) { 583 *try = *(fte->feeder); 584 try->source = source; 585 try->desc = trydesc; 586 trydesc->out = fte->desc->out; 587 trydesc->idx = fte->idx; 588 ret = chainok(try, stop)? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL; 589 if (ret != NULL) 590 return ret; 591 } 592 } 593 free(try, M_DEVBUF); 594 free(trydesc, M_DEVBUF); 595 /* printf("giving up %s...\n", source->name); */ 596 return NULL; 597} 598 599u_int32_t 600chn_feedchain(pcm_channel *c, u_int32_t *to) 601{ 602 pcm_feeder *try, *stop; 603 int max; 604 605 stop = c->feeder; 606 try = NULL; 607 max = 0; 608 while (try == NULL && max < 8) { 609 try = feeder_fmtchain(to, c->feeder, stop, max); 610 max++; 611 } 612 if (try == NULL) 613 return 0; 614 c->feeder = try; 615 c->align = 0; 616#ifdef FEEDER_DEBUG 617 printf("chain: "); 618#endif 619 while (try && (try != stop)) { 620#ifdef FEEDER_DEBUG 621 printf("%s [%d]", try->name, try->desc->idx); 622 if (try->source) 623 printf(" -> "); 624#endif 625 if (try->init) 626 try->init(try); 627 if (try->align > 0) 628 c->align += try->align; 629 else if (try->align < 0 && c->align < -try->align) 630 c->align = -try->align; 631 try = try->source; 632 } 633#ifdef FEEDER_DEBUG 634 printf("%s [%d]\n", try->name, try->desc->idx); 635#endif 636 return c->feeder->desc->out; 637} 638