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