xref: /freebsd/sys/dev/sound/pcm/buffer.c (revision 8f9aabbdbcd55b25b698bd762e8693d43f295bbd)
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