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$"); 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; 96219548Smarius b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT; 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 304233164Smavvoid 305233164Smavsndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl) 306233164Smav{ 307233164Smav if (b->bufsize > 0) 308233164Smav memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize); 309233164Smav b->rp = 0; 310233164Smav b->rl = min(b->bufsize, rl); 311233164Smav} 312233164Smav 313162588Snetchild/** 314162588Snetchild * @brief Reset buffer w/o flushing statistics 315162588Snetchild * 316162588Snetchild * This function just zeroes out buffer contents and sets the "ready length" 317162588Snetchild * to zero. This was originally to facilitate minimal playback interruption 318162588Snetchild * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls. 319162588Snetchild * 320162588Snetchild * @param b buffer context 321162588Snetchild */ 32277265Scgvoid 323162588Snetchildsndbuf_softreset(struct snd_dbuf *b) 324162588Snetchild{ 325162588Snetchild b->rl = 0; 326162588Snetchild if (b->buf && b->bufsize > 0) 327162588Snetchild sndbuf_clear(b, b->bufsize); 328162588Snetchild} 329162588Snetchild 330162588Snetchildvoid 33174763Scgsndbuf_reset(struct snd_dbuf *b) 33270291Scg{ 33374763Scg b->hp = 0; 33474763Scg b->rp = 0; 33574763Scg b->rl = 0; 33674763Scg b->dl = 0; 33774763Scg b->prev_total = 0; 33874763Scg b->total = 0; 33974763Scg b->xrun = 0; 34070291Scg if (b->buf && b->bufsize > 0) 34170291Scg sndbuf_clear(b, b->bufsize); 342162588Snetchild sndbuf_clearshadow(b); 34370291Scg} 34470291Scg 34574763Scgu_int32_t 34674763Scgsndbuf_getfmt(struct snd_dbuf *b) 34774763Scg{ 34874763Scg return b->fmt; 34974763Scg} 35074763Scg 35170291Scgint 35274763Scgsndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) 35370291Scg{ 35470291Scg b->fmt = fmt; 355193640Sariff b->bps = AFMT_BPS(b->fmt); 356193640Sariff b->align = AFMT_ALIGN(b->fmt); 357193640Sariff#if 0 358193640Sariff b->bps = AFMT_CHANNEL(b->fmt); 359148606Snetchild if (b->fmt & AFMT_16BIT) 360148606Snetchild b->bps <<= 1; 361148606Snetchild else if (b->fmt & AFMT_24BIT) 362148606Snetchild b->bps *= 3; 363148606Snetchild else if (b->fmt & AFMT_32BIT) 364148606Snetchild b->bps <<= 2; 365193640Sariff#endif 36670291Scg return 0; 36770291Scg} 36870291Scg 36974763Scgunsigned int 37074763Scgsndbuf_getspd(struct snd_dbuf *b) 37170291Scg{ 37274763Scg return b->spd; 37374763Scg} 37474763Scg 37574763Scgvoid 37674763Scgsndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 37774763Scg{ 37874763Scg b->spd = spd; 37974763Scg} 38074763Scg 38174763Scgunsigned int 38274763Scgsndbuf_getalign(struct snd_dbuf *b) 38374763Scg{ 384193640Sariff return (b->align); 38574763Scg} 38674763Scg 38774763Scgunsigned int 38874763Scgsndbuf_getblkcnt(struct snd_dbuf *b) 38974763Scg{ 39074763Scg return b->blkcnt; 39174763Scg} 39274763Scg 39374763Scgvoid 39474763Scgsndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) 39574763Scg{ 39674763Scg b->blkcnt = blkcnt; 39774763Scg} 39874763Scg 39974763Scgunsigned int 40074763Scgsndbuf_getblksz(struct snd_dbuf *b) 40174763Scg{ 40274763Scg return b->blksz; 40374763Scg} 40474763Scg 40574763Scgvoid 40674763Scgsndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) 40774763Scg{ 40874763Scg b->blksz = blksz; 40974763Scg} 41074763Scg 41174763Scgunsigned int 41274763Scgsndbuf_getbps(struct snd_dbuf *b) 41374763Scg{ 41470291Scg return b->bps; 41570291Scg} 41670291Scg 41770291Scgvoid * 41874763Scgsndbuf_getbuf(struct snd_dbuf *b) 41970291Scg{ 42070291Scg return b->buf; 42170291Scg} 42270291Scg 42374763Scgvoid * 42474763Scgsndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 42570291Scg{ 42689771Scg KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 42774763Scg 42874763Scg return b->buf + ofs; 42974763Scg} 43074763Scg 43174763Scgunsigned int 43274763Scgsndbuf_getsize(struct snd_dbuf *b) 43374763Scg{ 43470291Scg return b->bufsize; 43570291Scg} 43670291Scg 43774763Scgunsigned int 43874763Scgsndbuf_getmaxsize(struct snd_dbuf *b) 43970291Scg{ 44074763Scg return b->maxsize; 44174763Scg} 44274763Scg 44374763Scgunsigned int 444170722Sariffsndbuf_getallocsize(struct snd_dbuf *b) 445170722Sariff{ 446170722Sariff return b->allocsize; 447170722Sariff} 448170722Sariff 449170722Sariffunsigned int 45074763Scgsndbuf_runsz(struct snd_dbuf *b) 45174763Scg{ 45270291Scg return b->dl; 45370291Scg} 45470291Scg 45574763Scgvoid 45674763Scgsndbuf_setrun(struct snd_dbuf *b, int go) 45774763Scg{ 45874763Scg b->dl = go? b->blksz : 0; 45974763Scg} 46074763Scg 46174763Scgstruct selinfo * 46274763Scgsndbuf_getsel(struct snd_dbuf *b) 46374763Scg{ 46474763Scg return &b->sel; 46574763Scg} 46674763Scg 46774763Scg/************************************************************/ 46874763Scgunsigned int 46974763Scgsndbuf_getxrun(struct snd_dbuf *b) 47074763Scg{ 47174763Scg SNDBUF_LOCKASSERT(b); 47274763Scg 47374763Scg return b->xrun; 47474763Scg} 47574763Scg 47674763Scgvoid 477160439Snetchildsndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun) 47874763Scg{ 47974763Scg SNDBUF_LOCKASSERT(b); 48074763Scg 481160439Snetchild b->xrun = xrun; 48274763Scg} 48374763Scg 48474763Scgunsigned int 48574763Scgsndbuf_gethwptr(struct snd_dbuf *b) 48674763Scg{ 48774763Scg SNDBUF_LOCKASSERT(b); 48874763Scg 48974763Scg return b->hp; 49074763Scg} 49174763Scg 49274763Scgvoid 49374763Scgsndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) 49474763Scg{ 49574763Scg SNDBUF_LOCKASSERT(b); 49674763Scg 49774763Scg b->hp = ptr; 49874763Scg} 49974763Scg 50074763Scgunsigned int 50174763Scgsndbuf_getready(struct snd_dbuf *b) 50274763Scg{ 50374763Scg SNDBUF_LOCKASSERT(b); 50487599Sobrien KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 50574763Scg 50674763Scg return b->rl; 50774763Scg} 50874763Scg 50974763Scgunsigned int 51074763Scgsndbuf_getreadyptr(struct snd_dbuf *b) 51174763Scg{ 51274763Scg SNDBUF_LOCKASSERT(b); 51387599Sobrien KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 51474763Scg 51574763Scg return b->rp; 51674763Scg} 51774763Scg 51874763Scgunsigned int 51974763Scgsndbuf_getfree(struct snd_dbuf *b) 52074763Scg{ 52174763Scg SNDBUF_LOCKASSERT(b); 52287599Sobrien KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 52374763Scg 52474763Scg return b->bufsize - b->rl; 52574763Scg} 52674763Scg 52774763Scgunsigned int 52874763Scgsndbuf_getfreeptr(struct snd_dbuf *b) 52974763Scg{ 53074763Scg SNDBUF_LOCKASSERT(b); 53187599Sobrien KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 53287599Sobrien KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 53374763Scg 53474763Scg return (b->rp + b->rl) % b->bufsize; 53574763Scg} 53674763Scg 537193640Sariffu_int64_t 53874763Scgsndbuf_getblocks(struct snd_dbuf *b) 53974763Scg{ 54074763Scg SNDBUF_LOCKASSERT(b); 54174763Scg 54274763Scg return b->total / b->blksz; 54374763Scg} 54474763Scg 545193640Sariffu_int64_t 54674763Scgsndbuf_getprevblocks(struct snd_dbuf *b) 54774763Scg{ 54874763Scg SNDBUF_LOCKASSERT(b); 54974763Scg 55074763Scg return b->prev_total / b->blksz; 55174763Scg} 55274763Scg 553193640Sariffu_int64_t 55474763Scgsndbuf_gettotal(struct snd_dbuf *b) 55574763Scg{ 55674763Scg SNDBUF_LOCKASSERT(b); 55774763Scg 55874763Scg return b->total; 55974763Scg} 56074763Scg 561193640Sariffu_int64_t 562193640Sariffsndbuf_getprevtotal(struct snd_dbuf *b) 563193640Sariff{ 564193640Sariff SNDBUF_LOCKASSERT(b); 565193640Sariff 566193640Sariff return b->prev_total; 567193640Sariff} 568193640Sariff 56974763Scgvoid 57074763Scgsndbuf_updateprevtotal(struct snd_dbuf *b) 57174763Scg{ 57274763Scg SNDBUF_LOCKASSERT(b); 57374763Scg 57474763Scg b->prev_total = b->total; 57574763Scg} 57674763Scg 577164614Sariffunsigned int 578164614Sariffsndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to) 579164614Sariff{ 580164614Sariff if (from == NULL || to == NULL || v == 0) 581164614Sariff return 0; 582164614Sariff 583193640Sariff return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from), 584193640Sariff sndbuf_getalign(to) * sndbuf_getspd(to)); 585164614Sariff} 586164614Sariff 587164614Sariffu_int8_t 588164614Sariffsndbuf_zerodata(u_int32_t fmt) 589164614Sariff{ 590193640Sariff if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH)) 591164614Sariff return (0x00); 592164614Sariff else if (fmt & AFMT_MU_LAW) 593164614Sariff return (0x7f); 594164614Sariff else if (fmt & AFMT_A_LAW) 595164614Sariff return (0x55); 596164614Sariff return (0x80); 597164614Sariff} 598164614Sariff 59974763Scg/************************************************************/ 60074763Scg 601162588Snetchild/** 602162588Snetchild * @brief Acquire buffer space to extend ready area 603162588Snetchild * 604162588Snetchild * This function extends the ready area length by @c count bytes, and may 605162588Snetchild * optionally copy samples from another location stored in @c from. The 606162588Snetchild * counter @c snd_dbuf::total is also incremented by @c count bytes. 607162588Snetchild * 608162588Snetchild * @param b audio buffer 609162588Snetchild * @param from sample source (optional) 610162588Snetchild * @param count number of bytes to acquire 611162588Snetchild * 612162588Snetchild * @retval 0 Unconditional 613162588Snetchild */ 61470291Scgint 61574763Scgsndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) 61670291Scg{ 61774763Scg int l; 61874763Scg 61987599Sobrien KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b))); 62087599Sobrien KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 62174763Scg b->total += count; 62274763Scg if (from != NULL) { 62374763Scg while (count > 0) { 624167641Sariff l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b)); 62574763Scg bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 62674763Scg from += l; 62774763Scg b->rl += l; 62874763Scg count -= l; 62974763Scg } 63074763Scg } else 63174763Scg b->rl += count; 63287599Sobrien KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 63374763Scg 63474763Scg return 0; 63574763Scg} 63674763Scg 637162588Snetchild/** 638162588Snetchild * @brief Dispose samples from channel buffer, increasing size of ready area 639162588Snetchild * 640162588Snetchild * This function discards samples from the supplied buffer by advancing the 641162588Snetchild * ready area start pointer and decrementing the ready area length. If 642162588Snetchild * @c to is not NULL, then the discard samples will be copied to the location 643162588Snetchild * it points to. 644162588Snetchild * 645162588Snetchild * @param b PCM channel sound buffer 646162588Snetchild * @param to destination buffer (optional) 647162588Snetchild * @param count number of bytes to discard 648162588Snetchild * 649162588Snetchild * @returns 0 unconditionally 650162588Snetchild */ 65174763Scgint 65274763Scgsndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) 65374763Scg{ 65474763Scg int l; 65574763Scg 65687599Sobrien KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 65787599Sobrien KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 65874763Scg if (to != NULL) { 65974763Scg while (count > 0) { 660167641Sariff l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b)); 66174763Scg bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 66274763Scg to += l; 66374763Scg b->rl -= l; 66474763Scg b->rp = (b->rp + l) % b->bufsize; 66574763Scg count -= l; 66674763Scg } 66774763Scg } else { 66874763Scg b->rl -= count; 66974763Scg b->rp = (b->rp + count) % b->bufsize; 67074763Scg } 67187599Sobrien KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 67274763Scg 67374763Scg return 0; 67474763Scg} 67574763Scg 676193640Sariff#ifdef SND_DIAGNOSTIC 677193640Sariffstatic uint32_t snd_feeder_maxfeed = 0; 678217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD, 679193640Sariff &snd_feeder_maxfeed, 0, "maximum feeder count request"); 680193640Sariff 681193640Sariffstatic uint32_t snd_feeder_maxcycle = 0; 682217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD, 683193640Sariff &snd_feeder_maxcycle, 0, "maximum feeder cycle"); 684193640Sariff#endif 685193640Sariff 68674763Scg/* count is number of bytes we want added to destination buffer */ 68774763Scgint 68874763Scgsndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 68974763Scg{ 690193640Sariff unsigned int cnt, maxfeed; 691193640Sariff#ifdef SND_DIAGNOSTIC 692193640Sariff unsigned int cycle; 693164614Sariff 694193640Sariff if (count > snd_feeder_maxfeed) 695193640Sariff snd_feeder_maxfeed = count; 696193640Sariff 697193640Sariff cycle = 0; 698193640Sariff#endif 699193640Sariff 70077265Scg KASSERT(count > 0, ("can't feed 0 bytes")); 70177265Scg 70274763Scg if (sndbuf_getfree(to) < count) 703193640Sariff return (EINVAL); 70474763Scg 705193640Sariff maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to)); 706193640Sariff 707164614Sariff do { 708193640Sariff cnt = FEEDER_FEED(feeder, channel, to->tmpbuf, 709193640Sariff min(count, maxfeed), from); 710193640Sariff if (cnt == 0) 711193640Sariff break; 712193640Sariff sndbuf_acquire(to, to->tmpbuf, cnt); 713193640Sariff count -= cnt; 714193640Sariff#ifdef SND_DIAGNOSTIC 715193640Sariff cycle++; 716193640Sariff#endif 717193640Sariff } while (count != 0); 71874763Scg 719193640Sariff#ifdef SND_DIAGNOSTIC 720193640Sariff if (cycle > snd_feeder_maxcycle) 721193640Sariff snd_feeder_maxcycle = cycle; 722193640Sariff#endif 723193640Sariff 724193640Sariff return (0); 72574763Scg} 72674763Scg 72774763Scg/************************************************************/ 72874763Scg 72974763Scgvoid 73074763Scgsndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what) 73174763Scg{ 73274763Scg printf("%s: [", s); 73374763Scg if (what & 0x01) 73474763Scg printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize); 73574763Scg if (what & 0x02) 73674763Scg printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp); 73774763Scg if (what & 0x04) 738193640Sariff printf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun); 73974763Scg if (what & 0x08) 74074763Scg printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd); 74174763Scg if (what & 0x10) 74274763Scg printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags); 74374763Scg printf(" ]\n"); 74474763Scg} 74574763Scg 74674763Scg/************************************************************/ 74774763Scgu_int32_t 74874763Scgsndbuf_getflags(struct snd_dbuf *b) 74974763Scg{ 75074763Scg return b->flags; 75174763Scg} 75274763Scg 75374763Scgvoid 75474763Scgsndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on) 75574763Scg{ 75674763Scg b->flags &= ~flags; 75774763Scg if (on) 75874763Scg b->flags |= flags; 75974763Scg} 76074763Scg 761162588Snetchild/** 762162588Snetchild * @brief Clear the shadow buffer by filling with samples equal to zero. 763162588Snetchild * 764162588Snetchild * @param b buffer to clear 765162588Snetchild */ 766162588Snetchildvoid 767162588Snetchildsndbuf_clearshadow(struct snd_dbuf *b) 768162588Snetchild{ 769162588Snetchild KASSERT(b != NULL, ("b is a null pointer")); 770162588Snetchild KASSERT(b->sl >= 0, ("illegal shadow length")); 771162588Snetchild 772164614Sariff if ((b->shadbuf != NULL) && (b->sl > 0)) 773164614Sariff memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl); 774162588Snetchild} 775162588Snetchild 776162588Snetchild#ifdef OSSV4_EXPERIMENT 777162588Snetchild/** 778162588Snetchild * @brief Return peak value from samples in buffer ready area. 779162588Snetchild * 780162588Snetchild * Peak ranges from 0-32767. If channel is monaural, most significant 16 781162588Snetchild * bits will be zero. For now, only expects to work with 1-2 channel 782162588Snetchild * buffers. 783162588Snetchild * 784162588Snetchild * @note Currently only operates with linear PCM formats. 785162588Snetchild * 786162588Snetchild * @param b buffer to analyze 787162588Snetchild * @param lpeak pointer to store left peak value 788162588Snetchild * @param rpeak pointer to store right peak value 789162588Snetchild */ 790162588Snetchildvoid 791162588Snetchildsndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp) 792162588Snetchild{ 793162588Snetchild u_int32_t lpeak, rpeak; 794162588Snetchild 795162588Snetchild lpeak = 0; 796162588Snetchild rpeak = 0; 797162588Snetchild 798162588Snetchild /** 799162588Snetchild * @todo fill this in later 800162588Snetchild */ 801162588Snetchild} 802162588Snetchild#endif 803