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