2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/dev/sound/pcm/buffer.c,v 1.25.2.3 2007/04/26 08:21:43 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.11 2008/01/06 16:55:51 swildner Exp $
30 #include <dev/sound/pcm/sound.h>
32 #include "feeder_if.h"
34 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.11 2008/01/06 16:55:51 swildner Exp $");
37 * sndbuf_seltask is a taskqueue callback routine, called from
38 * taskqueue_swi, which runs under the MP lock.
40 * The only purpose is to be able to selwakeup() from a sound
41 * interrupt, which is running without MP lock held and thus
42 * can't call selwakeup() directly.
45 sndbuf_seltask(void *context
, int pending
)
47 struct snd_dbuf
*b
= context
;
49 selwakeup(sndbuf_getsel(b
));
53 sndbuf_create(device_t dev
, char *drv
, char *desc
, struct pcm_channel
*channel
)
57 b
= kmalloc(sizeof(*b
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
58 ksnprintf(b
->name
, SNDBUF_NAMELEN
, "%s:%s", drv
, desc
);
61 TASK_INIT(&b
->seltask
, 0, sndbuf_seltask
, b
);
67 sndbuf_destroy(struct snd_dbuf
*b
)
74 sndbuf_getbufaddr(struct snd_dbuf
*buf
)
76 return (buf
->buf_addr
);
80 sndbuf_setmap(void *arg
, bus_dma_segment_t
*segs
, int nseg
, int error
)
82 struct snd_dbuf
*b
= (struct snd_dbuf
*)arg
;
85 device_printf(b
->dev
, "sndbuf_setmap %lx, %lx; ",
86 (u_long
)segs
[0].ds_addr
, (u_long
)segs
[0].ds_len
);
87 kprintf("%p -> %lx\n", b
->buf
, (u_long
)segs
[0].ds_addr
);
90 b
->buf_addr
= segs
[0].ds_addr
;
96 * Allocate memory for DMA buffer. If the device does not use DMA transfers,
97 * the driver can call kmalloc(9) and sndbuf_setup() itself.
101 sndbuf_alloc(struct snd_dbuf
*b
, bus_dma_tag_t dmatag
, unsigned int size
)
107 b
->bufsize
= b
->maxsize
;
109 b
->flags
|= SNDBUF_F_MANAGED
;
110 if (bus_dmamem_alloc(b
->dmatag
, (void **)&b
->buf
, BUS_DMA_NOWAIT
,
115 if (bus_dmamap_load(b
->dmatag
, b
->dmamap
, b
->buf
, b
->maxsize
,
116 sndbuf_setmap
, b
, 0) != 0 || b
->buf_addr
== 0) {
121 ret
= sndbuf_resize(b
, 2, b
->maxsize
/ 2);
129 sndbuf_setup(struct snd_dbuf
*b
, void *buf
, unsigned int size
)
131 b
->flags
&= ~SNDBUF_F_MANAGED
;
133 b
->flags
|= SNDBUF_F_MANAGED
;
136 b
->bufsize
= b
->maxsize
;
137 return sndbuf_resize(b
, 2, b
->maxsize
/ 2);
141 sndbuf_free(struct snd_dbuf
*b
)
144 kfree(b
->tmpbuf
, M_DEVBUF
);
146 if (b
->flags
& SNDBUF_F_MANAGED
) {
148 bus_dmamap_unload(b
->dmatag
, b
->dmamap
);
150 bus_dmamem_free(b
->dmatag
, b
->buf
, b
->dmamap
);
152 kfree(b
->buf
, M_DEVBUF
);
162 sndbuf_resize(struct snd_dbuf
*b
, unsigned int blkcnt
, unsigned int blksz
)
164 u_int8_t
*tmpbuf
, *f2
;
166 chn_lock(b
->channel
);
173 if (blkcnt
< 2 || blksz
< 16 || (blkcnt
* blksz
> b
->maxsize
)) {
174 chn_unlock(b
->channel
);
177 if (blkcnt
== b
->blkcnt
&& blksz
== b
->blksz
)
180 chn_unlock(b
->channel
);
181 tmpbuf
= kmalloc(blkcnt
* blksz
, M_DEVBUF
, M_NOWAIT
);
184 chn_lock(b
->channel
);
187 b
->bufsize
= blkcnt
* blksz
;
191 chn_unlock(b
->channel
);
196 chn_unlock(b
->channel
);
201 sndbuf_remalloc(struct snd_dbuf
*b
, unsigned int blkcnt
, unsigned int blksz
)
203 u_int8_t
*buf
, *tmpbuf
, *f1
, *f2
;
204 unsigned int bufsize
;
207 if (blkcnt
< 2 || blksz
< 16)
210 bufsize
= blksz
* blkcnt
;
212 chn_unlock(b
->channel
);
213 buf
= kmalloc(bufsize
, M_DEVBUF
, M_WAITOK
);
214 tmpbuf
= kmalloc(bufsize
, M_DEVBUF
, M_WAITOK
);
215 chn_lock(b
->channel
);
219 b
->bufsize
= bufsize
;
220 b
->maxsize
= bufsize
;
228 chn_unlock(b
->channel
);
235 chn_lock(b
->channel
);
240 sndbuf_clear(struct snd_dbuf
*b
, unsigned int length
)
247 if (length
> b
->bufsize
)
250 if (b
->fmt
& AFMT_SIGNED
)
255 i
= sndbuf_getfreeptr(b
);
256 p
= sndbuf_getbuf(b
);
267 sndbuf_fillsilence(struct snd_dbuf
*b
)
272 if (b
->fmt
& AFMT_SIGNED
)
278 p
= sndbuf_getbuf(b
);
279 while (i
< b
->bufsize
)
286 sndbuf_reset(struct snd_dbuf
*b
)
295 if (b
->buf
&& b
->bufsize
> 0)
296 sndbuf_clear(b
, b
->bufsize
);
300 sndbuf_getfmt(struct snd_dbuf
*b
)
306 sndbuf_setfmt(struct snd_dbuf
*b
, u_int32_t fmt
)
310 b
->bps
<<= (b
->fmt
& AFMT_STEREO
)? 1 : 0;
311 if (b
->fmt
& AFMT_16BIT
)
313 else if (b
->fmt
& AFMT_24BIT
)
315 else if (b
->fmt
& AFMT_32BIT
)
321 sndbuf_getspd(struct snd_dbuf
*b
)
327 sndbuf_setspd(struct snd_dbuf
*b
, unsigned int spd
)
333 sndbuf_getalign(struct snd_dbuf
*b
)
335 static int align
[] = {0, 1, 1, 2, 2, 2, 2, 3};
337 return align
[b
->bps
- 1];
341 sndbuf_getblkcnt(struct snd_dbuf
*b
)
347 sndbuf_setblkcnt(struct snd_dbuf
*b
, unsigned int blkcnt
)
353 sndbuf_getblksz(struct snd_dbuf
*b
)
359 sndbuf_setblksz(struct snd_dbuf
*b
, unsigned int blksz
)
365 sndbuf_getbps(struct snd_dbuf
*b
)
371 sndbuf_getbuf(struct snd_dbuf
*b
)
377 sndbuf_getbufofs(struct snd_dbuf
*b
, unsigned int ofs
)
379 KASSERT(ofs
< b
->bufsize
, ("%s: ofs invalid %d", __func__
, ofs
));
385 sndbuf_getsize(struct snd_dbuf
*b
)
391 sndbuf_getmaxsize(struct snd_dbuf
*b
)
397 sndbuf_runsz(struct snd_dbuf
*b
)
403 sndbuf_setrun(struct snd_dbuf
*b
, int go
)
405 b
->dl
= go
? b
->blksz
: 0;
409 sndbuf_getsel(struct snd_dbuf
*b
)
414 /************************************************************/
416 sndbuf_getxrun(struct snd_dbuf
*b
)
418 SNDBUF_LOCKASSERT(b
);
424 sndbuf_setxrun(struct snd_dbuf
*b
, unsigned int cnt
)
426 SNDBUF_LOCKASSERT(b
);
432 sndbuf_gethwptr(struct snd_dbuf
*b
)
434 SNDBUF_LOCKASSERT(b
);
440 sndbuf_sethwptr(struct snd_dbuf
*b
, unsigned int ptr
)
442 SNDBUF_LOCKASSERT(b
);
448 sndbuf_getready(struct snd_dbuf
*b
)
450 SNDBUF_LOCKASSERT(b
);
451 KASSERT((b
->rl
>= 0) && (b
->rl
<= b
->bufsize
), ("%s: b->rl invalid %d", __func__
, b
->rl
));
457 sndbuf_getreadyptr(struct snd_dbuf
*b
)
459 SNDBUF_LOCKASSERT(b
);
460 KASSERT((b
->rp
>= 0) && (b
->rp
<= b
->bufsize
), ("%s: b->rp invalid %d", __func__
, b
->rp
));
466 sndbuf_getfree(struct snd_dbuf
*b
)
468 SNDBUF_LOCKASSERT(b
);
469 KASSERT((b
->rl
>= 0) && (b
->rl
<= b
->bufsize
), ("%s: b->rl invalid %d", __func__
, b
->rl
));
471 return b
->bufsize
- b
->rl
;
475 sndbuf_getfreeptr(struct snd_dbuf
*b
)
477 SNDBUF_LOCKASSERT(b
);
478 KASSERT((b
->rp
>= 0) && (b
->rp
<= b
->bufsize
), ("%s: b->rp invalid %d", __func__
, b
->rp
));
479 KASSERT((b
->rl
>= 0) && (b
->rl
<= b
->bufsize
), ("%s: b->rl invalid %d", __func__
, b
->rl
));
481 return (b
->rp
+ b
->rl
) % b
->bufsize
;
485 sndbuf_getblocks(struct snd_dbuf
*b
)
487 SNDBUF_LOCKASSERT(b
);
489 return b
->total
/ b
->blksz
;
493 sndbuf_getprevblocks(struct snd_dbuf
*b
)
495 SNDBUF_LOCKASSERT(b
);
497 return b
->prev_total
/ b
->blksz
;
501 sndbuf_gettotal(struct snd_dbuf
*b
)
503 SNDBUF_LOCKASSERT(b
);
509 sndbuf_updateprevtotal(struct snd_dbuf
*b
)
511 SNDBUF_LOCKASSERT(b
);
513 b
->prev_total
= b
->total
;
516 /************************************************************/
519 sndbuf_acquire(struct snd_dbuf
*b
, u_int8_t
*from
, unsigned int count
)
523 KASSERT(count
<= sndbuf_getfree(b
), ("%s: count %d > kfree %d", __func__
, count
, sndbuf_getfree(b
)));
524 KASSERT((b
->rl
>= 0) && (b
->rl
<= b
->bufsize
), ("%s: b->rl invalid %d", __func__
, b
->rl
));
528 l
= MIN(count
, sndbuf_getsize(b
) - sndbuf_getfreeptr(b
));
529 bcopy(from
, sndbuf_getbufofs(b
, sndbuf_getfreeptr(b
)), l
);
536 KASSERT((b
->rl
>= 0) && (b
->rl
<= b
->bufsize
), ("%s: b->rl invalid %d, count %d", __func__
, b
->rl
, count
));
542 sndbuf_dispose(struct snd_dbuf
*b
, u_int8_t
*to
, unsigned int count
)
546 KASSERT(count
<= sndbuf_getready(b
), ("%s: count %d > ready %d", __func__
, count
, sndbuf_getready(b
)));
547 KASSERT((b
->rl
>= 0) && (b
->rl
<= b
->bufsize
), ("%s: b->rl invalid %d", __func__
, b
->rl
));
550 l
= MIN(count
, sndbuf_getsize(b
) - sndbuf_getreadyptr(b
));
551 bcopy(sndbuf_getbufofs(b
, sndbuf_getreadyptr(b
)), to
, l
);
554 b
->rp
= (b
->rp
+ l
) % b
->bufsize
;
559 b
->rp
= (b
->rp
+ count
) % b
->bufsize
;
561 KASSERT((b
->rl
>= 0) && (b
->rl
<= b
->bufsize
), ("%s: b->rl invalid %d, count %d", __func__
, b
->rl
, count
));
566 /* count is number of bytes we want added to destination buffer */
568 sndbuf_feed(struct snd_dbuf
*from
, struct snd_dbuf
*to
, struct pcm_channel
*channel
, struct pcm_feeder
*feeder
, unsigned int count
)
570 KASSERT(count
> 0, ("can't feed 0 bytes"));
572 if (sndbuf_getfree(to
) < count
)
575 count
= FEEDER_FEED(feeder
, channel
, to
->tmpbuf
, count
, from
);
577 sndbuf_acquire(to
, to
->tmpbuf
, count
);
578 /* the root feeder has called sndbuf_dispose(from, , bytes fetched) */
583 /************************************************************/
586 sndbuf_dump(struct snd_dbuf
*b
, char *s
, u_int32_t what
)
590 kprintf(" bufsize: %d, maxsize: %d", b
->bufsize
, b
->maxsize
);
592 kprintf(" dl: %d, rp: %d, rl: %d, hp: %d", b
->dl
, b
->rp
, b
->rl
, b
->hp
);
594 kprintf(" total: %d, prev_total: %d, xrun: %d", b
->total
, b
->prev_total
, b
->xrun
);
596 kprintf(" fmt: 0x%x, spd: %d", b
->fmt
, b
->spd
);
598 kprintf(" blksz: %d, blkcnt: %d, flags: 0x%x", b
->blksz
, b
->blkcnt
, b
->flags
);
602 /************************************************************/
604 sndbuf_getflags(struct snd_dbuf
*b
)
610 sndbuf_setflags(struct snd_dbuf
*b
, u_int32_t flags
, int on
)