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