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 * Copyright (c) 2025 The FreeBSD Foundation 9 * 10 * Portions of this software were developed by Christos Margiolis 11 * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #ifdef HAVE_KERNEL_OPTION_HEADERS 36 #include "opt_snd.h" 37 #endif 38 39 #include <sys/refcount.h> 40 #include <dev/sound/pcm/sound.h> 41 42 #include "feeder_if.h" 43 44 #define SND_USE_FXDIV 45 #define SND_DECLARE_FXDIV 46 #include "snd_fxdiv_gen.h" 47 48 struct snd_dbuf * 49 sndbuf_create(struct pcm_channel *channel, uint32_t fmt, uint32_t spd, 50 const char *desc) 51 { 52 struct snd_dbuf *b; 53 54 b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO); 55 refcount_init(&b->refcount, 1); 56 snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", channel->name, desc); 57 b->channel = channel; 58 sndbuf_setfmt(b, fmt); 59 sndbuf_setspd(b, spd); 60 61 return b; 62 } 63 64 void 65 sndbuf_destroy(struct snd_dbuf *b) 66 { 67 b->flags |= SNDBUF_F_DETACHED; 68 sndbuf_rele(b); 69 } 70 71 void 72 sndbuf_ref(struct snd_dbuf *b) 73 { 74 unsigned int count __diagused; 75 76 CHN_LOCK(b->channel); 77 count = refcount_acquire(&b->refcount); 78 KASSERT(count > 0, ("sndbuf %p refcount 0", b)); 79 CHN_UNLOCK(b->channel); 80 } 81 82 void 83 sndbuf_rele(struct snd_dbuf *b) 84 { 85 if (refcount_release(&b->refcount)) { 86 sndbuf_free(b); 87 KASSERT(refcount_load(&b->refcount) == 0, 88 ("sndbuf %p still referenced", b)); 89 free(b, M_DEVBUF); 90 } 91 } 92 93 static void 94 sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 95 { 96 struct snd_dbuf *b = (struct snd_dbuf *)arg; 97 98 if (snd_verbose > 3) { 99 printf("sndbuf_setmap %lx, %lx; ", 100 (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len); 101 printf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr); 102 } 103 if (error == 0) 104 b->buf_addr = segs[0].ds_addr; 105 else 106 b->buf_addr = 0; 107 } 108 109 /* 110 * Allocate memory for DMA buffer. If the device does not use DMA transfers, 111 * the driver can call malloc(9) and sndbuf_setup() itself. 112 */ 113 114 int 115 sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags, 116 unsigned int size) 117 { 118 int ret; 119 120 b->dmatag = dmatag; 121 b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT; 122 b->maxsize = size; 123 b->bufsize = b->maxsize; 124 b->buf_addr = 0; 125 b->flags |= SNDBUF_F_MANAGED; 126 if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags, 127 &b->dmamap)) { 128 sndbuf_free(b); 129 return (ENOMEM); 130 } 131 if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, 132 sndbuf_setmap, b, BUS_DMA_NOWAIT) != 0 || b->buf_addr == 0) { 133 sndbuf_free(b); 134 return (ENOMEM); 135 } 136 137 ret = sndbuf_resize(b, 2, b->maxsize / 2); 138 if (ret != 0) 139 sndbuf_free(b); 140 141 return (ret); 142 } 143 144 int 145 sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size) 146 { 147 b->flags &= ~SNDBUF_F_MANAGED; 148 if (buf) 149 b->flags |= SNDBUF_F_MANAGED; 150 b->buf = buf; 151 b->maxsize = size; 152 b->bufsize = b->maxsize; 153 return sndbuf_resize(b, 2, b->maxsize / 2); 154 } 155 156 void 157 sndbuf_free(struct snd_dbuf *b) 158 { 159 free(b->tmpbuf, M_DEVBUF); 160 free(b->shadbuf, M_DEVBUF); 161 162 if (b->buf) { 163 if (b->flags & SNDBUF_F_MANAGED) { 164 if (b->buf_addr) 165 bus_dmamap_unload(b->dmatag, b->dmamap); 166 if (b->dmatag) 167 bus_dmamem_free(b->dmatag, b->buf, b->dmamap); 168 } else 169 free(b->buf, M_DEVBUF); 170 } 171 seldrain(&b->sel); 172 173 b->tmpbuf = NULL; 174 b->shadbuf = NULL; 175 b->buf = NULL; 176 b->sl = 0; 177 b->dmatag = NULL; 178 b->dmamap = NULL; 179 } 180 181 #define SNDBUF_CACHE_SHIFT 5 182 183 int 184 sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 185 { 186 unsigned int bufsize, allocsize; 187 uint8_t *tmpbuf; 188 189 CHN_LOCK(b->channel); 190 if (b->maxsize == 0) 191 goto out; 192 if (blkcnt == 0) 193 blkcnt = b->blkcnt; 194 if (blksz == 0) 195 blksz = b->blksz; 196 if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) { 197 CHN_UNLOCK(b->channel); 198 return EINVAL; 199 } 200 if (blkcnt == b->blkcnt && blksz == b->blksz) 201 goto out; 202 203 bufsize = blkcnt * blksz; 204 205 if (bufsize > b->allocsize || 206 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 207 if (refcount_load(&b->refcount) > 1 || 208 (b->flags & SNDBUF_F_DETACHED) != 0) { 209 CHN_UNLOCK(b->channel); 210 return (EBUSY); 211 } 212 allocsize = round_page(bufsize); 213 CHN_UNLOCK(b->channel); 214 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 215 CHN_LOCK(b->channel); 216 if (snd_verbose > 3) 217 printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n", 218 __func__, b, b->tmpbuf, tmpbuf, 219 b->allocsize, allocsize, bufsize); 220 free(b->tmpbuf, M_DEVBUF); 221 b->tmpbuf = tmpbuf; 222 b->allocsize = allocsize; 223 } else if (snd_verbose > 3) 224 printf("%s(): b=%p %d [%d] NOCHANGE\n", 225 __func__, b, b->allocsize, b->bufsize); 226 227 b->blkcnt = blkcnt; 228 b->blksz = blksz; 229 b->bufsize = bufsize; 230 231 sndbuf_reset(b); 232 out: 233 CHN_UNLOCK(b->channel); 234 return 0; 235 } 236 237 int 238 sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 239 { 240 unsigned int bufsize, allocsize; 241 uint8_t *buf, *tmpbuf, *shadbuf; 242 243 if (blkcnt < 2 || blksz < 16) 244 return EINVAL; 245 246 CHN_LOCKASSERT(b->channel); 247 248 bufsize = blksz * blkcnt; 249 250 if (bufsize > b->allocsize || 251 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 252 if (refcount_load(&b->refcount) > 1 || 253 (b->flags & SNDBUF_F_DETACHED) != 0) 254 return (EBUSY); 255 allocsize = round_page(bufsize); 256 CHN_UNLOCK(b->channel); 257 buf = malloc(allocsize, M_DEVBUF, M_WAITOK); 258 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 259 shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 260 CHN_LOCK(b->channel); 261 free(b->buf, M_DEVBUF); 262 b->buf = buf; 263 free(b->tmpbuf, M_DEVBUF); 264 b->tmpbuf = tmpbuf; 265 free(b->shadbuf, M_DEVBUF); 266 b->shadbuf = shadbuf; 267 if (snd_verbose > 3) 268 printf("%s(): b=%p %d -> %d [%d]\n", 269 __func__, b, b->allocsize, allocsize, bufsize); 270 b->allocsize = allocsize; 271 } else if (snd_verbose > 3) 272 printf("%s(): b=%p %d [%d] NOCHANGE\n", 273 __func__, b, b->allocsize, b->bufsize); 274 275 b->blkcnt = blkcnt; 276 b->blksz = blksz; 277 b->bufsize = bufsize; 278 b->maxsize = bufsize; 279 b->sl = bufsize; 280 281 sndbuf_reset(b); 282 283 return 0; 284 } 285 286 /** 287 * @brief Zero out space in buffer free area 288 * 289 * This function clears a chunk of @c length bytes in the buffer free area 290 * (i.e., where the next write will be placed). 291 * 292 * @param b buffer context 293 * @param length number of bytes to blank 294 */ 295 void 296 sndbuf_clear(struct snd_dbuf *b, unsigned int length) 297 { 298 int i; 299 u_char data, *p; 300 301 if (length == 0) 302 return; 303 if (length > b->bufsize) 304 length = b->bufsize; 305 306 data = sndbuf_zerodata(b->fmt); 307 i = sndbuf_getfreeptr(b); 308 p = b->buf; 309 for (; length > 0; length--, i++) 310 p[i % b->bufsize] = data; 311 } 312 313 /** 314 * @brief Zap buffer contents, resetting "ready area" fields 315 * 316 * @param b buffer context 317 */ 318 void 319 sndbuf_fillsilence(struct snd_dbuf *b) 320 { 321 if (b->bufsize > 0) 322 memset(b->buf, sndbuf_zerodata(b->fmt), b->bufsize); 323 b->rp = 0; 324 b->rl = b->bufsize; 325 } 326 327 void 328 sndbuf_fillsilence_rl(struct snd_dbuf *b, unsigned int rl) 329 { 330 if (b->bufsize > 0) 331 memset(b->buf, sndbuf_zerodata(b->fmt), b->bufsize); 332 b->rp = 0; 333 b->rl = min(b->bufsize, rl); 334 } 335 336 /** 337 * @brief Reset buffer w/o flushing statistics 338 * 339 * This function just zeroes out buffer contents and sets the "ready length" 340 * to zero. This was originally to facilitate minimal playback interruption 341 * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls. 342 * 343 * @param b buffer context 344 */ 345 void 346 sndbuf_softreset(struct snd_dbuf *b) 347 { 348 b->rl = 0; 349 if (b->buf && b->bufsize > 0) 350 sndbuf_clear(b, b->bufsize); 351 } 352 353 void 354 sndbuf_reset(struct snd_dbuf *b) 355 { 356 b->hp = 0; 357 b->rp = 0; 358 b->rl = 0; 359 b->dl = 0; 360 b->prev_total = 0; 361 b->total = 0; 362 b->xrun = 0; 363 if (b->buf && b->bufsize > 0) 364 sndbuf_clear(b, b->bufsize); 365 sndbuf_clearshadow(b); 366 } 367 368 int 369 sndbuf_setfmt(struct snd_dbuf *b, uint32_t fmt) 370 { 371 b->fmt = fmt; 372 b->bps = AFMT_BPS(b->fmt); 373 b->align = AFMT_ALIGN(b->fmt); 374 return 0; 375 } 376 377 void 378 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 379 { 380 b->spd = spd; 381 } 382 383 void * 384 sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 385 { 386 KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 387 388 return b->buf + ofs; 389 } 390 391 unsigned int 392 sndbuf_runsz(struct snd_dbuf *b) 393 { 394 return b->dl; 395 } 396 397 void 398 sndbuf_setrun(struct snd_dbuf *b, int go) 399 { 400 b->dl = go? b->blksz : 0; 401 } 402 403 void 404 sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun) 405 { 406 b->xrun = xrun; 407 } 408 409 unsigned int 410 sndbuf_getready(struct snd_dbuf *b) 411 { 412 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 413 414 return b->rl; 415 } 416 417 unsigned int 418 sndbuf_getreadyptr(struct snd_dbuf *b) 419 { 420 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 421 422 return b->rp; 423 } 424 425 unsigned int 426 sndbuf_getfree(struct snd_dbuf *b) 427 { 428 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 429 430 return b->bufsize - b->rl; 431 } 432 433 unsigned int 434 sndbuf_getfreeptr(struct snd_dbuf *b) 435 { 436 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 437 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 438 439 return (b->rp + b->rl) % b->bufsize; 440 } 441 442 uint64_t 443 sndbuf_getblocks(struct snd_dbuf *b) 444 { 445 return b->total / b->blksz; 446 } 447 448 unsigned int 449 sndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to) 450 { 451 if (from == NULL || to == NULL || v == 0) 452 return 0; 453 454 return snd_xbytes(v, from->align * from->spd, to->align * to->spd); 455 } 456 457 uint8_t 458 sndbuf_zerodata(uint32_t fmt) 459 { 460 if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH)) 461 return (0x00); 462 else if (fmt & AFMT_MU_LAW) 463 return (0x7f); 464 else if (fmt & AFMT_A_LAW) 465 return (0x55); 466 return (0x80); 467 } 468 469 /************************************************************/ 470 471 /** 472 * @brief Acquire buffer space to extend ready area 473 * 474 * This function extends the ready area length by @c count bytes, and may 475 * optionally copy samples from another location stored in @c from. The 476 * counter @c snd_dbuf::total is also incremented by @c count bytes. 477 * 478 * @param b audio buffer 479 * @param from sample source (optional) 480 * @param count number of bytes to acquire 481 * 482 * @retval 0 Unconditional 483 */ 484 int 485 sndbuf_acquire(struct snd_dbuf *b, uint8_t *from, unsigned int count) 486 { 487 int l; 488 489 KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b))); 490 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 491 b->total += count; 492 if (from != NULL) { 493 while (count > 0) { 494 l = min(count, b->bufsize - sndbuf_getfreeptr(b)); 495 bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 496 from += l; 497 b->rl += l; 498 count -= l; 499 } 500 } else 501 b->rl += count; 502 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 503 504 return 0; 505 } 506 507 /** 508 * @brief Dispose samples from channel buffer, increasing size of ready area 509 * 510 * This function discards samples from the supplied buffer by advancing the 511 * ready area start pointer and decrementing the ready area length. If 512 * @c to is not NULL, then the discard samples will be copied to the location 513 * it points to. 514 * 515 * @param b PCM channel sound buffer 516 * @param to destination buffer (optional) 517 * @param count number of bytes to discard 518 * 519 * @returns 0 unconditionally 520 */ 521 int 522 sndbuf_dispose(struct snd_dbuf *b, uint8_t *to, unsigned int count) 523 { 524 int l; 525 526 KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 527 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 528 if (to != NULL) { 529 while (count > 0) { 530 l = min(count, b->bufsize - sndbuf_getreadyptr(b)); 531 bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 532 to += l; 533 b->rl -= l; 534 b->rp = (b->rp + l) % b->bufsize; 535 count -= l; 536 } 537 } else { 538 b->rl -= count; 539 b->rp = (b->rp + count) % b->bufsize; 540 } 541 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 542 543 return 0; 544 } 545 546 /* count is number of bytes we want added to destination buffer */ 547 int 548 sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 549 { 550 unsigned int cnt, maxfeed; 551 552 KASSERT(count > 0, ("can't feed 0 bytes")); 553 554 if (sndbuf_getfree(to) < count) 555 return (EINVAL); 556 557 maxfeed = SND_FXROUND(SND_FXDIV_MAX, to->align); 558 559 do { 560 cnt = FEEDER_FEED(feeder, channel, to->tmpbuf, 561 min(count, maxfeed), from); 562 if (cnt == 0) 563 break; 564 sndbuf_acquire(to, to->tmpbuf, cnt); 565 count -= cnt; 566 } while (count != 0); 567 568 return (0); 569 } 570 571 /** 572 * @brief Clear the shadow buffer by filling with samples equal to zero. 573 * 574 * @param b buffer to clear 575 */ 576 void 577 sndbuf_clearshadow(struct snd_dbuf *b) 578 { 579 KASSERT(b != NULL, ("b is a null pointer")); 580 KASSERT(b->sl >= 0, ("illegal shadow length")); 581 582 if ((b->shadbuf != NULL) && (b->sl > 0)) 583 memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl); 584 } 585 586 #ifdef OSSV4_EXPERIMENT 587 /** 588 * @brief Return peak value from samples in buffer ready area. 589 * 590 * Peak ranges from 0-32767. If channel is monaural, most significant 16 591 * bits will be zero. For now, only expects to work with 1-2 channel 592 * buffers. 593 * 594 * @note Currently only operates with linear PCM formats. 595 * 596 * @param b buffer to analyze 597 * @param lpeak pointer to store left peak value 598 * @param rpeak pointer to store right peak value 599 */ 600 void 601 sndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp) 602 { 603 uint32_t lpeak, rpeak; 604 605 lpeak = 0; 606 rpeak = 0; 607 608 /** 609 * @todo fill this in later 610 */ 611 } 612 #endif 613