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