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, const char *desc) 50 { 51 struct snd_dbuf *b; 52 53 b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO); 54 refcount_init(&b->refcount, 1); 55 snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", channel->name, desc); 56 b->channel = channel; 57 58 return b; 59 } 60 61 void 62 sndbuf_destroy(struct snd_dbuf *b) 63 { 64 b->flags |= SNDBUF_F_DETACHED; 65 sndbuf_rele(b); 66 } 67 68 void 69 sndbuf_ref(struct snd_dbuf *b) 70 { 71 unsigned int count __diagused; 72 73 CHN_LOCK(b->channel); 74 count = refcount_acquire(&b->refcount); 75 KASSERT(count > 0, ("sndbuf %p refcount 0", b)); 76 CHN_UNLOCK(b->channel); 77 } 78 79 void 80 sndbuf_rele(struct snd_dbuf *b) 81 { 82 if (refcount_release(&b->refcount)) { 83 sndbuf_free(b); 84 KASSERT(refcount_load(&b->refcount) == 0, 85 ("sndbuf %p still referenced", b)); 86 free(b, M_DEVBUF); 87 } 88 } 89 90 static void 91 sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 92 { 93 struct snd_dbuf *b = (struct snd_dbuf *)arg; 94 95 if (snd_verbose > 3) { 96 printf("sndbuf_setmap %lx, %lx; ", 97 (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len); 98 printf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr); 99 } 100 if (error == 0) 101 b->buf_addr = segs[0].ds_addr; 102 else 103 b->buf_addr = 0; 104 } 105 106 /* 107 * Allocate memory for DMA buffer. If the device does not use DMA transfers, 108 * the driver can call malloc(9) and sndbuf_setup() itself. 109 */ 110 111 int 112 sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags, 113 unsigned int size) 114 { 115 int ret; 116 117 b->dmatag = dmatag; 118 b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT; 119 b->maxsize = size; 120 b->bufsize = b->maxsize; 121 b->buf_addr = 0; 122 b->flags |= SNDBUF_F_MANAGED; 123 if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags, 124 &b->dmamap)) { 125 sndbuf_free(b); 126 return (ENOMEM); 127 } 128 if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, 129 sndbuf_setmap, b, BUS_DMA_NOWAIT) != 0 || b->buf_addr == 0) { 130 sndbuf_free(b); 131 return (ENOMEM); 132 } 133 134 ret = sndbuf_resize(b, 2, b->maxsize / 2); 135 if (ret != 0) 136 sndbuf_free(b); 137 138 return (ret); 139 } 140 141 int 142 sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size) 143 { 144 b->flags &= ~SNDBUF_F_MANAGED; 145 if (buf) 146 b->flags |= SNDBUF_F_MANAGED; 147 b->buf = buf; 148 b->maxsize = size; 149 b->bufsize = b->maxsize; 150 return sndbuf_resize(b, 2, b->maxsize / 2); 151 } 152 153 void 154 sndbuf_free(struct snd_dbuf *b) 155 { 156 free(b->tmpbuf, M_DEVBUF); 157 free(b->shadbuf, M_DEVBUF); 158 159 if (b->buf) { 160 if (b->flags & SNDBUF_F_MANAGED) { 161 if (b->buf_addr) 162 bus_dmamap_unload(b->dmatag, b->dmamap); 163 if (b->dmatag) 164 bus_dmamem_free(b->dmatag, b->buf, b->dmamap); 165 } else 166 free(b->buf, M_DEVBUF); 167 } 168 seldrain(&b->sel); 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 if (refcount_load(&b->refcount) > 1 || 205 (b->flags & SNDBUF_F_DETACHED) != 0) { 206 CHN_UNLOCK(b->channel); 207 return (EBUSY); 208 } 209 allocsize = round_page(bufsize); 210 CHN_UNLOCK(b->channel); 211 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 212 CHN_LOCK(b->channel); 213 if (snd_verbose > 3) 214 printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n", 215 __func__, b, b->tmpbuf, tmpbuf, 216 b->allocsize, allocsize, bufsize); 217 free(b->tmpbuf, M_DEVBUF); 218 b->tmpbuf = tmpbuf; 219 b->allocsize = allocsize; 220 } else if (snd_verbose > 3) 221 printf("%s(): b=%p %d [%d] NOCHANGE\n", 222 __func__, b, b->allocsize, b->bufsize); 223 224 b->blkcnt = blkcnt; 225 b->blksz = blksz; 226 b->bufsize = bufsize; 227 228 sndbuf_reset(b); 229 out: 230 CHN_UNLOCK(b->channel); 231 return 0; 232 } 233 234 int 235 sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 236 { 237 unsigned int bufsize, allocsize; 238 u_int8_t *buf, *tmpbuf, *shadbuf; 239 240 if (blkcnt < 2 || blksz < 16) 241 return EINVAL; 242 243 CHN_LOCKASSERT(b->channel); 244 245 bufsize = blksz * blkcnt; 246 247 if (bufsize > b->allocsize || 248 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 249 if (refcount_load(&b->refcount) > 1 || 250 (b->flags & SNDBUF_F_DETACHED) != 0) 251 return (EBUSY); 252 allocsize = round_page(bufsize); 253 CHN_UNLOCK(b->channel); 254 buf = malloc(allocsize, M_DEVBUF, M_WAITOK); 255 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 256 shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 257 CHN_LOCK(b->channel); 258 free(b->buf, M_DEVBUF); 259 b->buf = buf; 260 free(b->tmpbuf, M_DEVBUF); 261 b->tmpbuf = tmpbuf; 262 free(b->shadbuf, M_DEVBUF); 263 b->shadbuf = shadbuf; 264 if (snd_verbose > 3) 265 printf("%s(): b=%p %d -> %d [%d]\n", 266 __func__, b, b->allocsize, allocsize, bufsize); 267 b->allocsize = allocsize; 268 } else if (snd_verbose > 3) 269 printf("%s(): b=%p %d [%d] NOCHANGE\n", 270 __func__, b, b->allocsize, b->bufsize); 271 272 b->blkcnt = blkcnt; 273 b->blksz = blksz; 274 b->bufsize = bufsize; 275 b->maxsize = bufsize; 276 b->sl = bufsize; 277 278 sndbuf_reset(b); 279 280 return 0; 281 } 282 283 /** 284 * @brief Zero out space in buffer free area 285 * 286 * This function clears a chunk of @c length bytes in the buffer free area 287 * (i.e., where the next write will be placed). 288 * 289 * @param b buffer context 290 * @param length number of bytes to blank 291 */ 292 void 293 sndbuf_clear(struct snd_dbuf *b, unsigned int length) 294 { 295 int i; 296 u_char data, *p; 297 298 if (length == 0) 299 return; 300 if (length > b->bufsize) 301 length = b->bufsize; 302 303 data = sndbuf_zerodata(b->fmt); 304 i = sndbuf_getfreeptr(b); 305 p = b->buf; 306 for (; length > 0; length--, i++) 307 p[i % b->bufsize] = data; 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(b->buf, 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(b->buf, 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 int 366 sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) 367 { 368 b->fmt = fmt; 369 b->bps = AFMT_BPS(b->fmt); 370 b->align = AFMT_ALIGN(b->fmt); 371 return 0; 372 } 373 374 void 375 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 376 { 377 b->spd = spd; 378 } 379 380 void * 381 sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 382 { 383 KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 384 385 return b->buf + ofs; 386 } 387 388 unsigned int 389 sndbuf_runsz(struct snd_dbuf *b) 390 { 391 return b->dl; 392 } 393 394 void 395 sndbuf_setrun(struct snd_dbuf *b, int go) 396 { 397 b->dl = go? b->blksz : 0; 398 } 399 400 void 401 sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun) 402 { 403 b->xrun = xrun; 404 } 405 406 unsigned int 407 sndbuf_getready(struct snd_dbuf *b) 408 { 409 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 410 411 return b->rl; 412 } 413 414 unsigned int 415 sndbuf_getreadyptr(struct snd_dbuf *b) 416 { 417 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 418 419 return b->rp; 420 } 421 422 unsigned int 423 sndbuf_getfree(struct snd_dbuf *b) 424 { 425 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 426 427 return b->bufsize - b->rl; 428 } 429 430 unsigned int 431 sndbuf_getfreeptr(struct snd_dbuf *b) 432 { 433 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 434 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 435 436 return (b->rp + b->rl) % b->bufsize; 437 } 438 439 u_int64_t 440 sndbuf_getblocks(struct snd_dbuf *b) 441 { 442 return b->total / b->blksz; 443 } 444 445 unsigned int 446 sndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to) 447 { 448 if (from == NULL || to == NULL || v == 0) 449 return 0; 450 451 return snd_xbytes(v, from->align * from->spd, to->align * to->spd); 452 } 453 454 u_int8_t 455 sndbuf_zerodata(u_int32_t fmt) 456 { 457 if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH)) 458 return (0x00); 459 else if (fmt & AFMT_MU_LAW) 460 return (0x7f); 461 else if (fmt & AFMT_A_LAW) 462 return (0x55); 463 return (0x80); 464 } 465 466 /************************************************************/ 467 468 /** 469 * @brief Acquire buffer space to extend ready area 470 * 471 * This function extends the ready area length by @c count bytes, and may 472 * optionally copy samples from another location stored in @c from. The 473 * counter @c snd_dbuf::total is also incremented by @c count bytes. 474 * 475 * @param b audio buffer 476 * @param from sample source (optional) 477 * @param count number of bytes to acquire 478 * 479 * @retval 0 Unconditional 480 */ 481 int 482 sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) 483 { 484 int l; 485 486 KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b))); 487 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 488 b->total += count; 489 if (from != NULL) { 490 while (count > 0) { 491 l = min(count, b->bufsize - sndbuf_getfreeptr(b)); 492 bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 493 from += l; 494 b->rl += l; 495 count -= l; 496 } 497 } else 498 b->rl += count; 499 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 500 501 return 0; 502 } 503 504 /** 505 * @brief Dispose samples from channel buffer, increasing size of ready area 506 * 507 * This function discards samples from the supplied buffer by advancing the 508 * ready area start pointer and decrementing the ready area length. If 509 * @c to is not NULL, then the discard samples will be copied to the location 510 * it points to. 511 * 512 * @param b PCM channel sound buffer 513 * @param to destination buffer (optional) 514 * @param count number of bytes to discard 515 * 516 * @returns 0 unconditionally 517 */ 518 int 519 sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) 520 { 521 int l; 522 523 KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 524 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 525 if (to != NULL) { 526 while (count > 0) { 527 l = min(count, b->bufsize - sndbuf_getreadyptr(b)); 528 bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 529 to += l; 530 b->rl -= l; 531 b->rp = (b->rp + l) % b->bufsize; 532 count -= l; 533 } 534 } else { 535 b->rl -= count; 536 b->rp = (b->rp + count) % b->bufsize; 537 } 538 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 539 540 return 0; 541 } 542 543 /* count is number of bytes we want added to destination buffer */ 544 int 545 sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 546 { 547 unsigned int cnt, maxfeed; 548 549 KASSERT(count > 0, ("can't feed 0 bytes")); 550 551 if (sndbuf_getfree(to) < count) 552 return (EINVAL); 553 554 maxfeed = SND_FXROUND(SND_FXDIV_MAX, to->align); 555 556 do { 557 cnt = FEEDER_FEED(feeder, channel, to->tmpbuf, 558 min(count, maxfeed), from); 559 if (cnt == 0) 560 break; 561 sndbuf_acquire(to, to->tmpbuf, cnt); 562 count -= cnt; 563 } while (count != 0); 564 565 return (0); 566 } 567 568 /** 569 * @brief Clear the shadow buffer by filling with samples equal to zero. 570 * 571 * @param b buffer to clear 572 */ 573 void 574 sndbuf_clearshadow(struct snd_dbuf *b) 575 { 576 KASSERT(b != NULL, ("b is a null pointer")); 577 KASSERT(b->sl >= 0, ("illegal shadow length")); 578 579 if ((b->shadbuf != NULL) && (b->sl > 0)) 580 memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl); 581 } 582 583 #ifdef OSSV4_EXPERIMENT 584 /** 585 * @brief Return peak value from samples in buffer ready area. 586 * 587 * Peak ranges from 0-32767. If channel is monaural, most significant 16 588 * bits will be zero. For now, only expects to work with 1-2 channel 589 * buffers. 590 * 591 * @note Currently only operates with linear PCM formats. 592 * 593 * @param b buffer to analyze 594 * @param lpeak pointer to store left peak value 595 * @param rpeak pointer to store right peak value 596 */ 597 void 598 sndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp) 599 { 600 u_int32_t lpeak, rpeak; 601 602 lpeak = 0; 603 rpeak = 0; 604 605 /** 606 * @todo fill this in later 607 */ 608 } 609 #endif 610