1139749Simp/*-
2193640Sariff * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3193640Sariff * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
450724Scg * All rights reserved.
550724Scg *
650724Scg * Redistribution and use in source and binary forms, with or without
750724Scg * modification, are permitted provided that the following conditions
850724Scg * are met:
950724Scg * 1. Redistributions of source code must retain the above copyright
1050724Scg *    notice, this list of conditions and the following disclaimer.
1150724Scg * 2. Redistributions in binary form must reproduce the above copyright
1250724Scg *    notice, this list of conditions and the following disclaimer in the
1350724Scg *    documentation and/or other materials provided with the distribution.
1450724Scg *
1550724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1650724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1750724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1850724Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1950724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2050724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2150724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2250724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2350724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2450724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2550724Scg * SUCH DAMAGE.
2650724Scg */
2750724Scg
28193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
29193640Sariff#include "opt_snd.h"
30193640Sariff#endif
31193640Sariff
3253465Scg#include <dev/sound/pcm/sound.h>
3350724Scg
3470134Scg#include "feeder_if.h"
3570134Scg
3682180ScgSND_DECLARE_FILE("$FreeBSD$");
3782180Scg
38227293Sedstatic MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder");
3970134Scg
4066308Scg#define MAXFEEDERS 	256
4165645Scg#undef FEEDER_DEBUG
4250724Scg
4364881Scgstruct feedertab_entry {
4464881Scg	SLIST_ENTRY(feedertab_entry) link;
4570134Scg	struct feeder_class *feederclass;
4664881Scg	struct pcm_feederdesc *desc;
4764881Scg
4864881Scg	int idx;
4964881Scg};
5064881Scgstatic SLIST_HEAD(, feedertab_entry) feedertab;
5164881Scg
5250724Scg/*****************************************************************************/
5350724Scg
5464881Scgvoid
5564881Scgfeeder_register(void *p)
5664881Scg{
5789834Scg	static int feedercnt = 0;
5889834Scg
5970134Scg	struct feeder_class *fc = p;
6064881Scg	struct feedertab_entry *fte;
6164881Scg	int i;
6264881Scg
6364881Scg	if (feedercnt == 0) {
6489834Scg		KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name));
6589834Scg
6664881Scg		SLIST_INIT(&feedertab);
67111909Sorion		fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO);
6889834Scg		if (fte == NULL) {
6997274Sbde			printf("can't allocate memory for root feeder: %s\n",
7097274Sbde			    fc->name);
7189834Scg
7289834Scg			return;
7389834Scg		}
7470134Scg		fte->feederclass = fc;
7564881Scg		fte->desc = NULL;
7664881Scg		fte->idx = feedercnt;
7764881Scg		SLIST_INSERT_HEAD(&feedertab, fte, link);
7864881Scg		feedercnt++;
7989834Scg
80164614Sariff		/* initialize global variables */
81164614Sariff
82170161Sariff		if (snd_verbose < 0 || snd_verbose > 4)
83164614Sariff			snd_verbose = 1;
84164614Sariff
85170161Sariff		/* initialize unit numbering */
86170161Sariff		snd_unit_init();
87170161Sariff		if (snd_unit < 0 || snd_unit > PCMMAXUNIT)
88170884Sariff			snd_unit = -1;
89164614Sariff
90164614Sariff		if (snd_maxautovchans < 0 ||
91164614Sariff		    snd_maxautovchans > SND_MAXVCHANS)
92164614Sariff			snd_maxautovchans = 0;
93164614Sariff
94164614Sariff		if (chn_latency < CHN_LATENCY_MIN ||
95164614Sariff		    chn_latency > CHN_LATENCY_MAX)
96164614Sariff			chn_latency = CHN_LATENCY_DEFAULT;
97164614Sariff
98164614Sariff		if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN ||
99164614Sariff		    chn_latency_profile > CHN_LATENCY_PROFILE_MAX)
100164614Sariff			chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT;
101164614Sariff
102164614Sariff		if (feeder_rate_min < FEEDRATE_MIN ||
103164614Sariff			    feeder_rate_max < FEEDRATE_MIN ||
104164614Sariff			    feeder_rate_min > FEEDRATE_MAX ||
105164614Sariff			    feeder_rate_max > FEEDRATE_MAX ||
106164614Sariff			    !(feeder_rate_min < feeder_rate_max)) {
107164614Sariff			feeder_rate_min = FEEDRATE_RATEMIN;
108164614Sariff			feeder_rate_max = FEEDRATE_RATEMAX;
109164614Sariff		}
110164614Sariff
111164614Sariff		if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN ||
112164614Sariff		    	    feeder_rate_round > FEEDRATE_ROUNDHZ_MAX)
113164614Sariff			feeder_rate_round = FEEDRATE_ROUNDHZ;
114164614Sariff
115164614Sariff		if (bootverbose)
116164614Sariff			printf("%s: snd_unit=%d snd_maxautovchans=%d "
117193640Sariff			    "latency=%d "
118164614Sariff			    "feeder_rate_min=%d feeder_rate_max=%d "
119164614Sariff			    "feeder_rate_round=%d\n",
120164614Sariff			    __func__, snd_unit, snd_maxautovchans,
121193640Sariff			    chn_latency,
122164614Sariff			    feeder_rate_min, feeder_rate_max,
123164614Sariff			    feeder_rate_round);
124164614Sariff
12589834Scg		/* we've got our root feeder so don't veto pcm loading anymore */
12689834Scg		pcm_veto_load = 0;
12789834Scg
12864881Scg		return;
12964881Scg	}
13064881Scg
13189834Scg	KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name));
13289834Scg
13389834Scg	/* beyond this point failure is non-fatal but may result in some translations being unavailable */
13464881Scg	i = 0;
13570134Scg	while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) {
13675355Scg		/* printf("adding feeder %s, %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); */
137111909Sorion		fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO);
13889834Scg		if (fte == NULL) {
13989834Scg			printf("can't allocate memory for feeder '%s', %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out);
14089834Scg
14189834Scg			return;
14289834Scg		}
14370134Scg		fte->feederclass = fc;
14470134Scg		fte->desc = &fc->desc[i];
14564881Scg		fte->idx = feedercnt;
14664881Scg		fte->desc->idx = feedercnt;
14764881Scg		SLIST_INSERT_HEAD(&feedertab, fte, link);
14864881Scg		i++;
14964881Scg	}
15064881Scg	feedercnt++;
15164881Scg	if (feedercnt >= MAXFEEDERS)
15289834Scg		printf("MAXFEEDERS (%d >= %d) exceeded\n", feedercnt, MAXFEEDERS);
15364881Scg}
15464881Scg
15574363Scgstatic void
15674363Scgfeeder_unregisterall(void *p)
15774363Scg{
15874363Scg	struct feedertab_entry *fte, *next;
15974363Scg
16074363Scg	next = SLIST_FIRST(&feedertab);
16174363Scg	while (next != NULL) {
16274363Scg		fte = next;
16374363Scg		next = SLIST_NEXT(fte, link);
16474363Scg		free(fte, M_FEEDER);
16574363Scg	}
16674363Scg}
16774363Scg
16850724Scgstatic int
16964881Scgcmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m)
17050724Scg{
17166308Scg	return ((n->type == m->type) &&
17266308Scg		((n->in == 0) || (n->in == m->in)) &&
17366308Scg		((n->out == 0) || (n->out == m->out)) &&
17466308Scg		(n->flags == m->flags));
17550724Scg}
17650724Scg
17770134Scgstatic void
17874763Scgfeeder_destroy(struct pcm_feeder *f)
17950724Scg{
18070134Scg	FEEDER_FREE(f);
18170134Scg	kobj_delete((kobj_t)f, M_FEEDER);
18270134Scg}
18364881Scg
18474763Scgstatic struct pcm_feeder *
18570134Scgfeeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc)
18670134Scg{
18774763Scg	struct pcm_feeder *f;
18870134Scg	int err;
18970134Scg
190111909Sorion	f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO);
19189834Scg	if (f == NULL)
19289834Scg		return NULL;
19389834Scg
19489834Scg	f->data = fc->data;
19589834Scg	f->source = NULL;
19689834Scg	f->parent = NULL;
19789834Scg	f->class = fc;
19889834Scg	f->desc = &(f->desc_static);
19989834Scg
20089834Scg	if (desc) {
20170134Scg		*(f->desc) = *desc;
20289834Scg	} else {
20370134Scg		f->desc->type = FEEDER_ROOT;
20470134Scg		f->desc->in = 0;
20570134Scg		f->desc->out = 0;
20670134Scg		f->desc->flags = 0;
20770134Scg		f->desc->idx = 0;
20864881Scg	}
20989834Scg
21070134Scg	err = FEEDER_INIT(f);
21170134Scg	if (err) {
21275319Scg		printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err);
21370134Scg		feeder_destroy(f);
21489834Scg
21570134Scg		return NULL;
21689834Scg	}
21789834Scg
21889834Scg	return f;
21950724Scg}
22050724Scg
22170134Scgstruct feeder_class *
22270134Scgfeeder_getclass(struct pcm_feederdesc *desc)
22350724Scg{
22464881Scg	struct feedertab_entry *fte;
22550724Scg
22664881Scg	SLIST_FOREACH(fte, &feedertab, link) {
22770134Scg		if ((desc == NULL) && (fte->desc == NULL))
22870134Scg			return fte->feederclass;
22970134Scg		if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc))
23070134Scg			return fte->feederclass;
23164881Scg	}
23264881Scg	return NULL;
23350724Scg}
23450724Scg
23550724Scgint
23674763Scgchn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc)
23766308Scg{
23874763Scg	struct pcm_feeder *nf;
23970134Scg
24070134Scg	nf = feeder_create(fc, desc);
24170134Scg	if (nf == NULL)
24289834Scg		return ENOSPC;
24366308Scg
24470134Scg	nf->source = c->feeder;
24566308Scg
246117307Scg	if (c->feeder != NULL)
247117307Scg		c->feeder->parent = nf;
24866308Scg	c->feeder = nf;
24966308Scg
25066308Scg	return 0;
25166308Scg}
25266308Scg
25366308Scgint
25474763Scgchn_removefeeder(struct pcm_channel *c)
25550724Scg{
25674763Scg	struct pcm_feeder *f;
25750724Scg
25870134Scg	if (c->feeder == NULL)
25964881Scg		return -1;
26070134Scg	f = c->feeder;
26170134Scg	c->feeder = c->feeder->source;
26270134Scg	feeder_destroy(f);
26389834Scg
26464881Scg	return 0;
26550724Scg}
26650724Scg
26774763Scgstruct pcm_feeder *
26874763Scgchn_findfeeder(struct pcm_channel *c, u_int32_t type)
26966308Scg{
27074763Scg	struct pcm_feeder *f;
27166308Scg
27266308Scg	f = c->feeder;
27366308Scg	while (f != NULL) {
27466308Scg		if (f->desc->type == type)
27566308Scg			return f;
27666308Scg		f = f->source;
27766308Scg	}
27889834Scg
27966308Scg	return NULL;
28066308Scg}
28166308Scg
282164614Sariff/*
283164614Sariff * 14bit format scoring
284164614Sariff * --------------------
285164614Sariff *
286164614Sariff *  13  12  11  10   9   8        2        1   0    offset
287164614Sariff * +---+---+---+---+---+---+-------------+---+---+
288164614Sariff * | X | X | X | X | X | X | X X X X X X | X | X |
289164614Sariff * +---+---+---+---+---+---+-------------+---+---+
290164614Sariff *   |   |   |   |   |   |        |        |   |
291164614Sariff *   |   |   |   |   |   |        |        |   +--> signed?
292164614Sariff *   |   |   |   |   |   |        |        |
293164614Sariff *   |   |   |   |   |   |        |        +------> bigendian?
294164614Sariff *   |   |   |   |   |   |        |
295164614Sariff *   |   |   |   |   |   |        +---------------> total channels
296164614Sariff *   |   |   |   |   |   |
297164614Sariff *   |   |   |   |   |   +------------------------> AFMT_A_LAW
298164614Sariff *   |   |   |   |   |
299164614Sariff *   |   |   |   |   +----------------------------> AFMT_MU_LAW
300164614Sariff *   |   |   |   |
301164614Sariff *   |   |   |   +--------------------------------> AFMT_8BIT
302164614Sariff *   |   |   |
303164614Sariff *   |   |   +------------------------------------> AFMT_16BIT
304164614Sariff *   |   |
305164614Sariff *   |   +----------------------------------------> AFMT_24BIT
306164614Sariff *   |
307164614Sariff *   +--------------------------------------------> AFMT_32BIT
308164614Sariff */
309164614Sariff#define score_signeq(s1, s2)	(((s1) & 0x1) == ((s2) & 0x1))
310164614Sariff#define score_endianeq(s1, s2)	(((s1) & 0x2) == ((s2) & 0x2))
311164614Sariff#define score_cheq(s1, s2)	(((s1) & 0xfc) == ((s2) & 0xfc))
312193640Sariff#define score_chgt(s1, s2)	(((s1) & 0xfc) > ((s2) & 0xfc))
313193640Sariff#define score_chlt(s1, s2)	(((s1) & 0xfc) < ((s2) & 0xfc))
314164614Sariff#define score_val(s1)		((s1) & 0x3f00)
315164614Sariff#define score_cse(s1)		((s1) & 0x7f)
31664881Scg
317164614Sariffu_int32_t
318193640Sariffsnd_fmtscore(u_int32_t fmt)
319154684Sariff{
320164614Sariff	u_int32_t ret;
321164614Sariff
322164614Sariff	ret = 0;
323164614Sariff	if (fmt & AFMT_SIGNED)
324164614Sariff		ret |= 1 << 0;
325164614Sariff	if (fmt & AFMT_BIGENDIAN)
326164614Sariff		ret |= 1 << 1;
327193640Sariff	/*if (fmt & AFMT_STEREO)
328164614Sariff		ret |= (2 & 0x3f) << 2;
329164614Sariff	else
330193640Sariff		ret |= (1 & 0x3f) << 2;*/
331193640Sariff	ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2;
332154969Sariff	if (fmt & AFMT_A_LAW)
333164614Sariff		ret |= 1 << 8;
334164614Sariff	else if (fmt & AFMT_MU_LAW)
335164614Sariff		ret |= 1 << 9;
336164614Sariff	else if (fmt & AFMT_8BIT)
337164614Sariff		ret |= 1 << 10;
338164614Sariff	else if (fmt & AFMT_16BIT)
339164614Sariff		ret |= 1 << 11;
340164614Sariff	else if (fmt & AFMT_24BIT)
341164614Sariff		ret |= 1 << 12;
342164614Sariff	else if (fmt & AFMT_32BIT)
343164614Sariff		ret |= 1 << 13;
344164614Sariff
345164614Sariff	return ret;
346154684Sariff}
347154684Sariff
348164614Sariffstatic u_int32_t
349193640Sariffsnd_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq)
350154684Sariff{
351164614Sariff	u_int32_t best, score, score2, oldscore;
352164614Sariff	int i;
353154684Sariff
354164614Sariff	if (fmt == 0 || fmts == NULL || fmts[0] == 0)
355164614Sariff		return 0;
356164614Sariff
357193640Sariff	if (snd_fmtvalid(fmt, fmts))
358164614Sariff		return fmt;
359164614Sariff
360154684Sariff	best = 0;
361193640Sariff	score = snd_fmtscore(fmt);
362154684Sariff	oldscore = 0;
363154684Sariff	for (i = 0; fmts[i] != 0; i++) {
364193640Sariff		score2 = snd_fmtscore(fmts[i]);
365193640Sariff		if (cheq && !score_cheq(score, score2) &&
366193640Sariff		    (score_chlt(score2, score) ||
367193640Sariff		    (oldscore != 0 && score_chgt(score2, oldscore))))
368193640Sariff				continue;
369164614Sariff		if (oldscore == 0 ||
370164614Sariff			    (score_val(score2) == score_val(score)) ||
371164614Sariff			    (score_val(score2) == score_val(oldscore)) ||
372164614Sariff			    (score_val(score2) > score_val(oldscore) &&
373164614Sariff			    score_val(score2) < score_val(score)) ||
374164614Sariff			    (score_val(score2) < score_val(oldscore) &&
375164614Sariff			    score_val(score2) > score_val(score)) ||
376164614Sariff			    (score_val(oldscore) < score_val(score) &&
377164614Sariff			    score_val(score2) > score_val(oldscore))) {
378164614Sariff			if (score_val(oldscore) != score_val(score2) ||
379164614Sariff				    score_cse(score) == score_cse(score2) ||
380164614Sariff				    ((score_cse(oldscore) != score_cse(score) &&
381164614Sariff				    !score_endianeq(score, oldscore) &&
382164614Sariff				    (score_endianeq(score, score2) ||
383164614Sariff				    (!score_signeq(score, oldscore) &&
384164614Sariff				    score_signeq(score, score2)))))) {
385164614Sariff				best = fmts[i];
386164614Sariff				oldscore = score2;
387164614Sariff			}
388154684Sariff		}
389154684Sariff	}
390154684Sariff	return best;
391154684Sariff}
392154684Sariff
393154684Sariffu_int32_t
394193640Sariffsnd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts)
395164614Sariff{
396193640Sariff	return snd_fmtbestfunc(fmt, fmts, 0);
397164614Sariff}
398164614Sariff
399164614Sariffu_int32_t
400193640Sariffsnd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts)
401154684Sariff{
402193640Sariff	return snd_fmtbestfunc(fmt, fmts, 1);
403154684Sariff}
404154684Sariff
405154684Sariffu_int32_t
406193640Sariffsnd_fmtbest(u_int32_t fmt, u_int32_t *fmts)
407154684Sariff{
408154684Sariff	u_int32_t best1, best2;
409164614Sariff	u_int32_t score, score1, score2;
410154684Sariff
411193640Sariff	if (snd_fmtvalid(fmt, fmts))
412164614Sariff		return fmt;
413164614Sariff
414193640Sariff	best1 = snd_fmtbestchannel(fmt, fmts);
415193640Sariff	best2 = snd_fmtbestbit(fmt, fmts);
416154684Sariff
417164614Sariff	if (best1 != 0 && best2 != 0 && best1 != best2) {
418193640Sariff		/*if (fmt & AFMT_STEREO)*/
419193640Sariff		if (AFMT_CHANNEL(fmt) > 1)
420154684Sariff			return best1;
421154684Sariff		else {
422193640Sariff			score = score_val(snd_fmtscore(fmt));
423193640Sariff			score1 = score_val(snd_fmtscore(best1));
424193640Sariff			score2 = score_val(snd_fmtscore(best2));
425154969Sariff			if (score1 == score2 || score1 == score)
426154969Sariff				return best1;
427154969Sariff			else if (score2 == score)
428154684Sariff				return best2;
429154969Sariff			else if (score1 > score2)
430154684Sariff				return best1;
431154684Sariff			return best2;
432154684Sariff		}
433154684Sariff	} else if (best2 == 0)
434154684Sariff		return best1;
435155958Sjhb	else
436154684Sariff		return best2;
437154684Sariff}
438154684Sariff
439117307Scgvoid
440117307Scgfeeder_printchain(struct pcm_feeder *head)
441117307Scg{
442117307Scg	struct pcm_feeder *f;
443117307Scg
444117307Scg	printf("feeder chain (head @%p)\n", head);
445117307Scg	f = head;
446117307Scg	while (f != NULL) {
447117307Scg		printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f);
448117307Scg		f = f->source;
449117307Scg	}
450117307Scg	printf("[end]\n\n");
451117307Scg}
452117307Scg
45366308Scg/*****************************************************************************/
45466308Scg
45566308Scgstatic int
45674763Scgfeed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source)
45766308Scg{
45874763Scg	struct snd_dbuf *src = source;
459164614Sariff	int l, offset;
46066308Scg
46174763Scg	KASSERT(count > 0, ("feed_root: count == 0"));
46266308Scg
463164614Sariff	if (++ch->feedcount == 0)
464164614Sariff		ch->feedcount = 2;
465164614Sariff
46674763Scg	l = min(count, sndbuf_getready(src));
46766308Scg
468110287Sorion	/* When recording only return as much data as available */
469164614Sariff	if (ch->direction == PCMDIR_REC) {
470164614Sariff		sndbuf_dispose(src, buffer, l);
471110287Sorion		return l;
472164614Sariff	}
473110287Sorion
47474763Scg
475164614Sariff	offset = count - l;
47674763Scg
477164614Sariff	if (offset > 0) {
478164614Sariff		if (snd_verbose > 3)
479164614Sariff			printf("%s: (%s) %spending %d bytes "
480164614Sariff			    "(count=%d l=%d feed=%d)\n",
481164614Sariff			    __func__,
482164614Sariff			    (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
483164614Sariff			    (ch->feedcount == 1) ? "pre" : "ap",
484164614Sariff			    offset, count, l, ch->feedcount);
485164614Sariff
486164614Sariff		if (ch->feedcount == 1) {
487167644Sariff			memset(buffer,
488167644Sariff			    sndbuf_zerodata(sndbuf_getfmt(src)),
489167644Sariff			    offset);
490164614Sariff			if (l > 0)
491164614Sariff				sndbuf_dispose(src, buffer + offset, l);
492164614Sariff			else
493164614Sariff				ch->feedcount--;
494164614Sariff		} else {
495164614Sariff			if (l > 0)
496164614Sariff				sndbuf_dispose(src, buffer, l);
497167644Sariff			memset(buffer + l,
498167644Sariff			    sndbuf_zerodata(sndbuf_getfmt(src)),
499167644Sariff			    offset);
500167644Sariff			if (!(ch->flags & CHN_F_CLOSING))
501167644Sariff				ch->xruns++;
502164614Sariff		}
503164614Sariff	} else if (l > 0)
504164614Sariff		sndbuf_dispose(src, buffer, l);
505164614Sariff
50666308Scg	return count;
50766308Scg}
50870134Scg
50970134Scgstatic kobj_method_t feeder_root_methods[] = {
51070134Scg    	KOBJMETHOD(feeder_feed,		feed_root),
511193640Sariff	KOBJMETHOD_END
51266308Scg};
51370134Scgstatic struct feeder_class feeder_root_class = {
514118473Sdds	.name =		"feeder_root",
515118473Sdds	.methods =	feeder_root_methods,
516118473Sdds	.size =		sizeof(struct pcm_feeder),
517118473Sdds	.desc =		NULL,
518118473Sdds	.data =		NULL,
51970134Scg};
52070134ScgSYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class);
52174363ScgSYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL);
522