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