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