buffer.c revision 73768
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 * $FreeBSD: head/sys/dev/sound/pcm/buffer.c 73768 2001-03-05 16:45:38Z cg $
27 */
28
29#include <dev/sound/pcm/sound.h>
30
31static void
32sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
33{
34	snd_dbuf *b = (snd_dbuf *)arg;
35
36	if (bootverbose) {
37		printf("pcm: setmap %lx, %lx; ", (unsigned long)segs->ds_addr,
38		       (unsigned long)segs->ds_len);
39		printf("%p -> %lx\n", b->buf, (unsigned long)vtophys(b->buf));
40	}
41}
42
43/*
44 * Allocate memory for DMA buffer. If the device do not perform DMA transfer,
45 * the driver can call malloc(9) by its own.
46 */
47int
48sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size)
49{
50	b->dmatag = dmatag;
51	b->maxsize = size;
52	b->bufsize = b->maxsize;
53	if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, BUS_DMA_NOWAIT, &b->dmamap))
54		return ENOSPC;
55	if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, sndbuf_setmap, b, 0))
56		return ENOSPC;
57	return sndbuf_resize(b, 2, b->maxsize / 2);
58}
59
60int
61sndbuf_setup(snd_dbuf *b, void *buf, int size)
62{
63	bzero(b, sizeof(*b));
64	b->buf = buf;
65	b->maxsize = size;
66	b->bufsize = b->maxsize;
67	return sndbuf_resize(b, 2, b->maxsize / 2);
68}
69
70void
71sndbuf_free(snd_dbuf *b)
72{
73	bus_dmamap_unload(b->dmatag, b->dmamap);
74	bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
75}
76
77int
78sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz)
79{
80	if (blkcnt == 0)
81		blkcnt = b->blkcnt;
82	if (blksz == 0)
83		blksz = b->blksz;
84	if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz > b->maxsize))
85		return EINVAL;
86	b->blkcnt = blkcnt;
87	b->blksz = blksz;
88	b->bufsize = blkcnt * blksz;
89	sndbuf_reset(b);
90	return 0;
91}
92
93void
94sndbuf_clear(snd_dbuf *b, int length)
95{
96	int i;
97	u_char data, *p;
98
99	if (length == 0)
100		return;
101	if (length > b->bufsize)
102		length = b->bufsize;
103
104	if (b->fmt & AFMT_SIGNED)
105		data = 0x00;
106	else
107		data = 0x80;
108
109	i = b->fp;
110	p = b->buf;
111	while (length > 0) {
112		p[i] = data;
113		length--;
114		i++;
115		if (i >= b->bufsize)
116			i = 0;
117	}
118}
119
120void
121sndbuf_reset(snd_dbuf *b)
122{
123	b->rp = b->fp = 0;
124	b->dl = b->rl = 0;
125	b->fl = b->bufsize;
126	b->prev_total = b->total = 0;
127	b->prev_int_count = b->int_count = 0;
128	b->underflow = 0;
129	if (b->buf && b->bufsize > 0)
130		sndbuf_clear(b, b->bufsize);
131}
132
133int
134sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt)
135{
136	b->fmt = fmt;
137	b->bps = 1;
138	b->bps <<= (b->fmt & AFMT_STEREO)? 1 : 0;
139	b->bps <<= (b->fmt & AFMT_16BIT)? 1 : 0;
140	b->bps <<= (b->fmt & AFMT_32BIT)? 2 : 0;
141	return 0;
142}
143
144int
145sndbuf_getbps(snd_dbuf *b)
146{
147	return b->bps;
148}
149
150void *
151sndbuf_getbuf(snd_dbuf *b)
152{
153	return b->buf;
154}
155
156int
157sndbuf_getsize(snd_dbuf *b)
158{
159	return b->bufsize;
160}
161
162int
163sndbuf_runsz(snd_dbuf *b)
164{
165	return b->dl;
166}
167
168int
169sndbuf_isadmasetup(snd_dbuf *b, struct resource *drq)
170{
171	/* should do isa_dma_acquire/isa_dma_release here */
172	if (drq == NULL) {
173		b->flags &= ~SNDBUF_F_ISADMA;
174		b->chan = -1;
175	} else {
176		b->flags &= ~SNDBUF_F_ISADMA;
177		b->chan = rman_get_start(drq);
178	}
179	return 0;
180}
181
182int
183sndbuf_isadmasetdir(snd_dbuf *b, int dir)
184{
185	b->dir = (dir == PCMDIR_PLAY)? ISADMA_WRITE : ISADMA_READ;
186	return 0;
187}
188
189void
190sndbuf_isadma(snd_dbuf *b, int go)
191{
192	KASSERT(b, ("sndbuf_isadma called with b == NULL"));
193	KASSERT(ISA_DMA(b), ("sndbuf_isadma called on non-ISA channel"));
194
195	switch (go) {
196	case PCMTRIG_START:
197		/* isa_dmainit(b->chan, size); */
198		isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan);
199		break;
200
201	case PCMTRIG_STOP:
202	case PCMTRIG_ABORT:
203		isa_dmastop(b->chan);
204		isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan);
205		break;
206	}
207
208	DEB(printf("buf 0x%p ISA DMA %s, channel %d\n",
209		b,
210		(go == PCMTRIG_START)? "started" : "stopped",
211		b->chan));
212}
213
214int
215sndbuf_isadmaptr(snd_dbuf *b)
216{
217	if (ISA_DMA(b)) {
218		int i = b->dl? isa_dmastatus(b->chan) : b->bufsize;
219		if (i < 0)
220			i = 0;
221		return b->bufsize - i;
222    	} else KASSERT(1, ("sndbuf_isadmaptr called on invalid channel"));
223	return -1;
224}
225
226void
227sndbuf_isadmabounce(snd_dbuf *b)
228{
229	if (ISA_DMA(b)) {
230		/* tell isa_dma to bounce data in/out */
231    	} else
232		KASSERT(1, ("chn_isadmabounce called on invalid channel"));
233}
234
235