xref: /dragonfly/sys/dev/sound/pcm/buffer.c (revision e98bdfd3)
1 /*-
2  * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3  * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
4  * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #ifdef HAVE_KERNEL_OPTION_HEADERS
30 #include "opt_snd.h"
31 #endif
32 
33 #include <dev/sound/pcm/sound.h>
34 
35 #include "feeder_if.h"
36 
37 #define SND_USE_FXDIV
38 #include "snd_fxdiv_gen.h"
39 
40 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/buffer.c 267762 2014-06-23 03:45:39Z kan $");
41 
42 /*
43  * XXX
44  *
45  * sndbuf_kqtask is a taskqueue callback routine, called from
46  * taskqueue_swi, which runs under the MP lock.
47  *
48  * The only purpose is to be able to KNOTE() from a sound
49  * interrupt, which is running without MP lock held and thus
50  * can't call KNOTE() directly.
51  */
52 static void
53 sndbuf_kqtask(void *context, int pending)
54 {
55 	struct snd_dbuf *b = context;
56 	struct kqinfo *ki = sndbuf_getkq(b);
57 
58 	KNOTE(&ki->ki_note, 0);
59 }
60 
61 struct snd_dbuf *
62 sndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel)
63 {
64 	struct snd_dbuf *b;
65 
66 	b = kmalloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO);
67 	ksnprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc);
68 	b->dev = dev;
69 	b->channel = channel;
70 	TASK_INIT(&b->kqtask, 0, sndbuf_kqtask, b);
71 
72 	return b;
73 }
74 
75 void
76 sndbuf_destroy(struct snd_dbuf *b)
77 {
78 	sndbuf_free(b);
79 	kfree(b, M_DEVBUF);
80 }
81 
82 bus_addr_t
83 sndbuf_getbufaddr(struct snd_dbuf *buf)
84 {
85 	return (buf->buf_addr);
86 }
87 
88 static void
89 sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
90 {
91 	struct snd_dbuf *b = (struct snd_dbuf *)arg;
92 
93 	if (snd_verbose > 3) {
94 		device_printf(b->dev, "sndbuf_setmap %lx, %lx; ",
95 		    (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len);
96 		kprintf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr);
97 	}
98 	if (error == 0)
99 		b->buf_addr = segs[0].ds_addr;
100 	else
101 		b->buf_addr = 0;
102 }
103 
104 /*
105  * Allocate memory for DMA buffer. If the device does not use DMA transfers,
106  * the driver can call malloc(9) and sndbuf_setup() itself.
107  */
108 
109 int
110 sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags,
111     unsigned int size)
112 {
113 	int ret;
114 
115 	b->dmatag = dmatag;
116 	b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT;
117 	b->maxsize = size;
118 	b->bufsize = b->maxsize;
119 	b->buf_addr = 0;
120 	b->flags |= SNDBUF_F_MANAGED;
121 	if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags,
122 	    &b->dmamap)) {
123 		sndbuf_free(b);
124 		return (ENOMEM);
125 	}
126 	if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize,
127 	    sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) {
128 		sndbuf_free(b);
129 		return (ENOMEM);
130 	}
131 
132 	ret = sndbuf_resize(b, 2, b->maxsize / 2);
133 	if (ret != 0)
134 		sndbuf_free(b);
135 
136 	return (ret);
137 }
138 
139 int
140 sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size)
141 {
142 	b->flags &= ~SNDBUF_F_MANAGED;
143 	if (buf)
144 		b->flags |= SNDBUF_F_MANAGED;
145 	b->buf = buf;
146 	b->maxsize = size;
147 	b->bufsize = b->maxsize;
148 	return sndbuf_resize(b, 2, b->maxsize / 2);
149 }
150 
151 void
152 sndbuf_free(struct snd_dbuf *b)
153 {
154 	if (b->tmpbuf)
155 		kfree(b->tmpbuf, M_DEVBUF);
156 
157 	if (b->shadbuf)
158 		kfree(b->shadbuf, M_DEVBUF);
159 
160 	if (b->buf) {
161 		if (b->flags & SNDBUF_F_MANAGED) {
162 			if (b->buf_addr)
163 				bus_dmamap_unload(b->dmatag, b->dmamap);
164 			if (b->dmatag)
165 				bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
166 		} else
167 			kfree(b->buf, M_DEVBUF);
168 	}
169 
170 	b->tmpbuf = NULL;
171 	b->shadbuf = NULL;
172 	b->buf = NULL;
173 	b->sl = 0;
174 	b->dmatag = NULL;
175 	b->dmamap = NULL;
176 }
177 
178 #define SNDBUF_CACHE_SHIFT	5
179 
180 int
181 sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
182 {
183 	unsigned int bufsize, allocsize;
184 	u_int8_t *tmpbuf;
185 
186 	CHN_LOCK(b->channel);
187 	if (b->maxsize == 0)
188 		goto out;
189 	if (blkcnt == 0)
190 		blkcnt = b->blkcnt;
191 	if (blksz == 0)
192 		blksz = b->blksz;
193 	if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) {
194 		CHN_UNLOCK(b->channel);
195 		return EINVAL;
196 	}
197 	if (blkcnt == b->blkcnt && blksz == b->blksz)
198 		goto out;
199 
200 	bufsize = blkcnt * blksz;
201 
202 	if (bufsize > b->allocsize ||
203 	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
204 		allocsize = round_page(bufsize);
205 		CHN_UNLOCK(b->channel);
206 		tmpbuf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
207 		CHN_LOCK(b->channel);
208 		if (snd_verbose > 3)
209 			kprintf("%s(): b=%p %p -> %p [%d -> %d : %d]\n",
210 			    __func__, b, b->tmpbuf, tmpbuf,
211 			    b->allocsize, allocsize, bufsize);
212 		if (b->tmpbuf != NULL)
213 			kfree(b->tmpbuf, M_DEVBUF);
214 		b->tmpbuf = tmpbuf;
215 		b->allocsize = allocsize;
216 	} else if (snd_verbose > 3)
217 		kprintf("%s(): b=%p %d [%d] NOCHANGE\n",
218 		    __func__, b, b->allocsize, b->bufsize);
219 
220 	b->blkcnt = blkcnt;
221 	b->blksz = blksz;
222 	b->bufsize = bufsize;
223 
224 	sndbuf_reset(b);
225 out:
226 	CHN_UNLOCK(b->channel);
227 	return 0;
228 }
229 
230 int
231 sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
232 {
233         unsigned int bufsize, allocsize;
234 	u_int8_t *buf, *tmpbuf, *shadbuf;
235 
236 	if (blkcnt < 2 || blksz < 16)
237 		return EINVAL;
238 
239 	bufsize = blksz * blkcnt;
240 
241 	if (bufsize > b->allocsize ||
242 	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
243 		allocsize = round_page(bufsize);
244 		CHN_UNLOCK(b->channel);
245 		buf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
246 		tmpbuf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
247 		shadbuf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
248 		CHN_LOCK(b->channel);
249 		if (b->buf != NULL)
250 			kfree(b->buf, M_DEVBUF);
251 		b->buf = buf;
252 		if (b->tmpbuf != NULL)
253 			kfree(b->tmpbuf, M_DEVBUF);
254 		b->tmpbuf = tmpbuf;
255 		if (b->shadbuf != NULL)
256 			kfree(b->shadbuf, M_DEVBUF);
257 		b->shadbuf = shadbuf;
258 		if (snd_verbose > 3)
259 			kprintf("%s(): b=%p %d -> %d [%d]\n",
260 			    __func__, b, b->allocsize, allocsize, bufsize);
261 		b->allocsize = allocsize;
262 	} else if (snd_verbose > 3)
263 		kprintf("%s(): b=%p %d [%d] NOCHANGE\n",
264 		    __func__, b, b->allocsize, b->bufsize);
265 
266 	b->blkcnt = blkcnt;
267 	b->blksz = blksz;
268 	b->bufsize = bufsize;
269 	b->maxsize = bufsize;
270 	b->sl = bufsize;
271 
272 	sndbuf_reset(b);
273 
274 	return 0;
275 }
276 
277 /**
278  * @brief Zero out space in buffer free area
279  *
280  * This function clears a chunk of @c length bytes in the buffer free area
281  * (i.e., where the next write will be placed).
282  *
283  * @param b		buffer context
284  * @param length	number of bytes to blank
285  */
286 void
287 sndbuf_clear(struct snd_dbuf *b, unsigned int length)
288 {
289 	int i;
290 	u_char data, *p;
291 
292 	if (length == 0)
293 		return;
294 	if (length > b->bufsize)
295 		length = b->bufsize;
296 
297 	data = sndbuf_zerodata(b->fmt);
298 
299 	i = sndbuf_getfreeptr(b);
300 	p = sndbuf_getbuf(b);
301 	while (length > 0) {
302 		p[i] = data;
303 		length--;
304 		i++;
305 		if (i >= b->bufsize)
306 			i = 0;
307 	}
308 }
309 
310 /**
311  * @brief Zap buffer contents, resetting "ready area" fields
312  *
313  * @param b	buffer context
314  */
315 void
316 sndbuf_fillsilence(struct snd_dbuf *b)
317 {
318 	if (b->bufsize > 0)
319 		memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
320 	b->rp = 0;
321 	b->rl = b->bufsize;
322 }
323 
324 void
325 sndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl)
326 {
327 	if (b->bufsize > 0)
328 		memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
329 	b->rp = 0;
330 	b->rl = min(b->bufsize, rl);
331 }
332 
333 /**
334  * @brief Reset buffer w/o flushing statistics
335  *
336  * This function just zeroes out buffer contents and sets the "ready length"
337  * to zero.  This was originally to facilitate minimal playback interruption
338  * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls.
339  *
340  * @param b	buffer context
341  */
342 void
343 sndbuf_softreset(struct snd_dbuf *b)
344 {
345 	b->rl = 0;
346 	if (b->buf && b->bufsize > 0)
347 		sndbuf_clear(b, b->bufsize);
348 }
349 
350 void
351 sndbuf_reset(struct snd_dbuf *b)
352 {
353 	b->hp = 0;
354 	b->rp = 0;
355 	b->rl = 0;
356 	b->dl = 0;
357 	b->prev_total = 0;
358 	b->total = 0;
359 	b->xrun = 0;
360 	if (b->buf && b->bufsize > 0)
361 		sndbuf_clear(b, b->bufsize);
362 	sndbuf_clearshadow(b);
363 }
364 
365 u_int32_t
366 sndbuf_getfmt(struct snd_dbuf *b)
367 {
368 	return b->fmt;
369 }
370 
371 int
372 sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
373 {
374 	b->fmt = fmt;
375 	b->bps = AFMT_BPS(b->fmt);
376 	b->align = AFMT_ALIGN(b->fmt);
377 #if 0
378 	b->bps = AFMT_CHANNEL(b->fmt);
379 	if (b->fmt & AFMT_16BIT)
380 		b->bps <<= 1;
381 	else if (b->fmt & AFMT_24BIT)
382 		b->bps *= 3;
383 	else if (b->fmt & AFMT_32BIT)
384 		b->bps <<= 2;
385 #endif
386 	return 0;
387 }
388 
389 unsigned int
390 sndbuf_getspd(struct snd_dbuf *b)
391 {
392 	return b->spd;
393 }
394 
395 void
396 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
397 {
398 	b->spd = spd;
399 }
400 
401 unsigned int
402 sndbuf_getalign(struct snd_dbuf *b)
403 {
404 	return (b->align);
405 }
406 
407 unsigned int
408 sndbuf_getblkcnt(struct snd_dbuf *b)
409 {
410 	return b->blkcnt;
411 }
412 
413 void
414 sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt)
415 {
416 	b->blkcnt = blkcnt;
417 }
418 
419 unsigned int
420 sndbuf_getblksz(struct snd_dbuf *b)
421 {
422 	return b->blksz;
423 }
424 
425 void
426 sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz)
427 {
428 	b->blksz = blksz;
429 }
430 
431 unsigned int
432 sndbuf_getbps(struct snd_dbuf *b)
433 {
434 	return b->bps;
435 }
436 
437 void *
438 sndbuf_getbuf(struct snd_dbuf *b)
439 {
440 	return b->buf;
441 }
442 
443 void *
444 sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs)
445 {
446 	KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs));
447 
448 	return b->buf + ofs;
449 }
450 
451 unsigned int
452 sndbuf_getsize(struct snd_dbuf *b)
453 {
454 	return b->bufsize;
455 }
456 
457 unsigned int
458 sndbuf_getmaxsize(struct snd_dbuf *b)
459 {
460 	return b->maxsize;
461 }
462 
463 unsigned int
464 sndbuf_getallocsize(struct snd_dbuf *b)
465 {
466 	return b->allocsize;
467 }
468 
469 unsigned int
470 sndbuf_runsz(struct snd_dbuf *b)
471 {
472 	return b->dl;
473 }
474 
475 void
476 sndbuf_setrun(struct snd_dbuf *b, int go)
477 {
478 	b->dl = go? b->blksz : 0;
479 }
480 
481 struct kqinfo *
482 sndbuf_getkq(struct snd_dbuf *b)
483 {
484 	return &b->kq;
485 }
486 
487 /************************************************************/
488 unsigned int
489 sndbuf_getxrun(struct snd_dbuf *b)
490 {
491 	SNDBUF_LOCKASSERT(b);
492 
493 	return b->xrun;
494 }
495 
496 void
497 sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun)
498 {
499 	SNDBUF_LOCKASSERT(b);
500 
501 	b->xrun = xrun;
502 }
503 
504 unsigned int
505 sndbuf_gethwptr(struct snd_dbuf *b)
506 {
507 	SNDBUF_LOCKASSERT(b);
508 
509 	return b->hp;
510 }
511 
512 void
513 sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr)
514 {
515 	SNDBUF_LOCKASSERT(b);
516 
517 	b->hp = ptr;
518 }
519 
520 unsigned int
521 sndbuf_getready(struct snd_dbuf *b)
522 {
523 	SNDBUF_LOCKASSERT(b);
524 	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
525 
526 	return b->rl;
527 }
528 
529 unsigned int
530 sndbuf_getreadyptr(struct snd_dbuf *b)
531 {
532 	SNDBUF_LOCKASSERT(b);
533 	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
534 
535 	return b->rp;
536 }
537 
538 unsigned int
539 sndbuf_getfree(struct snd_dbuf *b)
540 {
541 	SNDBUF_LOCKASSERT(b);
542 	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
543 
544 	return b->bufsize - b->rl;
545 }
546 
547 unsigned int
548 sndbuf_getfreeptr(struct snd_dbuf *b)
549 {
550 	SNDBUF_LOCKASSERT(b);
551 	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
552 	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
553 
554 	return (b->rp + b->rl) % b->bufsize;
555 }
556 
557 u_int64_t
558 sndbuf_getblocks(struct snd_dbuf *b)
559 {
560 	SNDBUF_LOCKASSERT(b);
561 
562 	return b->total / b->blksz;
563 }
564 
565 u_int64_t
566 sndbuf_getprevblocks(struct snd_dbuf *b)
567 {
568 	SNDBUF_LOCKASSERT(b);
569 
570 	return b->prev_total / b->blksz;
571 }
572 
573 u_int64_t
574 sndbuf_gettotal(struct snd_dbuf *b)
575 {
576 	SNDBUF_LOCKASSERT(b);
577 
578 	return b->total;
579 }
580 
581 u_int64_t
582 sndbuf_getprevtotal(struct snd_dbuf *b)
583 {
584 	SNDBUF_LOCKASSERT(b);
585 
586 	return b->prev_total;
587 }
588 
589 void
590 sndbuf_updateprevtotal(struct snd_dbuf *b)
591 {
592 	SNDBUF_LOCKASSERT(b);
593 
594 	b->prev_total = b->total;
595 }
596 
597 unsigned int
598 sndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to)
599 {
600 	if (from == NULL || to == NULL || v == 0)
601 		return 0;
602 
603 	return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from),
604 	    sndbuf_getalign(to) * sndbuf_getspd(to));
605 }
606 
607 u_int8_t
608 sndbuf_zerodata(u_int32_t fmt)
609 {
610 	if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH))
611 		return (0x00);
612 	else if (fmt & AFMT_MU_LAW)
613 		return (0x7f);
614 	else if (fmt & AFMT_A_LAW)
615 		return (0x55);
616 	return (0x80);
617 }
618 
619 /************************************************************/
620 
621 /**
622  * @brief Acquire buffer space to extend ready area
623  *
624  * This function extends the ready area length by @c count bytes, and may
625  * optionally copy samples from another location stored in @c from.  The
626  * counter @c snd_dbuf::total is also incremented by @c count bytes.
627  *
628  * @param b	audio buffer
629  * @param from	sample source (optional)
630  * @param count	number of bytes to acquire
631  *
632  * @retval 0	Unconditional
633  */
634 int
635 sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count)
636 {
637 	int l;
638 
639 	KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b)));
640 	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
641 	b->total += count;
642 	if (from != NULL) {
643 		while (count > 0) {
644 			l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b));
645 			bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l);
646 			from += l;
647 			b->rl += l;
648 			count -= l;
649 		}
650 	} else
651 		b->rl += count;
652 	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
653 
654 	return 0;
655 }
656 
657 /**
658  * @brief Dispose samples from channel buffer, increasing size of ready area
659  *
660  * This function discards samples from the supplied buffer by advancing the
661  * ready area start pointer and decrementing the ready area length.  If
662  * @c to is not NULL, then the discard samples will be copied to the location
663  * it points to.
664  *
665  * @param b	PCM channel sound buffer
666  * @param to	destination buffer (optional)
667  * @param count	number of bytes to discard
668  *
669  * @returns 0 unconditionally
670  */
671 int
672 sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
673 {
674 	int l;
675 
676 	KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b)));
677 	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
678 	if (to != NULL) {
679 		while (count > 0) {
680 			l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b));
681 			bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l);
682 			to += l;
683 			b->rl -= l;
684 			b->rp = (b->rp + l) % b->bufsize;
685 			count -= l;
686 		}
687 	} else {
688 		b->rl -= count;
689 		b->rp = (b->rp + count) % b->bufsize;
690 	}
691 	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
692 
693 	return 0;
694 }
695 
696 #ifdef SND_DIAGNOSTIC
697 static uint32_t snd_feeder_maxfeed = 0;
698 SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD,
699     &snd_feeder_maxfeed, 0, "maximum feeder count request");
700 
701 static uint32_t snd_feeder_maxcycle = 0;
702 SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD,
703     &snd_feeder_maxcycle, 0, "maximum feeder cycle");
704 #endif
705 
706 /* count is number of bytes we want added to destination buffer */
707 int
708 sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)
709 {
710 	unsigned int cnt, maxfeed;
711 #ifdef SND_DIAGNOSTIC
712 	unsigned int cycle;
713 
714 	if (count > snd_feeder_maxfeed)
715 		snd_feeder_maxfeed = count;
716 
717 	cycle = 0;
718 #endif
719 
720 	KASSERT(count > 0, ("can't feed 0 bytes"));
721 
722 	if (sndbuf_getfree(to) < count)
723 		return (EINVAL);
724 
725 	maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to));
726 
727 	do {
728 		cnt = FEEDER_FEED(feeder, channel, to->tmpbuf,
729 		    min(count, maxfeed), from);
730 		if (cnt == 0)
731 			break;
732 		sndbuf_acquire(to, to->tmpbuf, cnt);
733 		count -= cnt;
734 #ifdef SND_DIAGNOSTIC
735 		cycle++;
736 #endif
737 	} while (count != 0);
738 
739 #ifdef SND_DIAGNOSTIC
740 	if (cycle > snd_feeder_maxcycle)
741 		snd_feeder_maxcycle = cycle;
742 #endif
743 
744 	return (0);
745 }
746 
747 /************************************************************/
748 
749 void
750 sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what)
751 {
752 	kprintf("%s: [", s);
753 	if (what & 0x01)
754 		kprintf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize);
755 	if (what & 0x02)
756 		kprintf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp);
757 	if (what & 0x04)
758 		kprintf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun);
759    	if (what & 0x08)
760 		kprintf(" fmt: 0x%x, spd: %d", b->fmt, b->spd);
761 	if (what & 0x10)
762 		kprintf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags);
763 	kprintf(" ]\n");
764 }
765 
766 /************************************************************/
767 u_int32_t
768 sndbuf_getflags(struct snd_dbuf *b)
769 {
770 	return b->flags;
771 }
772 
773 void
774 sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on)
775 {
776 	b->flags &= ~flags;
777 	if (on)
778 		b->flags |= flags;
779 }
780 
781 /**
782  * @brief Clear the shadow buffer by filling with samples equal to zero.
783  *
784  * @param b buffer to clear
785  */
786 void
787 sndbuf_clearshadow(struct snd_dbuf *b)
788 {
789 	KASSERT(b != NULL, ("b is a null pointer"));
790 	KASSERT(b->sl >= 0, ("illegal shadow length"));
791 
792 	if ((b->shadbuf != NULL) && (b->sl > 0))
793 		memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl);
794 }
795 
796 #ifdef OSSV4_EXPERIMENT
797 /**
798  * @brief Return peak value from samples in buffer ready area.
799  *
800  * Peak ranges from 0-32767.  If channel is monaural, most significant 16
801  * bits will be zero.  For now, only expects to work with 1-2 channel
802  * buffers.
803  *
804  * @note  Currently only operates with linear PCM formats.
805  *
806  * @param b buffer to analyze
807  * @param lpeak pointer to store left peak value
808  * @param rpeak pointer to store right peak value
809  */
810 void
811 sndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp)
812 {
813 	u_int32_t lpeak, rpeak;
814 
815 	lpeak = 0;
816 	rpeak = 0;
817 
818 	/**
819 	 * @todo fill this in later
820 	 */
821 }
822 #endif
823