buffer.c revision 123013
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 123013 2003-11-27 19:51:44Z matk $");
32
33struct snd_dbuf *
34sndbuf_create(device_t dev, char *drv, char *desc)
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
42	return b;
43}
44
45void
46sndbuf_destroy(struct snd_dbuf *b)
47{
48	free(b, M_DEVBUF);
49}
50
51bus_addr_t
52sndbuf_getbufaddr(struct snd_dbuf *buf)
53{
54	return (buf->buf_addr);
55}
56
57static void
58sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
59{
60	struct snd_dbuf *b = (struct snd_dbuf *)arg;
61
62	if (bootverbose) {
63		device_printf(b->dev, "sndbuf_setmap %lx, %lx; ", (unsigned long)segs->ds_addr,
64		       (unsigned long)segs->ds_len);
65		printf("%p -> %lx\n", b->buf, (unsigned long)vtophys(b->buf));
66	}
67	b->buf_addr = segs->ds_addr;
68}
69
70/*
71 * Allocate memory for DMA buffer. If the device does not use DMA transfers,
72 * the driver can call malloc(9) and sndbuf_setup() itself.
73 */
74
75int
76sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, unsigned int size)
77{
78	b->dmatag = dmatag;
79	b->maxsize = size;
80	b->bufsize = b->maxsize;
81	if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, BUS_DMA_NOWAIT, &b->dmamap))
82		return ENOSPC;
83	if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, sndbuf_setmap, b, 0))
84		return ENOSPC;
85	return sndbuf_resize(b, 2, b->maxsize / 2);
86}
87
88int
89sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size)
90{
91	b->buf = buf;
92	b->maxsize = size;
93	b->bufsize = b->maxsize;
94	return sndbuf_resize(b, 2, b->maxsize / 2);
95}
96
97void
98sndbuf_free(struct snd_dbuf *b)
99{
100	if (b->tmpbuf)
101		free(b->tmpbuf, M_DEVBUF);
102	b->tmpbuf = NULL;
103
104	if (b->dmamap)
105		bus_dmamap_unload(b->dmatag, b->dmamap);
106
107	if (b->dmamap && b->buf)
108		bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
109	b->dmamap = NULL;
110	b->buf = NULL;
111}
112
113int
114sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
115{
116	u_int8_t *tmpbuf;
117	if (b->maxsize == 0)
118		return 0;
119	if (blkcnt == 0)
120		blkcnt = b->blkcnt;
121	if (blksz == 0)
122		blksz = b->blksz;
123	if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz > b->maxsize))
124		return EINVAL;
125	if (blkcnt == b->blkcnt && blksz == b->blksz)
126		return 0;
127	b->blkcnt = blkcnt;
128	b->blksz = blksz;
129	b->bufsize = blkcnt * blksz;
130
131	tmpbuf = malloc(b->bufsize, M_DEVBUF, M_NOWAIT);
132	if (tmpbuf == NULL)
133		return ENOMEM;
134	free(b->tmpbuf, M_DEVBUF);
135	b->tmpbuf = tmpbuf;
136	sndbuf_reset(b);
137	return 0;
138}
139
140int
141sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
142{
143        u_int8_t *buf, *tmpbuf, *f1, *f2;
144        unsigned int bufsize;
145
146	if (blkcnt < 2 || blksz < 16)
147		return EINVAL;
148
149	bufsize = blksz * blkcnt;
150
151	buf = malloc(bufsize, M_DEVBUF, M_NOWAIT);
152	if (buf == NULL)
153		return ENOMEM;
154
155	tmpbuf = malloc(bufsize, M_DEVBUF, M_NOWAIT);
156   	if (tmpbuf == NULL) {
157		free(buf, M_DEVBUF);
158		return ENOMEM;
159	}
160
161	b->blkcnt = blkcnt;
162	b->blksz = blksz;
163	b->bufsize = bufsize;
164	b->maxsize = bufsize;
165	f1 = b->buf;
166	f2 = b->tmpbuf;
167	b->buf = buf;
168	b->tmpbuf = tmpbuf;
169
170      	if (f1)
171		free(f1, M_DEVBUF);
172      	if (f2)
173		free(f2, M_DEVBUF);
174
175	sndbuf_reset(b);
176	return 0;
177}
178
179void
180sndbuf_clear(struct snd_dbuf *b, unsigned int length)
181{
182	int i;
183	u_char data, *p;
184
185	if (length == 0)
186		return;
187	if (length > b->bufsize)
188		length = b->bufsize;
189
190	if (b->fmt & AFMT_SIGNED)
191		data = 0x00;
192	else
193		data = 0x80;
194
195	i = sndbuf_getfreeptr(b);
196	p = sndbuf_getbuf(b);
197	while (length > 0) {
198		p[i] = data;
199		length--;
200		i++;
201		if (i >= b->bufsize)
202			i = 0;
203	}
204}
205
206void
207sndbuf_fillsilence(struct snd_dbuf *b)
208{
209	int i;
210	u_char data, *p;
211
212	if (b->fmt & AFMT_SIGNED)
213		data = 0x00;
214	else
215		data = 0x80;
216
217	i = 0;
218	p = sndbuf_getbuf(b);
219	while (i < b->bufsize)
220		p[i++] = data;
221	b->rp = 0;
222	b->rl = b->bufsize;
223}
224
225void
226sndbuf_reset(struct snd_dbuf *b)
227{
228	b->hp = 0;
229	b->rp = 0;
230	b->rl = 0;
231	b->dl = 0;
232	b->prev_total = 0;
233	b->total = 0;
234	b->xrun = 0;
235	if (b->buf && b->bufsize > 0)
236		sndbuf_clear(b, b->bufsize);
237}
238
239u_int32_t
240sndbuf_getfmt(struct snd_dbuf *b)
241{
242	return b->fmt;
243}
244
245int
246sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
247{
248	b->fmt = fmt;
249	b->bps = 1;
250	b->bps <<= (b->fmt & AFMT_STEREO)? 1 : 0;
251	b->bps <<= (b->fmt & AFMT_16BIT)? 1 : 0;
252	b->bps <<= (b->fmt & AFMT_32BIT)? 2 : 0;
253	return 0;
254}
255
256unsigned int
257sndbuf_getspd(struct snd_dbuf *b)
258{
259	return b->spd;
260}
261
262void
263sndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
264{
265	b->spd = spd;
266}
267
268unsigned int
269sndbuf_getalign(struct snd_dbuf *b)
270{
271	static int align[] = {0, 1, 1, 2, 2, 2, 2, 3};
272
273	return align[b->bps - 1];
274}
275
276unsigned int
277sndbuf_getblkcnt(struct snd_dbuf *b)
278{
279	return b->blkcnt;
280}
281
282void
283sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt)
284{
285	b->blkcnt = blkcnt;
286}
287
288unsigned int
289sndbuf_getblksz(struct snd_dbuf *b)
290{
291	return b->blksz;
292}
293
294void
295sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz)
296{
297	b->blksz = blksz;
298}
299
300unsigned int
301sndbuf_getbps(struct snd_dbuf *b)
302{
303	return b->bps;
304}
305
306void *
307sndbuf_getbuf(struct snd_dbuf *b)
308{
309	return b->buf;
310}
311
312void *
313sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs)
314{
315	KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs));
316
317	return b->buf + ofs;
318}
319
320unsigned int
321sndbuf_getsize(struct snd_dbuf *b)
322{
323	return b->bufsize;
324}
325
326unsigned int
327sndbuf_getmaxsize(struct snd_dbuf *b)
328{
329	return b->maxsize;
330}
331
332unsigned int
333sndbuf_runsz(struct snd_dbuf *b)
334{
335	return b->dl;
336}
337
338void
339sndbuf_setrun(struct snd_dbuf *b, int go)
340{
341	b->dl = go? b->blksz : 0;
342}
343
344struct selinfo *
345sndbuf_getsel(struct snd_dbuf *b)
346{
347	return &b->sel;
348}
349
350/************************************************************/
351unsigned int
352sndbuf_getxrun(struct snd_dbuf *b)
353{
354	SNDBUF_LOCKASSERT(b);
355
356	return b->xrun;
357}
358
359void
360sndbuf_setxrun(struct snd_dbuf *b, unsigned int cnt)
361{
362	SNDBUF_LOCKASSERT(b);
363
364	b->xrun = cnt;
365}
366
367unsigned int
368sndbuf_gethwptr(struct snd_dbuf *b)
369{
370	SNDBUF_LOCKASSERT(b);
371
372	return b->hp;
373}
374
375void
376sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr)
377{
378	SNDBUF_LOCKASSERT(b);
379
380	b->hp = ptr;
381}
382
383unsigned int
384sndbuf_getready(struct snd_dbuf *b)
385{
386	SNDBUF_LOCKASSERT(b);
387	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
388
389	return b->rl;
390}
391
392unsigned int
393sndbuf_getreadyptr(struct snd_dbuf *b)
394{
395	SNDBUF_LOCKASSERT(b);
396	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
397
398	return b->rp;
399}
400
401unsigned int
402sndbuf_getfree(struct snd_dbuf *b)
403{
404	SNDBUF_LOCKASSERT(b);
405	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
406
407	return b->bufsize - b->rl;
408}
409
410unsigned int
411sndbuf_getfreeptr(struct snd_dbuf *b)
412{
413	SNDBUF_LOCKASSERT(b);
414	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
415	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
416
417	return (b->rp + b->rl) % b->bufsize;
418}
419
420unsigned int
421sndbuf_getblocks(struct snd_dbuf *b)
422{
423	SNDBUF_LOCKASSERT(b);
424
425	return b->total / b->blksz;
426}
427
428unsigned int
429sndbuf_getprevblocks(struct snd_dbuf *b)
430{
431	SNDBUF_LOCKASSERT(b);
432
433	return b->prev_total / b->blksz;
434}
435
436unsigned int
437sndbuf_gettotal(struct snd_dbuf *b)
438{
439	SNDBUF_LOCKASSERT(b);
440
441	return b->total;
442}
443
444void
445sndbuf_updateprevtotal(struct snd_dbuf *b)
446{
447	SNDBUF_LOCKASSERT(b);
448
449	b->prev_total = b->total;
450}
451
452/************************************************************/
453
454int
455sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count)
456{
457	int l;
458
459	KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b)));
460	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
461	b->total += count;
462	if (from != NULL) {
463		while (count > 0) {
464			l = MIN(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b));
465			bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l);
466			from += l;
467			b->rl += l;
468			count -= l;
469		}
470	} else
471		b->rl += count;
472	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
473
474	return 0;
475}
476
477int
478sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
479{
480	int l;
481
482	KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b)));
483	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
484	if (to != NULL) {
485		while (count > 0) {
486			l = MIN(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b));
487			bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l);
488			to += l;
489			b->rl -= l;
490			b->rp = (b->rp + l) % b->bufsize;
491			count -= l;
492		}
493	} else {
494		b->rl -= count;
495		b->rp = (b->rp + count) % b->bufsize;
496	}
497	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
498
499	return 0;
500}
501
502/* count is number of bytes we want added to destination buffer */
503int
504sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)
505{
506	KASSERT(count > 0, ("can't feed 0 bytes"));
507
508	if (sndbuf_getfree(to) < count)
509		return EINVAL;
510
511	count = FEEDER_FEED(feeder, channel, to->tmpbuf, count, from);
512	if (count)
513		sndbuf_acquire(to, to->tmpbuf, count);
514	/* the root feeder has called sndbuf_dispose(from, , bytes fetched) */
515
516	return 0;
517}
518
519/************************************************************/
520
521void
522sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what)
523{
524	printf("%s: [", s);
525	if (what & 0x01)
526		printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize);
527	if (what & 0x02)
528		printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp);
529	if (what & 0x04)
530		printf(" total: %d, prev_total: %d, xrun: %d", b->total, b->prev_total, b->xrun);
531   	if (what & 0x08)
532		printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd);
533	if (what & 0x10)
534		printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags);
535	printf(" ]\n");
536}
537
538/************************************************************/
539u_int32_t
540sndbuf_getflags(struct snd_dbuf *b)
541{
542	return b->flags;
543}
544
545void
546sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on)
547{
548	b->flags &= ~flags;
549	if (on)
550		b->flags |= flags;
551}
552
553