feeder.c revision 70134
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 70134 2000-12-18 01:36:41Z cg $ 2750724Scg */ 2850724Scg 2953465Scg#include <dev/sound/pcm/sound.h> 3050724Scg 3170134Scg#include "feeder_if.h" 3270134Scg 3370134ScgMALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder"); 3470134Scg 3566308Scg#define MAXFEEDERS 256 3665645Scg#undef FEEDER_DEBUG 3750724Scg 3864881Scgstruct feedertab_entry { 3964881Scg SLIST_ENTRY(feedertab_entry) link; 4070134Scg struct feeder_class *feederclass; 4164881Scg struct pcm_feederdesc *desc; 4264881Scg 4364881Scg int idx; 4464881Scg}; 4564881Scgstatic SLIST_HEAD(, feedertab_entry) feedertab; 4664881Scg 4750724Scg/*****************************************************************************/ 4850724Scg 4964881Scgvoid 5064881Scgfeeder_register(void *p) 5164881Scg{ 5270134Scg struct feeder_class *fc = p; 5364881Scg struct feedertab_entry *fte; 5464881Scg static int feedercnt = 0; 5564881Scg int i; 5664881Scg 5764881Scg if (feedercnt == 0) { 5870134Scg if (fc->desc) 5970134Scg panic("FIRST FEEDER NOT ROOT: %s\n", fc->name); 6064881Scg SLIST_INIT(&feedertab); 6170134Scg fte = malloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO); 6270134Scg fte->feederclass = fc; 6364881Scg fte->desc = NULL; 6464881Scg fte->idx = feedercnt; 6564881Scg SLIST_INSERT_HEAD(&feedertab, fte, link); 6664881Scg feedercnt++; 6764881Scg return; 6864881Scg } 6964881Scg /* printf("installing feeder: %s\n", f->name); */ 7064881Scg 7164881Scg i = 0; 7270134Scg while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) { 7370134Scg fte = malloc(sizeof(*fte), M_FEEDER, M_WAITOK | M_ZERO); 7470134Scg fte->feederclass = fc; 7570134Scg fte->desc = &fc->desc[i]; 7664881Scg fte->idx = feedercnt; 7764881Scg fte->desc->idx = feedercnt; 7864881Scg SLIST_INSERT_HEAD(&feedertab, fte, link); 7964881Scg i++; 8064881Scg } 8164881Scg feedercnt++; 8264881Scg if (feedercnt >= MAXFEEDERS) 8364881Scg printf("MAXFEEDERS exceeded\n"); 8464881Scg} 8564881Scg 8650724Scgstatic int 8764881Scgcmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 8850724Scg{ 8966308Scg return ((n->type == m->type) && 9066308Scg ((n->in == 0) || (n->in == m->in)) && 9166308Scg ((n->out == 0) || (n->out == m->out)) && 9266308Scg (n->flags == m->flags)); 9350724Scg} 9450724Scg 9570134Scgstatic void 9670134Scgfeeder_destroy(pcm_feeder *f) 9750724Scg{ 9870134Scg FEEDER_FREE(f); 9970134Scg free(f->desc, M_FEEDER); 10070134Scg kobj_delete((kobj_t)f, M_FEEDER); 10170134Scg} 10264881Scg 10370134Scgstatic pcm_feeder * 10470134Scgfeeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc) 10570134Scg{ 10670134Scg pcm_feeder *f; 10770134Scg int err; 10870134Scg 10970134Scg f = (pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_WAITOK | M_ZERO); 11070134Scg f->align = fc->align; 11170134Scg f->desc = malloc(sizeof(*(f->desc)), M_FEEDER, M_WAITOK | M_ZERO); 11270134Scg if (desc) 11370134Scg *(f->desc) = *desc; 11470134Scg else { 11570134Scg f->desc->type = FEEDER_ROOT; 11670134Scg f->desc->in = 0; 11770134Scg f->desc->out = 0; 11870134Scg f->desc->flags = 0; 11970134Scg f->desc->idx = 0; 12064881Scg } 12170134Scg f->data = fc->data; 12270134Scg f->source = NULL; 12370134Scg err = FEEDER_INIT(f); 12470134Scg if (err) { 12570134Scg feeder_destroy(f); 12670134Scg return NULL; 12770134Scg } else 12870134Scg return f; 12950724Scg} 13050724Scg 13170134Scgstruct feeder_class * 13270134Scgfeeder_getclass(struct pcm_feederdesc *desc) 13350724Scg{ 13464881Scg struct feedertab_entry *fte; 13550724Scg 13664881Scg SLIST_FOREACH(fte, &feedertab, link) { 13770134Scg if ((desc == NULL) && (fte->desc == NULL)) 13870134Scg return fte->feederclass; 13970134Scg if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc)) 14070134Scg return fte->feederclass; 14164881Scg } 14264881Scg return NULL; 14350724Scg} 14450724Scg 14550724Scgint 14670134Scgchn_addfeeder(pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) 14766308Scg{ 14870134Scg pcm_feeder *nf; 14970134Scg 15070134Scg nf = feeder_create(fc, desc); 15170134Scg if (nf == NULL) 15266308Scg return -1; 15366308Scg 15470134Scg nf->source = c->feeder; 15566308Scg 15666308Scg if (nf->align > 0) 15766308Scg c->align += nf->align; 15866308Scg else if (nf->align < 0 && c->align < -nf->align) 15966308Scg c->align = -nf->align; 16066308Scg 16166308Scg c->feeder = nf; 16266308Scg 16366308Scg return 0; 16466308Scg} 16566308Scg 16666308Scgint 16764881Scgchn_removefeeder(pcm_channel *c) 16850724Scg{ 16964881Scg pcm_feeder *f; 17050724Scg 17170134Scg if (c->feeder == NULL) 17264881Scg return -1; 17370134Scg f = c->feeder; 17470134Scg c->feeder = c->feeder->source; 17570134Scg feeder_destroy(f); 17664881Scg return 0; 17750724Scg} 17850724Scg 17966308Scgpcm_feeder * 18066308Scgchn_findfeeder(pcm_channel *c, u_int32_t type) 18166308Scg{ 18266308Scg pcm_feeder *f; 18366308Scg 18466308Scg f = c->feeder; 18566308Scg while (f != NULL) { 18666308Scg if (f->desc->type == type) 18766308Scg return f; 18866308Scg f = f->source; 18966308Scg } 19066308Scg return NULL; 19166308Scg} 19266308Scg 19350724Scgstatic int 19464881Scgchainok(pcm_feeder *test, pcm_feeder *stop) 19550724Scg{ 19664881Scg u_int32_t visited[MAXFEEDERS / 32]; 19764881Scg u_int32_t idx, mask; 19864881Scg 19964881Scg bzero(visited, sizeof(visited)); 20064881Scg while (test && (test != stop)) { 20164881Scg idx = test->desc->idx; 20264881Scg if (idx < 0) 20364881Scg panic("bad idx %d", idx); 20464881Scg if (idx >= MAXFEEDERS) 20564881Scg panic("bad idx %d", idx); 20664881Scg mask = 1 << (idx & 31); 20764881Scg idx >>= 5; 20864881Scg if (visited[idx] & mask) 20964881Scg return 0; 21064881Scg visited[idx] |= mask; 21164881Scg test = test->source; 21264881Scg } 21364881Scg return 1; 21450724Scg} 21550724Scg 21664881Scgstatic pcm_feeder * 21764881Scgfeeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth) 21850724Scg{ 21964881Scg struct feedertab_entry *fte; 22064881Scg pcm_feeder *try, *ret; 22170134Scg struct pcm_feederdesc trydesc; 22264881Scg 22364881Scg /* printf("trying %s...\n", source->name); */ 22464881Scg if (fmtvalid(source->desc->out, to)) { 22564881Scg /* printf("got it\n"); */ 22664881Scg return source; 22764881Scg } 22864881Scg 22964881Scg if (maxdepth < 0) 23064881Scg return NULL; 23164881Scg 23270134Scg trydesc.type = FEEDER_FMT; 23370134Scg trydesc.in = source->desc->out; 23470134Scg trydesc.out = 0; 23570134Scg trydesc.flags = 0; 23670134Scg trydesc.idx = -1; 23764881Scg 23864881Scg SLIST_FOREACH(fte, &feedertab, link) { 23964881Scg if ((fte->desc) && (fte->desc->in == source->desc->out)) { 24070134Scg trydesc.out = fte->desc->out; 24170134Scg trydesc.idx = fte->idx; 24270134Scg try = feeder_create(fte->feederclass, &trydesc); 24370134Scg if (try == NULL) 24470134Scg return NULL; 24564881Scg try->source = source; 24664881Scg ret = chainok(try, stop)? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL; 24764881Scg if (ret != NULL) 24864881Scg return ret; 24970134Scg feeder_destroy(try); 25064881Scg } 25164881Scg } 25264881Scg /* printf("giving up %s...\n", source->name); */ 25364881Scg return NULL; 25450724Scg} 25550724Scg 25664881Scgu_int32_t 25766308Scgchn_fmtchain(pcm_channel *c, u_int32_t *to) 25864881Scg{ 25964881Scg pcm_feeder *try, *stop; 26064881Scg int max; 26164881Scg 26264881Scg stop = c->feeder; 26364881Scg try = NULL; 26464881Scg max = 0; 26565645Scg while (try == NULL && max < 8) { 26664881Scg try = feeder_fmtchain(to, c->feeder, stop, max); 26765645Scg max++; 26865645Scg } 26964881Scg if (try == NULL) 27064881Scg return 0; 27164881Scg c->feeder = try; 27264881Scg c->align = 0; 27365645Scg#ifdef FEEDER_DEBUG 27465645Scg printf("chain: "); 27565645Scg#endif 27664881Scg while (try && (try != stop)) { 27765645Scg#ifdef FEEDER_DEBUG 27865645Scg printf("%s [%d]", try->name, try->desc->idx); 27965645Scg if (try->source) 28065645Scg printf(" -> "); 28165645Scg#endif 28264881Scg if (try->align > 0) 28364881Scg c->align += try->align; 28464881Scg else if (try->align < 0 && c->align < -try->align) 28564881Scg c->align = -try->align; 28664881Scg try = try->source; 28764881Scg } 28865645Scg#ifdef FEEDER_DEBUG 28965645Scg printf("%s [%d]\n", try->name, try->desc->idx); 29065645Scg#endif 29164881Scg return c->feeder->desc->out; 29264881Scg} 29366308Scg 29466308Scg/*****************************************************************************/ 29566308Scg 29666308Scgstatic int 29766308Scgfeed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream) 29866308Scg{ 29966308Scg int ret, s; 30066308Scg 30166308Scg KASSERT(count, ("feed_root: count == 0")); 30266308Scg count &= ~((1 << ch->align) - 1); 30366308Scg KASSERT(count, ("feed_root: aligned count == 0 (align = %d)", ch->align)); 30466308Scg 30566308Scg s = spltty(); 30666308Scg count = min(count, stream->uio_resid); 30766308Scg if (count) { 30866308Scg ret = uiomove(buffer, count, stream); 30970134Scg KASSERT(ret == 0, ("feed_root: uiomove failed (%d)", ret)); 31066308Scg } 31166308Scg splx(s); 31266308Scg 31366308Scg return count; 31466308Scg} 31570134Scg 31670134Scgstatic kobj_method_t feeder_root_methods[] = { 31770134Scg KOBJMETHOD(feeder_feed, feed_root), 31870134Scg { 0, 0 } 31966308Scg}; 32070134Scgstatic struct feeder_class feeder_root_class = { 32170134Scg name: "feeder_root", 32270134Scg methods: feeder_root_methods, 32370134Scg size: sizeof(pcm_feeder), 32470134Scg align: 0, 32570134Scg desc: NULL, 32670134Scg data: NULL, 32770134Scg}; 32870134ScgSYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class); 32966308Scg 33066308Scg 33166308Scg 33266308Scg 33370134Scg 334