1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 6 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#ifdef HAVE_KERNEL_OPTION_HEADERS 32#include "opt_snd.h" 33#endif 34 35#include <dev/sound/pcm/sound.h> 36 37#include "feeder_if.h" 38 39#define SND_USE_FXDIV 40#define SND_DECLARE_FXDIV 41#include "snd_fxdiv_gen.h" 42 43SND_DECLARE_FILE("$FreeBSD$"); 44 45struct snd_dbuf * 46sndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel) 47{ 48 struct snd_dbuf *b; 49 50 b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO); 51 snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc); 52 b->dev = dev; 53 b->channel = channel; 54 55 return b; 56} 57 58void 59sndbuf_destroy(struct snd_dbuf *b) 60{ 61 sndbuf_free(b); 62 free(b, M_DEVBUF); 63} 64 65bus_addr_t 66sndbuf_getbufaddr(struct snd_dbuf *buf) 67{ 68 return (buf->buf_addr); 69} 70 71static void 72sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 73{ 74 struct snd_dbuf *b = (struct snd_dbuf *)arg; 75 76 if (snd_verbose > 3) { 77 device_printf(b->dev, "sndbuf_setmap %lx, %lx; ", 78 (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len); 79 printf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr); 80 } 81 if (error == 0) 82 b->buf_addr = segs[0].ds_addr; 83 else 84 b->buf_addr = 0; 85} 86 87/* 88 * Allocate memory for DMA buffer. If the device does not use DMA transfers, 89 * the driver can call malloc(9) and sndbuf_setup() itself. 90 */ 91 92int 93sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags, 94 unsigned int size) 95{ 96 int ret; 97 98 b->dmatag = dmatag; 99 b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT; 100 b->maxsize = size; 101 b->bufsize = b->maxsize; 102 b->buf_addr = 0; 103 b->flags |= SNDBUF_F_MANAGED; 104 if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags, 105 &b->dmamap)) { 106 sndbuf_free(b); 107 return (ENOMEM); 108 } 109 if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, 110 sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) { 111 sndbuf_free(b); 112 return (ENOMEM); 113 } 114 115 ret = sndbuf_resize(b, 2, b->maxsize / 2); 116 if (ret != 0) 117 sndbuf_free(b); 118 119 return (ret); 120} 121 122int 123sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size) 124{ 125 b->flags &= ~SNDBUF_F_MANAGED; 126 if (buf) 127 b->flags |= SNDBUF_F_MANAGED; 128 b->buf = buf; 129 b->maxsize = size; 130 b->bufsize = b->maxsize; 131 return sndbuf_resize(b, 2, b->maxsize / 2); 132} 133 134void 135sndbuf_free(struct snd_dbuf *b) 136{ 137 if (b->tmpbuf) 138 free(b->tmpbuf, M_DEVBUF); 139 140 if (b->shadbuf) 141 free(b->shadbuf, M_DEVBUF); 142 143 if (b->buf) { 144 if (b->flags & SNDBUF_F_MANAGED) { 145 if (b->buf_addr) 146 bus_dmamap_unload(b->dmatag, b->dmamap); 147 if (b->dmatag) 148 bus_dmamem_free(b->dmatag, b->buf, b->dmamap); 149 } else 150 free(b->buf, M_DEVBUF); 151 } 152 153 b->tmpbuf = NULL; 154 b->shadbuf = NULL; 155 b->buf = NULL; 156 b->sl = 0; 157 b->dmatag = NULL; 158 b->dmamap = NULL; 159} 160 161#define SNDBUF_CACHE_SHIFT 5 162 163int 164sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 165{ 166 unsigned int bufsize, allocsize; 167 u_int8_t *tmpbuf; 168 169 CHN_LOCK(b->channel); 170 if (b->maxsize == 0) 171 goto out; 172 if (blkcnt == 0) 173 blkcnt = b->blkcnt; 174 if (blksz == 0) 175 blksz = b->blksz; 176 if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) { 177 CHN_UNLOCK(b->channel); 178 return EINVAL; 179 } 180 if (blkcnt == b->blkcnt && blksz == b->blksz) 181 goto out; 182 183 bufsize = blkcnt * blksz; 184 185 if (bufsize > b->allocsize || 186 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 187 allocsize = round_page(bufsize); 188 CHN_UNLOCK(b->channel); 189 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 190 CHN_LOCK(b->channel); 191 if (snd_verbose > 3) 192 printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n", 193 __func__, b, b->tmpbuf, tmpbuf, 194 b->allocsize, allocsize, bufsize); 195 if (b->tmpbuf != NULL) 196 free(b->tmpbuf, M_DEVBUF); 197 b->tmpbuf = tmpbuf; 198 b->allocsize = allocsize; 199 } else if (snd_verbose > 3) 200 printf("%s(): b=%p %d [%d] NOCHANGE\n", 201 __func__, b, b->allocsize, b->bufsize); 202 203 b->blkcnt = blkcnt; 204 b->blksz = blksz; 205 b->bufsize = bufsize; 206 207 sndbuf_reset(b); 208out: 209 CHN_UNLOCK(b->channel); 210 return 0; 211} 212 213int 214sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 215{ 216 unsigned int bufsize, allocsize; 217 u_int8_t *buf, *tmpbuf, *shadbuf; 218 219 if (blkcnt < 2 || blksz < 16) 220 return EINVAL; 221 222 bufsize = blksz * blkcnt; 223 224 if (bufsize > b->allocsize || 225 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 226 allocsize = round_page(bufsize); 227 CHN_UNLOCK(b->channel); 228 buf = malloc(allocsize, M_DEVBUF, M_WAITOK); 229 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 230 shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 231 CHN_LOCK(b->channel); 232 if (b->buf != NULL) 233 free(b->buf, M_DEVBUF); 234 b->buf = buf; 235 if (b->tmpbuf != NULL) 236 free(b->tmpbuf, M_DEVBUF); 237 b->tmpbuf = tmpbuf; 238 if (b->shadbuf != NULL) 239 free(b->shadbuf, M_DEVBUF); 240 b->shadbuf = shadbuf; 241 if (snd_verbose > 3) 242 printf("%s(): b=%p %d -> %d [%d]\n", 243 __func__, b, b->allocsize, allocsize, bufsize); 244 b->allocsize = allocsize; 245 } else if (snd_verbose > 3) 246 printf("%s(): b=%p %d [%d] NOCHANGE\n", 247 __func__, b, b->allocsize, b->bufsize); 248 249 b->blkcnt = blkcnt; 250 b->blksz = blksz; 251 b->bufsize = bufsize; 252 b->maxsize = bufsize; 253 b->sl = bufsize; 254 255 sndbuf_reset(b); 256 257 return 0; 258} 259 260/** 261 * @brief Zero out space in buffer free area 262 * 263 * This function clears a chunk of @c length bytes in the buffer free area 264 * (i.e., where the next write will be placed). 265 * 266 * @param b buffer context 267 * @param length number of bytes to blank 268 */ 269void 270sndbuf_clear(struct snd_dbuf *b, unsigned int length) 271{ 272 int i; 273 u_char data, *p; 274 275 if (length == 0) 276 return; 277 if (length > b->bufsize) 278 length = b->bufsize; 279 280 data = sndbuf_zerodata(b->fmt); 281 282 i = sndbuf_getfreeptr(b); 283 p = sndbuf_getbuf(b); 284 while (length > 0) { 285 p[i] = data; 286 length--; 287 i++; 288 if (i >= b->bufsize) 289 i = 0; 290 } 291} 292 293/** 294 * @brief Zap buffer contents, resetting "ready area" fields 295 * 296 * @param b buffer context 297 */ 298void 299sndbuf_fillsilence(struct snd_dbuf *b) 300{ 301 if (b->bufsize > 0) 302 memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize); 303 b->rp = 0; 304 b->rl = b->bufsize; 305} 306 307void 308sndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl) 309{ 310 if (b->bufsize > 0) 311 memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize); 312 b->rp = 0; 313 b->rl = min(b->bufsize, rl); 314} 315 316/** 317 * @brief Reset buffer w/o flushing statistics 318 * 319 * This function just zeroes out buffer contents and sets the "ready length" 320 * to zero. This was originally to facilitate minimal playback interruption 321 * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls. 322 * 323 * @param b buffer context 324 */ 325void 326sndbuf_softreset(struct snd_dbuf *b) 327{ 328 b->rl = 0; 329 if (b->buf && b->bufsize > 0) 330 sndbuf_clear(b, b->bufsize); 331} 332 333void 334sndbuf_reset(struct snd_dbuf *b) 335{ 336 b->hp = 0; 337 b->rp = 0; 338 b->rl = 0; 339 b->dl = 0; 340 b->prev_total = 0; 341 b->total = 0; 342 b->xrun = 0; 343 if (b->buf && b->bufsize > 0) 344 sndbuf_clear(b, b->bufsize); 345 sndbuf_clearshadow(b); 346} 347 348u_int32_t 349sndbuf_getfmt(struct snd_dbuf *b) 350{ 351 return b->fmt; 352} 353 354int 355sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) 356{ 357 b->fmt = fmt; 358 b->bps = AFMT_BPS(b->fmt); 359 b->align = AFMT_ALIGN(b->fmt); 360#if 0 361 b->bps = AFMT_CHANNEL(b->fmt); 362 if (b->fmt & AFMT_16BIT) 363 b->bps <<= 1; 364 else if (b->fmt & AFMT_24BIT) 365 b->bps *= 3; 366 else if (b->fmt & AFMT_32BIT) 367 b->bps <<= 2; 368#endif 369 return 0; 370} 371 372unsigned int 373sndbuf_getspd(struct snd_dbuf *b) 374{ 375 return b->spd; 376} 377 378void 379sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 380{ 381 b->spd = spd; 382} 383 384unsigned int 385sndbuf_getalign(struct snd_dbuf *b) 386{ 387 return (b->align); 388} 389 390unsigned int 391sndbuf_getblkcnt(struct snd_dbuf *b) 392{ 393 return b->blkcnt; 394} 395 396void 397sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) 398{ 399 b->blkcnt = blkcnt; 400} 401 402unsigned int 403sndbuf_getblksz(struct snd_dbuf *b) 404{ 405 return b->blksz; 406} 407 408void 409sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) 410{ 411 b->blksz = blksz; 412} 413 414unsigned int 415sndbuf_getbps(struct snd_dbuf *b) 416{ 417 return b->bps; 418} 419 420void * 421sndbuf_getbuf(struct snd_dbuf *b) 422{ 423 return b->buf; 424} 425 426void * 427sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 428{ 429 KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 430 431 return b->buf + ofs; 432} 433 434unsigned int 435sndbuf_getsize(struct snd_dbuf *b) 436{ 437 return b->bufsize; 438} 439 440unsigned int 441sndbuf_getmaxsize(struct snd_dbuf *b) 442{ 443 return b->maxsize; 444} 445 446unsigned int 447sndbuf_getallocsize(struct snd_dbuf *b) 448{ 449 return b->allocsize; 450} 451 452unsigned int 453sndbuf_runsz(struct snd_dbuf *b) 454{ 455 return b->dl; 456} 457 458void 459sndbuf_setrun(struct snd_dbuf *b, int go) 460{ 461 b->dl = go? b->blksz : 0; 462} 463 464struct selinfo * 465sndbuf_getsel(struct snd_dbuf *b) 466{ 467 return &b->sel; 468} 469 470/************************************************************/ 471unsigned int 472sndbuf_getxrun(struct snd_dbuf *b) 473{ 474 SNDBUF_LOCKASSERT(b); 475 476 return b->xrun; 477} 478 479void 480sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun) 481{ 482 SNDBUF_LOCKASSERT(b); 483 484 b->xrun = xrun; 485} 486 487unsigned int 488sndbuf_gethwptr(struct snd_dbuf *b) 489{ 490 SNDBUF_LOCKASSERT(b); 491 492 return b->hp; 493} 494 495void 496sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) 497{ 498 SNDBUF_LOCKASSERT(b); 499 500 b->hp = ptr; 501} 502 503unsigned int 504sndbuf_getready(struct snd_dbuf *b) 505{ 506 SNDBUF_LOCKASSERT(b); 507 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 508 509 return b->rl; 510} 511 512unsigned int 513sndbuf_getreadyptr(struct snd_dbuf *b) 514{ 515 SNDBUF_LOCKASSERT(b); 516 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 517 518 return b->rp; 519} 520 521unsigned int 522sndbuf_getfree(struct snd_dbuf *b) 523{ 524 SNDBUF_LOCKASSERT(b); 525 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 526 527 return b->bufsize - b->rl; 528} 529 530unsigned int 531sndbuf_getfreeptr(struct snd_dbuf *b) 532{ 533 SNDBUF_LOCKASSERT(b); 534 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 535 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 536 537 return (b->rp + b->rl) % b->bufsize; 538} 539 540u_int64_t 541sndbuf_getblocks(struct snd_dbuf *b) 542{ 543 SNDBUF_LOCKASSERT(b); 544 545 return b->total / b->blksz; 546} 547 548u_int64_t 549sndbuf_getprevblocks(struct snd_dbuf *b) 550{ 551 SNDBUF_LOCKASSERT(b); 552 553 return b->prev_total / b->blksz; 554} 555 556u_int64_t 557sndbuf_gettotal(struct snd_dbuf *b) 558{ 559 SNDBUF_LOCKASSERT(b); 560 561 return b->total; 562} 563 564u_int64_t 565sndbuf_getprevtotal(struct snd_dbuf *b) 566{ 567 SNDBUF_LOCKASSERT(b); 568 569 return b->prev_total; 570} 571 572void 573sndbuf_updateprevtotal(struct snd_dbuf *b) 574{ 575 SNDBUF_LOCKASSERT(b); 576 577 b->prev_total = b->total; 578} 579 580unsigned int 581sndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to) 582{ 583 if (from == NULL || to == NULL || v == 0) 584 return 0; 585 586 return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from), 587 sndbuf_getalign(to) * sndbuf_getspd(to)); 588} 589 590u_int8_t 591sndbuf_zerodata(u_int32_t fmt) 592{ 593 if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH)) 594 return (0x00); 595 else if (fmt & AFMT_MU_LAW) 596 return (0x7f); 597 else if (fmt & AFMT_A_LAW) 598 return (0x55); 599 return (0x80); 600} 601 602/************************************************************/ 603 604/** 605 * @brief Acquire buffer space to extend ready area 606 * 607 * This function extends the ready area length by @c count bytes, and may 608 * optionally copy samples from another location stored in @c from. The 609 * counter @c snd_dbuf::total is also incremented by @c count bytes. 610 * 611 * @param b audio buffer 612 * @param from sample source (optional) 613 * @param count number of bytes to acquire 614 * 615 * @retval 0 Unconditional 616 */ 617int 618sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) 619{ 620 int l; 621 622 KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b))); 623 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 624 b->total += count; 625 if (from != NULL) { 626 while (count > 0) { 627 l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b)); 628 bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 629 from += l; 630 b->rl += l; 631 count -= l; 632 } 633 } else 634 b->rl += count; 635 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 636 637 return 0; 638} 639 640/** 641 * @brief Dispose samples from channel buffer, increasing size of ready area 642 * 643 * This function discards samples from the supplied buffer by advancing the 644 * ready area start pointer and decrementing the ready area length. If 645 * @c to is not NULL, then the discard samples will be copied to the location 646 * it points to. 647 * 648 * @param b PCM channel sound buffer 649 * @param to destination buffer (optional) 650 * @param count number of bytes to discard 651 * 652 * @returns 0 unconditionally 653 */ 654int 655sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) 656{ 657 int l; 658 659 KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 660 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 661 if (to != NULL) { 662 while (count > 0) { 663 l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b)); 664 bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 665 to += l; 666 b->rl -= l; 667 b->rp = (b->rp + l) % b->bufsize; 668 count -= l; 669 } 670 } else { 671 b->rl -= count; 672 b->rp = (b->rp + count) % b->bufsize; 673 } 674 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 675 676 return 0; 677} 678 679#ifdef SND_DIAGNOSTIC 680static uint32_t snd_feeder_maxfeed = 0; 681SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD, 682 &snd_feeder_maxfeed, 0, "maximum feeder count request"); 683 684static uint32_t snd_feeder_maxcycle = 0; 685SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD, 686 &snd_feeder_maxcycle, 0, "maximum feeder cycle"); 687#endif 688 689/* count is number of bytes we want added to destination buffer */ 690int 691sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 692{ 693 unsigned int cnt, maxfeed; 694#ifdef SND_DIAGNOSTIC 695 unsigned int cycle; 696 697 if (count > snd_feeder_maxfeed) 698 snd_feeder_maxfeed = count; 699 700 cycle = 0; 701#endif 702 703 KASSERT(count > 0, ("can't feed 0 bytes")); 704 705 if (sndbuf_getfree(to) < count) 706 return (EINVAL); 707 708 maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to)); 709 710 do { 711 cnt = FEEDER_FEED(feeder, channel, to->tmpbuf, 712 min(count, maxfeed), from); 713 if (cnt == 0) 714 break; 715 sndbuf_acquire(to, to->tmpbuf, cnt); 716 count -= cnt; 717#ifdef SND_DIAGNOSTIC 718 cycle++; 719#endif 720 } while (count != 0); 721 722#ifdef SND_DIAGNOSTIC 723 if (cycle > snd_feeder_maxcycle) 724 snd_feeder_maxcycle = cycle; 725#endif 726 727 return (0); 728} 729 730/************************************************************/ 731 732void 733sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what) 734{ 735 printf("%s: [", s); 736 if (what & 0x01) 737 printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize); 738 if (what & 0x02) 739 printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp); 740 if (what & 0x04) 741 printf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun); 742 if (what & 0x08) 743 printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd); 744 if (what & 0x10) 745 printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags); 746 printf(" ]\n"); 747} 748 749/************************************************************/ 750u_int32_t 751sndbuf_getflags(struct snd_dbuf *b) 752{ 753 return b->flags; 754} 755 756void 757sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on) 758{ 759 b->flags &= ~flags; 760 if (on) 761 b->flags |= flags; 762} 763 764/** 765 * @brief Clear the shadow buffer by filling with samples equal to zero. 766 * 767 * @param b buffer to clear 768 */ 769void 770sndbuf_clearshadow(struct snd_dbuf *b) 771{ 772 KASSERT(b != NULL, ("b is a null pointer")); 773 KASSERT(b->sl >= 0, ("illegal shadow length")); 774 775 if ((b->shadbuf != NULL) && (b->sl > 0)) 776 memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl); 777} 778 779#ifdef OSSV4_EXPERIMENT 780/** 781 * @brief Return peak value from samples in buffer ready area. 782 * 783 * Peak ranges from 0-32767. If channel is monaural, most significant 16 784 * bits will be zero. For now, only expects to work with 1-2 channel 785 * buffers. 786 * 787 * @note Currently only operates with linear PCM formats. 788 * 789 * @param b buffer to analyze 790 * @param lpeak pointer to store left peak value 791 * @param rpeak pointer to store right peak value 792 */ 793void 794sndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp) 795{ 796 u_int32_t lpeak, rpeak; 797 798 lpeak = 0; 799 rpeak = 0; 800 801 /** 802 * @todo fill this in later 803 */ 804} 805#endif 806