From beb116954b9b7f3bb56412b2494b562f02b864b1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 7 Jan 1997 02:33:00 +0000 Subject: Import of Linux/MIPS 2.1.14 --- drivers/sound/dmabuf.c | 1972 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 1519 insertions(+), 453 deletions(-) (limited to 'drivers/sound/dmabuf.c') diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index a7c396f2f..9cc363b60 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -2,269 +2,575 @@ * sound/dmabuf.c * * The DMA buffer manager for digitized voice applications + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Copyright by Hannu Savolainen 1993, 1994 - * - * 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. - * + * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. */ +#include + #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD +#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW) -#include "sound_calls.h" +static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = +{NULL}; +static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = +{ + {0}}; +static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = +{NULL}; +static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = +{ + {0}}; + +#define NEUTRAL8 0x80 +#define NEUTRAL16 0x00 -#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS) +static int ndmaps = 0; + +#define MAX_DMAP (MAX_AUDIO_DEV*2) + +static struct dma_buffparms dmaps[MAX_DMAP] = +{ + {0}}; -DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]); +static int space_in_queue (int dev); -static struct dma_buffparms dmaps[MAX_AUDIO_DEV] = -{{0}}; /* - * Primitive way to allocate - * such a large array. - * Needs dynamic run-time allocation. - */ +static void dma_reset_output (int dev); +static void dma_reset_input (int dev); +static int dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact); static void -reorganize_buffers (int dev) +reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) { /* * This routine breaks the physical device buffers to logical ones. */ - struct dma_buffparms *dmap = audio_devs[dev]->dmap; struct audio_operations *dsp_dev = audio_devs[dev]; - unsigned i, p, n; + unsigned i, n; unsigned sr, nc, sz, bsz; - if (dmap->fragment_size == 0) - { /* Compute the fragment size using the default algorithm */ + sr = dsp_dev->d->set_speed (dev, 0); + nc = dsp_dev->d->set_channels (dev, 0); + sz = dsp_dev->d->set_bits (dev, 0); - 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 = NEUTRAL8; + else + dmap->neutral_byte = NEUTRAL16; - if (sr < 1 || nc < 1 || sz < 1) - { - printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", - dev, sr, nc, sz); - sr = DSP_DEFAULT_SPEED; - nc = 1; - sz = 8; - } + if (sr < 1 || nc < 1 || sz < 1) + { + printk ("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 /= 8; /* #bits -> #bytes */ + sz = sr * nc * sz; - sz = sr * nc * sz; + sz /= 8; /* #bits -> #bytes */ + dmap->data_rate = sz; + + if (dmap->fragment_size == 0) + { /* Compute the fragment size using the default algorithm */ /* - * Compute a buffer size for time not exceeding 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). - */ + * Compute a buffer size for time not exceeding 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 (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize) + if (bsz == dsp_dev->buffsize) bsz /= 2; /* Needs at least 2 buffers */ +/* + * Split the computed fragment to smaller parts. After 3.5a9 + * the default subdivision is 4 which should give better + * results when recording. + */ + if (dmap->subdivision == 0) /* Not already set */ - dmap->subdivision = 1; /* Init to default value */ + { + dmap->subdivision = 4; /* Init to the default value */ - bsz /= dmap->subdivision; + if ((bsz / dmap->subdivision) > 4096) + dmap->subdivision *= 2; + if ((bsz / dmap->subdivision) < 4096) + dmap->subdivision = 1; + } - if (bsz < 64) - bsz = 4096; /* Just a sanity check */ + bsz /= dmap->subdivision; - while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS) - bsz *= 2; + if (bsz < 16) + bsz = 16; /* Just a sanity check */ dmap->fragment_size = bsz; } else { /* - * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or - * the buffer size computation has already been done. - */ - if (dmap->fragment_size > audio_devs[dev]->buffsize) - dmap->fragment_size = audio_devs[dev]->buffsize; + * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or + * the buffer size 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; } - /* - * Now computing addresses for the logical buffers - */ + bsz &= ~0x03; /* Force size which is multiple of 4 bytes */ +#ifdef OS_DMA_ALIGN_CHECK + OS_DMA_ALIGN_CHECK (bsz); +#endif - n = 0; - for (i = 0; i < dmap->raw_count && - n < dmap->max_fragments && - n < MAX_SUB_BUFFERS; i++) - { - p = 0; + n = dsp_dev->buffsize / bsz; + if (n > MAX_SUB_BUFFERS) + n = MAX_SUB_BUFFERS; + if (n > dmap->max_fragments) + n = dmap->max_fragments; - while ((p + bsz) <= dsp_dev->buffsize && - n < dmap->max_fragments && - n < MAX_SUB_BUFFERS) - { - dmap->buf[n] = dmap->raw_buf[i] + p; - dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p; - p += bsz; - n++; - } + if (n < 2) + { + n = 2; + bsz /= 2; } dmap->nbufs = n; dmap->bytes_in_use = n * bsz; + dmap->fragment_size = bsz; + + if (dmap->raw_buf) + memset (dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); for (i = 0; i < dmap->nbufs; i++) { dmap->counts[i] = 0; } - dmap->flags |= DMA_ALLOC_DONE; + dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; } static void -dma_init_buffers (int dev) +dma_init_buffers (int dev, struct dma_buffparms *dmap) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev]; - - RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); + if (dmap == audio_devs[dev]->dmap_out) + { + out_sleep_flag[dev].opts = WK_NONE; + } + else + { + in_sleep_flag[dev].opts = 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->qlen = dmap->qtail = dmap->qhead = 0; dmap->dma_mode = DMODE_NONE; + dmap->mapping_flags = 0; + dmap->neutral_byte = NEUTRAL8; + dmap->data_rate = 8000; + dmap->cfrag = -1; + dmap->closing = 0; +} + +static int +open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) +{ + if (dmap->flags & DMA_BUSY) + return -EBUSY; + + { + int err; + + if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0) + return err; + } + + if (dmap->raw_buf == NULL) + { + printk ("Sound: DMA buffers not available\n"); + return -ENOSPC; /* Memory allocation failed during boot */ + } + + if (sound_open_dma (chan, audio_devs[dev]->name)) + { + printk ("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; + + + dma_init_buffers (dev, dmap); + + return 0; +} + +static void +close_dmap (int dev, struct dma_buffparms *dmap, int chan) +{ + sound_close_dma (chan); + + if (dmap->flags & DMA_BUSY) + dmap->dma_mode = DMODE_NONE; + dmap->flags &= ~DMA_BUSY; + + disable_dma (chan); + sound_free_dmap (dev, dmap, chan); +} + +static unsigned int +default_set_bits (int dev, unsigned int bits) +{ + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1); +} + +static int +default_set_speed (int dev, int speed) +{ + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) speed, 1); +} + +static short +default_set_channels (int dev, short channels) +{ + int c = channels; + + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) c, 1); +} + +static void +check_driver (struct audio_driver *d) +{ + if (d->set_speed == NULL) + d->set_speed = default_set_speed; + if (d->set_bits == NULL) + d->set_bits = default_set_bits; + if (d->set_channels == NULL) + d->set_channels = default_set_channels; } int DMAbuf_open (int dev, int mode) { int retval; - struct dma_buffparms *dmap = NULL; + struct dma_buffparms *dmap_in = NULL; + struct dma_buffparms *dmap_out = NULL; if (dev >= num_audiodevs) { - printk ("PCM device %d not installed.\n", dev); - return RET_ERROR (ENXIO); + /* printk ("PCM device %d not installed.\n", dev); */ + return -ENXIO; } if (!audio_devs[dev]) { - printk ("PCM device %d not initialized\n", dev); - return RET_ERROR (ENXIO); + /* printk ("PCM device %d not initialized\n", dev); */ + return -ENXIO; } - dmap = audio_devs[dev]->dmap = &dmaps[dev]; + 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 (dmap->flags & DMA_BUSY) - return RET_ERROR (EBUSY); + if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0) + return retval; -#ifdef USE_RUNTIME_DMAMEM - dmap->raw_buf[0] = NULL; - sound_dma_malloc (dev); -#endif + check_driver (audio_devs[dev]->d); - if (dmap->raw_buf[0] == NULL) - return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */ + dmap_out = audio_devs[dev]->dmap_out; + dmap_in = audio_devs[dev]->dmap_in; - if ((retval = audio_devs[dev]->open (dev, mode)) < 0) - return retval; + if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0) + { + audio_devs[dev]->d->close (dev); + return retval; + } - dmap->open_mode = mode; - dmap->subdivision = dmap->underrun_count = 0; - dmap->fragment_size = 0; - dmap->max_fragments = 65536; /* Just a large value */ + audio_devs[dev]->enable_bits = mode; + if (mode & OPEN_READ && + 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]->d->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].opts = WK_NONE; + out_sleep_flag[dev].opts = WK_NONE; - dma_init_buffers (dev); - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1); - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1); - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1); + audio_devs[dev]->d->set_bits (dev, 8); + audio_devs[dev]->d->set_channels (dev, 1); + audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED); return 0; } +void +DMAbuf_reset (int dev) +{ + unsigned long flags; + + save_flags (flags); + cli (); + audio_devs[dev]->d->reset (dev); + restore_flags (flags); + + dma_reset_output (dev); + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + dma_reset_input (dev); +} + static void -dma_reset (int dev) +dma_reset_output (int dev) { - int retval; unsigned long flags; + int tmout; + + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + if (dmap->dma_mode != DMODE_OUTPUT) + return; + + if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ + return; + +/* + * First wait until the current fragment has been played completely + */ + save_flags (flags); + cli (); + + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 10; /* Some safety distance */ - DISABLE_INTR (flags); + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; - audio_devs[dev]->reset (dev); - audio_devs[dev]->close (dev); + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - if ((retval = audio_devs[dev]->open (dev, audio_devs[dev]->dmap->open_mode)) < 0) - printk ("Sound: Reset failed - Can't reopen device\n"); - RESTORE_INTR (flags); + audio_devs[dev]->dmap_out->underrun_count = 0; + if (!(current->signal & ~current->blocked) + && audio_devs[dev]->dmap_out->qlen + && audio_devs[dev]->dmap_out->underrun_count == 0) + { + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on (&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + } + audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + audio_devs[dev]->dmap_out->flags |= DMA_RESTART; + +/* + * Finally shut the device off + */ + + if (!(audio_devs[dev]->flags & DMA_DUPLEX) || + !audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->reset (dev); + else + audio_devs[dev]->d->halt_output (dev); + audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; + restore_flags (flags); - dma_init_buffers (dev); - reorganize_buffers (dev); + dma_init_buffers (dev, audio_devs[dev]->dmap_out); + reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0); } -static int -dma_sync (int dev) +static void +dma_reset_input (int dev) +{ + unsigned long flags; + + save_flags (flags); + cli (); + if (!(audio_devs[dev]->flags & DMA_DUPLEX) || + !audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->reset (dev); + else + audio_devs[dev]->d->halt_input (dev); + audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; + restore_flags (flags); + + dma_init_buffers (dev, audio_devs[dev]->dmap_in); + reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1); +} + +static void +launch_output (int dev, struct dma_buffparms *dmap) +{ + dmap->flags |= DMA_ACTIVE; + + if (dmap->dma_mode == DMODE_NONE || dmap->flags & DMA_RESTART) + { + reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0); + audio_devs[dev]->d->prepare_for_output (dev, + dmap->fragment_size, dmap->nbufs); + } + + dmap->dma_mode |= DMODE_OUTPUT; + + if (dmap->counts[dmap->qhead] == 0) + dmap->counts[dmap->qhead] = dmap->fragment_size; + + audio_devs[dev]->d->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]->d->trigger) + audio_devs[dev]->d->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); +} + +int +DMAbuf_sync (int dev) { unsigned long flags; + int tmout; + + if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + return 0; - if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT) + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) { - DISABLE_INTR (flags); - while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) - && audio_devs[dev]->dmap->qlen) + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + save_flags (flags); + cli (); + + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 10; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + + ; + if (dmap->qlen > 0) + if (!(dmap->flags & DMA_ACTIVE)) + launch_output (dev, dmap); + ; + + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; + + audio_devs[dev]->dmap_out->underrun_count = 0; + while (!(current->signal & ~current->blocked) + && audio_devs[dev]->dmap_out->qlen + && audio_devs[dev]->dmap_out->underrun_count == 0) { - DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ); - if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on (&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) { - RESTORE_INTR (flags); - return audio_devs[dev]->dmap->qlen; + audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; + restore_flags (flags); + return audio_devs[dev]->dmap_out->qlen; } } - RESTORE_INTR (flags); - + audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + audio_devs[dev]->dmap_out->flags |= DMA_RESTART; + restore_flags (flags); /* * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait util the device has finished playing. + * audio data. We have to wait until the device has finished playing. */ - DISABLE_INTR (flags); - if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */ + save_flags (flags); + cli (); + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ { - while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) - && audio_devs[dev]->local_qlen (dev)) + while (!((current->signal & ~current->blocked)) + && audio_devs[dev]->d->local_qlen (dev)) { - DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ); + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on (&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; } } - RESTORE_INTR (flags); + restore_flags (flags); } - return audio_devs[dev]->dmap->qlen; + audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; + return audio_devs[dev]->dmap_out->qlen; } int @@ -272,94 +578,177 @@ DMAbuf_release (int dev, int mode) { unsigned long flags; - if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) - && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)) + audio_devs[dev]->dmap_out->closing = 1; + audio_devs[dev]->dmap_in->closing = 1; + + if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) + if (!((current->signal & ~current->blocked)) + && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) { - dma_sync (dev); + DMAbuf_sync (dev); } -#ifdef USE_RUNTIME_DMAMEM - sound_dma_free (dev); -#endif + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) + memset (audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->bytes_in_use); + + save_flags (flags); + cli (); + + audio_devs[dev]->d->halt_xfer (dev); + audio_devs[dev]->d->close (dev); + + close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); + + if (audio_devs[dev]->open_mode & OPEN_READ && + audio_devs[dev]->flags & DMA_DUPLEX) + close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); + audio_devs[dev]->open_mode = 0; + + restore_flags (flags); + + return 0; +} - DISABLE_INTR (flags); - audio_devs[dev]->reset (dev); +static int +activate_recording (int dev, struct dma_buffparms *dmap) +{ + int prepare = 0; + + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) + return 0; + + if (dmap->flags & DMA_RESTART) + { + dma_reset_input (dev); + dmap->flags &= ~DMA_RESTART; + prepare = 1; + } - audio_devs[dev]->close (dev); + if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ + { + DMAbuf_sync (dev); + DMAbuf_reset (dev); + dmap->dma_mode = DMODE_NONE; + } - audio_devs[dev]->dmap->dma_mode = DMODE_NONE; - audio_devs[dev]->dmap->flags &= ~DMA_BUSY; - RESTORE_INTR (flags); + if (prepare || !dmap->dma_mode) + { + int err; + + reorganize_buffers (dev, dmap, 1); + if ((err = audio_devs[dev]->d->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]->d->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]->d->trigger) + audio_devs[dev]->d->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } return 0; } int -DMAbuf_getrdbuffer (int dev, char **buf, int *len) +DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { unsigned long flags; int err = EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - DISABLE_INTR (flags); - if (!dmap->qlen) + save_flags (flags); + cli (); + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { - if (dmap->flags & DMA_RESTART) + printk ("Sound: Can't read from mmapped device (1)\n"); + return -EINVAL; + } + else if (!dmap->qlen) + { + int tmout; + + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || + !audio_devs[dev]->go) { - dma_reset (dev); - dmap->flags &= ~DMA_RESTART; + restore_flags (flags); + return -EAGAIN; } - if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ + if ((err = activate_recording (dev, dmap)) < 0) { - dma_sync (dev); - dma_reset (dev); - dmap->dma_mode = DMODE_NONE; + restore_flags (flags); + return err; } - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers (dev); + /* Wait for the next block */ - if (!dmap->dma_mode) + if (dontblock) { - int err; - - if ((err = audio_devs[dev]->prepare_for_input (dev, - dmap->fragment_size, dmap->nbufs)) < 0) - { - RESTORE_INTR (flags); - return err; - } - dmap->dma_mode = DMODE_INPUT; + restore_flags (flags); + return -EAGAIN; } - if (!(dmap->flags & DMA_ACTIVE)) + if (!audio_devs[dev]->go) + tmout = 0; + else { - audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail], - dmap->fragment_size, 0, - !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); - dmap->flags |= DMA_ACTIVE | DMA_STARTED; + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 10; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; } - /* Wait for the next block */ - DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); - if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + in_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on (&in_sleeper[dev]); + if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + in_sleep_flag[dev].opts |= WK_TIMEOUT; + } + in_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) { - printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); + printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); err = EIO; - SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); + audio_devs[dev]->d->reset (dev); + ; } else err = EINTR; } - RESTORE_INTR (flags); + restore_flags (flags); if (!dmap->qlen) - return RET_ERROR (err); + return -err; - *buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]]; + *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; *len = dmap->fragment_size - dmap->counts[dmap->qhead]; return dmap->qhead; @@ -368,11 +757,16 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len) int DMAbuf_rmchars (int dev, int buff_no, int c) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; int p = dmap->counts[dmap->qhead] + c; - if (p >= dmap->fragment_size) + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + { + printk ("Sound: Can't read from mmapped device (2)\n"); + return -EINVAL; + } + else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ dmap->counts[dmap->qhead] = 0; if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) @@ -387,128 +781,444 @@ DMAbuf_rmchars (int dev, int buff_no, int c) return 0; } +static int +dma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +{ + if (fact == 0) + { + fact = dmap->subdivision; + if (fact == 0) + fact = 1; + return ioctl_out (arg, fact); + } + + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too 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 ioctl_out (arg, fact); +} + +static int +dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +{ + int bytes, count; + + if (fact == 0) + return -EIO; + + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too late to change */ + return -EINVAL; + + bytes = fact & 0xffff; + count = (fact >> 16) & 0x7fff; + + if (count == 0) + count = MAX_SUB_BUFFERS; + + if (bytes < 4 || bytes > 17) /* <16 || > 512k */ + return -EINVAL; + + if (count < 2) + return -EINVAL; + + if (audio_devs[dev]->min_fragment > 0) + if (bytes < audio_devs[dev]->min_fragment) + bytes = audio_devs[dev]->min_fragment; + +#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 */ + if (arg) + return ioctl_out (arg, bytes | (count << 16)); + else + return 0; +} + +static int +get_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap) +{ +/* + * Try to approximate the active byte position of the DMA pointer within the + * buffer area as well as possible. + */ + int pos; + unsigned long flags; + + save_flags (flags); + cli (); + if (!(dmap->flags & DMA_ACTIVE)) + pos = 0; + else + { + clear_dma_ff (chan); + disable_dma (chan); + pos = get_dma_residue (chan); + if (chan > 3) /* Word count */ + pos *= 2; + pos = dmap->bytes_in_use - pos - 1; + if (pos < 0) + pos = 0; + if (pos > dmap->bytes_in_use) + pos = dmap->bytes_in_use; + enable_dma (chan); + } + restore_flags (flags); + /* printk ("%04x ", pos); */ + + return pos; +} + + int -DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + 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; + case SNDCTL_DSP_GETBLKSIZE: + if (!(dmap_out->flags & DMA_ALLOC_DONE)) + { + reorganize_buffers (dev, dmap_out, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + reorganize_buffers (dev, dmap_in, + (audio_devs[dev]->open_mode == OPEN_READ)); + } + + if (local) + return dmap_out->fragment_size; + else + return ioctl_out (arg, dmap_out->fragment_size); break; - case SNDCTL_DSP_SYNC: - dma_sync (dev); - dma_reset (dev); - return 0; + case SNDCTL_DSP_SUBDIVIDE: + { + int fact; + int ret; + + get_user (fact, (int *) arg); + + ret = dma_subdivide (dev, dmap_out, arg, fact); + if (ret < 0) + return ret; + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + ret = dma_subdivide (dev, dmap_in, arg, fact); + + return ret; + } break; - case SNDCTL_DSP_GETBLKSIZE: - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers (dev); + case SNDCTL_DSP_SETFRAGMENT: + { + int fact; + int ret; - return IOCTL_OUT (arg, dmap->fragment_size); + get_user (fact, (int *) arg); + ret = dma_set_fragment (dev, dmap_out, arg, fact); + if (ret < 0) + return ret; + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + ret = dma_set_fragment (dev, dmap_in, arg, fact); + + return ret; + } break; - case SNDCTL_DSP_SUBDIVIDE: + 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]->open_mode & OPEN_READ)) + return -EINVAL; + + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) + dmap = dmap_in; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return -EINVAL; + + if (!(dmap->flags & DMA_ALLOC_DONE)) + reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); + + 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]->d->local_qlen) + { + int tmp = audio_devs[dev]->d->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: { - int fact = IOCTL_IN (arg); + unsigned long flags; + + int bits; + int changed; + + get_user (bits, (int *) arg); + bits &= audio_devs[dev]->open_mode; + + if (audio_devs[dev]->d->trigger == NULL) + return -EINVAL; + + if (!(audio_devs[dev]->flags & DMA_DUPLEX)) + if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) + { + printk ("Sound: Device doesn't have full duplex capability\n"); + return -EINVAL; + } + + save_flags (flags); + cli (); + changed = audio_devs[dev]->enable_bits ^ bits; - if (fact == 0) + if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) { - fact = dmap->subdivision; - if (fact == 0) - fact = 1; - return IOCTL_OUT (arg, fact); + int err; + + reorganize_buffers (dev, dmap_in, 1); + + if ((err = audio_devs[dev]->d->prepare_for_input (dev, + dmap_in->fragment_size, dmap_in->nbufs)) < 0) + return -err; + + audio_devs[dev]->enable_bits = bits; + activate_recording (dev, dmap_in); } - if (dmap->subdivision != 0 || - dmap->fragment_size)/* Too late to change */ - return RET_ERROR (EINVAL); - if (fact > MAX_REALTIME_FACTOR) - return RET_ERROR (EINVAL); + 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, 0); + } - if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) - return RET_ERROR (EINVAL); + ; + dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; + launch_output (dev, dmap_out); + ; + } - dmap->subdivision = fact; - return IOCTL_OUT (arg, fact); + audio_devs[dev]->enable_bits = bits; + if (changed && audio_devs[dev]->d->trigger) + { + audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go); + } + restore_flags (flags); } + case SNDCTL_DSP_GETTRIGGER: + return ioctl_out (arg, audio_devs[dev]->enable_bits); break; - case SNDCTL_DSP_SETFRAGMENT: - { - int fact = IOCTL_IN (arg); - int bytes, count; + case SNDCTL_DSP_SETSYNCRO: - if (fact == 0) - return RET_ERROR (EIO); + if (!audio_devs[dev]->d->trigger) + return -EINVAL; - if (dmap->subdivision != 0 || - dmap->fragment_size)/* Too late to change */ - return RET_ERROR (EINVAL); + audio_devs[dev]->d->trigger (dev, 0); + audio_devs[dev]->go = 0; + return 0; + break; - bytes = fact & 0xffff; - count = (fact >> 16) & 0xffff; + case SNDCTL_DSP_GETIPTR: + { + count_info info; + unsigned long flags; + + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + + save_flags (flags); + cli (); + 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; + { + char *fixit = (char *) &info; - if (count == 0) - count = MAX_SUB_BUFFERS; + copy_to_user (&((char *) arg)[0], fixit, sizeof (info)); + }; - if (bytes < 7 || bytes > 17) /* <64 || > 128k */ - return RET_ERROR (EINVAL); + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + audio_devs[dev]->dmap_in->qlen = 0; /* Acknowledge interrupts */ + restore_flags (flags); + return 0; + } + break; - if (count < 2) - return RET_ERROR (EINVAL); + case SNDCTL_DSP_GETOPTR: + { + count_info info; + unsigned long flags; + + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + + save_flags (flags); + cli (); + 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; + { + char *fixit = (char *) &info; - dmap->fragment_size = (1 << bytes); - dmap->max_fragments = count; + copy_to_user (&((char *) arg)[0], fixit, sizeof (info)); + }; - if (dmap->fragment_size > audio_devs[dev]->buffsize) - dmap->fragment_size = audio_devs[dev]->buffsize; + if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) + audio_devs[dev]->dmap_out->qlen = 0; /* Acknowledge interrupts */ + restore_flags (flags); + return 0; + } + break; - 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 IOCTL_OUT (arg, bytes | (count << 16)); - } + case SNDCTL_DSP_POST: + ; + if (audio_devs[dev]->dmap_out->qlen > 0) + if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) + launch_output (dev, audio_devs[dev]->dmap_out); + ; + return 0; break; default: - return audio_devs[dev]->ioctl (dev, cmd, arg, local); + return audio_devs[dev]->d->ioctl (dev, cmd, arg, local); } - return RET_ERROR (EIO); +} + +/* + * DMAbuf_start_devices() is called by the /dev/music driver to start + * one or more audio devices at desired moment. + */ + +void +DMAbuf_start_device (int 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]->d->trigger) + audio_devs[dev]->d->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } +} + +void +DMAbuf_start_devices (unsigned int devmask) +{ + int dev; + + for (dev = 0; dev < num_audiodevs; dev++) + if (devmask & (1 << dev)) + DMAbuf_start_device (dev); } static int space_in_queue (int dev) { int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if (dmap->qlen == dmap->nbufs)/* No space at all */ + /* Don't allow touching pages too close to the playing ones */ + int lim = dmap->nbufs - 1; + + if (lim < 2) + lim = 2; + + if (dmap->qlen >= lim) /* No space at all */ return 0; /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ + * 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) + if (audio_devs[dev]->d->local_qlen) { - tmp = audio_devs[dev]->local_qlen (dev); - if (tmp & len) + tmp = audio_devs[dev]->d->local_qlen (dev); + if (tmp && len) tmp--; /* - * This buffer has been counted twice - */ + * This buffer has been counted twice + */ len += tmp; } @@ -518,70 +1228,127 @@ space_in_queue (int dev) } int -DMAbuf_getwrbuffer (int dev, char **buf, int *size) +DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { unsigned long flags; int abort, err = EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + dmap->flags &= ~DMA_CLEAN; + + if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) + { + printk ("Sound: Can't write to mmapped device (3)\n"); + return -EINVAL; + } if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ { - dma_reset (dev); + DMAbuf_reset (dev); dmap->dma_mode = DMODE_NONE; } else if (dmap->flags & DMA_RESTART) /* Restart buffering */ { - dma_sync (dev); - dma_reset (dev); + DMAbuf_sync (dev); + dma_reset_output (dev); + dmap->dma_mode = DMODE_NONE; } - dmap->flags &= ~DMA_RESTART; - - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers (dev); + dmap->flags &= ~(DMA_RESTART | DMA_EMPTY); if (!dmap->dma_mode) { int err; + reorganize_buffers (dev, dmap, 0); dmap->dma_mode = DMODE_OUTPUT; - if ((err = audio_devs[dev]->prepare_for_output (dev, + if ((err = audio_devs[dev]->d->prepare_for_output (dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; } - - DISABLE_INTR (flags); + save_flags (flags); + cli (); abort = 0; while (!space_in_queue (dev) && !abort) { + int tmout; + + if (dontblock) + { + restore_flags (flags); + return -EAGAIN; + } + + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + { + restore_flags (flags); + return -EAGAIN; + } + /* * Wait for free space */ - DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); - if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) + if (!audio_devs[dev]->go) + tmout = 0; + else + { + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 10; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + } + + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on (&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) { - printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); + printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); err = EIO; abort = 1; - SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); + ; + if (audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; + audio_devs[dev]->d->reset (dev); } - else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) + else if ((current->signal & ~current->blocked)) { err = EINTR; abort = 1; } } - RESTORE_INTR (flags); + restore_flags (flags); if (!space_in_queue (dev)) { - return RET_ERROR (err); /* Caught a signal ? */ + return -err; /* Caught a signal ? */ } - *buf = dmap->buf[dmap->qtail]; + *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; *size = dmap->fragment_size; dmap->counts[dmap->qtail] = 0; @@ -589,52 +1356,131 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size) } int -DMAbuf_start_output (int dev, int buff_no, int l) +DMAbuf_get_curr_buffer (int dev, int *buf_no, char **dma_buf, int *buf_ptr, int *buf_size) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if (buff_no != dmap->qtail) - printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail); + if (dmap->cfrag < 0) + return -1; - dmap->qlen++; - if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) - printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n", - dev, dmap->qlen, dmap->nbufs); + *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; + *buf_ptr = dmap->counts[dmap->qtail]; + *buf_size = dmap->fragment_size; + return *buf_no = dmap->cfrag; +} - dmap->counts[dmap->qtail] = l; +int +DMAbuf_set_count (int dev, int buff_no, int l) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if ((l != dmap->fragment_size) && - ((audio_devs[dev]->flags & DMA_AUTOMODE) && - audio_devs[dev]->flags & NEEDS_RESTART)) - dmap->flags |= DMA_RESTART; + if (buff_no == dmap->qtail) + { + dmap->cfrag = buff_no; + dmap->counts[buff_no] = l; + } else - dmap->flags &= ~DMA_RESTART; + dmap->cfrag = -1; + return 0; +} + +int +DMAbuf_start_output (int dev, int buff_no, int l) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int restart = 0; + int post = dmap->flags & DMA_POST; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + ; - if (!(dmap->flags & DMA_ACTIVE)) + dmap->flags &= ~DMA_POST; + + dmap->cfrag = -1; + if (dmap->flags & DMA_RESTART) + restart = 1; + +/* + * Bypass buffering if using mmapped access + */ + + if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) { - dmap->flags |= DMA_ACTIVE; - audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead], - dmap->counts[dmap->qhead], 0, - !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); - dmap->flags |= DMA_STARTED; + l = dmap->fragment_size; + dmap->counts[dmap->qtail] = l; + dmap->flags &= ~DMA_RESTART; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } + else + { + + dmap->qlen++; + + dmap->counts[dmap->qtail] = l; + if (l < dmap->fragment_size) + { + int p = dmap->fragment_size * dmap->qtail; + +#if defined(PPC) || defined(sparc) || defined(HPPA) + dmap->neutral_byte = dmap->raw_buf[p + l - 2]; +#else + dmap->neutral_byte = dmap->raw_buf[p + l - 1]; +#endif + + memset (dmap->raw_buf + p + l, + dmap->neutral_byte, + dmap->fragment_size - l); + } + else + dmap->neutral_byte = + dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1]; + + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } + /* Delay playback until there are at least two fragments (to prevent hiccup) */ + if (dmap->qlen > 1 || post || + (dmap->qlen > 0 && dmap->nbufs <= 2) || + (dmap->qlen > 0 && dmap->flags & DMA_SYNCING) || + restart || l != dmap->fragment_size) + if (!(dmap->flags & DMA_ACTIVE)) + { + launch_output (dev, dmap); + } + + ; return 0; } int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) { - int chan = audio_devs[dev]->dmachan; - struct dma_buffparms *dmap = audio_devs[dev]->dmap; - unsigned long flags; + int chan; + struct dma_buffparms *dmap; - /* - * This function is not as portable as it should be. - */ + if (dma_mode == DMA_MODE_WRITE) + { + chan = audio_devs[dev]->dmachan1; + dmap = audio_devs[dev]->dmap_out; + } + else + { + chan = audio_devs[dev]->dmachan2; + dmap = audio_devs[dev]->dmap_in; + } + + if (dmap->raw_buf == NULL) + { + printk ("sound: DMA buffer == NULL\n"); + return 0; + } + + /* Handle cards with non automode DMA in new way */ + if (physaddr != dmap->raw_buf_phys) /* Not fragment 0 */ + return count; + count = dmap->bytes_in_use; + + if (chan < 0) + return 0; /* * The count must be one less than the actual size. This is handled by @@ -646,163 +1492,268 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) * Auto restart mode. Transfer the whole * * buffer */ -#ifdef linux - DISABLE_INTR (flags); + unsigned long flags; + + save_flags (flags); + cli (); disable_dma (chan); clear_dma_ff (chan); set_dma_mode (chan, dma_mode | DMA_AUTOINIT); - set_dma_addr (chan, dmap->raw_buf_phys[0]); + set_dma_addr (chan, dmap->raw_buf_phys); set_dma_count (chan, dmap->bytes_in_use); enable_dma (chan); - RESTORE_INTR (flags); -#else - -#ifdef __386BSD__ - printk ("sound: Invalid DMA mode for device %d\n", dev); - - isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, - dmap->raw_buf_phys[0], - dmap->bytes_in_use, - chan); -#else -#if defined(GENERIC_SYSV) -#ifndef DMAMODE_AUTO - printk ("sound: Invalid DMA mode for device %d\n", dev); -#endif - dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) -#ifdef DMAMODE_AUTO - | DMAMODE_AUTO -#endif - , - dmap->raw_buf_phys[0], dmap->bytes_in_use); - dma_enable (chan); -#else -#error This routine is not valid for this OS. -#endif -#endif - -#endif + restore_flags (flags); } else { -#ifdef linux - DISABLE_INTR (flags); + unsigned long flags; + + save_flags (flags); + cli (); disable_dma (chan); clear_dma_ff (chan); set_dma_mode (chan, dma_mode); set_dma_addr (chan, physaddr); set_dma_count (chan, count); enable_dma (chan); - RESTORE_INTR (flags); -#else -#ifdef __386BSD__ - isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, - physaddr, - count, - chan); -#else - -#if defined(GENERIC_SYSV) - dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode), - physaddr, count); - dma_enable (chan); -#else -#error This routine is not valid for this OS. -#endif /* GENERIC_SYSV */ -#endif - -#endif + restore_flags (flags); } return count; } -long -DMAbuf_init (long mem_start) +void +DMAbuf_init (void) { int dev; + /* - * NOTE! This routine could be called several times. - */ + * NOTE! This routine could be called several times. + */ for (dev = 0; dev < num_audiodevs; dev++) - audio_devs[dev]->dmap = &dmaps[dev]; - return mem_start; + 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++]; + } +} + +static void +force_restart (int dev, struct dma_buffparms *dmap) +{ + unsigned long flags; + + if ((audio_devs[dev]->flags & DMA_DUPLEX) && + audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->halt_output (dev); + else + audio_devs[dev]->d->halt_xfer (dev); + + dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED); + dmap->flags |= DMA_RESTART; + dmap->qlen = dmap->qhead = dmap->qtail = 0; + + save_flags (flags); + cli (); + if ((out_sleep_flag[dev].opts & WK_SLEEP)) + { + { + out_sleep_flag[dev].opts = WK_WAKEUP; + wake_up (&out_sleeper[dev]); + }; + } + restore_flags (flags); } 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. - */ + * 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 it's local + * buffer. + */ unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int this_fragment; + +#ifdef OS_DMA_INTR + if (audio_devs[dev]->dmachan1 >= 0) + sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); +#endif + + if (dmap->raw_buf == NULL) + { + printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + /* mmapped access */ + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + if (dmap->qhead == 0) /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; + 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)) + { + if (dmap->counts[dmap->qhead] == 0) + dmap->counts[dmap->qhead] = dmap->fragment_size; - if (event_type != 2) + audio_devs[dev]->d->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]->d->trigger) + audio_devs[dev]->d->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; + } + else if (event_type != 2) { if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) { printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n", dev, dmap->qlen, dmap->nbufs); + force_restart (dev, dmap); return; } + save_flags (flags); + cli (); + dmap->qlen--; + this_fragment = dmap->qhead; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + + if (dmap->qhead == 0) /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; dmap->flags &= ~DMA_ACTIVE; + if (event_type == 1 && dmap->qlen < 1) + { + dmap->underrun_count++; + + dmap->qlen = 0; + force_restart (dev, dmap); + } + if (dmap->qlen) { - audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead], - dmap->counts[dmap->qhead], 1, + if (dmap->flags & DMA_CLEAN) + { + int p = dmap->fragment_size * this_fragment; + + memset (dmap->raw_buf + p, + dmap->neutral_byte, + dmap->fragment_size); + } + + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + + if (dmap->counts[dmap->qhead] == 0) + dmap->counts[dmap->qhead] = dmap->fragment_size; + + audio_devs[dev]->d->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]->d->trigger) + audio_devs[dev]->d->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } dmap->flags |= DMA_ACTIVE; } - else if (event_type == 1) - { - dmap->underrun_count++; - 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; - } + + restore_flags (flags); } /* event_type != 2 */ - DISABLE_INTR (flags); - if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) + save_flags (flags); + cli (); + if ((out_sleep_flag[dev].opts & WK_SLEEP)) { - WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); + { + out_sleep_flag[dev].opts = WK_WAKEUP; + wake_up (&out_sleeper[dev]); + }; } - RESTORE_INTR (flags); + restore_flags (flags); } void DMAbuf_inputintr (int dev) { unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - if (dmap->qlen == (dmap->nbufs - 1)) +#ifdef OS_DMA_INTR + if (audio_devs[dev]->dmachan2 >= 0) + sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); +#endif + + if (dmap->raw_buf == NULL) + { + printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; + dmap->qlen++; + + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + audio_devs[dev]->d->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]->d->trigger) + audio_devs[dev]->d->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + + dmap->flags |= DMA_ACTIVE; + } + else if (dmap->qlen == (dmap->nbufs - 1)) { - printk ("Sound: Recording overrun\n"); + /* printk ("Sound: Recording overrun\n"); */ dmap->underrun_count++; - 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; + { + /* Force restart on next read */ + if ((audio_devs[dev]->flags & DMA_DUPLEX) && + audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->halt_input (dev); + else + audio_devs[dev]->d->halt_xfer (dev); + + dmap->flags &= ~DMA_ACTIVE; + if (audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; + } } else { @@ -811,39 +1762,62 @@ DMAbuf_inputintr (int dev) printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n", dev, dmap->qlen, dmap->nbufs); dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; + } - audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail], - dmap->fragment_size, 1, + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - dmap->flags |= DMA_ACTIVE; + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); } - DISABLE_INTR (flags); - if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) + dmap->flags |= DMA_ACTIVE; + + save_flags (flags); + cli (); + if ((in_sleep_flag[dev].opts & WK_SLEEP)) { - WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); + { + in_sleep_flag[dev].opts = WK_WAKEUP; + wake_up (&in_sleeper[dev]); + }; } - RESTORE_INTR (flags); + restore_flags (flags); } int DMAbuf_open_dma (int dev) { +/* + * NOTE! This routine opens only the primary DMA channel (output). + */ + + int chan = audio_devs[dev]->dmachan1; + int err; unsigned long flags; - int chan = audio_devs[dev]->dmachan; - if (ALLOC_DMA_CHN (chan,"audio")) + if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) { - printk ("Unable to grab DMA%d for the audio driver\n", chan); - return RET_ERROR (EBUSY); + 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; - DISABLE_INTR (flags); -#ifdef linux - disable_dma (chan); - clear_dma_ff (chan); -#endif - RESTORE_INTR (flags); + if (chan >= 0) + { + save_flags (flags); + cli (); + disable_dma (chan); + clear_dma_ff (chan); + restore_flags (flags); + } return 0; } @@ -851,26 +1825,122 @@ DMAbuf_open_dma (int dev) void DMAbuf_close_dma (int dev) { - int chan = audio_devs[dev]->dmachan; - - DMAbuf_reset_dma (chan); - RELEASE_DMA_CHN (chan); + DMAbuf_reset_dma (dev); + close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); } void -DMAbuf_reset_dma (int chan) +DMAbuf_reset_dma (int dev) { } -/* - * The sound_mem_init() is called by mem_init() immediately after mem_map is - * initialized and before free_page_list is created. - * - * This routine allocates DMA buffers at the end of available physical memory ( - * <16M) and marks pages reserved at mem_map. - */ +int +DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +{ + struct dma_buffparms *dmap; + unsigned long flags; -#else + switch (sel_type) + { + case SEL_IN: + if (!(audio_devs[dev]->open_mode)) + return 0; + + dmap = audio_devs[dev]->dmap_in; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags (flags); + cli (); + + in_sleep_flag[dev].opts = WK_SLEEP; + select_wait (&in_sleeper[dev], wait); + restore_flags (flags); + return 0; + } + + if (dmap->dma_mode != DMODE_INPUT) + { + if (dmap->dma_mode == DMODE_NONE && + audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && + !dmap->qlen && + audio_devs[dev]->go) + { + unsigned long flags; + + save_flags (flags); + cli (); + activate_recording (dev, dmap); + restore_flags (flags); + } + return 0; + } + + if (!dmap->qlen) + { + save_flags (flags); + cli (); + + in_sleep_flag[dev].opts = WK_SLEEP; + select_wait (&in_sleeper[dev], wait); + restore_flags (flags); + return 0; + } + return 1; + break; + + case SEL_OUT: + dmap = audio_devs[dev]->dmap_out; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags (flags); + cli (); + + out_sleep_flag[dev].opts = WK_SLEEP; + select_wait (&out_sleeper[dev], wait); + restore_flags (flags); + return 0; + } + + if (dmap->dma_mode == DMODE_INPUT) + { + return 0; + } + + if (dmap->dma_mode == DMODE_NONE) + { + return 1; + } + + if (!space_in_queue (dev)) + { + save_flags (flags); + cli (); + + out_sleep_flag[dev].opts = WK_SLEEP; + select_wait (&out_sleeper[dev], wait); + restore_flags (flags); + return 0; + } + return 1; + break; + + case SEL_EX: + return 0; + } + + return 0; +} + + +#else /* CONFIG_AUDIO */ /* * Stub versions if audio services not included */ @@ -878,7 +1948,7 @@ DMAbuf_reset_dma (int chan) int DMAbuf_open (int dev, int mode) { - return RET_ERROR (ENXIO); + return -ENXIO; } int @@ -888,61 +1958,60 @@ DMAbuf_release (int dev, int mode) } int -DMAbuf_getwrbuffer (int dev, char **buf, int *size) +DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { - return RET_ERROR (EIO); + return -EIO; } int -DMAbuf_getrdbuffer (int dev, char **buf, int *len) +DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { - return RET_ERROR (EIO); + return -EIO; } int DMAbuf_rmchars (int dev, int buff_no, int c) { - return RET_ERROR (EIO); + return -EIO; } int DMAbuf_start_output (int dev, int buff_no, int l) { - return RET_ERROR (EIO); + return -EIO; } int -DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { - return RET_ERROR (EIO); + return -EIO; } -long -DMAbuf_init (long mem_start) +void +DMAbuf_init (void) { - return mem_start; } int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) { - return RET_ERROR (EIO); + return -EIO; } int -DMAbuf_open_dma (int chan) +DMAbuf_open_dma (int dev) { - return RET_ERROR (ENXIO); + return -ENXIO; } void -DMAbuf_close_dma (int chan) +DMAbuf_close_dma (int dev) { return; } void -DMAbuf_reset_dma (int chan) +DMAbuf_reset_dma (int dev) { return; } @@ -958,7 +2027,4 @@ DMAbuf_outputintr (int dev, int underrun_flag) { return; } - -#endif - #endif -- cgit v1.2.3