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 43 SND_DECLARE_FILE("$FreeBSD$"); 44 45 struct snd_dbuf * 46 sndbuf_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 58 void 59 sndbuf_destroy(struct snd_dbuf *b) 60 { 61 sndbuf_free(b); 62 free(b, M_DEVBUF); 63 } 64 65 bus_addr_t 66 sndbuf_getbufaddr(struct snd_dbuf *buf) 67 { 68 return (buf->buf_addr); 69 } 70 71 static void 72 sndbuf_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 92 int 93 sndbuf_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, BUS_DMA_NOWAIT) != 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 122 int 123 sndbuf_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 134 void 135 sndbuf_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 163 int 164 sndbuf_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); 208 out: 209 CHN_UNLOCK(b->channel); 210 return 0; 211 } 212 213 int 214 sndbuf_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 */ 269 void 270 sndbuf_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 */ 298 void 299 sndbuf_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 307 void 308 sndbuf_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 */ 325 void 326 sndbuf_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 333 void 334 sndbuf_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 348 u_int32_t 349 sndbuf_getfmt(struct snd_dbuf *b) 350 { 351 return b->fmt; 352 } 353 354 int 355 sndbuf_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 372 unsigned int 373 sndbuf_getspd(struct snd_dbuf *b) 374 { 375 return b->spd; 376 } 377 378 void 379 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 380 { 381 b->spd = spd; 382 } 383 384 unsigned int 385 sndbuf_getalign(struct snd_dbuf *b) 386 { 387 return (b->align); 388 } 389 390 unsigned int 391 sndbuf_getblkcnt(struct snd_dbuf *b) 392 { 393 return b->blkcnt; 394 } 395 396 void 397 sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) 398 { 399 b->blkcnt = blkcnt; 400 } 401 402 unsigned int 403 sndbuf_getblksz(struct snd_dbuf *b) 404 { 405 return b->blksz; 406 } 407 408 void 409 sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) 410 { 411 b->blksz = blksz; 412 } 413 414 unsigned int 415 sndbuf_getbps(struct snd_dbuf *b) 416 { 417 return b->bps; 418 } 419 420 void * 421 sndbuf_getbuf(struct snd_dbuf *b) 422 { 423 return b->buf; 424 } 425 426 void * 427 sndbuf_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 434 unsigned int 435 sndbuf_getsize(struct snd_dbuf *b) 436 { 437 return b->bufsize; 438 } 439 440 unsigned int 441 sndbuf_getmaxsize(struct snd_dbuf *b) 442 { 443 return b->maxsize; 444 } 445 446 unsigned int 447 sndbuf_getallocsize(struct snd_dbuf *b) 448 { 449 return b->allocsize; 450 } 451 452 unsigned int 453 sndbuf_runsz(struct snd_dbuf *b) 454 { 455 return b->dl; 456 } 457 458 void 459 sndbuf_setrun(struct snd_dbuf *b, int go) 460 { 461 b->dl = go? b->blksz : 0; 462 } 463 464 struct selinfo * 465 sndbuf_getsel(struct snd_dbuf *b) 466 { 467 return &b->sel; 468 } 469 470 /************************************************************/ 471 unsigned int 472 sndbuf_getxrun(struct snd_dbuf *b) 473 { 474 SNDBUF_LOCKASSERT(b); 475 476 return b->xrun; 477 } 478 479 void 480 sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun) 481 { 482 SNDBUF_LOCKASSERT(b); 483 484 b->xrun = xrun; 485 } 486 487 unsigned int 488 sndbuf_gethwptr(struct snd_dbuf *b) 489 { 490 SNDBUF_LOCKASSERT(b); 491 492 return b->hp; 493 } 494 495 void 496 sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) 497 { 498 SNDBUF_LOCKASSERT(b); 499 500 b->hp = ptr; 501 } 502 503 unsigned int 504 sndbuf_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 512 unsigned int 513 sndbuf_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 521 unsigned int 522 sndbuf_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 530 unsigned int 531 sndbuf_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 540 u_int64_t 541 sndbuf_getblocks(struct snd_dbuf *b) 542 { 543 SNDBUF_LOCKASSERT(b); 544 545 return b->total / b->blksz; 546 } 547 548 u_int64_t 549 sndbuf_getprevblocks(struct snd_dbuf *b) 550 { 551 SNDBUF_LOCKASSERT(b); 552 553 return b->prev_total / b->blksz; 554 } 555 556 u_int64_t 557 sndbuf_gettotal(struct snd_dbuf *b) 558 { 559 SNDBUF_LOCKASSERT(b); 560 561 return b->total; 562 } 563 564 u_int64_t 565 sndbuf_getprevtotal(struct snd_dbuf *b) 566 { 567 SNDBUF_LOCKASSERT(b); 568 569 return b->prev_total; 570 } 571 572 void 573 sndbuf_updateprevtotal(struct snd_dbuf *b) 574 { 575 SNDBUF_LOCKASSERT(b); 576 577 b->prev_total = b->total; 578 } 579 580 unsigned int 581 sndbuf_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 590 u_int8_t 591 sndbuf_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 */ 617 int 618 sndbuf_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 */ 654 int 655 sndbuf_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 680 static uint32_t snd_feeder_maxfeed = 0; 681 SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD, 682 &snd_feeder_maxfeed, 0, "maximum feeder count request"); 683 684 static uint32_t snd_feeder_maxcycle = 0; 685 SYSCTL_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 */ 690 int 691 sndbuf_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 732 void 733 sndbuf_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 /************************************************************/ 750 u_int32_t 751 sndbuf_getflags(struct snd_dbuf *b) 752 { 753 return b->flags; 754 } 755 756 void 757 sndbuf_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 */ 769 void 770 sndbuf_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 */ 793 void 794 sndbuf_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