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