feeder.c revision 53465
1133359Sobrien/* 2133359Sobrien * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3133359Sobrien * All rights reserved. 4133359Sobrien * 5133359Sobrien * Redistribution and use in source and binary forms, with or without 6133359Sobrien * modification, are permitted provided that the following conditions 7133359Sobrien * are met: 8133359Sobrien * 1. Redistributions of source code must retain the above copyright 9133359Sobrien * notice, this list of conditions and the following disclaimer. 10133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11133359Sobrien * notice, this list of conditions and the following disclaimer in the 12133359Sobrien * documentation and/or other materials provided with the distribution. 13133359Sobrien * 14133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18133359Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24133359Sobrien * SUCH DAMAGE. 25133359Sobrien * 26133359Sobrien * $FreeBSD: head/sys/dev/sound/pcm/feeder.c 53465 1999-11-20 16:50:33Z cg $ 2768349Sobrien */ 2868349Sobrien 29191736Sobrien#include <dev/sound/pcm/sound.h> 30267843Sdelphij 31191736Sobrienstatic int chn_addfeeder(pcm_channel *c, pcm_feeder *f); 32191736Sobrienstatic int chn_removefeeder(pcm_channel *c); 3368349Sobrien 3468349Sobrien#define FEEDBUFSZ 8192 3568349Sobrien 3668349Sobrienstatic unsigned char ulaw_to_u8[] = { 3768349Sobrien 3, 7, 11, 15, 19, 23, 27, 31, 3868349Sobrien 35, 39, 43, 47, 51, 55, 59, 63, 3968349Sobrien 66, 68, 70, 72, 74, 76, 78, 80, 4068349Sobrien 82, 84, 86, 88, 90, 92, 94, 96, 4168349Sobrien 98, 99, 100, 101, 102, 103, 104, 105, 42186690Sobrien 106, 107, 108, 109, 110, 111, 112, 113, 4368349Sobrien 113, 114, 114, 115, 115, 116, 116, 117, 4468349Sobrien 117, 118, 118, 119, 119, 120, 120, 121, 45169942Sobrien 121, 121, 122, 122, 122, 122, 123, 123, 46169942Sobrien 123, 123, 124, 124, 124, 124, 125, 125, 4768349Sobrien 125, 125, 125, 125, 126, 126, 126, 126, 48169942Sobrien 126, 126, 126, 126, 127, 127, 127, 127, 49186690Sobrien 127, 127, 127, 127, 127, 127, 127, 127, 50226048Sobrien 128, 128, 128, 128, 128, 128, 128, 128, 51267843Sdelphij 128, 128, 128, 128, 128, 128, 128, 128, 52186690Sobrien 128, 128, 128, 128, 128, 128, 128, 128, 53159764Sobrien 253, 249, 245, 241, 237, 233, 229, 225, 5468349Sobrien 221, 217, 213, 209, 205, 201, 197, 193, 55133359Sobrien 190, 188, 186, 184, 182, 180, 178, 176, 5668349Sobrien 174, 172, 170, 168, 166, 164, 162, 160, 57159764Sobrien 158, 157, 156, 155, 154, 153, 152, 151, 58159764Sobrien 150, 149, 148, 147, 146, 145, 144, 143, 59133359Sobrien 143, 142, 142, 141, 141, 140, 140, 139, 60133359Sobrien 139, 138, 138, 137, 137, 136, 136, 135, 61133359Sobrien 135, 135, 134, 134, 134, 134, 133, 133, 62133359Sobrien 133, 133, 132, 132, 132, 132, 131, 131, 63275666Sdelphij 131, 131, 131, 131, 130, 130, 130, 130, 64275666Sdelphij 130, 130, 130, 130, 129, 129, 129, 129, 65275666Sdelphij 129, 129, 129, 129, 129, 129, 129, 129, 66275666Sdelphij 128, 128, 128, 128, 128, 128, 128, 128, 67275666Sdelphij 128, 128, 128, 128, 128, 128, 128, 128, 68275666Sdelphij 128, 128, 128, 128, 128, 128, 128, 128, 69275666Sdelphij}; 70275666Sdelphij 71275666Sdelphijstatic unsigned char u8_to_ulaw[] = { 72275666Sdelphij 0, 0, 0, 0, 0, 1, 1, 1, 73275666Sdelphij 1, 2, 2, 2, 2, 3, 3, 3, 74275666Sdelphij 3, 4, 4, 4, 4, 5, 5, 5, 75133359Sobrien 5, 6, 6, 6, 6, 7, 7, 7, 76103373Sobrien 7, 8, 8, 8, 8, 9, 9, 9, 7768349Sobrien 9, 10, 10, 10, 10, 11, 11, 11, 7868349Sobrien 11, 12, 12, 12, 12, 13, 13, 13, 7968349Sobrien 13, 14, 14, 14, 14, 15, 15, 15, 8068349Sobrien 15, 16, 16, 17, 17, 18, 18, 19, 8168349Sobrien 19, 20, 20, 21, 21, 22, 22, 23, 8268349Sobrien 23, 24, 24, 25, 25, 26, 26, 27, 8368349Sobrien 27, 28, 28, 29, 29, 30, 30, 31, 8468349Sobrien 31, 32, 33, 34, 35, 36, 37, 38, 8568349Sobrien 39, 40, 41, 42, 43, 44, 45, 46, 8668349Sobrien 47, 49, 51, 53, 55, 57, 59, 61, 8768349Sobrien 63, 66, 70, 74, 78, 84, 92, 104, 8868349Sobrien 254, 231, 219, 211, 205, 201, 197, 193, 8968349Sobrien 190, 188, 186, 184, 182, 180, 178, 176, 9068349Sobrien 175, 174, 173, 172, 171, 170, 169, 168, 9168349Sobrien 167, 166, 165, 164, 163, 162, 161, 160, 9268349Sobrien 159, 159, 158, 158, 157, 157, 156, 156, 9368349Sobrien 155, 155, 154, 154, 153, 153, 152, 152, 94133359Sobrien 151, 151, 150, 150, 149, 149, 148, 148, 95103373Sobrien 147, 147, 146, 146, 145, 145, 144, 144, 9668349Sobrien 143, 143, 143, 143, 142, 142, 142, 142, 9768349Sobrien 141, 141, 141, 141, 140, 140, 140, 140, 9868349Sobrien 139, 139, 139, 139, 138, 138, 138, 138, 9968349Sobrien 137, 137, 137, 137, 136, 136, 136, 136, 10068349Sobrien 135, 135, 135, 135, 134, 134, 134, 134, 10168349Sobrien 133, 133, 133, 133, 132, 132, 132, 132, 10268349Sobrien 131, 131, 131, 131, 130, 130, 130, 130, 10368349Sobrien 129, 129, 129, 129, 128, 128, 128, 128, 10468349Sobrien}; 10568349Sobrien 10668349Sobrien/*****************************************************************************/ 10768349Sobrien 10868349Sobrienstatic int 10968349Sobrienfeed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream) 11068349Sobrien{ 11168349Sobrien int ret, tmp = 0, c = 0; 11268349Sobrien if (!count) panic("feed_root: count == 0"); 11368349Sobrien count &= ~((1 << ch->align) - 1); 11468349Sobrien if (!count) panic("feed_root: aligned count == 0"); 115133359Sobrien if (ch->smegcnt > 0) { 116103373Sobrien c = min(ch->smegcnt, count); 11768349Sobrien bcopy(ch->smegbuf, buffer, c); 11868349Sobrien ch->smegcnt -= c; 11968349Sobrien } 12068349Sobrien while ((stream->uio_resid > 0) && (c < count)) { 12168349Sobrien tmp = stream->uio_resid; 12268349Sobrien ret = uiomove(buffer + c, count - c, stream); 12368349Sobrien if (ret) panic("feed_root: uiomove failed"); 12468349Sobrien tmp -= stream->uio_resid; 12568349Sobrien c += tmp; 12668349Sobrien } 12768349Sobrien if (!c) panic("feed_root: uiomove didn't"); 12868349Sobrien return c; 12968349Sobrien} 13068349Sobrienpcm_feeder feeder_root = { "root", 0, NULL, NULL, feed_root }; 13168349Sobrien 13268349Sobrien/*****************************************************************************/ 13368349Sobrien 13468349Sobrienstatic int 13568349Sobrienfeed_8to16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 13668349Sobrien{ 13768349Sobrien int i, j, k; 13868349Sobrien k = f->source->feed(f->source, c, b, count / 2, stream); 13968349Sobrien j = k - 1; 140186690Sobrien i = j * 2 + 1; 141186690Sobrien while (i > 0 && j >= 0) { 142267843Sdelphij b[i--] = b[j--]; 143159764Sobrien b[i--] = 0; 144186690Sobrien } 145267843Sdelphij return k * 2; 146267843Sdelphij} 147186690Sobrienstatic pcm_feeder feeder_8to16 = { "8to16", 0, NULL, NULL, feed_8to16 }; 148267843Sdelphij 149267843Sdelphij/*****************************************************************************/ 150267843Sdelphij 151186690Sobrienstatic int 152186690Sobrienfeed_16to8_init(pcm_feeder *f) 153226048Sobrien{ 154186690Sobrien f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 155186690Sobrien return (f->data == NULL); 156186690Sobrien} 157186690Sobrien 158186690Sobrienstatic int 159267843Sdelphijfeed_16to8_free(pcm_feeder *f) 160267843Sdelphij{ 161267843Sdelphij if (f->data) free(f->data, M_DEVBUF); 162186690Sobrien f->data = NULL; 163186690Sobrien return 0; 16468349Sobrien} 165186690Sobrien 166267843Sdelphijstatic int 167267843Sdelphijfeed_16to8le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 168186690Sobrien{ 169186690Sobrien u_int32_t i = 0, toget = count * 2; 170186690Sobrien int j = 1, k; 171186690Sobrien k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 172186690Sobrien while (j < k) { 173186690Sobrien b[i++] = ((u_int8_t *)f->data)[j]; 174186690Sobrien j += 2; 175186690Sobrien } 176186690Sobrien return i; 177186690Sobrien} 178186690Sobrienstatic pcm_feeder feeder_16to8le = 179186690Sobrien { "16to8le", 1, feed_16to8_init, feed_16to8_free, feed_16to8le }; 180186690Sobrien 181186690Sobrien/*****************************************************************************/ 182186690Sobrien 183267843Sdelphijstatic int 184267843Sdelphijfeed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 185186690Sobrien{ 186186690Sobrien int i, j, k = f->source->feed(f->source, c, b, count / 2, stream); 187186690Sobrien j = k - 1; 188186690Sobrien i = j * 2 + 1; 189186690Sobrien while (i > 0 && j >= 0) { 190133359Sobrien b[i--] = b[j]; 191186690Sobrien b[i--] = b[j]; 192186690Sobrien j--; 193186690Sobrien } 194186690Sobrien return k * 2; 195186690Sobrien} 196186690Sobrienstatic pcm_feeder feeder_monotostereo8 = 197186690Sobrien { "monotostereo8", 0, NULL, NULL, feed_monotostereo8 }; 198186690Sobrien 199186690Sobrien/*****************************************************************************/ 200186690Sobrien 201186690Sobrienstatic int 20268349Sobrienfeed_stereotomono8_init(pcm_feeder *f) 203186690Sobrien{ 204267843Sdelphij f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 205267843Sdelphij return (f->data == NULL); 206186690Sobrien} 207186690Sobrien 208186690Sobrienstatic int 209186690Sobrienfeed_stereotomono8_free(pcm_feeder *f) 210186690Sobrien{ 211186690Sobrien if (f->data) free(f->data, M_DEVBUF); 212186690Sobrien f->data = NULL; 213186690Sobrien return 0; 214186690Sobrien} 21568349Sobrien 21668349Sobrienstatic int 217186690Sobrienfeed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 218186690Sobrien{ 219186690Sobrien u_int32_t i = 0, toget = count * 2; 220186690Sobrien int j = 0, k; 221186690Sobrien k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 222186690Sobrien while (j < k) { 223186690Sobrien b[i++] = ((u_int8_t *)f->data)[j]; 224186690Sobrien j += 2; 225186690Sobrien } 226186690Sobrien return i; 227186690Sobrien} 228186690Sobrienstatic pcm_feeder feeder_stereotomono8 = 229186690Sobrien { "stereotomono8", 1, feed_stereotomono8_init, feed_stereotomono8_free, 230186690Sobrien feed_stereotomono8 }; 231186690Sobrien 232186690Sobrien/*****************************************************************************/ 23368349Sobrien 23468349Sobrienstatic int 23568349Sobrienfeed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 236186690Sobrien{ 237186690Sobrien u_int8_t t; 238186690Sobrien int i = 0, j = f->source->feed(f->source, c, b, count, stream); 239186690Sobrien while (i < j) { 240186690Sobrien t = b[i]; 241186690Sobrien b[i] = b[i + 1]; 242186690Sobrien b[i + 1] = t; 243186690Sobrien i += 2; 244186690Sobrien } 245186690Sobrien return i; 246186690Sobrien} 247186690Sobrienstatic pcm_feeder feeder_endian = { "endian", -1, NULL, NULL, feed_endian }; 248159764Sobrien 24968349Sobrien/*****************************************************************************/ 25068349Sobrien 25168349Sobrienstatic int 25268349Sobrienfeed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 25368349Sobrien{ 254186690Sobrien int i = 0, j = f->source->feed(f->source, c, b, count, stream); 25568349Sobrien int ssz = (int)f->data, ofs = ssz - 1; 25668349Sobrien while (i < j) { 25768349Sobrien b[i + ofs] ^= 0x80; 25868349Sobrien i += ssz; 25968349Sobrien } 26068349Sobrien return i; 26168349Sobrien} 26268349Sobrienstatic pcm_feeder feeder_sign8 = 26368349Sobrien { "sign8", 0, NULL, NULL, feed_sign, (void *)1 }; 26468349Sobrienstatic pcm_feeder feeder_sign16 = 26568349Sobrien { "sign16", -1, NULL, NULL, feed_sign, (void *)2 }; 26668349Sobrien 26768349Sobrien/*****************************************************************************/ 268186690Sobrien 269186690Sobrienstatic int 270186690Sobrienfeed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 271186690Sobrien{ 272186690Sobrien int i = 0, j = f->source->feed(f->source, c, b, count, stream); 273186690Sobrien while (i < j) { 274186690Sobrien b[i] = ((u_int8_t *)f->data)[b[i]]; 275186690Sobrien i++; 27668349Sobrien } 27768349Sobrien return i; 27868349Sobrien} 27968349Sobrienstatic pcm_feeder feeder_ulawtou8 = 28068349Sobrien { "ulawtou8", 0, NULL, NULL, feed_table, ulaw_to_u8 }; 28168349Sobrienstatic pcm_feeder feeder_u8toulaw = 28268349Sobrien { "u8toulaw", 0, NULL, NULL, feed_table, u8_to_ulaw }; 28368349Sobrien 284103373Sobrien/*****************************************************************************/ 285103373Sobrien 286103373Sobrienstruct fmtspec { 287103373Sobrien int stereo; 288103373Sobrien int sign; 289186690Sobrien int bit16; 290103373Sobrien int bigendian; 291103373Sobrien int ulaw; 292103373Sobrien int bad; 293103373Sobrien}; 294103373Sobrien 295226048Sobrienstruct fmtcvt { 296226048Sobrien pcm_feeder *f; 297226048Sobrien struct fmtspec ispec, ospec; 298226048Sobrien}; 299226048Sobrien 300159764Sobrienstruct fmtcvt cvttab[] = { 301133359Sobrien {&feeder_ulawtou8, {-1, 0, 0, 0, 1}, {-1, 0, 0, 0, 0}}, 302186690Sobrien {&feeder_u8toulaw, {-1, 0, 0, 0, 0}, {-1, 0, 0, 0, 1}}, 303169942Sobrien {&feeder_sign8, {-1, 0, 0, 0, 0}, {-1, 1, 0, 0, 0}}, 30468349Sobrien {&feeder_sign8, {-1, 1, 0, 0, 0}, {-1, 0, 0, 0, 0}}, 30568349Sobrien {&feeder_monotostereo8, { 0, -1, 0, 0, -1}, { 1, -1, 0, 0, -1}}, 30668349Sobrien {&feeder_stereotomono8, { 1, -1, 0, 0, -1}, { 0, -1, 0, 0, -1}}, 307267843Sdelphij {&feeder_sign16, {-1, 0, 1, 0, 0}, {-1, 1, 1, 0, 0}}, 308133359Sobrien {&feeder_sign16, {-1, 1, 1, 0, 0}, {-1, 0, 1, 0, 0}}, 309133359Sobrien {&feeder_8to16, {-1, -1, 0, 0, 0}, {-1, -1, 1, 0, 0}}, 31068349Sobrien {&feeder_16to8le, {-1, -1, 1, 0, 0}, {-1, -1, 0, 0, 0}}, 311159764Sobrien {&feeder_endian, {-1, -1, 1, 0, 0}, {-1, -1, 1, 1, 0}}, 312133359Sobrien {&feeder_endian, {-1, -1, 1, 1, 0}, {-1, -1, 1, 0, 0}}, 313133359Sobrien}; 314133359Sobrien#define FEEDERTABSZ (sizeof(cvttab) / sizeof(struct fmtcvt)) 315133359Sobrien 316159764Sobrienstatic int 31768349Sobriengetspec(u_int32_t fmt, struct fmtspec *spec) 31868349Sobrien{ 31968349Sobrien spec->stereo = (fmt & AFMT_STEREO)? 1 : 0; 32068349Sobrien spec->sign = (fmt & AFMT_SIGNED)? 1 : 0; 321267843Sdelphij spec->bit16 = (fmt & AFMT_16BIT)? 1 : 0; 322133359Sobrien spec->bigendian = (fmt & AFMT_BIGENDIAN)? 1 : 0; 323133359Sobrien spec->ulaw = (fmt & AFMT_MU_LAW)? 1 : 0; 324133359Sobrien spec->bad = (fmt & (AFMT_A_LAW | AFMT_MPEG))? 1 : 0; 325226048Sobrien return 0; 326226048Sobrien} 327169942Sobrien 328226048Sobrienstatic int 329169942Sobriencmp(int x, int y) 330169942Sobrien{ 331169942Sobrien return (x == -1 || x == y || y == -1)? 1 : 0; 332159764Sobrien} 33368349Sobrien 33468349Sobrienstatic int 33568349Sobriencmpspec(struct fmtspec *x, struct fmtspec *y) 33668349Sobrien{ 33768349Sobrien int i = 0; 33868349Sobrien if (cmp(x->stereo, y->stereo)) i |= 0x01; 339267843Sdelphij if (cmp(x->sign, y->sign)) i |= 0x02; 340267843Sdelphij if (cmp(x->bit16, y->bit16)) i |= 0x04; 341133359Sobrien if (cmp(x->bigendian, y->bigendian)) i |= 0x08; 342133359Sobrien if (cmp(x->ulaw, y->ulaw)) i |= 0x10; 343133359Sobrien return i; 34468349Sobrien} 34568349Sobrien 346133359Sobrienstatic int 34768349Sobriencvtapply(pcm_channel *c, struct fmtcvt *cvt, struct fmtspec *s) 348133359Sobrien{ 349186690Sobrien int i = cmpspec(s, &cvt->ospec); 350133359Sobrien chn_addfeeder(c, cvt->f); 351133359Sobrien if (cvt->ospec.stereo != -1) s->stereo = cvt->ospec.stereo; 35268349Sobrien if (cvt->ospec.sign != -1) s->sign = cvt->ospec.sign; 353133359Sobrien if (cvt->ospec.bit16 != -1) s->bit16 = cvt->ospec.bit16; 354133359Sobrien if (cvt->ospec.bigendian != -1) s->bigendian = cvt->ospec.bigendian; 355133359Sobrien if (cvt->ospec.ulaw != -1) s->ulaw = cvt->ospec.ulaw; 356133359Sobrien return i; 357133359Sobrien} 358133359Sobrien 359267843Sdelphijint 360267843Sdelphijchn_feedchain(pcm_channel *c) 361267843Sdelphij{ 362267843Sdelphij int i, chosen, iter; 363267843Sdelphij u_int32_t mask; 364267843Sdelphij struct fmtspec s, t; 365267843Sdelphij struct fmtcvt *e; 366267843Sdelphij 367267843Sdelphij while (chn_removefeeder(c) != -1); 368267843Sdelphij c->align = 0; 369267843Sdelphij if ((c->format & chn_getcaps(c)->formats) == c->format) 370267843Sdelphij return c->format; 371267843Sdelphij getspec(c->format, &s); 372267843Sdelphij if (s.bad) return -1; 373267843Sdelphij getspec(chn_getcaps(c)->bestfmt, &t); 374267843Sdelphij mask = (~cmpspec(&s, &t)) & 0x1f; 375267843Sdelphij iter = 0; 376267843Sdelphij do { 377267843Sdelphij if (mask == 0 || iter >= 8) break; 378267843Sdelphij chosen = -1; 379267843Sdelphij for (i = 0; i < FEEDERTABSZ && chosen == -1; i++) { 380267843Sdelphij e = &cvttab[i]; 381267843Sdelphij if ((cmpspec(&s, &e->ispec) == 0x1f) && 382267843Sdelphij ((~cmpspec(&e->ispec, &e->ospec)) & mask)) 383267843Sdelphij chosen = i; 384267843Sdelphij } 385267843Sdelphij if (chosen != -1) mask &= cvtapply(c, &cvttab[chosen], &s); 386267843Sdelphij iter++; 387267843Sdelphij } while (chosen != -1); 388267843Sdelphij return (iter < 8)? chn_getcaps(c)->bestfmt : -1; 389267843Sdelphij} 390267843Sdelphij 391267843Sdelphijstatic int 392267843Sdelphijchn_addfeeder(pcm_channel *c, pcm_feeder *f) 393267843Sdelphij{ 394267843Sdelphij pcm_feeder *n; 395267843Sdelphij n = malloc(sizeof(pcm_feeder), M_DEVBUF, M_NOWAIT); 396267843Sdelphij *n = *f; 397267843Sdelphij n->source = c->feeder; 398267843Sdelphij c->feeder = n; 399267843Sdelphij if (n->init) n->init(n); 400267843Sdelphij if (n->align > 0) c->align += n->align; 401267843Sdelphij else if (n->align < 0 && c->align < -n->align) c->align -= n->align; 402267843Sdelphij return 0; 403267843Sdelphij} 404267843Sdelphij 405267843Sdelphijstatic int 406267843Sdelphijchn_removefeeder(pcm_channel *c) 407267843Sdelphij{ 408267843Sdelphij pcm_feeder *f; 409267843Sdelphij if (c->feeder == &feeder_root) return -1; 410267843Sdelphij f = c->feeder->source; 411267843Sdelphij if (c->feeder->free) c->feeder->free(c->feeder); 412267843Sdelphij free(c->feeder, M_DEVBUF); 413267843Sdelphij c->feeder = f; 414267843Sdelphij return 0; 415267843Sdelphij} 416267843Sdelphij 417267843Sdelphij