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