feeder.c revision 65645
150724Scg/* 250724Scg * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 350724Scg * All rights reserved. 450724Scg * 550724Scg * Redistribution and use in source and binary forms, with or without 650724Scg * modification, are permitted provided that the following conditions 750724Scg * are met: 850724Scg * 1. Redistributions of source code must retain the above copyright 950724Scg * notice, this list of conditions and the following disclaimer. 1050724Scg * 2. Redistributions in binary form must reproduce the above copyright 1150724Scg * notice, this list of conditions and the following disclaimer in the 1250724Scg * documentation and/or other materials provided with the distribution. 1350724Scg * 1450724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750724Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2250724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450724Scg * SUCH DAMAGE. 2550724Scg * 2650733Speter * $FreeBSD: head/sys/dev/sound/pcm/feeder.c 65645 2000-09-09 21:24:03Z cg $ 2750724Scg */ 2850724Scg 2953465Scg#include <dev/sound/pcm/sound.h> 3050724Scg 3150724Scg#define FEEDBUFSZ 8192 3265645Scg#undef FEEDER_DEBUG 3350724Scg 3450724Scgstatic unsigned char ulaw_to_u8[] = { 3550724Scg 3, 7, 11, 15, 19, 23, 27, 31, 3650724Scg 35, 39, 43, 47, 51, 55, 59, 63, 3750724Scg 66, 68, 70, 72, 74, 76, 78, 80, 3850724Scg 82, 84, 86, 88, 90, 92, 94, 96, 3950724Scg 98, 99, 100, 101, 102, 103, 104, 105, 4050724Scg 106, 107, 108, 109, 110, 111, 112, 113, 4150724Scg 113, 114, 114, 115, 115, 116, 116, 117, 4250724Scg 117, 118, 118, 119, 119, 120, 120, 121, 4350724Scg 121, 121, 122, 122, 122, 122, 123, 123, 4450724Scg 123, 123, 124, 124, 124, 124, 125, 125, 4550724Scg 125, 125, 125, 125, 126, 126, 126, 126, 4650724Scg 126, 126, 126, 126, 127, 127, 127, 127, 4750724Scg 127, 127, 127, 127, 127, 127, 127, 127, 4850724Scg 128, 128, 128, 128, 128, 128, 128, 128, 4950724Scg 128, 128, 128, 128, 128, 128, 128, 128, 5050724Scg 128, 128, 128, 128, 128, 128, 128, 128, 5150724Scg 253, 249, 245, 241, 237, 233, 229, 225, 5250724Scg 221, 217, 213, 209, 205, 201, 197, 193, 5350724Scg 190, 188, 186, 184, 182, 180, 178, 176, 5450724Scg 174, 172, 170, 168, 166, 164, 162, 160, 5550724Scg 158, 157, 156, 155, 154, 153, 152, 151, 5650724Scg 150, 149, 148, 147, 146, 145, 144, 143, 5750724Scg 143, 142, 142, 141, 141, 140, 140, 139, 5850724Scg 139, 138, 138, 137, 137, 136, 136, 135, 5950724Scg 135, 135, 134, 134, 134, 134, 133, 133, 6050724Scg 133, 133, 132, 132, 132, 132, 131, 131, 6150724Scg 131, 131, 131, 131, 130, 130, 130, 130, 6250724Scg 130, 130, 130, 130, 129, 129, 129, 129, 6350724Scg 129, 129, 129, 129, 129, 129, 129, 129, 6450724Scg 128, 128, 128, 128, 128, 128, 128, 128, 6550724Scg 128, 128, 128, 128, 128, 128, 128, 128, 6650724Scg 128, 128, 128, 128, 128, 128, 128, 128, 6750724Scg}; 6850724Scg 6950724Scgstatic unsigned char u8_to_ulaw[] = { 7050724Scg 0, 0, 0, 0, 0, 1, 1, 1, 7150724Scg 1, 2, 2, 2, 2, 3, 3, 3, 7250724Scg 3, 4, 4, 4, 4, 5, 5, 5, 7350724Scg 5, 6, 6, 6, 6, 7, 7, 7, 7450724Scg 7, 8, 8, 8, 8, 9, 9, 9, 7550724Scg 9, 10, 10, 10, 10, 11, 11, 11, 7650724Scg 11, 12, 12, 12, 12, 13, 13, 13, 7750724Scg 13, 14, 14, 14, 14, 15, 15, 15, 7850724Scg 15, 16, 16, 17, 17, 18, 18, 19, 7950724Scg 19, 20, 20, 21, 21, 22, 22, 23, 8050724Scg 23, 24, 24, 25, 25, 26, 26, 27, 8150724Scg 27, 28, 28, 29, 29, 30, 30, 31, 8250724Scg 31, 32, 33, 34, 35, 36, 37, 38, 8350724Scg 39, 40, 41, 42, 43, 44, 45, 46, 8450724Scg 47, 49, 51, 53, 55, 57, 59, 61, 8550724Scg 63, 66, 70, 74, 78, 84, 92, 104, 8650724Scg 254, 231, 219, 211, 205, 201, 197, 193, 8750724Scg 190, 188, 186, 184, 182, 180, 178, 176, 8850724Scg 175, 174, 173, 172, 171, 170, 169, 168, 8950724Scg 167, 166, 165, 164, 163, 162, 161, 160, 9050724Scg 159, 159, 158, 158, 157, 157, 156, 156, 9150724Scg 155, 155, 154, 154, 153, 153, 152, 152, 9250724Scg 151, 151, 150, 150, 149, 149, 148, 148, 9350724Scg 147, 147, 146, 146, 145, 145, 144, 144, 9450724Scg 143, 143, 143, 143, 142, 142, 142, 142, 9550724Scg 141, 141, 141, 141, 140, 140, 140, 140, 9650724Scg 139, 139, 139, 139, 138, 138, 138, 138, 9750724Scg 137, 137, 137, 137, 136, 136, 136, 136, 9850724Scg 135, 135, 135, 135, 134, 134, 134, 134, 9950724Scg 133, 133, 133, 133, 132, 132, 132, 132, 10050724Scg 131, 131, 131, 131, 130, 130, 130, 130, 10150724Scg 129, 129, 129, 129, 128, 128, 128, 128, 10250724Scg}; 10350724Scg 10464881Scgstruct feedertab_entry { 10564881Scg SLIST_ENTRY(feedertab_entry) link; 10664881Scg pcm_feeder *feeder; 10764881Scg struct pcm_feederdesc *desc; 10864881Scg 10964881Scg int idx; 11064881Scg}; 11164881Scgstatic SLIST_HEAD(, feedertab_entry) feedertab; 11264881Scg 11350724Scg/*****************************************************************************/ 11450724Scg 11564881Scgvoid 11664881Scgfeeder_register(void *p) 11764881Scg{ 11864881Scg pcm_feeder *f = p; 11964881Scg struct feedertab_entry *fte; 12064881Scg static int feedercnt = 0; 12164881Scg int i; 12264881Scg 12364881Scg if (feedercnt == 0) { 12464881Scg if (f->desc) 12564881Scg panic("FIRST FEEDER NOT ROOT: %s\n", f->name); 12664881Scg SLIST_INIT(&feedertab); 12764881Scg fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT); 12864881Scg fte->feeder = f; 12964881Scg fte->desc = NULL; 13064881Scg fte->idx = feedercnt; 13164881Scg SLIST_INSERT_HEAD(&feedertab, fte, link); 13264881Scg feedercnt++; 13364881Scg return; 13464881Scg } 13564881Scg /* printf("installing feeder: %s\n", f->name); */ 13664881Scg 13764881Scg i = 0; 13864881Scg while ((feedercnt < MAXFEEDERS) && (f->desc[i].type > 0)) { 13964881Scg fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT); 14064881Scg fte->feeder = f; 14164881Scg fte->desc = &f->desc[i]; 14264881Scg fte->idx = feedercnt; 14364881Scg fte->desc->idx = feedercnt; 14464881Scg SLIST_INSERT_HEAD(&feedertab, fte, link); 14564881Scg i++; 14664881Scg } 14764881Scg feedercnt++; 14864881Scg if (feedercnt >= MAXFEEDERS) 14964881Scg printf("MAXFEEDERS exceeded\n"); 15064881Scg} 15164881Scg 15264881Scg/*****************************************************************************/ 15364881Scg 15450724Scgstatic int 15553205Scgfeed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream) 15650724Scg{ 15764881Scg int ret, s; 15864881Scg 15954155Scg KASSERT(count, ("feed_root: count == 0")); 16053205Scg count &= ~((1 << ch->align) - 1); 16154155Scg KASSERT(count, ("feed_root: aligned count == 0")); 16264881Scg 16354155Scg s = spltty(); 16454155Scg count = min(count, stream->uio_resid); 16554155Scg if (count) { 16654155Scg ret = uiomove(buffer, count, stream); 16754155Scg KASSERT(ret == 0, ("feed_root: uiomove failed")); 16850923Scg } 16954155Scg splx(s); 17064881Scg 17164881Scg return count; 17250724Scg} 17364881Scgstatic pcm_feeder feeder_root = { "root", 0, NULL, NULL, NULL, feed_root }; 17464881ScgSYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root); 17550724Scg 17650724Scg/*****************************************************************************/ 17750724Scg 17850724Scgstatic int 17964881Scgfeed_8to16le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 18050724Scg{ 18150724Scg int i, j, k; 18264881Scg 18353205Scg k = f->source->feed(f->source, c, b, count / 2, stream); 18450724Scg j = k - 1; 18550724Scg i = j * 2 + 1; 18650724Scg while (i > 0 && j >= 0) { 18750724Scg b[i--] = b[j--]; 18850724Scg b[i--] = 0; 18950724Scg } 19050724Scg return k * 2; 19150724Scg} 19250724Scg 19364881Scgstatic struct pcm_feederdesc desc_8to16le[] = { 19464881Scg {FEEDER_FMT, AFMT_U8, AFMT_U16_LE, 0}, 19564881Scg {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, 19664881Scg {FEEDER_FMT, AFMT_S8, AFMT_S16_LE, 0}, 19764881Scg {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, 19864881Scg {0}, 19964881Scg}; 20064881Scgstatic pcm_feeder feeder_8to16le = 20164881Scg { "8to16le", 0, desc_8to16le, NULL, NULL, feed_8to16le }; 20264881ScgSYSINIT(feeder_8to16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_8to16le); 20364881Scg 20450724Scg/*****************************************************************************/ 20550724Scg 20650724Scgstatic int 20750724Scgfeed_16to8_init(pcm_feeder *f) 20850724Scg{ 20950724Scg f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 21050724Scg return (f->data == NULL); 21150724Scg} 21250724Scg 21350724Scgstatic int 21450724Scgfeed_16to8_free(pcm_feeder *f) 21550724Scg{ 21650724Scg if (f->data) free(f->data, M_DEVBUF); 21750724Scg f->data = NULL; 21850724Scg return 0; 21950724Scg} 22050724Scg 22150724Scgstatic int 22264881Scgfeed_16leto8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 22350724Scg{ 22450724Scg u_int32_t i = 0, toget = count * 2; 22550724Scg int j = 1, k; 22664881Scg 22753205Scg k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 22850724Scg while (j < k) { 22950724Scg b[i++] = ((u_int8_t *)f->data)[j]; 23050724Scg j += 2; 23150724Scg } 23250724Scg return i; 23350724Scg} 23450724Scg 23564881Scgstatic struct pcm_feederdesc desc_16leto8[] = { 23664881Scg {FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0}, 23764881Scg {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, 23864881Scg {FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0}, 23964881Scg {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, 24064881Scg {0}, 24164881Scg}; 24264881Scgstatic pcm_feeder feeder_16leto8 = 24364881Scg { "16leto8", 1, desc_16leto8, feed_16to8_init, feed_16to8_free, feed_16leto8 }; 24464881ScgSYSINIT(feeder_16leto8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_16leto8); 24564881Scg 24650724Scg/*****************************************************************************/ 24750724Scg 24850724Scgstatic int 24953205Scgfeed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 25050724Scg{ 25153205Scg int i, j, k = f->source->feed(f->source, c, b, count / 2, stream); 25264881Scg 25350724Scg j = k - 1; 25450724Scg i = j * 2 + 1; 25550724Scg while (i > 0 && j >= 0) { 25650724Scg b[i--] = b[j]; 25750724Scg b[i--] = b[j]; 25850724Scg j--; 25950724Scg } 26050724Scg return k * 2; 26150724Scg} 26264881Scg 26364881Scgstatic struct pcm_feederdesc desc_monotostereo8[] = { 26464881Scg {FEEDER_FMT, AFMT_U8, AFMT_U8 | AFMT_STEREO, 0}, 26564881Scg {FEEDER_FMT, AFMT_S8, AFMT_S8 | AFMT_STEREO, 0}, 26664881Scg {0}, 26764881Scg}; 26850724Scgstatic pcm_feeder feeder_monotostereo8 = 26964881Scg { "monotostereo8", 0, desc_monotostereo8, NULL, NULL, feed_monotostereo8 }; 27064881ScgSYSINIT(feeder_monotostereo8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_monotostereo8); 27150724Scg 27250724Scg/*****************************************************************************/ 27350724Scg 27450724Scgstatic int 27565645Scgfeed_monotostereo16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 27665645Scg{ 27765645Scg int i, j, k = f->source->feed(f->source, c, b, count / 2, stream); 27865645Scg u_int8_t x, y; 27965645Scg 28065645Scg j = k - 1; 28165645Scg i = j * 2 + 1; 28265645Scg while (i > 3 && j >= 1) { 28365645Scg x = b[j--]; 28465645Scg y = b[j--]; 28565645Scg b[i--] = x; 28665645Scg b[i--] = y; 28765645Scg b[i--] = x; 28865645Scg b[i--] = y; 28965645Scg } 29065645Scg return k * 2; 29165645Scg} 29265645Scg 29365645Scgstatic struct pcm_feederdesc desc_monotostereo16[] = { 29465645Scg {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE | AFMT_STEREO, 0}, 29565645Scg {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE | AFMT_STEREO, 0}, 29665645Scg {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE | AFMT_STEREO, 0}, 29765645Scg {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE | AFMT_STEREO, 0}, 29865645Scg {0}, 29965645Scg}; 30065645Scgstatic pcm_feeder feeder_monotostereo16 = 30165645Scg { "monotostereo16", 0, desc_monotostereo16, NULL, NULL, feed_monotostereo16 }; 30265645ScgSYSINIT(feeder_monotostereo16, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_monotostereo16); 30365645Scg 30465645Scg/*****************************************************************************/ 30565645Scg 30665645Scgstatic int 30750724Scgfeed_stereotomono8_init(pcm_feeder *f) 30850724Scg{ 30950724Scg f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 31050724Scg return (f->data == NULL); 31150724Scg} 31250724Scg 31350724Scgstatic int 31450724Scgfeed_stereotomono8_free(pcm_feeder *f) 31550724Scg{ 31650724Scg if (f->data) free(f->data, M_DEVBUF); 31750724Scg f->data = NULL; 31850724Scg return 0; 31950724Scg} 32050724Scg 32150724Scgstatic int 32253205Scgfeed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 32350724Scg{ 32450724Scg u_int32_t i = 0, toget = count * 2; 32550724Scg int j = 0, k; 32664881Scg 32753205Scg k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 32850724Scg while (j < k) { 32950724Scg b[i++] = ((u_int8_t *)f->data)[j]; 33050724Scg j += 2; 33150724Scg } 33250724Scg return i; 33350724Scg} 33464881Scg 33564881Scgstatic struct pcm_feederdesc desc_stereotomono8[] = { 33664881Scg {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U8, 0}, 33764881Scg {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S8, 0}, 33864881Scg {0}, 33964881Scg}; 34050724Scgstatic pcm_feeder feeder_stereotomono8 = 34164881Scg { "stereotomono8", 1, desc_stereotomono8, feed_stereotomono8_init, feed_stereotomono8_free, feed_stereotomono8 }; 34264881ScgSYSINIT(feeder_stereotomono8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_stereotomono8); 34350724Scg 34450724Scg/*****************************************************************************/ 34550724Scg 34650724Scgstatic int 34765645Scgfeed_stereotomono16_init(pcm_feeder *f) 34865645Scg{ 34965645Scg f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT); 35065645Scg return (f->data == NULL); 35165645Scg} 35265645Scg 35365645Scgstatic int 35465645Scgfeed_stereotomono16_free(pcm_feeder *f) 35565645Scg{ 35665645Scg if (f->data) free(f->data, M_DEVBUF); 35765645Scg f->data = NULL; 35865645Scg return 0; 35965645Scg} 36065645Scg 36165645Scgstatic int 36265645Scgfeed_stereotomono16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 36365645Scg{ 36465645Scg u_int32_t i = 0, toget = count * 2; 36565645Scg int j = 0, k; 36665645Scg 36765645Scg k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); 36865645Scg while (j < k) { 36965645Scg b[i++] = ((u_int8_t *)f->data)[j]; 37065645Scg b[i++] = ((u_int8_t *)f->data)[j + 1]; 37165645Scg j += 4; 37265645Scg } 37365645Scg return i; 37465645Scg} 37565645Scg 37665645Scgstatic struct pcm_feederdesc desc_stereotomono16[] = { 37765645Scg {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE, 0}, 37865645Scg {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE, 0}, 37965645Scg {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE, 0}, 38065645Scg {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE, 0}, 38165645Scg {0}, 38265645Scg}; 38365645Scgstatic pcm_feeder feeder_stereotomono16 = 38465645Scg { "stereotomono16", 1, desc_stereotomono16, feed_stereotomono16_init, feed_stereotomono16_free, feed_stereotomono16 }; 38565645ScgSYSINIT(feeder_stereotomono16, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_stereotomono16); 38665645Scg 38765645Scg/*****************************************************************************/ 38865645Scg 38965645Scgstatic int 39053205Scgfeed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 39150724Scg{ 39250724Scg u_int8_t t; 39353205Scg int i = 0, j = f->source->feed(f->source, c, b, count, stream); 39464881Scg 39550724Scg while (i < j) { 39650724Scg t = b[i]; 39750724Scg b[i] = b[i + 1]; 39850724Scg b[i + 1] = t; 39950724Scg i += 2; 40050724Scg } 40150923Scg return i; 40250724Scg} 40350724Scg 40464881Scgstatic struct pcm_feederdesc desc_endian[] = { 40564881Scg {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_BE, 0}, 40664881Scg {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, 40764881Scg {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_BE, 0}, 40864881Scg {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, 40964881Scg {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_LE, 0}, 41064881Scg {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, 41164881Scg {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_LE, 0}, 41264881Scg {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, 41364881Scg {0}, 41464881Scg}; 41564881Scgstatic pcm_feeder feeder_endian = { "endian", -1, desc_endian, NULL, NULL, feed_endian }; 41664881ScgSYSINIT(feeder_endian, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_endian); 41764881Scg 41850724Scg/*****************************************************************************/ 41950724Scg 42050724Scgstatic int 42153205Scgfeed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 42250724Scg{ 42353205Scg int i = 0, j = f->source->feed(f->source, c, b, count, stream); 42450724Scg int ssz = (int)f->data, ofs = ssz - 1; 42564881Scg 42650724Scg while (i < j) { 42750724Scg b[i + ofs] ^= 0x80; 42850724Scg i += ssz; 42950724Scg } 43050724Scg return i; 43150724Scg} 43264881Scg 43364881Scgstatic struct pcm_feederdesc desc_sign8[] = { 43464881Scg {FEEDER_FMT, AFMT_U8, AFMT_S8, 0}, 43564881Scg {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, 43664881Scg {FEEDER_FMT, AFMT_S8, AFMT_U8, 0}, 43764881Scg {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, 43864881Scg {0}, 43964881Scg}; 44050724Scgstatic pcm_feeder feeder_sign8 = 44164881Scg { "sign8", 0, desc_sign8, NULL, NULL, feed_sign, (void *)1 }; 44264881ScgSYSINIT(feeder_sign8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign8); 44350724Scg 44464881Scgstatic struct pcm_feederdesc desc_sign16le[] = { 44564881Scg {FEEDER_FMT, AFMT_U16_LE, AFMT_S16_LE, 0}, 44664881Scg {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, 44764881Scg {FEEDER_FMT, AFMT_S16_LE, AFMT_U16_LE, 0}, 44864881Scg {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, 44964881Scg {0}, 45064881Scg}; 45164881Scgstatic pcm_feeder feeder_sign16le = 45264881Scg { "sign16le", -1, desc_sign16le, NULL, NULL, feed_sign, (void *)2 }; 45364881ScgSYSINIT(feeder_sign16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign16le); 45464881Scg 45550724Scg/*****************************************************************************/ 45650724Scg 45750724Scgstatic int 45853205Scgfeed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) 45950724Scg{ 46053205Scg int i = 0, j = f->source->feed(f->source, c, b, count, stream); 46164881Scg 46250724Scg while (i < j) { 46350724Scg b[i] = ((u_int8_t *)f->data)[b[i]]; 46450724Scg i++; 46550724Scg } 46650724Scg return i; 46750724Scg} 46850724Scg 46964881Scgstatic struct pcm_feederdesc desc_ulawtou8[] = { 47064881Scg {FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0}, 47164881Scg {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, 47264881Scg {0}, 47350724Scg}; 47464881Scgstatic pcm_feeder feeder_ulawtou8 = 47564881Scg { "ulawtou8", 0, desc_ulawtou8, NULL, NULL, feed_table, ulaw_to_u8 }; 47664881ScgSYSINIT(feeder_ulawtou8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_ulawtou8); 47750724Scg 47864881Scgstatic struct pcm_feederdesc desc_u8toulaw[] = { 47964881Scg {FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0}, 48064881Scg {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0}, 48164881Scg {0}, 48250724Scg}; 48364881Scgstatic pcm_feeder feeder_u8toulaw = 48464881Scg { "u8toulaw", 0, desc_u8toulaw, NULL, NULL, feed_table, u8_to_ulaw }; 48564881ScgSYSINIT(feeder_u8toulaw, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_u8toulaw); 48650724Scg 48764881Scg/*****************************************************************************/ 48850724Scg 48950724Scgstatic int 49064881Scgcmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 49150724Scg{ 49264881Scg return ((n->type == m->type) && (n->in == m->in) && (n->out == m->out) && (n->flags == m->flags)); 49350724Scg} 49450724Scg 49564881Scgpcm_feeder * 49664881Scgfeeder_get(struct pcm_feederdesc *desc) 49750724Scg{ 49864881Scg struct feedertab_entry *fte; 49964881Scg 50064881Scg SLIST_FOREACH(fte, &feedertab, link) { 50164881Scg if ((fte->desc != NULL) && cmpdesc(desc, fte->desc)) 50264881Scg return fte->feeder; 50364881Scg } 50464881Scg return NULL; 50550724Scg} 50650724Scg 50764881Scgpcm_feeder * 50864881Scgfeeder_getroot() 50950724Scg{ 51064881Scg struct feedertab_entry *fte; 51150724Scg 51264881Scg SLIST_FOREACH(fte, &feedertab, link) { 51364881Scg if (fte->desc == NULL) 51464881Scg return fte->feeder; 51564881Scg } 51664881Scg return NULL; 51750724Scg} 51850724Scg 51950724Scgint 52064881Scgchn_removefeeder(pcm_channel *c) 52150724Scg{ 52264881Scg pcm_feeder *f; 52350724Scg 52464881Scg if (c->feeder->source == NULL) 52564881Scg return -1; 52664881Scg f = c->feeder->source; 52764881Scg if (c->feeder->free) 52864881Scg c->feeder->free(c->feeder); 52964881Scg free(c->feeder, M_DEVBUF); 53064881Scg c->feeder = f; 53164881Scg return 0; 53250724Scg} 53350724Scg 53450724Scgstatic int 53564881Scgchainok(pcm_feeder *test, pcm_feeder *stop) 53650724Scg{ 53764881Scg u_int32_t visited[MAXFEEDERS / 32]; 53864881Scg u_int32_t idx, mask; 53964881Scg 54064881Scg bzero(visited, sizeof(visited)); 54164881Scg while (test && (test != stop)) { 54264881Scg idx = test->desc->idx; 54364881Scg if (idx < 0) 54464881Scg panic("bad idx %d", idx); 54564881Scg if (idx >= MAXFEEDERS) 54664881Scg panic("bad idx %d", idx); 54764881Scg mask = 1 << (idx & 31); 54864881Scg idx >>= 5; 54964881Scg if (visited[idx] & mask) 55064881Scg return 0; 55164881Scg visited[idx] |= mask; 55264881Scg test = test->source; 55364881Scg } 55464881Scg return 1; 55550724Scg} 55650724Scg 55764881Scgstatic pcm_feeder * 55864881Scgfeeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth) 55950724Scg{ 56064881Scg struct feedertab_entry *fte; 56164881Scg pcm_feeder *try, *ret; 56264881Scg struct pcm_feederdesc *trydesc; 56364881Scg 56464881Scg /* printf("trying %s...\n", source->name); */ 56564881Scg if (fmtvalid(source->desc->out, to)) { 56664881Scg /* printf("got it\n"); */ 56764881Scg return source; 56864881Scg } 56964881Scg 57064881Scg if (maxdepth < 0) 57164881Scg return NULL; 57264881Scg 57364881Scg try = malloc(sizeof(*try), M_DEVBUF, M_NOWAIT); 57464881Scg trydesc = malloc(sizeof(*trydesc), M_DEVBUF, M_NOWAIT); 57564881Scg trydesc->type = FEEDER_FMT; 57664881Scg trydesc->in = source->desc->out; 57764881Scg trydesc->out = 0; 57864881Scg trydesc->flags = 0; 57964881Scg trydesc->idx = -1; 58064881Scg 58164881Scg SLIST_FOREACH(fte, &feedertab, link) { 58264881Scg if ((fte->desc) && (fte->desc->in == source->desc->out)) { 58364881Scg *try = *(fte->feeder); 58464881Scg try->source = source; 58564881Scg try->desc = trydesc; 58664881Scg trydesc->out = fte->desc->out; 58764881Scg trydesc->idx = fte->idx; 58864881Scg ret = chainok(try, stop)? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL; 58964881Scg if (ret != NULL) 59064881Scg return ret; 59164881Scg } 59264881Scg } 59364881Scg free(try, M_DEVBUF); 59464881Scg free(trydesc, M_DEVBUF); 59564881Scg /* printf("giving up %s...\n", source->name); */ 59664881Scg return NULL; 59750724Scg} 59850724Scg 59964881Scgu_int32_t 60064881Scgchn_feedchain(pcm_channel *c, u_int32_t *to) 60164881Scg{ 60264881Scg pcm_feeder *try, *stop; 60364881Scg int max; 60464881Scg 60564881Scg stop = c->feeder; 60664881Scg try = NULL; 60764881Scg max = 0; 60865645Scg while (try == NULL && max < 8) { 60964881Scg try = feeder_fmtchain(to, c->feeder, stop, max); 61065645Scg max++; 61165645Scg } 61264881Scg if (try == NULL) 61364881Scg return 0; 61464881Scg c->feeder = try; 61564881Scg c->align = 0; 61665645Scg#ifdef FEEDER_DEBUG 61765645Scg printf("chain: "); 61865645Scg#endif 61964881Scg while (try && (try != stop)) { 62065645Scg#ifdef FEEDER_DEBUG 62165645Scg printf("%s [%d]", try->name, try->desc->idx); 62265645Scg if (try->source) 62365645Scg printf(" -> "); 62465645Scg#endif 62564881Scg if (try->init) 62664881Scg try->init(try); 62764881Scg if (try->align > 0) 62864881Scg c->align += try->align; 62964881Scg else if (try->align < 0 && c->align < -try->align) 63064881Scg c->align = -try->align; 63164881Scg try = try->source; 63264881Scg } 63365645Scg#ifdef FEEDER_DEBUG 63465645Scg printf("%s [%d]\n", try->name, try->desc->idx); 63565645Scg#endif 63664881Scg return c->feeder->desc->out; 63764881Scg} 638