buffer.c revision 217368
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
38193640Sariff#include "snd_fxdiv_gen.h"
39193640Sariff
4082180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/buffer.c 217368 2011-01-13 18:20:27Z mdf $");
4182180Scg
4274763Scgstruct snd_dbuf *
43125136Struckmansndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel)
4474763Scg{
4574763Scg	struct snd_dbuf *b;
4674763Scg
47111119Simp	b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO);
4874763Scg	snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc);
4989834Scg	b->dev = dev;
50125136Struckman	b->channel = channel;
5189834Scg
5274763Scg	return b;
5374763Scg}
5474763Scg
5574763Scgvoid
5674763Scgsndbuf_destroy(struct snd_dbuf *b)
5774763Scg{
58167773Sariff	sndbuf_free(b);
5974763Scg	free(b, M_DEVBUF);
6074763Scg}
6174763Scg
62111183Scognetbus_addr_t
63111183Scognetsndbuf_getbufaddr(struct snd_dbuf *buf)
64111183Scognet{
65111183Scognet	return (buf->buf_addr);
66111183Scognet}
67111183Scognet
6870291Scgstatic void
6970291Scgsndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
7070291Scg{
7174763Scg	struct snd_dbuf *b = (struct snd_dbuf *)arg;
7270291Scg
7370291Scg	if (bootverbose) {
74136531Syongari		device_printf(b->dev, "sndbuf_setmap %lx, %lx; ",
75136531Syongari		    (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len);
76136531Syongari		printf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr);
7770291Scg	}
78136531Syongari	if (error == 0)
79136531Syongari		b->buf_addr = segs[0].ds_addr;
80136531Syongari	else
81136531Syongari		b->buf_addr = 0;
8270291Scg}
8370291Scg
8470291Scg/*
8574763Scg * Allocate memory for DMA buffer. If the device does not use DMA transfers,
8674763Scg * the driver can call malloc(9) and sndbuf_setup() itself.
8770291Scg */
88111183Scognet
8970291Scgint
90168847Sariffsndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags,
91168847Sariff    unsigned int size)
9270291Scg{
93136531Syongari	int ret;
94136531Syongari
9570291Scg	b->dmatag = dmatag;
96168847Sariff	b->dmaflags = dmaflags | BUS_DMA_NOWAIT;
9770291Scg	b->maxsize = size;
9870291Scg	b->bufsize = b->maxsize;
99136531Syongari	b->buf_addr = 0;
100166393Sariff	b->flags |= SNDBUF_F_MANAGED;
101168847Sariff	if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags,
102167773Sariff	    &b->dmamap)) {
103167773Sariff		sndbuf_free(b);
104136531Syongari		return (ENOMEM);
105167773Sariff	}
106136531Syongari	if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize,
107136531Syongari	    sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) {
108167773Sariff		sndbuf_free(b);
109136531Syongari		return (ENOMEM);
110136531Syongari	}
111136531Syongari
112136531Syongari	ret = sndbuf_resize(b, 2, b->maxsize / 2);
113136531Syongari	if (ret != 0)
114136531Syongari		sndbuf_free(b);
115167773Sariff
116136531Syongari	return (ret);
11770291Scg}
11870291Scg
11970291Scgint
12074763Scgsndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size)
12170291Scg{
122167773Sariff	b->flags &= ~SNDBUF_F_MANAGED;
123166393Sariff	if (buf)
124166393Sariff		b->flags |= SNDBUF_F_MANAGED;
12570291Scg	b->buf = buf;
12670291Scg	b->maxsize = size;
12770291Scg	b->bufsize = b->maxsize;
12870291Scg	return sndbuf_resize(b, 2, b->maxsize / 2);
12970291Scg}
13070291Scg
13170291Scgvoid
13274763Scgsndbuf_free(struct snd_dbuf *b)
13370291Scg{
13474763Scg	if (b->tmpbuf)
13574763Scg		free(b->tmpbuf, M_DEVBUF);
13674763Scg
137162588Snetchild	if (b->shadbuf)
138162588Snetchild		free(b->shadbuf, M_DEVBUF);
139167773Sariff
140167773Sariff	if (b->buf) {
141167773Sariff		if (b->flags & SNDBUF_F_MANAGED) {
142167773Sariff			if (b->dmamap)
143167773Sariff				bus_dmamap_unload(b->dmatag, b->dmamap);
144167773Sariff			if (b->dmatag)
145167773Sariff				bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
146167773Sariff		} else
147167773Sariff			free(b->buf, M_DEVBUF);
148167773Sariff	}
149167773Sariff
150167773Sariff	b->tmpbuf = NULL;
151162588Snetchild	b->shadbuf = NULL;
152167773Sariff	b->buf = NULL;
153162588Snetchild	b->sl = 0;
154167773Sariff	b->dmatag = NULL;
15577265Scg	b->dmamap = NULL;
15670291Scg}
15770291Scg
158170722Sariff#define SNDBUF_CACHE_SHIFT	5
159170722Sariff
16070291Scgint
16174763Scgsndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
16270291Scg{
163170722Sariff	unsigned int bufsize, allocsize;
164170722Sariff	u_int8_t *tmpbuf;
165125136Struckman
166193640Sariff	CHN_LOCK(b->channel);
16774763Scg	if (b->maxsize == 0)
168125136Struckman		goto out;
16970291Scg	if (blkcnt == 0)
17070291Scg		blkcnt = b->blkcnt;
17170291Scg	if (blksz == 0)
17270291Scg		blksz = b->blksz;
173170722Sariff	if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) {
174193640Sariff		CHN_UNLOCK(b->channel);
17570291Scg		return EINVAL;
176125136Struckman	}
17789834Scg	if (blkcnt == b->blkcnt && blksz == b->blksz)
178125136Struckman		goto out;
179125136Struckman
180170722Sariff	bufsize = blkcnt * blksz;
181170722Sariff
182170815Sariff	if (bufsize > b->allocsize ||
183170722Sariff	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
184170722Sariff		allocsize = round_page(bufsize);
185193640Sariff		CHN_UNLOCK(b->channel);
186170722Sariff		tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
187193640Sariff		CHN_LOCK(b->channel);
188170722Sariff		if (snd_verbose > 3)
189170722Sariff			printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n",
190170722Sariff			    __func__, b, b->tmpbuf, tmpbuf,
191170722Sariff			    b->allocsize, allocsize, bufsize);
192170722Sariff		if (b->tmpbuf != NULL)
193170722Sariff			free(b->tmpbuf, M_DEVBUF);
194170722Sariff		b->tmpbuf = tmpbuf;
195170722Sariff		b->allocsize = allocsize;
196170722Sariff	} else if (snd_verbose > 3)
197170722Sariff		printf("%s(): b=%p %d [%d] NOCHANGE\n",
198170722Sariff		    __func__, b, b->allocsize, b->bufsize);
199170722Sariff
20070291Scg	b->blkcnt = blkcnt;
20170291Scg	b->blksz = blksz;
202170722Sariff	b->bufsize = bufsize;
203170722Sariff
20470291Scg	sndbuf_reset(b);
205125136Struckmanout:
206193640Sariff	CHN_UNLOCK(b->channel);
207125136Struckman	return 0;
20870291Scg}
20970291Scg
21074763Scgint
21174763Scgsndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
21274763Scg{
213170722Sariff        unsigned int bufsize, allocsize;
214170722Sariff	u_int8_t *buf, *tmpbuf, *shadbuf;
215107237Scg
21674763Scg	if (blkcnt < 2 || blksz < 16)
21774763Scg		return EINVAL;
21874763Scg
219107237Scg	bufsize = blksz * blkcnt;
22074763Scg
221170722Sariff	if (bufsize > b->allocsize ||
222170722Sariff	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
223170722Sariff		allocsize = round_page(bufsize);
224193640Sariff		CHN_UNLOCK(b->channel);
225170722Sariff		buf = malloc(allocsize, M_DEVBUF, M_WAITOK);
226170722Sariff		tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
227170722Sariff		shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
228193640Sariff		CHN_LOCK(b->channel);
229170722Sariff		if (b->buf != NULL)
230170722Sariff			free(b->buf, M_DEVBUF);
231170722Sariff		b->buf = buf;
232170722Sariff		if (b->tmpbuf != NULL)
233170722Sariff			free(b->tmpbuf, M_DEVBUF);
234170722Sariff		b->tmpbuf = tmpbuf;
235170722Sariff		if (b->shadbuf != NULL)
236170722Sariff			free(b->shadbuf, M_DEVBUF);
237170722Sariff		b->shadbuf = shadbuf;
238170722Sariff		if (snd_verbose > 3)
239170722Sariff			printf("%s(): b=%p %d -> %d [%d]\n",
240170722Sariff			    __func__, b, b->allocsize, allocsize, bufsize);
241170722Sariff		b->allocsize = allocsize;
242170722Sariff	} else if (snd_verbose > 3)
243170722Sariff		printf("%s(): b=%p %d [%d] NOCHANGE\n",
244170722Sariff		    __func__, b, b->allocsize, b->bufsize);
245162588Snetchild
246107237Scg	b->blkcnt = blkcnt;
247107237Scg	b->blksz = blksz;
248107237Scg	b->bufsize = bufsize;
249107237Scg	b->maxsize = bufsize;
250162588Snetchild	b->sl = bufsize;
251107237Scg
252125136Struckman	sndbuf_reset(b);
253125136Struckman
254170722Sariff	return 0;
25574763Scg}
25674763Scg
257162588Snetchild/**
258162588Snetchild * @brief Zero out space in buffer free area
259162588Snetchild *
260162588Snetchild * This function clears a chunk of @c length bytes in the buffer free area
261162588Snetchild * (i.e., where the next write will be placed).
262162588Snetchild *
263162588Snetchild * @param b		buffer context
264162588Snetchild * @param length	number of bytes to blank
265162588Snetchild */
26670291Scgvoid
26774763Scgsndbuf_clear(struct snd_dbuf *b, unsigned int length)
26870291Scg{
26970291Scg	int i;
27073768Scg	u_char data, *p;
27170291Scg
27270291Scg	if (length == 0)
27370291Scg		return;
27473768Scg	if (length > b->bufsize)
27573768Scg		length = b->bufsize;
27670291Scg
277164614Sariff	data = sndbuf_zerodata(b->fmt);
27870291Scg
27974763Scg	i = sndbuf_getfreeptr(b);
28074763Scg	p = sndbuf_getbuf(b);
28173768Scg	while (length > 0) {
28273768Scg		p[i] = data;
28373768Scg		length--;
28473768Scg		i++;
28573768Scg		if (i >= b->bufsize)
28670291Scg			i = 0;
28770291Scg	}
28870291Scg}
28970291Scg
290162588Snetchild/**
291162588Snetchild * @brief Zap buffer contents, resetting "ready area" fields
292162588Snetchild *
293162588Snetchild * @param b	buffer context
294162588Snetchild */
29570291Scgvoid
29677265Scgsndbuf_fillsilence(struct snd_dbuf *b)
29777265Scg{
298164614Sariff	if (b->bufsize > 0)
299164614Sariff		memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
30077265Scg	b->rp = 0;
30177265Scg	b->rl = b->bufsize;
30277265Scg}
30377265Scg
304162588Snetchild/**
305162588Snetchild * @brief Reset buffer w/o flushing statistics
306162588Snetchild *
307162588Snetchild * This function just zeroes out buffer contents and sets the "ready length"
308162588Snetchild * to zero.  This was originally to facilitate minimal playback interruption
309162588Snetchild * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls.
310162588Snetchild *
311162588Snetchild * @param b	buffer context
312162588Snetchild */
31377265Scgvoid
314162588Snetchildsndbuf_softreset(struct snd_dbuf *b)
315162588Snetchild{
316162588Snetchild	b->rl = 0;
317162588Snetchild	if (b->buf && b->bufsize > 0)
318162588Snetchild		sndbuf_clear(b, b->bufsize);
319162588Snetchild}
320162588Snetchild
321162588Snetchildvoid
32274763Scgsndbuf_reset(struct snd_dbuf *b)
32370291Scg{
32474763Scg	b->hp = 0;
32574763Scg	b->rp = 0;
32674763Scg	b->rl = 0;
32774763Scg	b->dl = 0;
32874763Scg	b->prev_total = 0;
32974763Scg	b->total = 0;
33074763Scg	b->xrun = 0;
33170291Scg	if (b->buf && b->bufsize > 0)
33270291Scg		sndbuf_clear(b, b->bufsize);
333162588Snetchild	sndbuf_clearshadow(b);
33470291Scg}
33570291Scg
33674763Scgu_int32_t
33774763Scgsndbuf_getfmt(struct snd_dbuf *b)
33874763Scg{
33974763Scg	return b->fmt;
34074763Scg}
34174763Scg
34270291Scgint
34374763Scgsndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
34470291Scg{
34570291Scg	b->fmt = fmt;
346193640Sariff	b->bps = AFMT_BPS(b->fmt);
347193640Sariff	b->align = AFMT_ALIGN(b->fmt);
348193640Sariff#if 0
349193640Sariff	b->bps = AFMT_CHANNEL(b->fmt);
350148606Snetchild	if (b->fmt & AFMT_16BIT)
351148606Snetchild		b->bps <<= 1;
352148606Snetchild	else if (b->fmt & AFMT_24BIT)
353148606Snetchild		b->bps *= 3;
354148606Snetchild	else if (b->fmt & AFMT_32BIT)
355148606Snetchild		b->bps <<= 2;
356193640Sariff#endif
35770291Scg	return 0;
35870291Scg}
35970291Scg
36074763Scgunsigned int
36174763Scgsndbuf_getspd(struct snd_dbuf *b)
36270291Scg{
36374763Scg	return b->spd;
36474763Scg}
36574763Scg
36674763Scgvoid
36774763Scgsndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
36874763Scg{
36974763Scg	b->spd = spd;
37074763Scg}
37174763Scg
37274763Scgunsigned int
37374763Scgsndbuf_getalign(struct snd_dbuf *b)
37474763Scg{
375193640Sariff	return (b->align);
37674763Scg}
37774763Scg
37874763Scgunsigned int
37974763Scgsndbuf_getblkcnt(struct snd_dbuf *b)
38074763Scg{
38174763Scg	return b->blkcnt;
38274763Scg}
38374763Scg
38474763Scgvoid
38574763Scgsndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt)
38674763Scg{
38774763Scg	b->blkcnt = blkcnt;
38874763Scg}
38974763Scg
39074763Scgunsigned int
39174763Scgsndbuf_getblksz(struct snd_dbuf *b)
39274763Scg{
39374763Scg	return b->blksz;
39474763Scg}
39574763Scg
39674763Scgvoid
39774763Scgsndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz)
39874763Scg{
39974763Scg	b->blksz = blksz;
40074763Scg}
40174763Scg
40274763Scgunsigned int
40374763Scgsndbuf_getbps(struct snd_dbuf *b)
40474763Scg{
40570291Scg	return b->bps;
40670291Scg}
40770291Scg
40870291Scgvoid *
40974763Scgsndbuf_getbuf(struct snd_dbuf *b)
41070291Scg{
41170291Scg	return b->buf;
41270291Scg}
41370291Scg
41474763Scgvoid *
41574763Scgsndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs)
41670291Scg{
41789771Scg	KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs));
41874763Scg
41974763Scg	return b->buf + ofs;
42074763Scg}
42174763Scg
42274763Scgunsigned int
42374763Scgsndbuf_getsize(struct snd_dbuf *b)
42474763Scg{
42570291Scg	return b->bufsize;
42670291Scg}
42770291Scg
42874763Scgunsigned int
42974763Scgsndbuf_getmaxsize(struct snd_dbuf *b)
43070291Scg{
43174763Scg	return b->maxsize;
43274763Scg}
43374763Scg
43474763Scgunsigned int
435170722Sariffsndbuf_getallocsize(struct snd_dbuf *b)
436170722Sariff{
437170722Sariff	return b->allocsize;
438170722Sariff}
439170722Sariff
440170722Sariffunsigned int
44174763Scgsndbuf_runsz(struct snd_dbuf *b)
44274763Scg{
44370291Scg	return b->dl;
44470291Scg}
44570291Scg
44674763Scgvoid
44774763Scgsndbuf_setrun(struct snd_dbuf *b, int go)
44874763Scg{
44974763Scg	b->dl = go? b->blksz : 0;
45074763Scg}
45174763Scg
45274763Scgstruct selinfo *
45374763Scgsndbuf_getsel(struct snd_dbuf *b)
45474763Scg{
45574763Scg	return &b->sel;
45674763Scg}
45774763Scg
45874763Scg/************************************************************/
45974763Scgunsigned int
46074763Scgsndbuf_getxrun(struct snd_dbuf *b)
46174763Scg{
46274763Scg	SNDBUF_LOCKASSERT(b);
46374763Scg
46474763Scg	return b->xrun;
46574763Scg}
46674763Scg
46774763Scgvoid
468160439Snetchildsndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun)
46974763Scg{
47074763Scg	SNDBUF_LOCKASSERT(b);
47174763Scg
472160439Snetchild	b->xrun = xrun;
47374763Scg}
47474763Scg
47574763Scgunsigned int
47674763Scgsndbuf_gethwptr(struct snd_dbuf *b)
47774763Scg{
47874763Scg	SNDBUF_LOCKASSERT(b);
47974763Scg
48074763Scg	return b->hp;
48174763Scg}
48274763Scg
48374763Scgvoid
48474763Scgsndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr)
48574763Scg{
48674763Scg	SNDBUF_LOCKASSERT(b);
48774763Scg
48874763Scg	b->hp = ptr;
48974763Scg}
49074763Scg
49174763Scgunsigned int
49274763Scgsndbuf_getready(struct snd_dbuf *b)
49374763Scg{
49474763Scg	SNDBUF_LOCKASSERT(b);
49587599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
49674763Scg
49774763Scg	return b->rl;
49874763Scg}
49974763Scg
50074763Scgunsigned int
50174763Scgsndbuf_getreadyptr(struct snd_dbuf *b)
50274763Scg{
50374763Scg	SNDBUF_LOCKASSERT(b);
50487599Sobrien	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
50574763Scg
50674763Scg	return b->rp;
50774763Scg}
50874763Scg
50974763Scgunsigned int
51074763Scgsndbuf_getfree(struct snd_dbuf *b)
51174763Scg{
51274763Scg	SNDBUF_LOCKASSERT(b);
51387599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
51474763Scg
51574763Scg	return b->bufsize - b->rl;
51674763Scg}
51774763Scg
51874763Scgunsigned int
51974763Scgsndbuf_getfreeptr(struct snd_dbuf *b)
52074763Scg{
52174763Scg	SNDBUF_LOCKASSERT(b);
52287599Sobrien	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
52387599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
52474763Scg
52574763Scg	return (b->rp + b->rl) % b->bufsize;
52674763Scg}
52774763Scg
528193640Sariffu_int64_t
52974763Scgsndbuf_getblocks(struct snd_dbuf *b)
53074763Scg{
53174763Scg	SNDBUF_LOCKASSERT(b);
53274763Scg
53374763Scg	return b->total / b->blksz;
53474763Scg}
53574763Scg
536193640Sariffu_int64_t
53774763Scgsndbuf_getprevblocks(struct snd_dbuf *b)
53874763Scg{
53974763Scg	SNDBUF_LOCKASSERT(b);
54074763Scg
54174763Scg	return b->prev_total / b->blksz;
54274763Scg}
54374763Scg
544193640Sariffu_int64_t
54574763Scgsndbuf_gettotal(struct snd_dbuf *b)
54674763Scg{
54774763Scg	SNDBUF_LOCKASSERT(b);
54874763Scg
54974763Scg	return b->total;
55074763Scg}
55174763Scg
552193640Sariffu_int64_t
553193640Sariffsndbuf_getprevtotal(struct snd_dbuf *b)
554193640Sariff{
555193640Sariff	SNDBUF_LOCKASSERT(b);
556193640Sariff
557193640Sariff	return b->prev_total;
558193640Sariff}
559193640Sariff
56074763Scgvoid
56174763Scgsndbuf_updateprevtotal(struct snd_dbuf *b)
56274763Scg{
56374763Scg	SNDBUF_LOCKASSERT(b);
56474763Scg
56574763Scg	b->prev_total = b->total;
56674763Scg}
56774763Scg
568164614Sariffunsigned int
569164614Sariffsndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to)
570164614Sariff{
571164614Sariff	if (from == NULL || to == NULL || v == 0)
572164614Sariff		return 0;
573164614Sariff
574193640Sariff	return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from),
575193640Sariff	    sndbuf_getalign(to) * sndbuf_getspd(to));
576164614Sariff}
577164614Sariff
578164614Sariffu_int8_t
579164614Sariffsndbuf_zerodata(u_int32_t fmt)
580164614Sariff{
581193640Sariff	if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH))
582164614Sariff		return (0x00);
583164614Sariff	else if (fmt & AFMT_MU_LAW)
584164614Sariff		return (0x7f);
585164614Sariff	else if (fmt & AFMT_A_LAW)
586164614Sariff		return (0x55);
587164614Sariff	return (0x80);
588164614Sariff}
589164614Sariff
59074763Scg/************************************************************/
59174763Scg
592162588Snetchild/**
593162588Snetchild * @brief Acquire buffer space to extend ready area
594162588Snetchild *
595162588Snetchild * This function extends the ready area length by @c count bytes, and may
596162588Snetchild * optionally copy samples from another location stored in @c from.  The
597162588Snetchild * counter @c snd_dbuf::total is also incremented by @c count bytes.
598162588Snetchild *
599162588Snetchild * @param b	audio buffer
600162588Snetchild * @param from	sample source (optional)
601162588Snetchild * @param count	number of bytes to acquire
602162588Snetchild *
603162588Snetchild * @retval 0	Unconditional
604162588Snetchild */
60570291Scgint
60674763Scgsndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count)
60770291Scg{
60874763Scg	int l;
60974763Scg
61087599Sobrien	KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b)));
61187599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
61274763Scg	b->total += count;
61374763Scg	if (from != NULL) {
61474763Scg		while (count > 0) {
615167641Sariff			l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b));
61674763Scg			bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l);
61774763Scg			from += l;
61874763Scg			b->rl += l;
61974763Scg			count -= l;
62074763Scg		}
62174763Scg	} else
62274763Scg		b->rl += count;
62387599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
62474763Scg
62574763Scg	return 0;
62674763Scg}
62774763Scg
628162588Snetchild/**
629162588Snetchild * @brief Dispose samples from channel buffer, increasing size of ready area
630162588Snetchild *
631162588Snetchild * This function discards samples from the supplied buffer by advancing the
632162588Snetchild * ready area start pointer and decrementing the ready area length.  If
633162588Snetchild * @c to is not NULL, then the discard samples will be copied to the location
634162588Snetchild * it points to.
635162588Snetchild *
636162588Snetchild * @param b	PCM channel sound buffer
637162588Snetchild * @param to	destination buffer (optional)
638162588Snetchild * @param count	number of bytes to discard
639162588Snetchild *
640162588Snetchild * @returns 0 unconditionally
641162588Snetchild */
64274763Scgint
64374763Scgsndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
64474763Scg{
64574763Scg	int l;
64674763Scg
64787599Sobrien	KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b)));
64887599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
64974763Scg	if (to != NULL) {
65074763Scg		while (count > 0) {
651167641Sariff			l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b));
65274763Scg			bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l);
65374763Scg			to += l;
65474763Scg			b->rl -= l;
65574763Scg			b->rp = (b->rp + l) % b->bufsize;
65674763Scg			count -= l;
65774763Scg		}
65874763Scg	} else {
65974763Scg		b->rl -= count;
66074763Scg		b->rp = (b->rp + count) % b->bufsize;
66174763Scg	}
66287599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
66374763Scg
66474763Scg	return 0;
66574763Scg}
66674763Scg
667193640Sariff#ifdef SND_DIAGNOSTIC
668193640Sariffstatic uint32_t snd_feeder_maxfeed = 0;
669217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD,
670193640Sariff    &snd_feeder_maxfeed, 0, "maximum feeder count request");
671193640Sariff
672193640Sariffstatic uint32_t snd_feeder_maxcycle = 0;
673217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD,
674193640Sariff    &snd_feeder_maxcycle, 0, "maximum feeder cycle");
675193640Sariff#endif
676193640Sariff
67774763Scg/* count is number of bytes we want added to destination buffer */
67874763Scgint
67974763Scgsndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)
68074763Scg{
681193640Sariff	unsigned int cnt, maxfeed;
682193640Sariff#ifdef SND_DIAGNOSTIC
683193640Sariff	unsigned int cycle;
684164614Sariff
685193640Sariff	if (count > snd_feeder_maxfeed)
686193640Sariff		snd_feeder_maxfeed = count;
687193640Sariff
688193640Sariff	cycle = 0;
689193640Sariff#endif
690193640Sariff
69177265Scg	KASSERT(count > 0, ("can't feed 0 bytes"));
69277265Scg
69374763Scg	if (sndbuf_getfree(to) < count)
694193640Sariff		return (EINVAL);
69574763Scg
696193640Sariff	maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to));
697193640Sariff
698164614Sariff	do {
699193640Sariff		cnt = FEEDER_FEED(feeder, channel, to->tmpbuf,
700193640Sariff		    min(count, maxfeed), from);
701193640Sariff		if (cnt == 0)
702193640Sariff			break;
703193640Sariff		sndbuf_acquire(to, to->tmpbuf, cnt);
704193640Sariff		count -= cnt;
705193640Sariff#ifdef SND_DIAGNOSTIC
706193640Sariff		cycle++;
707193640Sariff#endif
708193640Sariff	} while (count != 0);
70974763Scg
710193640Sariff#ifdef SND_DIAGNOSTIC
711193640Sariff	if (cycle > snd_feeder_maxcycle)
712193640Sariff		snd_feeder_maxcycle = cycle;
713193640Sariff#endif
714193640Sariff
715193640Sariff	return (0);
71674763Scg}
71774763Scg
71874763Scg/************************************************************/
71974763Scg
72074763Scgvoid
72174763Scgsndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what)
72274763Scg{
72374763Scg	printf("%s: [", s);
72474763Scg	if (what & 0x01)
72574763Scg		printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize);
72674763Scg	if (what & 0x02)
72774763Scg		printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp);
72874763Scg	if (what & 0x04)
729193640Sariff		printf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun);
73074763Scg   	if (what & 0x08)
73174763Scg		printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd);
73274763Scg	if (what & 0x10)
73374763Scg		printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags);
73474763Scg	printf(" ]\n");
73574763Scg}
73674763Scg
73774763Scg/************************************************************/
73874763Scgu_int32_t
73974763Scgsndbuf_getflags(struct snd_dbuf *b)
74074763Scg{
74174763Scg	return b->flags;
74274763Scg}
74374763Scg
74474763Scgvoid
74574763Scgsndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on)
74674763Scg{
74774763Scg	b->flags &= ~flags;
74874763Scg	if (on)
74974763Scg		b->flags |= flags;
75074763Scg}
75174763Scg
752162588Snetchild/**
753162588Snetchild * @brief Clear the shadow buffer by filling with samples equal to zero.
754162588Snetchild *
755162588Snetchild * @param b buffer to clear
756162588Snetchild */
757162588Snetchildvoid
758162588Snetchildsndbuf_clearshadow(struct snd_dbuf *b)
759162588Snetchild{
760162588Snetchild	KASSERT(b != NULL, ("b is a null pointer"));
761162588Snetchild	KASSERT(b->sl >= 0, ("illegal shadow length"));
762162588Snetchild
763164614Sariff	if ((b->shadbuf != NULL) && (b->sl > 0))
764164614Sariff		memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl);
765162588Snetchild}
766162588Snetchild
767162588Snetchild#ifdef OSSV4_EXPERIMENT
768162588Snetchild/**
769162588Snetchild * @brief Return peak value from samples in buffer ready area.
770162588Snetchild *
771162588Snetchild * Peak ranges from 0-32767.  If channel is monaural, most significant 16
772162588Snetchild * bits will be zero.  For now, only expects to work with 1-2 channel
773162588Snetchild * buffers.
774162588Snetchild *
775162588Snetchild * @note  Currently only operates with linear PCM formats.
776162588Snetchild *
777162588Snetchild * @param b buffer to analyze
778162588Snetchild * @param lpeak pointer to store left peak value
779162588Snetchild * @param rpeak pointer to store right peak value
780162588Snetchild */
781162588Snetchildvoid
782162588Snetchildsndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp)
783162588Snetchild{
784162588Snetchild	u_int32_t lpeak, rpeak;
785162588Snetchild
786162588Snetchild	lpeak = 0;
787162588Snetchild	rpeak = 0;
788162588Snetchild
789162588Snetchild	/**
790162588Snetchild	 * @todo fill this in later
791162588Snetchild	 */
792162588Snetchild}
793162588Snetchild#endif
794