home *** CD-ROM | disk | FTP | other *** search
- /*
- * sound/dmabuf.c
- *
- * The DMA buffer manager for digitized voice applications
- *
- * 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.
- *
- */
-
- #include "sound_config.h"
-
- #ifdef CONFIGURE_SOUNDCARD
-
- #include "sound_calls.h"
-
- #if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
-
- DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_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
- reorganize_buffers (int dev)
- {
- /*
- * 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 sr, nc, sz, bsz;
-
- 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 (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;
-
- /*
- * 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)
- bsz /= 2; /* Needs at least 2 buffers */
-
- if (dmap->subdivision == 0) /* Not already set */
- dmap->subdivision = 1; /* Init to default value */
-
- bsz /= dmap->subdivision;
-
- if (bsz < 64)
- bsz = 4096; /* Just a sanity check */
-
- while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
- bsz *= 2;
-
- 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;
- bsz = dmap->fragment_size;
- }
-
- /*
- * Now computing addresses for the logical buffers
- */
-
- n = 0;
- for (i = 0; i < dmap->raw_count &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS; i++)
- {
- p = 0;
-
- 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++;
- }
- }
-
- dmap->nbufs = n;
- dmap->bytes_in_use = n * bsz;
-
- for (i = 0; i < dmap->nbufs; i++)
- {
- dmap->counts[i] = 0;
- }
-
- dmap->flags |= DMA_ALLOC_DONE;
- }
-
- static void
- dma_init_buffers (int dev)
- {
- struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-
- dmap->flags = DMA_BUSY; /* Other flags off */
- dmap->qlen = dmap->qhead = dmap->qtail = 0;
-
- dmap->qlen = dmap->qtail = dmap->qhead = 0;
- dmap->dma_mode = DMODE_NONE;
- }
-
- int
- DMAbuf_open (int dev, int mode)
- {
- int retval;
- struct dma_buffparms *dmap = NULL;
-
- if (dev >= num_audiodevs)
- {
- printk ("PCM device %d not installed.\n", dev);
- return RET_ERROR (ENXIO);
- }
-
- if (!audio_devs[dev])
- {
- printk ("PCM device %d not initialized\n", dev);
- return RET_ERROR (ENXIO);
- }
-
- dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- if (dmap->flags & DMA_BUSY)
- return RET_ERROR (EBUSY);
-
- #ifdef USE_RUNTIME_DMAMEM
- dmap->raw_buf[0] = NULL;
- sound_dma_malloc (dev);
- #endif
-
- if (dmap->raw_buf[0] == NULL)
- return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
-
- if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
- return retval;
-
- dmap->open_mode = mode;
- dmap->subdivision = dmap->underrun_count = 0;
- dmap->fragment_size = 0;
- dmap->max_fragments = 65536; /* Just a large value */
-
- 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);
-
- return 0;
- }
-
- static void
- dma_reset (int dev)
- {
- int retval;
- unsigned long flags;
-
- DISABLE_INTR (flags);
-
- audio_devs[dev]->reset (dev);
- audio_devs[dev]->close (dev);
-
- 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);
-
- dma_init_buffers (dev);
- reorganize_buffers (dev);
- }
-
- static int
- dma_sync (int dev)
- {
- unsigned long flags;
-
- if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
- {
- DISABLE_INTR (flags);
-
- while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])
- && audio_devs[dev]->dmap->qlen)
- {
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- RESTORE_INTR (flags);
- return audio_devs[dev]->dmap->qlen;
- }
- }
- RESTORE_INTR (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.
- */
-
- DISABLE_INTR (flags);
- if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */
- {
- while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- && audio_devs[dev]->local_qlen (dev))
- {
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ);
- }
- }
- RESTORE_INTR (flags);
- }
- return audio_devs[dev]->dmap->qlen;
- }
-
- int
- 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))
- {
- dma_sync (dev);
- }
-
- #ifdef USE_RUNTIME_DMAMEM
- sound_dma_free (dev);
- #endif
-
- DISABLE_INTR (flags);
- audio_devs[dev]->reset (dev);
-
- audio_devs[dev]->close (dev);
-
- audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
- audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
- RESTORE_INTR (flags);
-
- return 0;
- }
-
- int
- DMAbuf_getrdbuffer (int dev, char **buf, int *len)
- {
- unsigned long flags;
- int err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- DISABLE_INTR (flags);
- if (!dmap->qlen)
- {
- if (dmap->flags & DMA_RESTART)
- {
- dma_reset (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);
-
- if (!dmap->dma_mode)
- {
- 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;
- }
-
- if (!(dmap->flags & DMA_ACTIVE))
- {
- 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;
- }
-
- /* 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]))
- {
- printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
- err = EIO;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- else
- err = EINTR;
- }
- RESTORE_INTR (flags);
-
- if (!dmap->qlen)
- return RET_ERROR (err);
-
- *buf = &dmap->buf[dmap->qhead][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;
-
- int p = dmap->counts[dmap->qhead] + c;
-
- if (p >= dmap->fragment_size)
- { /* This buffer is completely empty */
- dmap->counts[dmap->qhead] = 0;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\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;
- }
-
- int
- DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
- {
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- 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->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
-
- return IOCTL_OUT (arg, dmap->fragment_size);
- break;
-
- case SNDCTL_DSP_SUBDIVIDE:
- {
- int fact = IOCTL_IN (arg);
-
- 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 RET_ERROR (EINVAL);
-
- if (fact > MAX_REALTIME_FACTOR)
- return RET_ERROR (EINVAL);
-
- if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
- return RET_ERROR (EINVAL);
-
- dmap->subdivision = fact;
- return IOCTL_OUT (arg, fact);
- }
- break;
-
- case SNDCTL_DSP_SETFRAGMENT:
- {
- int fact = IOCTL_IN (arg);
- int bytes, count;
-
- if (fact == 0)
- return RET_ERROR (EIO);
-
- if (dmap->subdivision != 0 ||
- dmap->fragment_size)/* Too late to change */
- return RET_ERROR (EINVAL);
-
- bytes = fact & 0xffff;
- count = (fact >> 16) & 0xffff;
-
- if (count == 0)
- count = MAX_SUB_BUFFERS;
-
- if (bytes < 7 || bytes > 17) /* <64 || > 128k */
- return RET_ERROR (EINVAL);
-
- if (count < 2)
- return RET_ERROR (EINVAL);
-
- 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 IOCTL_OUT (arg, bytes | (count << 16));
- }
- break;
-
- default:
- return audio_devs[dev]->ioctl (dev, cmd, arg, local);
- }
-
- return RET_ERROR (EIO);
- }
-
- static int
- space_in_queue (int dev)
- {
- int len, max, tmp;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- 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)
- {
- unsigned long flags;
- int abort, err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- 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 (dev);
- }
-
- dmap->flags &= ~DMA_RESTART;
-
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
-
- 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;
- }
-
-
- DISABLE_INTR (flags);
-
- abort = 0;
- while (!space_in_queue (dev) &&
- !abort)
- {
- /*
- * 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]))
- {
- printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
- err = EIO;
- abort = 1;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- err = EINTR;
- abort = 1;
- }
- }
- RESTORE_INTR (flags);
-
- if (!space_in_queue (dev))
- {
- return RET_ERROR (err); /* Caught a signal ? */
- }
-
- *buf = dmap->buf[dmap->qtail];
- *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;
-
- if (buff_no != dmap->qtail)
- printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
-
- 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);
-
- 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->buf_phys[dmap->qhead],
- dmap->counts[dmap->qhead], 0,
- !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
- !(dmap->flags & DMA_STARTED));
- dmap->flags |= DMA_STARTED;
- }
-
- 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;
-
- /*
- * This function is not as portable as it should be.
- */
-
- /*
- * The count must be one less than the actual size. This is handled by
- * set_dma_addr()
- */
-
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- { /*
- * Auto restart mode. Transfer the whole *
- * buffer
- */
- #ifdef linux
- DISABLE_INTR (flags);
- 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_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
- }
- else
- {
- #ifdef linux
- DISABLE_INTR (flags);
- 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
- }
-
- return count;
- }
-
- long
- DMAbuf_init (long mem_start)
- {
- int dev;
-
- /*
- * NOTE! This routine could be called several times.
- */
-
- for (dev = 0; dev < num_audiodevs; dev++)
- audio_devs[dev]->dmap = &dmaps[dev];
- return mem_start;
- }
-
- 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.
- */
-
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- 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);
- return;
- }
-
- dmap->qlen--;
- dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
- dmap->flags &= ~DMA_ACTIVE;
-
- if (dmap->qlen)
- {
- audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
- dmap->counts[dmap->qhead], 1,
- !(audio_devs[dev]->flags & DMA_AUTOMODE));
- 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;
- }
- } /* event_type != 2 */
-
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- RESTORE_INTR (flags);
- }
-
- void
- DMAbuf_inputintr (int dev)
- {
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- if (dmap->qlen == (dmap->nbufs - 1))
- {
- 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;
- }
- else
- {
- dmap->qlen++;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-
- audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
- dmap->fragment_size, 1,
- !(audio_devs[dev]->flags & DMA_AUTOMODE));
- dmap->flags |= DMA_ACTIVE;
- }
-
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- RESTORE_INTR (flags);
- }
-
- int
- DMAbuf_open_dma (int dev)
- {
- unsigned long flags;
- int chan = audio_devs[dev]->dmachan;
-
- if (ALLOC_DMA_CHN (chan,"audio"))
- {
- printk ("Unable to grab DMA%d for the audio driver\n", chan);
- return RET_ERROR (EBUSY);
- }
-
- DISABLE_INTR (flags);
- #ifdef linux
- disable_dma (chan);
- clear_dma_ff (chan);
- #endif
- RESTORE_INTR (flags);
-
- return 0;
- }
-
- void
- DMAbuf_close_dma (int dev)
- {
- int chan = audio_devs[dev]->dmachan;
-
- DMAbuf_reset_dma (chan);
- RELEASE_DMA_CHN (chan);
- }
-
- void
- DMAbuf_reset_dma (int chan)
- {
- }
-
- /*
- * 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.
- */
-
- #else
- /*
- * Stub versions if audio services not included
- */
-
- int
- DMAbuf_open (int dev, int mode)
- {
- return RET_ERROR (ENXIO);
- }
-
- int
- DMAbuf_release (int dev, int mode)
- {
- return 0;
- }
-
- int
- DMAbuf_getwrbuffer (int dev, char **buf, int *size)
- {
- return RET_ERROR (EIO);
- }
-
- int
- DMAbuf_getrdbuffer (int dev, char **buf, int *len)
- {
- return RET_ERROR (EIO);
- }
-
- int
- DMAbuf_rmchars (int dev, int buff_no, int c)
- {
- return RET_ERROR (EIO);
- }
-
- int
- DMAbuf_start_output (int dev, int buff_no, int l)
- {
- return RET_ERROR (EIO);
- }
-
- int
- DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
- {
- return RET_ERROR (EIO);
- }
-
- long
- DMAbuf_init (long mem_start)
- {
- return mem_start;
- }
-
- int
- DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
- {
- return RET_ERROR (EIO);
- }
-
- int
- DMAbuf_open_dma (int chan)
- {
- return RET_ERROR (ENXIO);
- }
-
- void
- DMAbuf_close_dma (int chan)
- {
- return;
- }
-
- void
- DMAbuf_reset_dma (int chan)
- {
- return;
- }
-
- void
- DMAbuf_inputintr (int dev)
- {
- return;
- }
-
- void
- DMAbuf_outputintr (int dev, int underrun_flag)
- {
- return;
- }
-
- #endif
-
- #endif
-