1139749Simp/*-
2193640Sariff * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3193640Sariff * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
4193640Sariff * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
570291Scg * All rights reserved.
670291Scg *
770291Scg * Redistribution and use in source and binary forms, with or without
870291Scg * modification, are permitted provided that the following conditions
970291Scg * are met:
1070291Scg * 1. Redistributions of source code must retain the above copyright
1170291Scg *    notice, this list of conditions and the following disclaimer.
1270291Scg * 2. Redistributions in binary form must reproduce the above copyright
1370291Scg *    notice, this list of conditions and the following disclaimer in the
1470291Scg *    documentation and/or other materials provided with the distribution.
1570291Scg *
1670291Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1770291Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1870291Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1970291Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2070291Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2170291Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2270291Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2370291Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2470291Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2570291Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2670291Scg * SUCH DAMAGE.
2770291Scg */
2870291Scg
29193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
30193640Sariff#include "opt_snd.h"
31193640Sariff#endif
32193640Sariff
3370291Scg#include <dev/sound/pcm/sound.h>
3470291Scg
3574763Scg#include "feeder_if.h"
3674763Scg
37193640Sariff#define SND_USE_FXDIV
38319065Shselasky#define	SND_DECLARE_FXDIV
39193640Sariff#include "snd_fxdiv_gen.h"
40193640Sariff
4182180ScgSND_DECLARE_FILE("$FreeBSD: stable/11/sys/dev/sound/pcm/buffer.c 319065 2017-05-28 10:43:16Z hselasky $");
4282180Scg
4374763Scgstruct snd_dbuf *
44125136Struckmansndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel)
4574763Scg{
4674763Scg	struct snd_dbuf *b;
4774763Scg
48111119Simp	b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO);
4974763Scg	snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc);
5089834Scg	b->dev = dev;
51125136Struckman	b->channel = channel;
5289834Scg
5374763Scg	return b;
5474763Scg}
5574763Scg
5674763Scgvoid
5774763Scgsndbuf_destroy(struct snd_dbuf *b)
5874763Scg{
59167773Sariff	sndbuf_free(b);
6074763Scg	free(b, M_DEVBUF);
6174763Scg}
6274763Scg
63111183Scognetbus_addr_t
64111183Scognetsndbuf_getbufaddr(struct snd_dbuf *buf)
65111183Scognet{
66111183Scognet	return (buf->buf_addr);
67111183Scognet}
68111183Scognet
6970291Scgstatic void
7070291Scgsndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
7170291Scg{
7274763Scg	struct snd_dbuf *b = (struct snd_dbuf *)arg;
7370291Scg
74243450Smav	if (snd_verbose > 3) {
75136531Syongari		device_printf(b->dev, "sndbuf_setmap %lx, %lx; ",
76136531Syongari		    (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len);
77136531Syongari		printf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr);
7870291Scg	}
79136531Syongari	if (error == 0)
80136531Syongari		b->buf_addr = segs[0].ds_addr;
81136531Syongari	else
82136531Syongari		b->buf_addr = 0;
8370291Scg}
8470291Scg
8570291Scg/*
8674763Scg * Allocate memory for DMA buffer. If the device does not use DMA transfers,
8774763Scg * the driver can call malloc(9) and sndbuf_setup() itself.
8870291Scg */
89111183Scognet
9070291Scgint
91168847Sariffsndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags,
92168847Sariff    unsigned int size)
9370291Scg{
94136531Syongari	int ret;
95136531Syongari
9670291Scg	b->dmatag = dmatag;
97219548Smarius	b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT;
9870291Scg	b->maxsize = size;
9970291Scg	b->bufsize = b->maxsize;
100136531Syongari	b->buf_addr = 0;
101166393Sariff	b->flags |= SNDBUF_F_MANAGED;
102168847Sariff	if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags,
103167773Sariff	    &b->dmamap)) {
104167773Sariff		sndbuf_free(b);
105136531Syongari		return (ENOMEM);
106167773Sariff	}
107136531Syongari	if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize,
108136531Syongari	    sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) {
109167773Sariff		sndbuf_free(b);
110136531Syongari		return (ENOMEM);
111136531Syongari	}
112136531Syongari
113136531Syongari	ret = sndbuf_resize(b, 2, b->maxsize / 2);
114136531Syongari	if (ret != 0)
115136531Syongari		sndbuf_free(b);
116167773Sariff
117136531Syongari	return (ret);
11870291Scg}
11970291Scg
12070291Scgint
12174763Scgsndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size)
12270291Scg{
123167773Sariff	b->flags &= ~SNDBUF_F_MANAGED;
124166393Sariff	if (buf)
125166393Sariff		b->flags |= SNDBUF_F_MANAGED;
12670291Scg	b->buf = buf;
12770291Scg	b->maxsize = size;
12870291Scg	b->bufsize = b->maxsize;
12970291Scg	return sndbuf_resize(b, 2, b->maxsize / 2);
13070291Scg}
13170291Scg
13270291Scgvoid
13374763Scgsndbuf_free(struct snd_dbuf *b)
13470291Scg{
13574763Scg	if (b->tmpbuf)
13674763Scg		free(b->tmpbuf, M_DEVBUF);
13774763Scg
138162588Snetchild	if (b->shadbuf)
139162588Snetchild		free(b->shadbuf, M_DEVBUF);
140167773Sariff
141167773Sariff	if (b->buf) {
142167773Sariff		if (b->flags & SNDBUF_F_MANAGED) {
143267581Sjhb			if (b->buf_addr)
144167773Sariff				bus_dmamap_unload(b->dmatag, b->dmamap);
145267762Skan			if (b->dmatag)
146267762Skan				bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
147167773Sariff		} else
148167773Sariff			free(b->buf, M_DEVBUF);
149167773Sariff	}
150167773Sariff
151167773Sariff	b->tmpbuf = NULL;
152162588Snetchild	b->shadbuf = NULL;
153167773Sariff	b->buf = NULL;
154162588Snetchild	b->sl = 0;
155167773Sariff	b->dmatag = NULL;
15677265Scg	b->dmamap = NULL;
15770291Scg}
15870291Scg
159170722Sariff#define SNDBUF_CACHE_SHIFT	5
160170722Sariff
16170291Scgint
16274763Scgsndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
16370291Scg{
164170722Sariff	unsigned int bufsize, allocsize;
165170722Sariff	u_int8_t *tmpbuf;
166125136Struckman
167193640Sariff	CHN_LOCK(b->channel);
16874763Scg	if (b->maxsize == 0)
169125136Struckman		goto out;
17070291Scg	if (blkcnt == 0)
17170291Scg		blkcnt = b->blkcnt;
17270291Scg	if (blksz == 0)
17370291Scg		blksz = b->blksz;
174170722Sariff	if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) {
175193640Sariff		CHN_UNLOCK(b->channel);
17670291Scg		return EINVAL;
177125136Struckman	}
17889834Scg	if (blkcnt == b->blkcnt && blksz == b->blksz)
179125136Struckman		goto out;
180125136Struckman
181170722Sariff	bufsize = blkcnt * blksz;
182170722Sariff
183170815Sariff	if (bufsize > b->allocsize ||
184170722Sariff	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
185170722Sariff		allocsize = round_page(bufsize);
186193640Sariff		CHN_UNLOCK(b->channel);
187170722Sariff		tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
188193640Sariff		CHN_LOCK(b->channel);
189170722Sariff		if (snd_verbose > 3)
190170722Sariff			printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n",
191170722Sariff			    __func__, b, b->tmpbuf, tmpbuf,
192170722Sariff			    b->allocsize, allocsize, bufsize);
193170722Sariff		if (b->tmpbuf != NULL)
194170722Sariff			free(b->tmpbuf, M_DEVBUF);
195170722Sariff		b->tmpbuf = tmpbuf;
196170722Sariff		b->allocsize = allocsize;
197170722Sariff	} else if (snd_verbose > 3)
198170722Sariff		printf("%s(): b=%p %d [%d] NOCHANGE\n",
199170722Sariff		    __func__, b, b->allocsize, b->bufsize);
200170722Sariff
20170291Scg	b->blkcnt = blkcnt;
20270291Scg	b->blksz = blksz;
203170722Sariff	b->bufsize = bufsize;
204170722Sariff
20570291Scg	sndbuf_reset(b);
206125136Struckmanout:
207193640Sariff	CHN_UNLOCK(b->channel);
208125136Struckman	return 0;
20970291Scg}
21070291Scg
21174763Scgint
21274763Scgsndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
21374763Scg{
214170722Sariff        unsigned int bufsize, allocsize;
215170722Sariff	u_int8_t *buf, *tmpbuf, *shadbuf;
216107237Scg
21774763Scg	if (blkcnt < 2 || blksz < 16)
21874763Scg		return EINVAL;
21974763Scg
220107237Scg	bufsize = blksz * blkcnt;
22174763Scg
222170722Sariff	if (bufsize > b->allocsize ||
223170722Sariff	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
224170722Sariff		allocsize = round_page(bufsize);
225193640Sariff		CHN_UNLOCK(b->channel);
226170722Sariff		buf = malloc(allocsize, M_DEVBUF, M_WAITOK);
227170722Sariff		tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
228170722Sariff		shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
229193640Sariff		CHN_LOCK(b->channel);
230170722Sariff		if (b->buf != NULL)
231170722Sariff			free(b->buf, M_DEVBUF);
232170722Sariff		b->buf = buf;
233170722Sariff		if (b->tmpbuf != NULL)
234170722Sariff			free(b->tmpbuf, M_DEVBUF);
235170722Sariff		b->tmpbuf = tmpbuf;
236170722Sariff		if (b->shadbuf != NULL)
237170722Sariff			free(b->shadbuf, M_DEVBUF);
238170722Sariff		b->shadbuf = shadbuf;
239170722Sariff		if (snd_verbose > 3)
240170722Sariff			printf("%s(): b=%p %d -> %d [%d]\n",
241170722Sariff			    __func__, b, b->allocsize, allocsize, bufsize);
242170722Sariff		b->allocsize = allocsize;
243170722Sariff	} else if (snd_verbose > 3)
244170722Sariff		printf("%s(): b=%p %d [%d] NOCHANGE\n",
245170722Sariff		    __func__, b, b->allocsize, b->bufsize);
246162588Snetchild
247107237Scg	b->blkcnt = blkcnt;
248107237Scg	b->blksz = blksz;
249107237Scg	b->bufsize = bufsize;
250107237Scg	b->maxsize = bufsize;
251162588Snetchild	b->sl = bufsize;
252107237Scg
253125136Struckman	sndbuf_reset(b);
254125136Struckman
255170722Sariff	return 0;
25674763Scg}
25774763Scg
258162588Snetchild/**
259162588Snetchild * @brief Zero out space in buffer free area
260162588Snetchild *
261162588Snetchild * This function clears a chunk of @c length bytes in the buffer free area
262162588Snetchild * (i.e., where the next write will be placed).
263162588Snetchild *
264162588Snetchild * @param b		buffer context
265162588Snetchild * @param length	number of bytes to blank
266162588Snetchild */
26770291Scgvoid
26874763Scgsndbuf_clear(struct snd_dbuf *b, unsigned int length)
26970291Scg{
27070291Scg	int i;
27173768Scg	u_char data, *p;
27270291Scg
27370291Scg	if (length == 0)
27470291Scg		return;
27573768Scg	if (length > b->bufsize)
27673768Scg		length = b->bufsize;
27770291Scg
278164614Sariff	data = sndbuf_zerodata(b->fmt);
27970291Scg
28074763Scg	i = sndbuf_getfreeptr(b);
28174763Scg	p = sndbuf_getbuf(b);
28273768Scg	while (length > 0) {
28373768Scg		p[i] = data;
28473768Scg		length--;
28573768Scg		i++;
28673768Scg		if (i >= b->bufsize)
28770291Scg			i = 0;
28870291Scg	}
28970291Scg}
29070291Scg
291162588Snetchild/**
292162588Snetchild * @brief Zap buffer contents, resetting "ready area" fields
293162588Snetchild *
294162588Snetchild * @param b	buffer context
295162588Snetchild */
29670291Scgvoid
29777265Scgsndbuf_fillsilence(struct snd_dbuf *b)
29877265Scg{
299164614Sariff	if (b->bufsize > 0)
300164614Sariff		memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
30177265Scg	b->rp = 0;
30277265Scg	b->rl = b->bufsize;
30377265Scg}
30477265Scg
305230845Smavvoid
306230845Smavsndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl)
307230845Smav{
308230845Smav	if (b->bufsize > 0)
309230845Smav		memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
310230845Smav	b->rp = 0;
311230845Smav	b->rl = min(b->bufsize, rl);
312230845Smav}
313230845Smav
314162588Snetchild/**
315162588Snetchild * @brief Reset buffer w/o flushing statistics
316162588Snetchild *
317162588Snetchild * This function just zeroes out buffer contents and sets the "ready length"
318162588Snetchild * to zero.  This was originally to facilitate minimal playback interruption
319162588Snetchild * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls.
320162588Snetchild *
321162588Snetchild * @param b	buffer context
322162588Snetchild */
32377265Scgvoid
324162588Snetchildsndbuf_softreset(struct snd_dbuf *b)
325162588Snetchild{
326162588Snetchild	b->rl = 0;
327162588Snetchild	if (b->buf && b->bufsize > 0)
328162588Snetchild		sndbuf_clear(b, b->bufsize);
329162588Snetchild}
330162588Snetchild
331162588Snetchildvoid
33274763Scgsndbuf_reset(struct snd_dbuf *b)
33370291Scg{
33474763Scg	b->hp = 0;
33574763Scg	b->rp = 0;
33674763Scg	b->rl = 0;
33774763Scg	b->dl = 0;
33874763Scg	b->prev_total = 0;
33974763Scg	b->total = 0;
34074763Scg	b->xrun = 0;
34170291Scg	if (b->buf && b->bufsize > 0)
34270291Scg		sndbuf_clear(b, b->bufsize);
343162588Snetchild	sndbuf_clearshadow(b);
34470291Scg}
34570291Scg
34674763Scgu_int32_t
34774763Scgsndbuf_getfmt(struct snd_dbuf *b)
34874763Scg{
34974763Scg	return b->fmt;
35074763Scg}
35174763Scg
35270291Scgint
35374763Scgsndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
35470291Scg{
35570291Scg	b->fmt = fmt;
356193640Sariff	b->bps = AFMT_BPS(b->fmt);
357193640Sariff	b->align = AFMT_ALIGN(b->fmt);
358193640Sariff#if 0
359193640Sariff	b->bps = AFMT_CHANNEL(b->fmt);
360148606Snetchild	if (b->fmt & AFMT_16BIT)
361148606Snetchild		b->bps <<= 1;
362148606Snetchild	else if (b->fmt & AFMT_24BIT)
363148606Snetchild		b->bps *= 3;
364148606Snetchild	else if (b->fmt & AFMT_32BIT)
365148606Snetchild		b->bps <<= 2;
366193640Sariff#endif
36770291Scg	return 0;
36870291Scg}
36970291Scg
37074763Scgunsigned int
37174763Scgsndbuf_getspd(struct snd_dbuf *b)
37270291Scg{
37374763Scg	return b->spd;
37474763Scg}
37574763Scg
37674763Scgvoid
37774763Scgsndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
37874763Scg{
37974763Scg	b->spd = spd;
38074763Scg}
38174763Scg
38274763Scgunsigned int
38374763Scgsndbuf_getalign(struct snd_dbuf *b)
38474763Scg{
385193640Sariff	return (b->align);
38674763Scg}
38774763Scg
38874763Scgunsigned int
38974763Scgsndbuf_getblkcnt(struct snd_dbuf *b)
39074763Scg{
39174763Scg	return b->blkcnt;
39274763Scg}
39374763Scg
39474763Scgvoid
39574763Scgsndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt)
39674763Scg{
39774763Scg	b->blkcnt = blkcnt;
39874763Scg}
39974763Scg
40074763Scgunsigned int
40174763Scgsndbuf_getblksz(struct snd_dbuf *b)
40274763Scg{
40374763Scg	return b->blksz;
40474763Scg}
40574763Scg
40674763Scgvoid
40774763Scgsndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz)
40874763Scg{
40974763Scg	b->blksz = blksz;
41074763Scg}
41174763Scg
41274763Scgunsigned int
41374763Scgsndbuf_getbps(struct snd_dbuf *b)
41474763Scg{
41570291Scg	return b->bps;
41670291Scg}
41770291Scg
41870291Scgvoid *
41974763Scgsndbuf_getbuf(struct snd_dbuf *b)
42070291Scg{
42170291Scg	return b->buf;
42270291Scg}
42370291Scg
42474763Scgvoid *
42574763Scgsndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs)
42670291Scg{
42789771Scg	KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs));
42874763Scg
42974763Scg	return b->buf + ofs;
43074763Scg}
43174763Scg
43274763Scgunsigned int
43374763Scgsndbuf_getsize(struct snd_dbuf *b)
43474763Scg{
43570291Scg	return b->bufsize;
43670291Scg}
43770291Scg
43874763Scgunsigned int
43974763Scgsndbuf_getmaxsize(struct snd_dbuf *b)
44070291Scg{
44174763Scg	return b->maxsize;
44274763Scg}
44374763Scg
44474763Scgunsigned int
445170722Sariffsndbuf_getallocsize(struct snd_dbuf *b)
446170722Sariff{
447170722Sariff	return b->allocsize;
448170722Sariff}
449170722Sariff
450170722Sariffunsigned int
45174763Scgsndbuf_runsz(struct snd_dbuf *b)
45274763Scg{
45370291Scg	return b->dl;
45470291Scg}
45570291Scg
45674763Scgvoid
45774763Scgsndbuf_setrun(struct snd_dbuf *b, int go)
45874763Scg{
45974763Scg	b->dl = go? b->blksz : 0;
46074763Scg}
46174763Scg
46274763Scgstruct selinfo *
46374763Scgsndbuf_getsel(struct snd_dbuf *b)
46474763Scg{
46574763Scg	return &b->sel;
46674763Scg}
46774763Scg
46874763Scg/************************************************************/
46974763Scgunsigned int
47074763Scgsndbuf_getxrun(struct snd_dbuf *b)
47174763Scg{
47274763Scg	SNDBUF_LOCKASSERT(b);
47374763Scg
47474763Scg	return b->xrun;
47574763Scg}
47674763Scg
47774763Scgvoid
478160439Snetchildsndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun)
47974763Scg{
48074763Scg	SNDBUF_LOCKASSERT(b);
48174763Scg
482160439Snetchild	b->xrun = xrun;
48374763Scg}
48474763Scg
48574763Scgunsigned int
48674763Scgsndbuf_gethwptr(struct snd_dbuf *b)
48774763Scg{
48874763Scg	SNDBUF_LOCKASSERT(b);
48974763Scg
49074763Scg	return b->hp;
49174763Scg}
49274763Scg
49374763Scgvoid
49474763Scgsndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr)
49574763Scg{
49674763Scg	SNDBUF_LOCKASSERT(b);
49774763Scg
49874763Scg	b->hp = ptr;
49974763Scg}
50074763Scg
50174763Scgunsigned int
50274763Scgsndbuf_getready(struct snd_dbuf *b)
50374763Scg{
50474763Scg	SNDBUF_LOCKASSERT(b);
50587599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
50674763Scg
50774763Scg	return b->rl;
50874763Scg}
50974763Scg
51074763Scgunsigned int
51174763Scgsndbuf_getreadyptr(struct snd_dbuf *b)
51274763Scg{
51374763Scg	SNDBUF_LOCKASSERT(b);
51487599Sobrien	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
51574763Scg
51674763Scg	return b->rp;
51774763Scg}
51874763Scg
51974763Scgunsigned int
52074763Scgsndbuf_getfree(struct snd_dbuf *b)
52174763Scg{
52274763Scg	SNDBUF_LOCKASSERT(b);
52387599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
52474763Scg
52574763Scg	return b->bufsize - b->rl;
52674763Scg}
52774763Scg
52874763Scgunsigned int
52974763Scgsndbuf_getfreeptr(struct snd_dbuf *b)
53074763Scg{
53174763Scg	SNDBUF_LOCKASSERT(b);
53287599Sobrien	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
53387599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
53474763Scg
53574763Scg	return (b->rp + b->rl) % b->bufsize;
53674763Scg}
53774763Scg
538193640Sariffu_int64_t
53974763Scgsndbuf_getblocks(struct snd_dbuf *b)
54074763Scg{
54174763Scg	SNDBUF_LOCKASSERT(b);
54274763Scg
54374763Scg	return b->total / b->blksz;
54474763Scg}
54574763Scg
546193640Sariffu_int64_t
54774763Scgsndbuf_getprevblocks(struct snd_dbuf *b)
54874763Scg{
54974763Scg	SNDBUF_LOCKASSERT(b);
55074763Scg
55174763Scg	return b->prev_total / b->blksz;
55274763Scg}
55374763Scg
554193640Sariffu_int64_t
55574763Scgsndbuf_gettotal(struct snd_dbuf *b)
55674763Scg{
55774763Scg	SNDBUF_LOCKASSERT(b);
55874763Scg
55974763Scg	return b->total;
56074763Scg}
56174763Scg
562193640Sariffu_int64_t
563193640Sariffsndbuf_getprevtotal(struct snd_dbuf *b)
564193640Sariff{
565193640Sariff	SNDBUF_LOCKASSERT(b);
566193640Sariff
567193640Sariff	return b->prev_total;
568193640Sariff}
569193640Sariff
57074763Scgvoid
57174763Scgsndbuf_updateprevtotal(struct snd_dbuf *b)
57274763Scg{
57374763Scg	SNDBUF_LOCKASSERT(b);
57474763Scg
57574763Scg	b->prev_total = b->total;
57674763Scg}
57774763Scg
578164614Sariffunsigned int
579164614Sariffsndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to)
580164614Sariff{
581164614Sariff	if (from == NULL || to == NULL || v == 0)
582164614Sariff		return 0;
583164614Sariff
584193640Sariff	return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from),
585193640Sariff	    sndbuf_getalign(to) * sndbuf_getspd(to));
586164614Sariff}
587164614Sariff
588164614Sariffu_int8_t
589164614Sariffsndbuf_zerodata(u_int32_t fmt)
590164614Sariff{
591193640Sariff	if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH))
592164614Sariff		return (0x00);
593164614Sariff	else if (fmt & AFMT_MU_LAW)
594164614Sariff		return (0x7f);
595164614Sariff	else if (fmt & AFMT_A_LAW)
596164614Sariff		return (0x55);
597164614Sariff	return (0x80);
598164614Sariff}
599164614Sariff
60074763Scg/************************************************************/
60174763Scg
602162588Snetchild/**
603162588Snetchild * @brief Acquire buffer space to extend ready area
604162588Snetchild *
605162588Snetchild * This function extends the ready area length by @c count bytes, and may
606162588Snetchild * optionally copy samples from another location stored in @c from.  The
607162588Snetchild * counter @c snd_dbuf::total is also incremented by @c count bytes.
608162588Snetchild *
609162588Snetchild * @param b	audio buffer
610162588Snetchild * @param from	sample source (optional)
611162588Snetchild * @param count	number of bytes to acquire
612162588Snetchild *
613162588Snetchild * @retval 0	Unconditional
614162588Snetchild */
61570291Scgint
61674763Scgsndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count)
61770291Scg{
61874763Scg	int l;
61974763Scg
62087599Sobrien	KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b)));
62187599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
62274763Scg	b->total += count;
62374763Scg	if (from != NULL) {
62474763Scg		while (count > 0) {
625167641Sariff			l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b));
62674763Scg			bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l);
62774763Scg			from += l;
62874763Scg			b->rl += l;
62974763Scg			count -= l;
63074763Scg		}
63174763Scg	} else
63274763Scg		b->rl += count;
63387599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
63474763Scg
63574763Scg	return 0;
63674763Scg}
63774763Scg
638162588Snetchild/**
639162588Snetchild * @brief Dispose samples from channel buffer, increasing size of ready area
640162588Snetchild *
641162588Snetchild * This function discards samples from the supplied buffer by advancing the
642162588Snetchild * ready area start pointer and decrementing the ready area length.  If
643162588Snetchild * @c to is not NULL, then the discard samples will be copied to the location
644162588Snetchild * it points to.
645162588Snetchild *
646162588Snetchild * @param b	PCM channel sound buffer
647162588Snetchild * @param to	destination buffer (optional)
648162588Snetchild * @param count	number of bytes to discard
649162588Snetchild *
650162588Snetchild * @returns 0 unconditionally
651162588Snetchild */
65274763Scgint
65374763Scgsndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
65474763Scg{
65574763Scg	int l;
65674763Scg
65787599Sobrien	KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b)));
65887599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
65974763Scg	if (to != NULL) {
66074763Scg		while (count > 0) {
661167641Sariff			l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b));
66274763Scg			bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l);
66374763Scg			to += l;
66474763Scg			b->rl -= l;
66574763Scg			b->rp = (b->rp + l) % b->bufsize;
66674763Scg			count -= l;
66774763Scg		}
66874763Scg	} else {
66974763Scg		b->rl -= count;
67074763Scg		b->rp = (b->rp + count) % b->bufsize;
67174763Scg	}
67287599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
67374763Scg
67474763Scg	return 0;
67574763Scg}
67674763Scg
677193640Sariff#ifdef SND_DIAGNOSTIC
678193640Sariffstatic uint32_t snd_feeder_maxfeed = 0;
679217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD,
680193640Sariff    &snd_feeder_maxfeed, 0, "maximum feeder count request");
681193640Sariff
682193640Sariffstatic uint32_t snd_feeder_maxcycle = 0;
683217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD,
684193640Sariff    &snd_feeder_maxcycle, 0, "maximum feeder cycle");
685193640Sariff#endif
686193640Sariff
68774763Scg/* count is number of bytes we want added to destination buffer */
68874763Scgint
68974763Scgsndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)
69074763Scg{
691193640Sariff	unsigned int cnt, maxfeed;
692193640Sariff#ifdef SND_DIAGNOSTIC
693193640Sariff	unsigned int cycle;
694164614Sariff
695193640Sariff	if (count > snd_feeder_maxfeed)
696193640Sariff		snd_feeder_maxfeed = count;
697193640Sariff
698193640Sariff	cycle = 0;
699193640Sariff#endif
700193640Sariff
70177265Scg	KASSERT(count > 0, ("can't feed 0 bytes"));
70277265Scg
70374763Scg	if (sndbuf_getfree(to) < count)
704193640Sariff		return (EINVAL);
70574763Scg
706193640Sariff	maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to));
707193640Sariff
708164614Sariff	do {
709193640Sariff		cnt = FEEDER_FEED(feeder, channel, to->tmpbuf,
710193640Sariff		    min(count, maxfeed), from);
711193640Sariff		if (cnt == 0)
712193640Sariff			break;
713193640Sariff		sndbuf_acquire(to, to->tmpbuf, cnt);
714193640Sariff		count -= cnt;
715193640Sariff#ifdef SND_DIAGNOSTIC
716193640Sariff		cycle++;
717193640Sariff#endif
718193640Sariff	} while (count != 0);
71974763Scg
720193640Sariff#ifdef SND_DIAGNOSTIC
721193640Sariff	if (cycle > snd_feeder_maxcycle)
722193640Sariff		snd_feeder_maxcycle = cycle;
723193640Sariff#endif
724193640Sariff
725193640Sariff	return (0);
72674763Scg}
72774763Scg
72874763Scg/************************************************************/
72974763Scg
73074763Scgvoid
73174763Scgsndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what)
73274763Scg{
73374763Scg	printf("%s: [", s);
73474763Scg	if (what & 0x01)
73574763Scg		printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize);
73674763Scg	if (what & 0x02)
73774763Scg		printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp);
73874763Scg	if (what & 0x04)
739193640Sariff		printf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun);
74074763Scg   	if (what & 0x08)
74174763Scg		printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd);
74274763Scg	if (what & 0x10)
74374763Scg		printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags);
74474763Scg	printf(" ]\n");
74574763Scg}
74674763Scg
74774763Scg/************************************************************/
74874763Scgu_int32_t
74974763Scgsndbuf_getflags(struct snd_dbuf *b)
75074763Scg{
75174763Scg	return b->flags;
75274763Scg}
75374763Scg
75474763Scgvoid
75574763Scgsndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on)
75674763Scg{
75774763Scg	b->flags &= ~flags;
75874763Scg	if (on)
75974763Scg		b->flags |= flags;
76074763Scg}
76174763Scg
762162588Snetchild/**
763162588Snetchild * @brief Clear the shadow buffer by filling with samples equal to zero.
764162588Snetchild *
765162588Snetchild * @param b buffer to clear
766162588Snetchild */
767162588Snetchildvoid
768162588Snetchildsndbuf_clearshadow(struct snd_dbuf *b)
769162588Snetchild{
770162588Snetchild	KASSERT(b != NULL, ("b is a null pointer"));
771162588Snetchild	KASSERT(b->sl >= 0, ("illegal shadow length"));
772162588Snetchild
773164614Sariff	if ((b->shadbuf != NULL) && (b->sl > 0))
774164614Sariff		memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl);
775162588Snetchild}
776162588Snetchild
777162588Snetchild#ifdef OSSV4_EXPERIMENT
778162588Snetchild/**
779162588Snetchild * @brief Return peak value from samples in buffer ready area.
780162588Snetchild *
781162588Snetchild * Peak ranges from 0-32767.  If channel is monaural, most significant 16
782162588Snetchild * bits will be zero.  For now, only expects to work with 1-2 channel
783162588Snetchild * buffers.
784162588Snetchild *
785162588Snetchild * @note  Currently only operates with linear PCM formats.
786162588Snetchild *
787162588Snetchild * @param b buffer to analyze
788162588Snetchild * @param lpeak pointer to store left peak value
789162588Snetchild * @param rpeak pointer to store right peak value
790162588Snetchild */
791162588Snetchildvoid
792162588Snetchildsndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp)
793162588Snetchild{
794162588Snetchild	u_int32_t lpeak, rpeak;
795162588Snetchild
796162588Snetchild	lpeak = 0;
797162588Snetchild	rpeak = 0;
798162588Snetchild
799162588Snetchild	/**
800162588Snetchild	 * @todo fill this in later
801162588Snetchild	 */
802162588Snetchild}
803162588Snetchild#endif
804