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 *
sndbuf_create(struct pcm_channel * channel,const char * desc)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
sndbuf_destroy(struct snd_dbuf * b)60 sndbuf_destroy(struct snd_dbuf *b)
61 {
62 sndbuf_free(b);
63 free(b, M_DEVBUF);
64 }
65
66 static void
sndbuf_setmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)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
sndbuf_alloc(struct snd_dbuf * b,bus_dma_tag_t dmatag,int dmaflags,unsigned int size)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
sndbuf_setup(struct snd_dbuf * b,void * buf,unsigned int size)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
sndbuf_free(struct snd_dbuf * b)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
sndbuf_resize(struct snd_dbuf * b,unsigned int blkcnt,unsigned int blksz)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
sndbuf_remalloc(struct snd_dbuf * b,unsigned int blkcnt,unsigned int blksz)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
sndbuf_clear(struct snd_dbuf * b,unsigned int length)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
sndbuf_fillsilence(struct snd_dbuf * b)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
sndbuf_fillsilence_rl(struct snd_dbuf * b,u_int rl)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
sndbuf_softreset(struct snd_dbuf * b)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
sndbuf_reset(struct snd_dbuf * b)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
sndbuf_setfmt(struct snd_dbuf * b,u_int32_t fmt)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
sndbuf_setspd(struct snd_dbuf * b,unsigned int spd)341 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
342 {
343 b->spd = spd;
344 }
345
346 void *
sndbuf_getbufofs(struct snd_dbuf * b,unsigned int ofs)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
sndbuf_runsz(struct snd_dbuf * b)355 sndbuf_runsz(struct snd_dbuf *b)
356 {
357 return b->dl;
358 }
359
360 void
sndbuf_setrun(struct snd_dbuf * b,int go)361 sndbuf_setrun(struct snd_dbuf *b, int go)
362 {
363 b->dl = go? b->blksz : 0;
364 }
365
366 void
sndbuf_setxrun(struct snd_dbuf * b,unsigned int xrun)367 sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun)
368 {
369 b->xrun = xrun;
370 }
371
372 unsigned int
sndbuf_getready(struct snd_dbuf * b)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
sndbuf_getreadyptr(struct snd_dbuf * b)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
sndbuf_getfree(struct snd_dbuf * b)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
sndbuf_getfreeptr(struct snd_dbuf * b)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
sndbuf_getblocks(struct snd_dbuf * b)406 sndbuf_getblocks(struct snd_dbuf *b)
407 {
408 return b->total / b->blksz;
409 }
410
411 unsigned int
sndbuf_xbytes(unsigned int v,struct snd_dbuf * from,struct snd_dbuf * to)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
sndbuf_zerodata(u_int32_t fmt)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
sndbuf_acquire(struct snd_dbuf * b,u_int8_t * from,unsigned int count)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
sndbuf_dispose(struct snd_dbuf * b,u_int8_t * to,unsigned int count)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
sndbuf_feed(struct snd_dbuf * from,struct snd_dbuf * to,struct pcm_channel * channel,struct pcm_feeder * feeder,unsigned int count)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
sndbuf_clearshadow(struct snd_dbuf * b)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
sndbuf_getpeaks(struct snd_dbuf * b,int * lp,int * rp)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