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