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