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