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