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