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