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