xref: /dragonfly/sys/dev/sound/pcm/buffer.c (revision 52b1a712425f78997df963f067f86f7e251fd912)
1 /*-
2  * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3  * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
4  * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #ifdef HAVE_KERNEL_OPTION_HEADERS
30 #include "opt_snd.h"
31 #endif
32 
33 #include <dev/sound/pcm/sound.h>
34 
35 #include "feeder_if.h"
36 
37 #define SND_USE_FXDIV
38 #include "snd_fxdiv_gen.h"
39 
40 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/buffer.c 267762 2014-06-23 03:45:39Z kan $");
41 
42 struct snd_dbuf *
sndbuf_create(device_t dev,char * drv,char * desc,struct pcm_channel * channel)43 sndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel)
44 {
45           struct snd_dbuf *b;
46 
47           b = kmalloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO);
48           ksnprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc);
49           b->dev = dev;
50           b->channel = channel;
51 
52           return b;
53 }
54 
55 void
sndbuf_destroy(struct snd_dbuf * b)56 sndbuf_destroy(struct snd_dbuf *b)
57 {
58           sndbuf_free(b);
59           kfree(b, M_DEVBUF);
60 }
61 
62 bus_addr_t
sndbuf_getbufaddr(struct snd_dbuf * buf)63 sndbuf_getbufaddr(struct snd_dbuf *buf)
64 {
65           return (buf->buf_addr);
66 }
67 
68 static void
sndbuf_setmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)69 sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
70 {
71           struct snd_dbuf *b = (struct snd_dbuf *)arg;
72 
73           if (snd_verbose > 3) {
74                     device_printf(b->dev, "sndbuf_setmap %lx, %lx; ",
75                         (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len);
76                     kprintf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr);
77           }
78           if (error == 0)
79                     b->buf_addr = segs[0].ds_addr;
80           else
81                     b->buf_addr = 0;
82 }
83 
84 /*
85  * Allocate memory for DMA buffer. If the device does not use DMA transfers,
86  * the driver can call malloc(9) and sndbuf_setup() itself.
87  */
88 
89 int
sndbuf_alloc(struct snd_dbuf * b,bus_dma_tag_t dmatag,int dmaflags,unsigned int size)90 sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags,
91     unsigned int size)
92 {
93           int ret;
94 
95           b->dmatag = dmatag;
96           b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT;
97           b->maxsize = size;
98           b->bufsize = b->maxsize;
99           b->buf_addr = 0;
100           b->flags |= SNDBUF_F_MANAGED;
101           if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags,
102               &b->dmamap)) {
103                     sndbuf_free(b);
104                     return (ENOMEM);
105           }
106           if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize,
107               sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) {
108                     sndbuf_free(b);
109                     return (ENOMEM);
110           }
111 
112           ret = sndbuf_resize(b, 2, b->maxsize / 2);
113           if (ret != 0)
114                     sndbuf_free(b);
115 
116           return (ret);
117 }
118 
119 int
sndbuf_setup(struct snd_dbuf * b,void * buf,unsigned int size)120 sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size)
121 {
122           b->flags &= ~SNDBUF_F_MANAGED;
123           if (buf)
124                     b->flags |= SNDBUF_F_MANAGED;
125           b->buf = buf;
126           b->maxsize = size;
127           b->bufsize = b->maxsize;
128           return sndbuf_resize(b, 2, b->maxsize / 2);
129 }
130 
131 void
sndbuf_free(struct snd_dbuf * b)132 sndbuf_free(struct snd_dbuf *b)
133 {
134           if (b->tmpbuf)
135                     kfree(b->tmpbuf, M_DEVBUF);
136 
137           if (b->shadbuf)
138                     kfree(b->shadbuf, M_DEVBUF);
139 
140           if (b->buf) {
141                     if (b->flags & SNDBUF_F_MANAGED) {
142                               if (b->buf_addr)
143                                         bus_dmamap_unload(b->dmatag, b->dmamap);
144                               if (b->dmatag)
145                                         bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
146                     } else
147                               kfree(b->buf, M_DEVBUF);
148           }
149 
150           b->tmpbuf = NULL;
151           b->shadbuf = NULL;
152           b->buf = NULL;
153           b->sl = 0;
154           b->dmatag = NULL;
155           b->dmamap = NULL;
156 }
157 
158 #define SNDBUF_CACHE_SHIFT    5
159 
160 int
sndbuf_resize(struct snd_dbuf * b,unsigned int blkcnt,unsigned int blksz)161 sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
162 {
163           unsigned int bufsize, allocsize;
164           u_int8_t *tmpbuf;
165 
166           CHN_LOCK(b->channel);
167           if (b->maxsize == 0)
168                     goto out;
169           if (blkcnt == 0)
170                     blkcnt = b->blkcnt;
171           if (blksz == 0)
172                     blksz = b->blksz;
173           if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) {
174                     CHN_UNLOCK(b->channel);
175                     return EINVAL;
176           }
177           if (blkcnt == b->blkcnt && blksz == b->blksz)
178                     goto out;
179 
180           bufsize = blkcnt * blksz;
181 
182           if (bufsize > b->allocsize ||
183               bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
184                     allocsize = round_page(bufsize);
185                     CHN_UNLOCK(b->channel);
186                     tmpbuf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
187                     CHN_LOCK(b->channel);
188                     if (snd_verbose > 3)
189                               kprintf("%s(): b=%p %p -> %p [%d -> %d : %d]\n",
190                                   __func__, b, b->tmpbuf, tmpbuf,
191                                   b->allocsize, allocsize, bufsize);
192                     if (b->tmpbuf != NULL)
193                               kfree(b->tmpbuf, M_DEVBUF);
194                     b->tmpbuf = tmpbuf;
195                     b->allocsize = allocsize;
196           } else if (snd_verbose > 3)
197                     kprintf("%s(): b=%p %d [%d] NOCHANGE\n",
198                         __func__, b, b->allocsize, b->bufsize);
199 
200           b->blkcnt = blkcnt;
201           b->blksz = blksz;
202           b->bufsize = bufsize;
203 
204           sndbuf_reset(b);
205 out:
206           CHN_UNLOCK(b->channel);
207           return 0;
208 }
209 
210 int
sndbuf_remalloc(struct snd_dbuf * b,unsigned int blkcnt,unsigned int blksz)211 sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
212 {
213         unsigned int bufsize, allocsize;
214           u_int8_t *buf, *tmpbuf, *shadbuf;
215 
216           if (blkcnt < 2 || blksz < 16)
217                     return EINVAL;
218 
219           bufsize = blksz * blkcnt;
220 
221           if (bufsize > b->allocsize ||
222               bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
223                     allocsize = round_page(bufsize);
224                     CHN_UNLOCK(b->channel);
225                     buf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
226                     tmpbuf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
227                     shadbuf = kmalloc(allocsize, M_DEVBUF, M_WAITOK);
228                     CHN_LOCK(b->channel);
229                     if (b->buf != NULL)
230                               kfree(b->buf, M_DEVBUF);
231                     b->buf = buf;
232                     if (b->tmpbuf != NULL)
233                               kfree(b->tmpbuf, M_DEVBUF);
234                     b->tmpbuf = tmpbuf;
235                     if (b->shadbuf != NULL)
236                               kfree(b->shadbuf, M_DEVBUF);
237                     b->shadbuf = shadbuf;
238                     if (snd_verbose > 3)
239                               kprintf("%s(): b=%p %d -> %d [%d]\n",
240                                   __func__, b, b->allocsize, allocsize, bufsize);
241                     b->allocsize = allocsize;
242           } else if (snd_verbose > 3)
243                     kprintf("%s(): b=%p %d [%d] NOCHANGE\n",
244                         __func__, b, b->allocsize, b->bufsize);
245 
246           b->blkcnt = blkcnt;
247           b->blksz = blksz;
248           b->bufsize = bufsize;
249           b->maxsize = bufsize;
250           b->sl = bufsize;
251 
252           sndbuf_reset(b);
253 
254           return 0;
255 }
256 
257 /**
258  * @brief Zero out space in buffer free area
259  *
260  * This function clears a chunk of @c length bytes in the buffer free area
261  * (i.e., where the next write will be placed).
262  *
263  * @param b                   buffer context
264  * @param length    number of bytes to blank
265  */
266 void
sndbuf_clear(struct snd_dbuf * b,unsigned int length)267 sndbuf_clear(struct snd_dbuf *b, unsigned int length)
268 {
269           int i;
270           u_char data, *p;
271 
272           if (length == 0)
273                     return;
274           if (length > b->bufsize)
275                     length = b->bufsize;
276 
277           data = sndbuf_zerodata(b->fmt);
278 
279           i = sndbuf_getfreeptr(b);
280           p = sndbuf_getbuf(b);
281           while (length > 0) {
282                     p[i] = data;
283                     length--;
284                     i++;
285                     if (i >= b->bufsize)
286                               i = 0;
287           }
288 }
289 
290 /**
291  * @brief Zap buffer contents, resetting "ready area" fields
292  *
293  * @param b         buffer context
294  */
295 void
sndbuf_fillsilence(struct snd_dbuf * b)296 sndbuf_fillsilence(struct snd_dbuf *b)
297 {
298           if (b->bufsize > 0)
299                     memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
300           b->rp = 0;
301           b->rl = b->bufsize;
302 }
303 
304 void
sndbuf_fillsilence_rl(struct snd_dbuf * b,u_int rl)305 sndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl)
306 {
307           if (b->bufsize > 0)
308                     memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
309           b->rp = 0;
310           b->rl = min(b->bufsize, rl);
311 }
312 
313 /**
314  * @brief Reset buffer w/o flushing statistics
315  *
316  * This function just zeroes out buffer contents and sets the "ready length"
317  * to zero.  This was originally to facilitate minimal playback interruption
318  * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls.
319  *
320  * @param b         buffer context
321  */
322 void
sndbuf_softreset(struct snd_dbuf * b)323 sndbuf_softreset(struct snd_dbuf *b)
324 {
325           b->rl = 0;
326           if (b->buf && b->bufsize > 0)
327                     sndbuf_clear(b, b->bufsize);
328 }
329 
330 void
sndbuf_reset(struct snd_dbuf * b)331 sndbuf_reset(struct snd_dbuf *b)
332 {
333           b->hp = 0;
334           b->rp = 0;
335           b->rl = 0;
336           b->dl = 0;
337           b->prev_total = 0;
338           b->total = 0;
339           b->xrun = 0;
340           if (b->buf && b->bufsize > 0)
341                     sndbuf_clear(b, b->bufsize);
342           sndbuf_clearshadow(b);
343 }
344 
345 u_int32_t
sndbuf_getfmt(struct snd_dbuf * b)346 sndbuf_getfmt(struct snd_dbuf *b)
347 {
348           return b->fmt;
349 }
350 
351 int
sndbuf_setfmt(struct snd_dbuf * b,u_int32_t fmt)352 sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
353 {
354           b->fmt = fmt;
355           b->bps = AFMT_BPS(b->fmt);
356           b->align = AFMT_ALIGN(b->fmt);
357 #if 0
358           b->bps = AFMT_CHANNEL(b->fmt);
359           if (b->fmt & AFMT_16BIT)
360                     b->bps <<= 1;
361           else if (b->fmt & AFMT_24BIT)
362                     b->bps *= 3;
363           else if (b->fmt & AFMT_32BIT)
364                     b->bps <<= 2;
365 #endif
366           return 0;
367 }
368 
369 unsigned int
sndbuf_getspd(struct snd_dbuf * b)370 sndbuf_getspd(struct snd_dbuf *b)
371 {
372           return b->spd;
373 }
374 
375 void
sndbuf_setspd(struct snd_dbuf * b,unsigned int spd)376 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
377 {
378           b->spd = spd;
379 }
380 
381 unsigned int
sndbuf_getalign(struct snd_dbuf * b)382 sndbuf_getalign(struct snd_dbuf *b)
383 {
384           return (b->align);
385 }
386 
387 unsigned int
sndbuf_getblkcnt(struct snd_dbuf * b)388 sndbuf_getblkcnt(struct snd_dbuf *b)
389 {
390           return b->blkcnt;
391 }
392 
393 void
sndbuf_setblkcnt(struct snd_dbuf * b,unsigned int blkcnt)394 sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt)
395 {
396           b->blkcnt = blkcnt;
397 }
398 
399 unsigned int
sndbuf_getblksz(struct snd_dbuf * b)400 sndbuf_getblksz(struct snd_dbuf *b)
401 {
402           return b->blksz;
403 }
404 
405 void
sndbuf_setblksz(struct snd_dbuf * b,unsigned int blksz)406 sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz)
407 {
408           b->blksz = blksz;
409 }
410 
411 unsigned int
sndbuf_getbps(struct snd_dbuf * b)412 sndbuf_getbps(struct snd_dbuf *b)
413 {
414           return b->bps;
415 }
416 
417 void *
sndbuf_getbuf(struct snd_dbuf * b)418 sndbuf_getbuf(struct snd_dbuf *b)
419 {
420           return b->buf;
421 }
422 
423 void *
sndbuf_getbufofs(struct snd_dbuf * b,unsigned int ofs)424 sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs)
425 {
426           KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs));
427 
428           return b->buf + ofs;
429 }
430 
431 unsigned int
sndbuf_getsize(struct snd_dbuf * b)432 sndbuf_getsize(struct snd_dbuf *b)
433 {
434           return b->bufsize;
435 }
436 
437 unsigned int
sndbuf_getmaxsize(struct snd_dbuf * b)438 sndbuf_getmaxsize(struct snd_dbuf *b)
439 {
440           return b->maxsize;
441 }
442 
443 unsigned int
sndbuf_getallocsize(struct snd_dbuf * b)444 sndbuf_getallocsize(struct snd_dbuf *b)
445 {
446           return b->allocsize;
447 }
448 
449 unsigned int
sndbuf_runsz(struct snd_dbuf * b)450 sndbuf_runsz(struct snd_dbuf *b)
451 {
452           return b->dl;
453 }
454 
455 void
sndbuf_setrun(struct snd_dbuf * b,int go)456 sndbuf_setrun(struct snd_dbuf *b, int go)
457 {
458           b->dl = go? b->blksz : 0;
459 }
460 
461 struct kqinfo *
sndbuf_getkq(struct snd_dbuf * b)462 sndbuf_getkq(struct snd_dbuf *b)
463 {
464           return &b->kq;
465 }
466 
467 /************************************************************/
468 unsigned int
sndbuf_getxrun(struct snd_dbuf * b)469 sndbuf_getxrun(struct snd_dbuf *b)
470 {
471           SNDBUF_LOCKASSERT(b);
472 
473           return b->xrun;
474 }
475 
476 void
sndbuf_setxrun(struct snd_dbuf * b,unsigned int xrun)477 sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun)
478 {
479           SNDBUF_LOCKASSERT(b);
480 
481           b->xrun = xrun;
482 }
483 
484 unsigned int
sndbuf_gethwptr(struct snd_dbuf * b)485 sndbuf_gethwptr(struct snd_dbuf *b)
486 {
487           SNDBUF_LOCKASSERT(b);
488 
489           return b->hp;
490 }
491 
492 void
sndbuf_sethwptr(struct snd_dbuf * b,unsigned int ptr)493 sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr)
494 {
495           SNDBUF_LOCKASSERT(b);
496 
497           b->hp = ptr;
498 }
499 
500 unsigned int
sndbuf_getready(struct snd_dbuf * b)501 sndbuf_getready(struct snd_dbuf *b)
502 {
503           SNDBUF_LOCKASSERT(b);
504           KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
505 
506           return b->rl;
507 }
508 
509 unsigned int
sndbuf_getreadyptr(struct snd_dbuf * b)510 sndbuf_getreadyptr(struct snd_dbuf *b)
511 {
512           SNDBUF_LOCKASSERT(b);
513           KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
514 
515           return b->rp;
516 }
517 
518 unsigned int
sndbuf_getfree(struct snd_dbuf * b)519 sndbuf_getfree(struct snd_dbuf *b)
520 {
521           SNDBUF_LOCKASSERT(b);
522           KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
523 
524           return b->bufsize - b->rl;
525 }
526 
527 unsigned int
sndbuf_getfreeptr(struct snd_dbuf * b)528 sndbuf_getfreeptr(struct snd_dbuf *b)
529 {
530           SNDBUF_LOCKASSERT(b);
531           KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
532           KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
533 
534           return (b->rp + b->rl) % b->bufsize;
535 }
536 
537 u_int64_t
sndbuf_getblocks(struct snd_dbuf * b)538 sndbuf_getblocks(struct snd_dbuf *b)
539 {
540           SNDBUF_LOCKASSERT(b);
541 
542           return b->total / b->blksz;
543 }
544 
545 u_int64_t
sndbuf_getprevblocks(struct snd_dbuf * b)546 sndbuf_getprevblocks(struct snd_dbuf *b)
547 {
548           SNDBUF_LOCKASSERT(b);
549 
550           return b->prev_total / b->blksz;
551 }
552 
553 u_int64_t
sndbuf_gettotal(struct snd_dbuf * b)554 sndbuf_gettotal(struct snd_dbuf *b)
555 {
556           SNDBUF_LOCKASSERT(b);
557 
558           return b->total;
559 }
560 
561 u_int64_t
sndbuf_getprevtotal(struct snd_dbuf * b)562 sndbuf_getprevtotal(struct snd_dbuf *b)
563 {
564           SNDBUF_LOCKASSERT(b);
565 
566           return b->prev_total;
567 }
568 
569 void
sndbuf_updateprevtotal(struct snd_dbuf * b)570 sndbuf_updateprevtotal(struct snd_dbuf *b)
571 {
572           SNDBUF_LOCKASSERT(b);
573 
574           b->prev_total = b->total;
575 }
576 
577 unsigned int
sndbuf_xbytes(unsigned int v,struct snd_dbuf * from,struct snd_dbuf * to)578 sndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to)
579 {
580           if (from == NULL || to == NULL || v == 0)
581                     return 0;
582 
583           return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from),
584               sndbuf_getalign(to) * sndbuf_getspd(to));
585 }
586 
587 u_int8_t
sndbuf_zerodata(u_int32_t fmt)588 sndbuf_zerodata(u_int32_t fmt)
589 {
590           if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH))
591                     return (0x00);
592           else if (fmt & AFMT_MU_LAW)
593                     return (0x7f);
594           else if (fmt & AFMT_A_LAW)
595                     return (0x55);
596           return (0x80);
597 }
598 
599 /************************************************************/
600 
601 /**
602  * @brief Acquire buffer space to extend ready area
603  *
604  * This function extends the ready area length by @c count bytes, and may
605  * optionally copy samples from another location stored in @c from.  The
606  * counter @c snd_dbuf::total is also incremented by @c count bytes.
607  *
608  * @param b         audio buffer
609  * @param from      sample source (optional)
610  * @param count     number of bytes to acquire
611  *
612  * @retval 0        Unconditional
613  */
614 int
sndbuf_acquire(struct snd_dbuf * b,u_int8_t * from,unsigned int count)615 sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count)
616 {
617           int l;
618 
619           KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b)));
620           KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
621           b->total += count;
622           if (from != NULL) {
623                     while (count > 0) {
624                               l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b));
625                               bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l);
626                               from += l;
627                               b->rl += l;
628                               count -= l;
629                     }
630           } else
631                     b->rl += count;
632           KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
633 
634           return 0;
635 }
636 
637 /**
638  * @brief Dispose samples from channel buffer, increasing size of ready area
639  *
640  * This function discards samples from the supplied buffer by advancing the
641  * ready area start pointer and decrementing the ready area length.  If
642  * @c to is not NULL, then the discard samples will be copied to the location
643  * it points to.
644  *
645  * @param b         PCM channel sound buffer
646  * @param to        destination buffer (optional)
647  * @param count     number of bytes to discard
648  *
649  * @returns 0 unconditionally
650  */
651 int
sndbuf_dispose(struct snd_dbuf * b,u_int8_t * to,unsigned int count)652 sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
653 {
654           int l;
655 
656           KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b)));
657           KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
658           if (to != NULL) {
659                     while (count > 0) {
660                               l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b));
661                               bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l);
662                               to += l;
663                               b->rl -= l;
664                               b->rp = (b->rp + l) % b->bufsize;
665                               count -= l;
666                     }
667           } else {
668                     b->rl -= count;
669                     b->rp = (b->rp + count) % b->bufsize;
670           }
671           KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
672 
673           return 0;
674 }
675 
676 #ifdef SND_DIAGNOSTIC
677 static uint32_t snd_feeder_maxfeed = 0;
678 SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD,
679     &snd_feeder_maxfeed, 0, "maximum feeder count request");
680 
681 static uint32_t snd_feeder_maxcycle = 0;
682 SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD,
683     &snd_feeder_maxcycle, 0, "maximum feeder cycle");
684 #endif
685 
686 /* count is number of bytes we want added to destination buffer */
687 int
sndbuf_feed(struct snd_dbuf * from,struct snd_dbuf * to,struct pcm_channel * channel,struct pcm_feeder * feeder,unsigned int count)688 sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)
689 {
690           unsigned int cnt, maxfeed;
691 #ifdef SND_DIAGNOSTIC
692           unsigned int cycle;
693 
694           if (count > snd_feeder_maxfeed)
695                     snd_feeder_maxfeed = count;
696 
697           cycle = 0;
698 #endif
699 
700           KASSERT(count > 0, ("can't feed 0 bytes"));
701 
702           if (sndbuf_getfree(to) < count)
703                     return (EINVAL);
704 
705           maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to));
706 
707           do {
708                     cnt = FEEDER_FEED(feeder, channel, to->tmpbuf,
709                         min(count, maxfeed), from);
710                     if (cnt == 0)
711                               break;
712                     sndbuf_acquire(to, to->tmpbuf, cnt);
713                     count -= cnt;
714 #ifdef SND_DIAGNOSTIC
715                     cycle++;
716 #endif
717           } while (count != 0);
718 
719 #ifdef SND_DIAGNOSTIC
720           if (cycle > snd_feeder_maxcycle)
721                     snd_feeder_maxcycle = cycle;
722 #endif
723 
724           return (0);
725 }
726 
727 /************************************************************/
728 
729 void
sndbuf_dump(struct snd_dbuf * b,char * s,u_int32_t what)730 sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what)
731 {
732           kprintf("%s: [", s);
733           if (what & 0x01)
734                     kprintf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize);
735           if (what & 0x02)
736                     kprintf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp);
737           if (what & 0x04)
738                     kprintf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun);
739           if (what & 0x08)
740                     kprintf(" fmt: 0x%x, spd: %d", b->fmt, b->spd);
741           if (what & 0x10)
742                     kprintf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags);
743           kprintf(" ]\n");
744 }
745 
746 /************************************************************/
747 u_int32_t
sndbuf_getflags(struct snd_dbuf * b)748 sndbuf_getflags(struct snd_dbuf *b)
749 {
750           return b->flags;
751 }
752 
753 void
sndbuf_setflags(struct snd_dbuf * b,u_int32_t flags,int on)754 sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on)
755 {
756           b->flags &= ~flags;
757           if (on)
758                     b->flags |= flags;
759 }
760 
761 /**
762  * @brief Clear the shadow buffer by filling with samples equal to zero.
763  *
764  * @param b buffer to clear
765  */
766 void
sndbuf_clearshadow(struct snd_dbuf * b)767 sndbuf_clearshadow(struct snd_dbuf *b)
768 {
769           KASSERT(b != NULL, ("b is a null pointer"));
770           KASSERT(b->sl >= 0, ("illegal shadow length"));
771 
772           if ((b->shadbuf != NULL) && (b->sl > 0))
773                     memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl);
774 }
775 
776 #ifdef OSSV4_EXPERIMENT
777 /**
778  * @brief Return peak value from samples in buffer ready area.
779  *
780  * Peak ranges from 0-32767.  If channel is monaural, most significant 16
781  * bits will be zero.  For now, only expects to work with 1-2 channel
782  * buffers.
783  *
784  * @note  Currently only operates with linear PCM formats.
785  *
786  * @param b buffer to analyze
787  * @param lpeak pointer to store left peak value
788  * @param rpeak pointer to store right peak value
789  */
790 void
sndbuf_getpeaks(struct snd_dbuf * b,int * lp,int * rp)791 sndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp)
792 {
793           u_int32_t lpeak, rpeak;
794 
795           lpeak = 0;
796           rpeak = 0;
797 
798           /**
799            * @todo fill this in later
800            */
801 }
802 #endif
803