diff options
Diffstat (limited to 'sys/i386/isa/sound/dmabuf.c')
-rw-r--r-- | sys/i386/isa/sound/dmabuf.c | 1601 |
1 files changed, 0 insertions, 1601 deletions
diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c deleted file mode 100644 index 76494ad..0000000 --- a/sys/i386/isa/sound/dmabuf.c +++ /dev/null @@ -1,1601 +0,0 @@ -/* - * sound/dmabuf.c - * - * The DMA buffer manager for digitized voice applications - * - * Copyright by Hannu Savolainen 1993, 1994, 1995 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include <i386/isa/sound/sound_config.h> - -#include <machine/md_var.h> - -#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS) -#ifdef ALLOW_POLL - -int -DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait); -#endif; - -static void -reorganize_buffers(int dev, struct dma_buffparms * dmap); - -static int *in_sleeper[MAX_AUDIO_DEV] = {NULL}; -static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = {{0}}; -static int *out_sleeper[MAX_AUDIO_DEV] = {NULL}; -static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = {{0}}; - -static int ndmaps = 0; - -#define MAX_DMAP (MAX_AUDIO_DEV*2) - -static struct dma_buffparms dmaps[MAX_DMAP] = {{0}}; -/* - * Primitive way to allocate such a large array. Needs dynamic run-time - * alloction. - */ - -static int space_in_queue(int dev); - -static void dma_reset_output(int dev); -static void dma_reset_input(int dev); - -static void -reorganize_buffers(int dev, struct dma_buffparms * dmap) -{ - /* - * This routine breaks the physical device buffers to logical ones. - */ - - struct audio_operations *dsp_dev = audio_devs[dev]; - u_int sr, nc; - int bsz, sz, n, i; - - if (dmap->fragment_size == 0) { - /* Compute the fragment size using the default algorithm */ - - sr = dsp_dev->ioctl(dev, SOUND_PCM_READ_RATE, 0, 1); - nc = dsp_dev->ioctl(dev, SOUND_PCM_READ_CHANNELS, 0, 1); - sz = dsp_dev->ioctl(dev, SOUND_PCM_READ_BITS, 0, 1); - - if (sz == 8) - dmap->neutral_byte = 254; - else - dmap->neutral_byte = 0x00; - - if (sr < 1 || nc < 1 || sz < 1) { - printf("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", - dev, sr, nc, sz); - sr = DSP_DEFAULT_SPEED; - nc = 1; - sz = 8; - } - sz = sr * nc * sz; - - sz /= 8; /* #bits -> #bytes */ - - /* - * Compute a buffer size for time not exeeding 1 second. - * Usually this algorithm gives a buffer size for 0.5 to 1.0 - * seconds of sound (using the current speed, sample size and - * #channels). - */ - - bsz = dsp_dev->buffsize; - while (bsz > sz) - bsz /= 2; - - if (bsz == dsp_dev->buffsize) - bsz /= 2; /* Needs at least 2 buffers */ - - if (dmap->subdivision == 0) /* Not already set */ - dmap->subdivision = 1; /* Init to default value */ - else - bsz /= dmap->subdivision; - - if (bsz < 16) - bsz = 16; /* Just a sanity check */ - - dmap->fragment_size = bsz; - } else { - /* - * The process has specified the buffer sice with - * SNDCTL_DSP_SETFRAGMENT or the buffer sice computation has - * already been done. - */ - - if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2)) - dmap->fragment_size = (audio_devs[dev]->buffsize / 2); - bsz = dmap->fragment_size; - } - - bsz &= ~0x03; /* Force size which is multiple of 4 bytes */ -#ifdef OS_DMA_ALIGN_CHECK - OS_DMA_ALIGN_CHECK(bsz); -#endif - - n = dsp_dev->buffsize / bsz; - - if (n > MAX_SUB_BUFFERS) - n = MAX_SUB_BUFFERS; - - if (n > dmap->max_fragments) - n = dmap->max_fragments; - dmap->nbufs = n; - dmap->bytes_in_use = n * bsz; - - for (i = 0; i < dmap->nbufs; i++) { - dmap->counts[i] = 0; - } - - if (dmap->raw_buf) - fillw (dmap->neutral_byte, dmap->raw_buf, - dmap->bytes_in_use/2); - - dmap->flags |= DMA_ALLOC_DONE; - -} - -static void -dma_init_buffers(int dev, struct dma_buffparms * dmap) -{ - if (dmap == audio_devs[dev]->dmap_out) { - out_sleep_flag[dev].aborting = 0; - out_sleep_flag[dev].mode = WK_NONE; - } else { - in_sleep_flag[dev].aborting = 0; - in_sleep_flag[dev].mode = WK_NONE; - } - - dmap->flags = DMA_BUSY; /* Other flags off */ - dmap->qlen = dmap->qhead = dmap->qtail = 0; - dmap->nbufs = 1; - dmap->bytes_in_use = audio_devs[dev]->buffsize; - - dmap->dma_mode = DMODE_NONE; - dmap->mapping_flags = 0; - dmap->neutral_byte = 0x00; -} - -static int -open_dmap(int dev, int mode, struct dma_buffparms * dmap, int chan) -{ - if (dmap->flags & DMA_BUSY) - return -(EBUSY); - -#ifdef RUNTIME_DMA_ALLOC - { - int err; - - if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0) - return err; - } -#endif - - if (dmap->raw_buf == NULL) - return -(ENOSPC); /* Memory allocation failed during boot */ - - if (0) { - printf("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -(EBUSY); - } - dmap->open_mode = mode; - dmap->subdivision = dmap->underrun_count = 0; - dmap->fragment_size = 0; - dmap->max_fragments = 65536; /* Just a large value */ - dmap->byte_counter = 0; - isa_dma_acquire(chan); - dmap->dma_chan = chan; - dma_init_buffers(dev, dmap); - - return 0; -} - -static void -close_dmap(int dev, struct dma_buffparms * dmap, int chan) -{ - if (dmap->flags & DMA_BUSY) - dmap->dma_mode = DMODE_NONE; - dmap->flags &= ~DMA_BUSY; - isa_dma_release(dmap->dma_chan); -#ifdef RUNTIME_DMA_ALLOC - sound_free_dmap(dev, dmap); -#endif -} - -int -DMAbuf_open(int dev, int mode) -{ - int retval; - struct dma_buffparms *dmap_in = NULL; - struct dma_buffparms *dmap_out = NULL; - - if (dev >= num_audiodevs) { - printf("PCM device %d not installed.\n", dev); - return -(ENXIO); - } - if (!audio_devs[dev]) { - printf("PCM device %d not initialized\n", dev); - return -(ENXIO); - } - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1; - } - if ((retval = audio_devs[dev]->open(dev, mode)) < 0) - return retval; - - dmap_out = audio_devs[dev]->dmap_out; - dmap_in = audio_devs[dev]->dmap_in; - - if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0) { - audio_devs[dev]->close(dev); - return retval; - } - audio_devs[dev]->enable_bits = mode; - - if (audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) { - if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0) { - audio_devs[dev]->close(dev); - close_dmap(dev, dmap_out, audio_devs[dev]->dmachan1); - return retval; - } - } - audio_devs[dev]->open_mode = mode; - audio_devs[dev]->go = 1; - - in_sleep_flag[dev].aborting = 0; - in_sleep_flag[dev].mode = WK_NONE; - - out_sleep_flag[dev].aborting = 0; - out_sleep_flag[dev].mode = WK_NONE; - - audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_BITS, (ioctl_arg) 8, 1); - audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_CHANNELS, (ioctl_arg) 1, 1); - audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_RATE, (ioctl_arg) DSP_DEFAULT_SPEED, 1); - - return 0; -} - -static void -dma_reset(int dev) -{ - u_long flags; - - flags = splhigh(); - audio_devs[dev]->reset(dev); - splx(flags); - - dma_reset_output(dev); - - if (audio_devs[dev]->flags & DMA_DUPLEX) - dma_reset_input(dev); -} - -static void -dma_reset_output(int dev) -{ - u_long flags; - - flags = splhigh(); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->halt_output) - audio_devs[dev]->reset(dev); - else - audio_devs[dev]->halt_output(dev); - splx(flags); - - dma_init_buffers(dev, audio_devs[dev]->dmap_out); - reorganize_buffers(dev, audio_devs[dev]->dmap_out); -} - -static void -dma_reset_input(int dev) -{ - u_long flags; - - flags = splhigh(); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->halt_input) - audio_devs[dev]->reset(dev); - else - audio_devs[dev]->halt_input(dev); - splx(flags); - - dma_init_buffers(dev, audio_devs[dev]->dmap_in); - reorganize_buffers(dev, audio_devs[dev]->dmap_in); -} - -static int -dma_sync(int dev) -{ - u_long flags; - - if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - return 0; - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) { - flags = splhigh(); - - out_sleep_flag[dev].aborting = 0; -#ifdef ALLOW_BUFFER_MAPPING - if(audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED && - audio_devs[dev]->dmap_out->qlen) { - splx(flags); - - return audio_devs[dev]->dmap_out->qlen; - } - -#endif - while (!PROCESS_ABORTING (out_sleep_flag[dev]) - && audio_devs[dev]->dmap_out->qlen){ - int chn; - - out_sleeper[dev] = &chn; - DO_SLEEP1(chn, out_sleep_flag[dev], 10 * hz); - if (TIMED_OUT (out_sleep_flag[dev]) ) { - - splx(flags); - - return audio_devs[dev]->dmap_out->qlen; - - } - } - - - splx(flags); - - /* - * Some devices such as GUS have huge amount of on board RAM - * for the audio data. We have to wait until the device has - * finished playing. - */ - - flags = splhigh(); - if (audio_devs[dev]->local_qlen) { /* Device has hidden buffers */ - while (!(PROCESS_ABORTING (out_sleep_flag[dev])) - && audio_devs[dev]->local_qlen(dev)) { - int chn; - out_sleeper[dev] = &chn; - DO_SLEEP(chn, out_sleep_flag[dev], 10 * hz); - - } - } - splx(flags); - } - return audio_devs[dev]->dmap_out->qlen; -} - -int -DMAbuf_release(int dev, int mode) -{ - u_long flags; - - if (!((out_sleep_flag[dev].aborting)) - && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) { - dma_sync(dev); - } - flags = splhigh(); - - audio_devs[dev]->close(dev); - - close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - - if (audio_devs[dev]->flags & DMA_DUPLEX) - close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); - audio_devs[dev]->open_mode = 0; - - splx(flags); - - return 0; -} - -static int -activate_recording(int dev, struct dma_buffparms * dmap) -{ - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) - return 0; - - if (dmap->flags & DMA_RESTART) { - dma_reset_input(dev); - dmap->flags &= ~DMA_RESTART; - } - if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ - dma_sync(dev); - dma_reset(dev); - dmap->dma_mode = DMODE_NONE; - } - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap); - - if (!dmap->dma_mode) { - int err; - - if ((err = audio_devs[dev]->prepare_for_input(dev, - dmap->fragment_size, dmap->nbufs)) < 0) { - return err; - } - dmap->dma_mode = DMODE_INPUT; - } - if (!(dmap->flags & DMA_ACTIVE)) { - audio_devs[dev]->start_input(dev, - dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0, - !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); - dmap->flags |= DMA_ACTIVE | DMA_STARTED; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - return 0; -} - -int -DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) -{ - u_long flags; - int err = EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - flags = splhigh(); -#ifdef ALLOW_BUFFER_MAPPING - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { - printf("Sound: Can't read from mmapped device (1)\n"); - return -(EINVAL); - } else -#endif - if (!dmap->qlen) { - int timeout; - - if ((err = activate_recording(dev, dmap)) < 0) { - splx(flags); - return err; - } - /* Wait for the next block */ - - if (dontblock) { - splx(flags); - return -(EAGAIN); - } - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) & - audio_devs[dev]->go) { - splx(flags); - return -(EAGAIN); - } - if (!audio_devs[dev]->go) - timeout = 0; - else - timeout = 2 * hz; - - { - int chn; - - in_sleeper[dev] = &chn; - DO_SLEEP(chn, in_sleep_flag[dev], timeout); - - }; - /* XXX note -- nobody seems to set the mode to WK_TIMEOUT - lr */ - if ((in_sleep_flag[dev].mode & WK_TIMEOUT)) { - /* XXX hey, we are in splhigh here ? lr 970705 */ - printf("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - err = EIO; - audio_devs[dev]->reset(dev); - in_sleep_flag[dev].aborting = 1; - } else - err = EINTR; - } - splx(flags); - - if (!dmap->qlen) - return -(err); - - *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; - *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - - return dmap->qhead; -} - -int -DMAbuf_rmchars(int dev, int buff_no, int c) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - int p = dmap->counts[dmap->qhead] + c; - -#ifdef ALLOW_BUFFER_MAPPING - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { - printf("Sound: Can't read from mmapped device (2)\n"); - return -(EINVAL); - } else -#endif - if (p >= dmap->fragment_size) { /* This buffer is completely empty */ - dmap->counts[dmap->qhead] = 0; - if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) - printf("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n", - dev, dmap->qlen, dmap->nbufs); - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - } else - dmap->counts[dmap->qhead] = p; - - return 0; -} - -static int -dma_subdivide(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact) -{ - if (fact == 0) { - fact = dmap->subdivision; - if (fact == 0) - fact = 1; - return *(int *) arg = fact; - } - if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */ - return -(EINVAL); - - if (fact > MAX_REALTIME_FACTOR) - return -(EINVAL); - - if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) - return -(EINVAL); - - dmap->subdivision = fact; - return *(int *) arg = fact; -} - -static int -dma_set_fragment(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact) -{ - int bytes, count; - - if (fact == 0) - return -(EIO); - - if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */ - return -(EINVAL); - - bytes = fact & 0xffff; - count = (fact >> 16) & 0xffff; - - if (count == 0) - count = MAX_SUB_BUFFERS; - -#if amancio - if (bytes < 4 || bytes > 17) /* <16 || > 128k */ - return -(EINVAL); -#endif - - if (count < 2) - return -(EINVAL); - -#ifdef OS_DMA_MINBITS - if (bytes < OS_DMA_MINBITS) - bytes = OS_DMA_MINBITS; -#endif - - dmap->fragment_size = (1 << bytes); - - dmap->max_fragments = count; - - if (dmap->fragment_size > audio_devs[dev]->buffsize) - dmap->fragment_size = audio_devs[dev]->buffsize; - - if (dmap->fragment_size == audio_devs[dev]->buffsize && - audio_devs[dev]->flags & DMA_AUTOMODE) - dmap->fragment_size /= 2; /* Needs at least 2 buffers */ - - dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ - return *(int *) arg = bytes | (count << 16); -} - -static int -get_buffer_pointer(int dev, int chan, struct dma_buffparms * dmap) -{ - int pos; - u_long flags; - - flags = splhigh(); - - if (!(dmap->flags & DMA_ACTIVE)) - pos = 0; - else - { - pos = isa_dmastatus(chan); - } - - splx(flags); - - pos = dmap->bytes_in_use - pos ; - if (audio_devs[dev]->flags & DMA_AUTOMODE) - return pos; - else - { - pos = dmap->fragment_size - pos; - if (pos < 0) - return 0; - return pos; - } - - -} - -int -DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local) -{ - struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; - struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; - - switch (cmd) { - - - case SNDCTL_DSP_RESET: - dma_reset(dev); - return 0; - break; - - case SNDCTL_DSP_SYNC: - dma_sync(dev); - dma_reset(dev); - return 0; - break; - - case SNDCTL_DSP_GETBLKSIZE: - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap_out); - - return *(int *) arg = dmap_out->fragment_size; - break; - - case SNDCTL_DSP_SETBLKSIZE: - { - int size = (*(int *) arg); - - if (!(dmap_out->flags & DMA_ALLOC_DONE) && size) { - if ((size >> 16) > 0 ) - dmap_out->fragment_size = size >> 16; - else { - dmap_out->fragment_size = size; - } - dmap_out->max_fragments = 8888; - - size &= 0xffff; - - if (audio_devs[dev]->flags & DMA_DUPLEX) { - dmap_in->fragment_size = size; - dmap_in->max_fragments = 8888; - } - return 0; - - } else - return -(EINVAL); /* Too late to change */ - - } - break; - - case SNDCTL_DSP_SUBDIVIDE: - { - int fact = (*(int *) arg); - int ret; - - ret = dma_subdivide(dev, dmap_out, arg, fact); - if (ret < 0) - return ret; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - ret = dma_subdivide(dev, dmap_in, arg, fact); - - return ret; - } - break; - - case SNDCTL_DSP_SETFRAGMENT: - { - int fact = (*(int *) arg); - int ret; - - ret = dma_set_fragment(dev, dmap_out, arg, fact); - if (ret < 0) - return ret; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - ret = dma_set_fragment(dev, dmap_in, arg, fact); - - return ret; - } - break; - - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_GETOSPACE: - if (!local) - return -(EINVAL); - else { - struct dma_buffparms *dmap = dmap_out; - - audio_buf_info *info = (audio_buf_info *) arg; - - if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) - dmap = dmap_in; - -#ifdef ALLOW_BUFFER_MAPPING - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return -(EINVAL); -#endif - - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap); - - info->fragstotal = dmap->nbufs; - - if (cmd == SNDCTL_DSP_GETISPACE) - info->fragments = dmap->qlen; - else { - if (!space_in_queue(dev)) - info->fragments = 0; - else { - info->fragments = dmap->nbufs - dmap->qlen; - if (audio_devs[dev]->local_qlen) { - int tmp = audio_devs[dev]->local_qlen(dev); - - if (tmp & info->fragments) - tmp--; /* This buffer has been counted twice */ - info->fragments -= tmp; - } - } - } - - if (info->fragments < 0) - info->fragments = 0; - else if (info->fragments > dmap->nbufs) - info->fragments = dmap->nbufs; - - info->fragsize = dmap->fragment_size; - info->bytes = info->fragments * dmap->fragment_size; - - if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) - info->bytes -= dmap->counts[dmap->qhead]; - } - return 0; - - case SNDCTL_DSP_SETTRIGGER: - { - u_long flags; - - int bits = (*(int *) arg) & audio_devs[dev]->open_mode; - int changed; - - if (audio_devs[dev]->trigger == NULL) - return -(EINVAL); - - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) { - printf("Sound: Device doesn't have full duplex capability\n"); - return -(EINVAL); - } - flags = splhigh(); - changed = audio_devs[dev]->enable_bits ^ bits; - - if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) { - if (!(dmap_in->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap_in); - activate_recording(dev, dmap_in); - } -#ifdef ALLOW_BUFFER_MAPPING - if ((changed & bits) & PCM_ENABLE_OUTPUT && - dmap_out->mapping_flags & DMA_MAP_MAPPED && - audio_devs[dev]->go) { - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap_out); - - audio_devs[dev]->prepare_for_output (dev, - dmap_out->fragment_size, dmap_out->nbufs); - - dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; - DMAbuf_start_output(dev, 0, dmap_out->fragment_size); - dmap_out->dma_mode = DMODE_OUTPUT; - } -#endif - - audio_devs[dev]->enable_bits = bits; - if (changed && audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, bits * audio_devs[dev]->go); - splx(flags); - } - case SNDCTL_DSP_GETTRIGGER: - return *(int *) arg = audio_devs[dev]->enable_bits; - break; - - case SNDCTL_DSP_SETSYNCRO: - - if (!audio_devs[dev]->trigger) - return -(EINVAL); - - audio_devs[dev]->trigger(dev, 0); - audio_devs[dev]->go = 0; - return 0; - break; - - case SNDCTL_DSP_GETIPTR: - { - count_info info; - u_long flags; - - flags = splhigh(); - info.bytes = audio_devs[dev]->dmap_in->byte_counter; - info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in); - info.blocks = audio_devs[dev]->dmap_in->qlen; - info.bytes += info.ptr; - - bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info)); - -#ifdef ALLOW_BUFFER_MAPPING - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - audio_devs[dev]->dmap_in->qlen = 0; /* Ack interrupts */ -#endif - splx(flags); - return 0; - } - break; - - case SNDCTL_DSP_GETOPTR: - { - count_info info; - u_long flags; - - flags = splhigh(); - info.bytes = audio_devs[dev]->dmap_out->byte_counter; - info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out); - info.blocks = audio_devs[dev]->dmap_out->qlen; - info.bytes += info.ptr; - bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info)); - -#ifdef ALLOW_BUFFER_MAPPING - if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) - audio_devs[dev]->dmap_out->qlen = 0; /* Ack interrupts */ -#endif - splx(flags); - return 0; - } - break; - - default: - return audio_devs[dev]->ioctl(dev, cmd, arg, local); - } -} - -/* - * DMAbuf_start_devices() is called by the /dev/music driver to start one or - * more audio devices at desired moment. - */ - -void -DMAbuf_start_devices(u_int devmask) -{ - int dev; - - for (dev = 0; dev < num_audiodevs; dev++) - if (devmask & (1 << dev)) - if (audio_devs[dev]->open_mode != 0) - if (!audio_devs[dev]->go) { - /* OK to start the device */ - audio_devs[dev]->go = 1; - - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } -} - -static int -space_in_queue(int dev) -{ - int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if (dmap->qlen >= dmap->nbufs) /* No space at all */ - return 0; - - /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ - - max = dmap->max_fragments; - len = dmap->qlen; - - if (audio_devs[dev]->local_qlen) { - tmp = audio_devs[dev]->local_qlen(dev); - if (tmp & len) - tmp--; /* This buffer has been counted twice */ - len += tmp; - } - - if (len >= max) - return 0; - return 1; -} - -int -DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) -{ - u_long flags; - int abort, err = EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - -#ifdef ALLOW_BUFFER_MAPPING - if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) { - printf("Sound: Can't write to mmapped device (3)\n"); - return -(EINVAL); - } -#endif - - if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ - dma_reset(dev); - dmap->dma_mode = DMODE_NONE; - } else if (dmap->flags & DMA_RESTART) { /* Restart buffering */ - dma_sync(dev); - dma_reset_output(dev); - } - dmap->flags &= ~DMA_RESTART; - - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap); - - if (!dmap->dma_mode) { - int err; - - dmap->dma_mode = DMODE_OUTPUT; - if ((err = audio_devs[dev]->prepare_for_output(dev, - dmap->fragment_size, dmap->nbufs)) < 0) - return err; - } - flags = splhigh(); - - abort = 0; - while (!space_in_queue(dev) && !abort) { - int timeout; - - if (dontblock) { - splx(flags); - return -(EAGAIN); - } - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) && - audio_devs[dev]->go) { - splx(flags); - return -(EAGAIN); - } - /* - * Wait for free space - */ - if (!audio_devs[dev]->go) - timeout = 0; - else - timeout = 2 * hz; - - { - int chn; - - out_sleep_flag[dev].mode = WK_SLEEP; - out_sleeper[dev] = &chn; - DO_SLEEP2(chn, out_sleep_flag[dev], timeout); - - if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) { - printf("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - err = EIO; - abort = 1; - out_sleep_flag[dev].aborting = 1; - audio_devs[dev]->reset(dev); - } else if ((out_sleep_flag[dev].aborting) || - CURSIG(curproc)) { - err = EINTR; - abort = 1; - } - } - } - splx(flags); - - if (!space_in_queue(dev)) { - return -(err); /* Caught a signal ? */ - } - *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; - *size = dmap->fragment_size; - dmap->counts[dmap->qtail] = 0; - return dmap->qtail; -} - -int -DMAbuf_start_output(int dev, int buff_no, int l) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - /* - * Bypass buffering if using mmaped access - */ - -#ifdef ALLOW_BUFFER_MAPPING - if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) { - l = dmap->fragment_size; - dmap->counts[dmap->qtail] = l; - dmap->flags &= ~DMA_RESTART; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } else -#else - if (dmap != NULL) -#endif - { - - if (buff_no != dmap->qtail) - printf("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail); - - dmap->qlen++; - if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) - printf("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n", - dev, dmap->qlen, dmap->nbufs); - - dmap->counts[dmap->qtail] = l; - - if ((l != dmap->fragment_size) && - ((audio_devs[dev]->flags & DMA_AUTOMODE) && - audio_devs[dev]->flags & NEEDS_RESTART)) - dmap->flags |= DMA_RESTART; - else - dmap->flags &= ~DMA_RESTART; - - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - if (!(dmap->flags & DMA_ACTIVE)) { - dmap->flags |= DMA_ACTIVE; - audio_devs[dev]->output_block(dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 0, - !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); - dmap->flags |= DMA_STARTED; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - return 0; -} - -int -DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode) -{ - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == 1) { - chan = audio_devs[dev]->dmachan1; - dmap = audio_devs[dev]->dmap_out; - - } else { - chan = audio_devs[dev]->dmachan2; - dmap = audio_devs[dev]->dmap_in; - } - - /* - * The count must be one less than the actual size. This is handled - * by set_dma_addr() - */ - -#ifndef PSEUDO_DMA_AUTOINIT - if (audio_devs[dev]->flags & DMA_AUTOMODE) { - /* Auto restart mode. Transfer the whole buffer */ - isa_dmastart(B_RAW | ((dma_mode == 0) ? B_READ : B_WRITE), - (caddr_t) (void *) (uintptr_t) dmap->raw_buf_phys, - dmap->bytes_in_use, chan); - - } else -#endif - { - isa_dmastart((dma_mode == 0) ? B_READ : B_WRITE, - (caddr_t) (void *) (uintptr_t) physaddr, count, chan); - } - return count; -} - -void -DMAbuf_init() -{ - int dev; - - /* - * NOTE! This routine could be called several times. - * XXX is it ok to make it run only the first time ? -- lr970710 - */ - - for (dev = 0; dev < num_audiodevs; dev++) - if (audio_devs[dev]->dmap_out == NULL) { - audio_devs[dev]->dmap_out = - audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; - } -} - -void -DMAbuf_outputintr(int dev, int event_type) -{ - /* - * Event types: 0 = DMA transfer done. Device still has more data in - * the local buffer. 1 = DMA transfer done. Device doesn't have local - * buffer or it's empty now. 2 = No DMA transfer but the device has - * now more space in its local buffer. - */ - - u_long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - dmap->byte_counter += dmap->counts[dmap->qhead]; -#ifdef OS_DMA_INTR - sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); -#endif -#ifdef ALLOW_BUFFER_MAPPING - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - /* mmapped access */ - - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->qlen++; /* Yes increment it (don't decrement) */ - dmap->flags &= ~DMA_ACTIVE; - dmap->counts[dmap->qhead] = dmap->fragment_size; - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { - audio_devs[dev]->output_block(dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1, - !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } -#ifdef PSEUDO_DMA_AUTOINIT - else { - DMAbuf_start_dma(dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - } -#endif - dmap->flags |= DMA_ACTIVE; - - } else -#endif - if (event_type != 2) { - if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) { - printf("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n", - dev, dmap->qlen, dmap->nbufs); - return; - } - isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan1); - - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->flags &= ~DMA_ACTIVE; - if (dmap->qlen) { - /* if (!(audio_devs[dev]->flags & NEEDS_RESTART)) */ - { - audio_devs[dev]->output_block(dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1, - !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - -#ifdef PSEUDO_DMA_AUTOINIT - /* else */ - { - DMAbuf_start_dma(dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - } -#endif - dmap->flags |= DMA_ACTIVE; - } else if (event_type == 1) { - dmap->underrun_count++; - if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_output) - audio_devs[dev]->halt_output(dev); - else - audio_devs[dev]->halt_xfer(dev); - - if ((audio_devs[dev]->flags & DMA_AUTOMODE) && - audio_devs[dev]->flags & NEEDS_RESTART) - dmap->flags |= DMA_RESTART; - else - dmap->flags &= ~DMA_RESTART; - } - } /* event_type != 2 */ - flags = splhigh(); - - if ((out_sleep_flag[dev].mode & WK_SLEEP)) { - out_sleep_flag[dev].mode = WK_WAKEUP; - wakeup(out_sleeper[dev]); - } - - if(selinfo[dev].si_pid) { - selwakeup(&selinfo[dev]); - } - - splx(flags); -} - -void -DMAbuf_inputintr(int dev) -{ - u_long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - dmap->byte_counter += dmap->fragment_size; - -#ifdef OS_DMA_INTR - sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); -#endif - isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan2); - -#ifdef ALLOW_BUFFER_MAPPING - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - - if (!(audio_devs[dev]->flags & NEEDS_RESTART)) { - audio_devs[dev]->start_input(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1, - !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } -#ifdef PSEUDO_DMA_AUTOINIT - else { - DMAbuf_start_dma(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->counts[dmap->qtail], 0); - } -#endif - - dmap->flags |= DMA_ACTIVE; - } else -#endif - if (dmap->qlen == (dmap->nbufs - 1)) { - /* printf ("Sound: Recording overrun\n"); */ - dmap->underrun_count++; - if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_input) - audio_devs[dev]->halt_input(dev); - else - audio_devs[dev]->halt_xfer(dev); - - dmap->flags &= ~DMA_ACTIVE; - if (audio_devs[dev]->flags & DMA_AUTOMODE) - dmap->flags |= DMA_RESTART; - else - dmap->flags &= ~DMA_RESTART; - } else { - dmap->qlen++; - if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) - printf("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n", - dev, dmap->qlen, dmap->nbufs); - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - - /* if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) */ - { - audio_devs[dev]->start_input(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1, - !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } -#ifdef PSEUDO_DMA_AUTOINIT - /* else */ - { - DMAbuf_start_dma(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->counts[dmap->qtail], 0); - } -#endif - - dmap->flags |= DMA_ACTIVE; - } - - flags = splhigh(); - if ((in_sleep_flag[dev].mode & WK_SLEEP)) { - in_sleep_flag[dev].mode = WK_WAKEUP; - wakeup(in_sleeper[dev]); - } - if (selinfo[dev].si_pid) - selwakeup(&selinfo[dev]); - splx(flags); -} - -int -DMAbuf_open_dma(int dev) -{ - int err; - u_long flags; - flags = splhigh(); - - if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, - audio_devs[dev]->dmachan1)) < 0) { - splx(flags); - return -(EBUSY); - } - dma_init_buffers(dev, audio_devs[dev]->dmap_out); - /* audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; */ - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize; - /* reorganize_buffers (dev, audio_devs[dev]->dmap_out); */ - - if (audio_devs[dev]->flags & DMA_DUPLEX) { - if ((err = open_dmap(dev, OPEN_READWRITE, - audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0) { - printf("Unable to grab DMA%d for the audio driver\n", - audio_devs[dev]->dmachan2); - close_dmap(dev, audio_devs[dev]->dmap_out, - audio_devs[dev]->dmachan1); - splx(flags); - return -(EBUSY); - } - dma_init_buffers(dev, audio_devs[dev]->dmap_in); - /* audio_devs[dev]->dmap_in->flags |= DMA_ALLOC_DONE; */ - audio_devs[dev]->dmap_in->fragment_size = audio_devs[dev]->buffsize; - /* reorganize_buffers (dev, audio_devs[dev]->dmap_in); */ - } else { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1; - } - - splx(flags); - return 0; -} - -void -DMAbuf_close_dma(int dev) -{ - DMAbuf_reset_dma(dev); - close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - - if (audio_devs[dev]->flags & DMA_DUPLEX) - close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); - -} - -void -DMAbuf_reset_dma(int dev) -{ -} - -#ifdef ALLOW_POLL - -int -DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait) -{ - struct dma_buffparms *dmap; - u_long flags; - int revents = 0; - - dmap = audio_devs[dev]->dmap_in; - - if (events & (POLLIN | POLLRDNORM)) { - if (dmap->dma_mode != DMODE_INPUT) { - if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen && - audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && - audio_devs[dev]->go) { - u_long flags; - - flags = splhigh(); - - activate_recording(dev, dmap); - splx(flags); - - } - return 0; - } - if (!dmap->qlen) { - flags = splhigh(); - - selrecord(wait, &selinfo[dev]); - - splx(flags); - - return 0; - } else - revents |= events & (POLLIN | POLLRDNORM); - - } - - if (events & (POLLOUT | POLLWRNORM)) { - - dmap = audio_devs[dev]->dmap_out; - if (dmap->dma_mode == DMODE_INPUT) - return 0; - - if (dmap->dma_mode == DMODE_NONE) - return ( events & (POLLOUT | POLLWRNORM)); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - - if(dmap->qlen) - return 1; - flags = splhigh(); - selrecord(wait, &selinfo[dev]); - - splx(flags); - - return 0; - - } - if (!space_in_queue(dev)) { - flags = splhigh(); - selrecord(wait, &selinfo[dev]); - splx(flags); - - } else - revents |= events & (POLLOUT | POLLWRNORM); - - - } - - return (revents); -} - - -#ifdef amancio -int -DMAbuf_select(int dev, struct fileinfo * file, int sel_type, select_table * wait) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - struct dma_buffparms *dmapin = audio_devs[dev]->dmap_in; - u_long flags; - - switch (sel_type) { - case FREAD: - if (dmapin->dma_mode != DMODE_INPUT) - return 0; - - if (!dmap->qlen) { - flags = splhigh(); - selrecord(wait, &selinfo[dev]); - splx(flags); - - return 0; - } - return 1; - break; - - case FWRITE: - if (dmap->dma_mode == DMODE_INPUT) - return 0; - - if (dmap->dma_mode == DMODE_NONE) - return 1; - - if (!space_in_queue(dev)) { - flags = splhigh(); - - selrecord(wait, &selinfo[dev]); - splx(flags); - - return 0; - } - return 1; - break; - - } - - return 0; -} - -#endif /* ALLOW_POLL */ -#endif - -#else /* CONFIG_AUDIO */ -/* - * Stub versions if audio services not included - */ - -int -DMAbuf_open(int dev, int mode) -{ - return -(ENXIO); -} - -int -DMAbuf_release(int dev, int mode) -{ - return 0; -} - -int -DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) -{ - return -(EIO); -} - -int -DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) -{ - return -(EIO); -} - -int -DMAbuf_rmchars(int dev, int buff_no, int c) -{ - return -(EIO); -} - -int -DMAbuf_start_output(int dev, int buff_no, int l) -{ - return -(EIO); -} - -int -DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local) -{ - return -(EIO); -} - -void -DMAbuf_init() -{ -} - -int -DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode) -{ - return -(EIO); -} - -int -DMAbuf_open_dma(int dev) -{ - return -(ENXIO); -} - -void -DMAbuf_close_dma(int dev) -{ - return; -} - -void -DMAbuf_reset_dma(int dev) -{ - return; -} - -void -DMAbuf_inputintr(int dev) -{ - return; -} - -void -DMAbuf_outputintr(int dev, int underrun_flag) -{ - return; -} -#endif /* CONFIG_AUDIO */ |