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