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