OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [armnommu/] [drivers/] [sound/] [dmabuf.c] - Diff between revs 1622 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 1622 Rev 1765
/*
/*
 * sound/dmabuf.c
 * sound/dmabuf.c
 *
 *
 * The DMA buffer manager for digitized voice applications
 * The DMA buffer manager for digitized voice applications
 */
 */
/*
/*
 * Copyright (C) by Hannu Savolainen 1993-1996
 * Copyright (C) by Hannu Savolainen 1993-1996
 *
 *
 * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
 * for more info.
 * for more info.
 */
 */
#include <linux/config.h>
#include <linux/config.h>
 
 
 
 
#include "sound_config.h"
#include "sound_config.h"
 
 
#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
 
 
static wait_handle *in_sleeper[MAX_AUDIO_DEV] =
static wait_handle *in_sleeper[MAX_AUDIO_DEV] =
{NULL};
{NULL};
static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] =
static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] =
{
{
  {0}};
  {0}};
static wait_handle *out_sleeper[MAX_AUDIO_DEV] =
static wait_handle *out_sleeper[MAX_AUDIO_DEV] =
{NULL};
{NULL};
static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] =
static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] =
{
{
  {0}};
  {0}};
 
 
#define NEUTRAL8        0x80
#define NEUTRAL8        0x80
#define NEUTRAL16       0x00
#define NEUTRAL16       0x00
 
 
static int      ndmaps = 0;
static int      ndmaps = 0;
 
 
#define MAX_DMAP (MAX_AUDIO_DEV*2)
#define MAX_DMAP (MAX_AUDIO_DEV*2)
 
 
static struct dma_buffparms dmaps[MAX_DMAP] =
static struct dma_buffparms dmaps[MAX_DMAP] =
{
{
  {0}};
  {0}};
 
 
static int      space_in_queue (int dev);
static int      space_in_queue (int dev);
 
 
static void     dma_reset_output (int dev);
static void     dma_reset_output (int dev);
static void     dma_reset_input (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 int      dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact);
 
 
static void
static void
reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording)
reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording)
{
{
  /*
  /*
   * This routine breaks the physical device buffers to logical ones.
   * This routine breaks the physical device buffers to logical ones.
   */
   */
 
 
  struct audio_operations *dsp_dev = audio_devs[dev];
  struct audio_operations *dsp_dev = audio_devs[dev];
 
 
  unsigned        i, n;
  unsigned        i, n;
  unsigned        sr, nc, sz, bsz;
  unsigned        sr, nc, sz, bsz;
 
 
  if (dmap->fragment_size == 0)
  if (dmap->fragment_size == 0)
    {                           /* Compute the fragment size using the default algorithm */
    {                           /* Compute the fragment size using the default algorithm */
 
 
      sr = dsp_dev->d->set_speed (dev, 0);
      sr = dsp_dev->d->set_speed (dev, 0);
      nc = dsp_dev->d->set_channels (dev, 0);
      nc = dsp_dev->d->set_channels (dev, 0);
      sz = dsp_dev->d->set_bits (dev, 0);
      sz = dsp_dev->d->set_bits (dev, 0);
 
 
      if (sz == 8)
      if (sz == 8)
        dmap->neutral_byte = NEUTRAL8;
        dmap->neutral_byte = NEUTRAL8;
      else
      else
        dmap->neutral_byte = NEUTRAL16;
        dmap->neutral_byte = NEUTRAL16;
 
 
      if (sr < 1 || nc < 1 || sz < 1)
      if (sr < 1 || nc < 1 || sz < 1)
        {
        {
          printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
          printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
                  dev, sr, nc, sz);
                  dev, sr, nc, sz);
          sr = DSP_DEFAULT_SPEED;
          sr = DSP_DEFAULT_SPEED;
          nc = 1;
          nc = 1;
          sz = 8;
          sz = 8;
        }
        }
 
 
      sz = sr * nc * sz;
      sz = sr * nc * sz;
 
 
      sz /= 8;                  /* #bits -> #bytes */
      sz /= 8;                  /* #bits -> #bytes */
 
 
      /*
      /*
         * Compute a buffer size for time not exceeding 1 second.
         * Compute a buffer size for time not exceeding 1 second.
         * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
         * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
         * of sound (using the current speed, sample size and #channels).
         * of sound (using the current speed, sample size and #channels).
       */
       */
 
 
      bsz = dsp_dev->buffsize;
      bsz = dsp_dev->buffsize;
      while (bsz > sz)
      while (bsz > sz)
        bsz /= 2;
        bsz /= 2;
 
 
      if (bsz == dsp_dev->buffsize)
      if (bsz == dsp_dev->buffsize)
        bsz /= 2;               /* Needs at least 2 buffers */
        bsz /= 2;               /* Needs at least 2 buffers */
 
 
/*
/*
 *    Split the computed fragment to smaller parts. After 3.5a9
 *    Split the computed fragment to smaller parts. After 3.5a9
 *      the default subdivision is 4 which should give better
 *      the default subdivision is 4 which should give better
 *      results when recording.
 *      results when recording.
 */
 */
 
 
      if (dmap->subdivision == 0)        /* Not already set */
      if (dmap->subdivision == 0)        /* Not already set */
        {
        {
          dmap->subdivision = 1;        /* Init to the default value */
          dmap->subdivision = 1;        /* Init to the default value */
#ifndef V35A9_COMPATIBLE
#ifndef V35A9_COMPATIBLE
          if (recording)
          if (recording)
            dmap->subdivision = 4;      /* Use shorter fragments when recording */
            dmap->subdivision = 4;      /* Use shorter fragments when recording */
#endif
#endif
        }
        }
 
 
      bsz /= dmap->subdivision;
      bsz /= dmap->subdivision;
 
 
      if (bsz < 16)
      if (bsz < 16)
        bsz = 16;               /* Just a sanity check */
        bsz = 16;               /* Just a sanity check */
 
 
      dmap->fragment_size = bsz;
      dmap->fragment_size = bsz;
    }
    }
  else
  else
    {
    {
      /*
      /*
         * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
         * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
         * the buffer size computation has already been done.
         * the buffer size computation has already been done.
       */
       */
      if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
      if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
        dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
        dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
      bsz = dmap->fragment_size;
      bsz = dmap->fragment_size;
    }
    }
 
 
  bsz &= ~0x03;                 /* Force size which is multiple of 4 bytes */
  bsz &= ~0x03;                 /* Force size which is multiple of 4 bytes */
#ifdef OS_DMA_ALIGN_CHECK
#ifdef OS_DMA_ALIGN_CHECK
  OS_DMA_ALIGN_CHECK (bsz);
  OS_DMA_ALIGN_CHECK (bsz);
#endif
#endif
 
 
  n = dsp_dev->buffsize / bsz;
  n = dsp_dev->buffsize / bsz;
  if (n > MAX_SUB_BUFFERS)
  if (n > MAX_SUB_BUFFERS)
    n = MAX_SUB_BUFFERS;
    n = MAX_SUB_BUFFERS;
  if (n > dmap->max_fragments)
  if (n > dmap->max_fragments)
    n = dmap->max_fragments;
    n = dmap->max_fragments;
  dmap->nbufs = n;
  dmap->nbufs = n;
  dmap->bytes_in_use = n * bsz;
  dmap->bytes_in_use = n * bsz;
 
 
  if (dmap->raw_buf)
  if (dmap->raw_buf)
    memset (dmap->raw_buf,
    memset (dmap->raw_buf,
            dmap->neutral_byte,
            dmap->neutral_byte,
            dmap->bytes_in_use);
            dmap->bytes_in_use);
 
 
  for (i = 0; i < dmap->nbufs; i++)
  for (i = 0; i < dmap->nbufs; i++)
    {
    {
      dmap->counts[i] = 0;
      dmap->counts[i] = 0;
    }
    }
 
 
  dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
  dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
}
}
 
 
static void
static void
dma_init_buffers (int dev, struct dma_buffparms *dmap)
dma_init_buffers (int dev, struct dma_buffparms *dmap)
{
{
  if (dmap == audio_devs[dev]->dmap_out)
  if (dmap == audio_devs[dev]->dmap_out)
    {
    {
      out_sleep_flag[dev].flags = WK_NONE;
      out_sleep_flag[dev].flags = WK_NONE;
    }
    }
  else
  else
    {
    {
      in_sleep_flag[dev].flags = WK_NONE;
      in_sleep_flag[dev].flags = WK_NONE;
    }
    }
 
 
  dmap->flags = DMA_BUSY;       /* Other flags off */
  dmap->flags = DMA_BUSY;       /* Other flags off */
  dmap->qlen = dmap->qhead = dmap->qtail = 0;
  dmap->qlen = dmap->qhead = dmap->qtail = 0;
  dmap->nbufs = 1;
  dmap->nbufs = 1;
  dmap->bytes_in_use = audio_devs[dev]->buffsize;
  dmap->bytes_in_use = audio_devs[dev]->buffsize;
 
 
  dmap->dma_mode = DMODE_NONE;
  dmap->dma_mode = DMODE_NONE;
  dmap->mapping_flags = 0;
  dmap->mapping_flags = 0;
  dmap->neutral_byte = NEUTRAL8;
  dmap->neutral_byte = NEUTRAL8;
  dmap->cfrag = -1;
  dmap->cfrag = -1;
  dmap->closing = 0;
  dmap->closing = 0;
}
}
 
 
static int
static int
open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan)
open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan)
{
{
  if (dmap->flags & DMA_BUSY)
  if (dmap->flags & DMA_BUSY)
    return -(EBUSY);
    return -(EBUSY);
 
 
  {
  {
    int             err;
    int             err;
 
 
    if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0)
    if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0)
      return err;
      return err;
  }
  }
 
 
  if (dmap->raw_buf == NULL)
  if (dmap->raw_buf == NULL)
    return -(ENOSPC);           /* Memory allocation failed during boot */
    return -(ENOSPC);           /* Memory allocation failed during boot */
 
 
  if (sound_open_dma (chan, audio_devs[dev]->name))
  if (sound_open_dma (chan, audio_devs[dev]->name))
    {
    {
      printk ("Unable to grab(2) DMA%d for the audio driver\n", chan);
      printk ("Unable to grab(2) DMA%d for the audio driver\n", chan);
      return -(EBUSY);
      return -(EBUSY);
    }
    }
 
 
  dmap->open_mode = mode;
  dmap->open_mode = mode;
  dmap->subdivision = dmap->underrun_count = 0;
  dmap->subdivision = dmap->underrun_count = 0;
  dmap->fragment_size = 0;
  dmap->fragment_size = 0;
  dmap->max_fragments = 65536;  /* Just a large value */
  dmap->max_fragments = 65536;  /* Just a large value */
  dmap->byte_counter = 0;
  dmap->byte_counter = 0;
 
 
  dma_init_buffers (dev, dmap);
  dma_init_buffers (dev, dmap);
 
 
  return 0;
  return 0;
}
}
 
 
static void
static void
close_dmap (int dev, struct dma_buffparms *dmap, int chan)
close_dmap (int dev, struct dma_buffparms *dmap, int chan)
{
{
  sound_close_dma (chan);
  sound_close_dma (chan);
 
 
  if (dmap->flags & DMA_BUSY)
  if (dmap->flags & DMA_BUSY)
    dmap->dma_mode = DMODE_NONE;
    dmap->dma_mode = DMODE_NONE;
  dmap->flags &= ~DMA_BUSY;
  dmap->flags &= ~DMA_BUSY;
 
 
  disable_dma (chan);
  disable_dma (chan);
  sound_free_dmap (dev, dmap);
  sound_free_dmap (dev, dmap);
}
}
 
 
static unsigned int
static unsigned int
default_set_bits (int dev, unsigned int bits)
default_set_bits (int dev, unsigned int bits)
{
{
  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) (long) bits, 1);
  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) (long) bits, 1);
}
}
 
 
static int
static int
default_set_speed (int dev, int speed)
default_set_speed (int dev, int speed)
{
{
  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) (long) speed, 1);
  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) (long) speed, 1);
}
}
 
 
static short
static short
default_set_channels (int dev, short channels)
default_set_channels (int dev, short channels)
{
{
  int             c = channels;
  int             c = channels;
 
 
  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) (long) c, 1);
  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) (long) c, 1);
}
}
 
 
static void
static void
check_driver (struct audio_driver *d)
check_driver (struct audio_driver *d)
{
{
  if (d->set_speed == NULL)
  if (d->set_speed == NULL)
    d->set_speed = default_set_speed;
    d->set_speed = default_set_speed;
  if (d->set_bits == NULL)
  if (d->set_bits == NULL)
    d->set_bits = default_set_bits;
    d->set_bits = default_set_bits;
  if (d->set_channels == NULL)
  if (d->set_channels == NULL)
    d->set_channels = default_set_channels;
    d->set_channels = default_set_channels;
}
}
 
 
int
int
DMAbuf_open (int dev, int mode)
DMAbuf_open (int dev, int mode)
{
{
  int             retval;
  int             retval;
  struct dma_buffparms *dmap_in = NULL;
  struct dma_buffparms *dmap_in = NULL;
  struct dma_buffparms *dmap_out = NULL;
  struct dma_buffparms *dmap_out = NULL;
 
 
  if (dev >= num_audiodevs)
  if (dev >= num_audiodevs)
    {
    {
      /*  printk ("PCM device %d not installed.\n", dev); */
      /*  printk ("PCM device %d not installed.\n", dev); */
      return -(ENXIO);
      return -(ENXIO);
    }
    }
 
 
  if (!audio_devs[dev])
  if (!audio_devs[dev])
    {
    {
      /* printk ("PCM device %d not initialized\n", dev); */
      /* printk ("PCM device %d not initialized\n", dev); */
      return -(ENXIO);
      return -(ENXIO);
    }
    }
 
 
  if (!(audio_devs[dev]->flags & DMA_DUPLEX))
  if (!(audio_devs[dev]->flags & DMA_DUPLEX))
    {
    {
      audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
      audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
      audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
      audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
    }
    }
 
 
  if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0)
  if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0)
    return retval;
    return retval;
 
 
  check_driver (audio_devs[dev]->d);
  check_driver (audio_devs[dev]->d);
 
 
  dmap_out = audio_devs[dev]->dmap_out;
  dmap_out = audio_devs[dev]->dmap_out;
  dmap_in = audio_devs[dev]->dmap_in;
  dmap_in = audio_devs[dev]->dmap_in;
 
 
  if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0)
  if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0)
    {
    {
      audio_devs[dev]->d->close (dev);
      audio_devs[dev]->d->close (dev);
      return retval;
      return retval;
    }
    }
 
 
  audio_devs[dev]->enable_bits = mode;
  audio_devs[dev]->enable_bits = mode;
  if (mode & OPEN_READ &&
  if (mode & OPEN_READ &&
      audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in)
      audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in)
    if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0)
    if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0)
      {
      {
        audio_devs[dev]->d->close (dev);
        audio_devs[dev]->d->close (dev);
        close_dmap (dev, dmap_out, audio_devs[dev]->dmachan1);
        close_dmap (dev, dmap_out, audio_devs[dev]->dmachan1);
        return retval;
        return retval;
      }
      }
  audio_devs[dev]->open_mode = mode;
  audio_devs[dev]->open_mode = mode;
  audio_devs[dev]->go = 1;
  audio_devs[dev]->go = 1;
  in_sleep_flag[dev].flags = WK_NONE;
  in_sleep_flag[dev].flags = WK_NONE;
  out_sleep_flag[dev].flags = WK_NONE;
  out_sleep_flag[dev].flags = WK_NONE;
 
 
  audio_devs[dev]->d->set_bits (dev, 8);
  audio_devs[dev]->d->set_bits (dev, 8);
  audio_devs[dev]->d->set_channels (dev, 1);
  audio_devs[dev]->d->set_channels (dev, 1);
  audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED);
  audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED);
 
 
  return 0;
  return 0;
}
}
 
 
static void
static void
dma_reset (int dev)
dma_reset (int dev)
{
{
  unsigned long   flags;
  unsigned long   flags;
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  audio_devs[dev]->d->reset (dev);
  audio_devs[dev]->d->reset (dev);
  restore_flags (flags);
  restore_flags (flags);
 
 
  dma_reset_output (dev);
  dma_reset_output (dev);
 
 
  if (audio_devs[dev]->flags & DMA_DUPLEX &&
  if (audio_devs[dev]->flags & DMA_DUPLEX &&
      audio_devs[dev]->open_mode & OPEN_READ)
      audio_devs[dev]->open_mode & OPEN_READ)
    dma_reset_input (dev);
    dma_reset_input (dev);
}
}
 
 
static void
static void
dma_reset_output (int dev)
dma_reset_output (int dev)
{
{
  unsigned long   flags;
  unsigned long   flags;
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
      !audio_devs[dev]->d->halt_output)
      !audio_devs[dev]->d->halt_output)
    audio_devs[dev]->d->reset (dev);
    audio_devs[dev]->d->reset (dev);
  else
  else
    audio_devs[dev]->d->halt_output (dev);
    audio_devs[dev]->d->halt_output (dev);
  restore_flags (flags);
  restore_flags (flags);
 
 
  dma_init_buffers (dev, audio_devs[dev]->dmap_out);
  dma_init_buffers (dev, audio_devs[dev]->dmap_out);
  reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0);
  reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0);
}
}
 
 
static void
static void
dma_reset_input (int dev)
dma_reset_input (int dev)
{
{
  unsigned long   flags;
  unsigned long   flags;
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
      !audio_devs[dev]->d->halt_input)
      !audio_devs[dev]->d->halt_input)
    audio_devs[dev]->d->reset (dev);
    audio_devs[dev]->d->reset (dev);
  else
  else
    audio_devs[dev]->d->halt_input (dev);
    audio_devs[dev]->d->halt_input (dev);
  restore_flags (flags);
  restore_flags (flags);
 
 
  dma_init_buffers (dev, audio_devs[dev]->dmap_in);
  dma_init_buffers (dev, audio_devs[dev]->dmap_in);
  reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1);
  reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1);
}
}
 
 
static int
static int
dma_sync (int dev)
dma_sync (int dev)
{
{
  unsigned long   flags;
  unsigned long   flags;
 
 
  if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
  if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
    return 0;
    return 0;
 
 
  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
    {
    {
      save_flags (flags);
      save_flags (flags);
      cli ();
      cli ();
 
 
      audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
      audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
 
 
      audio_devs[dev]->dmap_out->underrun_count = 0;
      audio_devs[dev]->dmap_out->underrun_count = 0;
      while (!current_got_fatal_signal ()
      while (!current_got_fatal_signal ()
             && audio_devs[dev]->dmap_out->qlen
             && audio_devs[dev]->dmap_out->qlen
             && audio_devs[dev]->dmap_out->underrun_count == 0)
             && audio_devs[dev]->dmap_out->underrun_count == 0)
        {
        {
 
 
          {
          {
            unsigned long   tlimit;
            unsigned long   tlimit;
 
 
            if (HZ)
            if (HZ)
              current_set_timeout (tlimit = jiffies + (HZ));
              current_set_timeout (tlimit = jiffies + (HZ));
            else
            else
              tlimit = (unsigned long) -1;
              tlimit = (unsigned long) -1;
            out_sleep_flag[dev].flags = WK_SLEEP;
            out_sleep_flag[dev].flags = WK_SLEEP;
            module_interruptible_sleep_on (&out_sleeper[dev]);
            module_interruptible_sleep_on (&out_sleeper[dev]);
            if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
            if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
              {
              {
                if (jiffies >= tlimit)
                if (jiffies >= tlimit)
                  out_sleep_flag[dev].flags |= WK_TIMEOUT;
                  out_sleep_flag[dev].flags |= WK_TIMEOUT;
              }
              }
            out_sleep_flag[dev].flags &= ~WK_SLEEP;
            out_sleep_flag[dev].flags &= ~WK_SLEEP;
          };
          };
          if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
          if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
            {
            {
              audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
              audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
              restore_flags (flags);
              restore_flags (flags);
              return audio_devs[dev]->dmap_out->qlen;
              return audio_devs[dev]->dmap_out->qlen;
            }
            }
        }
        }
      audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
      audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
      restore_flags (flags);
      restore_flags (flags);
 
 
      /*
      /*
       * Some devices such as GUS have huge amount of on board RAM for the
       * 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.
       * audio data. We have to wait until the device has finished playing.
       */
       */
      save_flags (flags);
      save_flags (flags);
      cli ();
      cli ();
      if (audio_devs[dev]->d->local_qlen)       /* Device has hidden buffers */
      if (audio_devs[dev]->d->local_qlen)       /* Device has hidden buffers */
        {
        {
          while (!(current_got_fatal_signal ())
          while (!(current_got_fatal_signal ())
                 && audio_devs[dev]->d->local_qlen (dev))
                 && audio_devs[dev]->d->local_qlen (dev))
            {
            {
 
 
              {
              {
                unsigned long   tlimit;
                unsigned long   tlimit;
 
 
                if (HZ)
                if (HZ)
                  current_set_timeout (tlimit = jiffies + (HZ));
                  current_set_timeout (tlimit = jiffies + (HZ));
                else
                else
                  tlimit = (unsigned long) -1;
                  tlimit = (unsigned long) -1;
                out_sleep_flag[dev].flags = WK_SLEEP;
                out_sleep_flag[dev].flags = WK_SLEEP;
                module_interruptible_sleep_on (&out_sleeper[dev]);
                module_interruptible_sleep_on (&out_sleeper[dev]);
                if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
                if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
                  {
                  {
                    if (jiffies >= tlimit)
                    if (jiffies >= tlimit)
                      out_sleep_flag[dev].flags |= WK_TIMEOUT;
                      out_sleep_flag[dev].flags |= WK_TIMEOUT;
                  }
                  }
                out_sleep_flag[dev].flags &= ~WK_SLEEP;
                out_sleep_flag[dev].flags &= ~WK_SLEEP;
              };
              };
            }
            }
        }
        }
      restore_flags (flags);
      restore_flags (flags);
    }
    }
  return audio_devs[dev]->dmap_out->qlen;
  return audio_devs[dev]->dmap_out->qlen;
}
}
 
 
int
int
DMAbuf_release (int dev, int mode)
DMAbuf_release (int dev, int mode)
{
{
  unsigned long   flags;
  unsigned long   flags;
 
 
  audio_devs[dev]->dmap_out->closing = 1;
  audio_devs[dev]->dmap_out->closing = 1;
  audio_devs[dev]->dmap_in->closing = 1;
  audio_devs[dev]->dmap_in->closing = 1;
 
 
  if (!(current_got_fatal_signal ())
  if (!(current_got_fatal_signal ())
      && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
      && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
    {
    {
      dma_sync (dev);
      dma_sync (dev);
    }
    }
 
 
  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
    memset (audio_devs[dev]->dmap_out->raw_buf,
    memset (audio_devs[dev]->dmap_out->raw_buf,
            audio_devs[dev]->dmap_out->neutral_byte,
            audio_devs[dev]->dmap_out->neutral_byte,
            audio_devs[dev]->dmap_out->bytes_in_use);
            audio_devs[dev]->dmap_out->bytes_in_use);
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
 
 
  audio_devs[dev]->d->halt_xfer (dev);
  audio_devs[dev]->d->halt_xfer (dev);
  audio_devs[dev]->d->close (dev);
  audio_devs[dev]->d->close (dev);
 
 
  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
 
 
  if (audio_devs[dev]->open_mode & OPEN_READ &&
  if (audio_devs[dev]->open_mode & OPEN_READ &&
      audio_devs[dev]->flags & DMA_DUPLEX)
      audio_devs[dev]->flags & DMA_DUPLEX)
    close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
    close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
  audio_devs[dev]->open_mode = 0;
  audio_devs[dev]->open_mode = 0;
 
 
  restore_flags (flags);
  restore_flags (flags);
 
 
  return 0;
  return 0;
}
}
 
 
static int
static int
activate_recording (int dev, struct dma_buffparms *dmap)
activate_recording (int dev, struct dma_buffparms *dmap)
{
{
  int             prepare = 0;
  int             prepare = 0;
 
 
  if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
  if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
    return 0;
    return 0;
 
 
  if (dmap->flags & DMA_RESTART)
  if (dmap->flags & DMA_RESTART)
    {
    {
      dma_reset_input (dev);
      dma_reset_input (dev);
      dmap->flags &= ~DMA_RESTART;
      dmap->flags &= ~DMA_RESTART;
      prepare = 1;
      prepare = 1;
    }
    }
 
 
  if (dmap->dma_mode == DMODE_OUTPUT)   /* Direction change */
  if (dmap->dma_mode == DMODE_OUTPUT)   /* Direction change */
    {
    {
      dma_sync (dev);
      dma_sync (dev);
      dma_reset (dev);
      dma_reset (dev);
      dmap->dma_mode = DMODE_NONE;
      dmap->dma_mode = DMODE_NONE;
    }
    }
 
 
  if (!(dmap->flags & DMA_ALLOC_DONE))
  if (!(dmap->flags & DMA_ALLOC_DONE))
    reorganize_buffers (dev, dmap, 1);
    reorganize_buffers (dev, dmap, 1);
 
 
  if (prepare || !dmap->dma_mode)
  if (prepare || !dmap->dma_mode)
    {
    {
      int             err;
      int             err;
 
 
      if ((err = audio_devs[dev]->d->prepare_for_input (dev,
      if ((err = audio_devs[dev]->d->prepare_for_input (dev,
                                     dmap->fragment_size, dmap->nbufs)) < 0)
                                     dmap->fragment_size, dmap->nbufs)) < 0)
        {
        {
          return err;
          return err;
        }
        }
      dmap->dma_mode = DMODE_INPUT;
      dmap->dma_mode = DMODE_INPUT;
    }
    }
 
 
  if (!(dmap->flags & DMA_ACTIVE))
  if (!(dmap->flags & DMA_ACTIVE))
    {
    {
      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
                                       dmap->qtail * dmap->fragment_size,
                                       dmap->qtail * dmap->fragment_size,
                                       dmap->fragment_size, 0,
                                       dmap->fragment_size, 0,
                                 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
                                 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
                                       !(dmap->flags & DMA_STARTED));
                                       !(dmap->flags & DMA_STARTED));
      dmap->flags |= DMA_ACTIVE | DMA_STARTED;
      dmap->flags |= DMA_ACTIVE | DMA_STARTED;
      if (audio_devs[dev]->d->trigger)
      if (audio_devs[dev]->d->trigger)
        audio_devs[dev]->d->trigger (dev,
        audio_devs[dev]->d->trigger (dev,
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
    }
    }
  return 0;
  return 0;
}
}
 
 
int
int
DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
{
{
  unsigned long   flags;
  unsigned long   flags;
  int             err = EIO;
  int             err = EIO;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
    {
    {
      printk ("Sound: Can't read from mmapped device (1)\n");
      printk ("Sound: Can't read from mmapped device (1)\n");
      return -(EINVAL);
      return -(EINVAL);
    }
    }
  else if (!dmap->qlen)
  else if (!dmap->qlen)
    {
    {
      int             tmout;
      int             tmout;
 
 
      if ((err = activate_recording (dev, dmap)) < 0)
      if ((err = activate_recording (dev, dmap)) < 0)
        {
        {
          restore_flags (flags);
          restore_flags (flags);
          return err;
          return err;
        }
        }
 
 
      /* Wait for the next block */
      /* Wait for the next block */
 
 
      if (dontblock)
      if (dontblock)
        {
        {
          restore_flags (flags);
          restore_flags (flags);
          return -(EAGAIN);
          return -(EAGAIN);
        }
        }
 
 
      if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
      if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
          audio_devs[dev]->go)
          audio_devs[dev]->go)
        {
        {
          restore_flags (flags);
          restore_flags (flags);
          return -(EAGAIN);
          return -(EAGAIN);
        }
        }
 
 
      if (!audio_devs[dev]->go)
      if (!audio_devs[dev]->go)
        tmout = 0;
        tmout = 0;
      else
      else
        tmout = 10 * HZ;
        tmout = 10 * HZ;
 
 
 
 
      {
      {
        unsigned long   tlimit;
        unsigned long   tlimit;
 
 
        if (tmout)
        if (tmout)
          current_set_timeout (tlimit = jiffies + (tmout));
          current_set_timeout (tlimit = jiffies + (tmout));
        else
        else
          tlimit = (unsigned long) -1;
          tlimit = (unsigned long) -1;
        in_sleep_flag[dev].flags = WK_SLEEP;
        in_sleep_flag[dev].flags = WK_SLEEP;
        module_interruptible_sleep_on (&in_sleeper[dev]);
        module_interruptible_sleep_on (&in_sleeper[dev]);
        if (!(in_sleep_flag[dev].flags & WK_WAKEUP))
        if (!(in_sleep_flag[dev].flags & WK_WAKEUP))
          {
          {
            if (jiffies >= tlimit)
            if (jiffies >= tlimit)
              in_sleep_flag[dev].flags |= WK_TIMEOUT;
              in_sleep_flag[dev].flags |= WK_TIMEOUT;
          }
          }
        in_sleep_flag[dev].flags &= ~WK_SLEEP;
        in_sleep_flag[dev].flags &= ~WK_SLEEP;
      };
      };
      if ((in_sleep_flag[dev].flags & WK_TIMEOUT))
      if ((in_sleep_flag[dev].flags & WK_TIMEOUT))
        {
        {
          printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
          printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
          err = EIO;
          err = EIO;
          audio_devs[dev]->d->reset (dev);
          audio_devs[dev]->d->reset (dev);
          ;
          ;
        }
        }
      else
      else
        err = EINTR;
        err = EINTR;
    }
    }
  restore_flags (flags);
  restore_flags (flags);
 
 
  if (!dmap->qlen)
  if (!dmap->qlen)
    return -(err);
    return -(err);
 
 
  *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + 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];
  *len = dmap->fragment_size - dmap->counts[dmap->qhead];
 
 
  return dmap->qhead;
  return dmap->qhead;
}
}
 
 
int
int
DMAbuf_rmchars (int dev, int buff_no, int c)
DMAbuf_rmchars (int dev, int buff_no, int c)
{
{
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
 
 
  int             p = dmap->counts[dmap->qhead] + c;
  int             p = dmap->counts[dmap->qhead] + c;
 
 
  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
    {
    {
      printk ("Sound: Can't read from mmapped device (2)\n");
      printk ("Sound: Can't read from mmapped device (2)\n");
      return -(EINVAL);
      return -(EINVAL);
    }
    }
  else if (p >= dmap->fragment_size)
  else if (p >= dmap->fragment_size)
    {                           /* This buffer is completely empty */
    {                           /* This buffer is completely empty */
      dmap->counts[dmap->qhead] = 0;
      dmap->counts[dmap->qhead] = 0;
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
        printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
        printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
                dev, dmap->qlen, dmap->nbufs);
                dev, dmap->qlen, dmap->nbufs);
      dmap->qlen--;
      dmap->qlen--;
      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
    }
    }
  else
  else
    dmap->counts[dmap->qhead] = p;
    dmap->counts[dmap->qhead] = p;
 
 
  return 0;
  return 0;
}
}
 
 
static int
static int
dma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
dma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
{
{
  if (fact == 0)
  if (fact == 0)
    {
    {
      fact = dmap->subdivision;
      fact = dmap->subdivision;
      if (fact == 0)
      if (fact == 0)
        fact = 1;
        fact = 1;
      return snd_ioctl_return ((int *) arg, fact);
      return snd_ioctl_return ((int *) arg, fact);
    }
    }
 
 
  if (dmap->subdivision != 0 ||
  if (dmap->subdivision != 0 ||
      dmap->fragment_size)      /* Too late to change */
      dmap->fragment_size)      /* Too late to change */
    return -(EINVAL);
    return -(EINVAL);
 
 
  if (fact > MAX_REALTIME_FACTOR)
  if (fact > MAX_REALTIME_FACTOR)
    return -(EINVAL);
    return -(EINVAL);
 
 
  if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
  if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
    return -(EINVAL);
    return -(EINVAL);
 
 
  dmap->subdivision = fact;
  dmap->subdivision = fact;
  return snd_ioctl_return ((int *) arg, fact);
  return snd_ioctl_return ((int *) arg, fact);
}
}
 
 
static int
static int
dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
{
{
  int             bytes, count;
  int             bytes, count;
 
 
  if (fact == 0)
  if (fact == 0)
    return -(EIO);
    return -(EIO);
 
 
  if (dmap->subdivision != 0 ||
  if (dmap->subdivision != 0 ||
      dmap->fragment_size)      /* Too late to change */
      dmap->fragment_size)      /* Too late to change */
    return -(EINVAL);
    return -(EINVAL);
 
 
  bytes = fact & 0xffff;
  bytes = fact & 0xffff;
  count = (fact >> 16) & 0x7fff;
  count = (fact >> 16) & 0x7fff;
 
 
  if (count == 0)
  if (count == 0)
    count = MAX_SUB_BUFFERS;
    count = MAX_SUB_BUFFERS;
 
 
  if (bytes < 4 || bytes > 17)  /* <16 || > 512k */
  if (bytes < 4 || bytes > 17)  /* <16 || > 512k */
    return -(EINVAL);
    return -(EINVAL);
 
 
  if (count < 2)
  if (count < 2)
    return -(EINVAL);
    return -(EINVAL);
 
 
  if (audio_devs[dev]->min_fragment > 0)
  if (audio_devs[dev]->min_fragment > 0)
    if (bytes < audio_devs[dev]->min_fragment)
    if (bytes < audio_devs[dev]->min_fragment)
      bytes = audio_devs[dev]->min_fragment;
      bytes = audio_devs[dev]->min_fragment;
 
 
#ifdef OS_DMA_MINBITS
#ifdef OS_DMA_MINBITS
  if (bytes < OS_DMA_MINBITS)
  if (bytes < OS_DMA_MINBITS)
    bytes = OS_DMA_MINBITS;
    bytes = OS_DMA_MINBITS;
#endif
#endif
 
 
  dmap->fragment_size = (1 << bytes);
  dmap->fragment_size = (1 << bytes);
  dmap->max_fragments = count;
  dmap->max_fragments = count;
 
 
  if (dmap->fragment_size > audio_devs[dev]->buffsize)
  if (dmap->fragment_size > audio_devs[dev]->buffsize)
    dmap->fragment_size = audio_devs[dev]->buffsize;
    dmap->fragment_size = audio_devs[dev]->buffsize;
 
 
  if (dmap->fragment_size == audio_devs[dev]->buffsize &&
  if (dmap->fragment_size == audio_devs[dev]->buffsize &&
      audio_devs[dev]->flags & DMA_AUTOMODE)
      audio_devs[dev]->flags & DMA_AUTOMODE)
    dmap->fragment_size /= 2;   /* Needs at least 2 buffers */
    dmap->fragment_size /= 2;   /* Needs at least 2 buffers */
 
 
  dmap->subdivision = 1;        /* Disable SNDCTL_DSP_SUBDIVIDE */
  dmap->subdivision = 1;        /* Disable SNDCTL_DSP_SUBDIVIDE */
  if (arg)
  if (arg)
    return snd_ioctl_return ((int *) arg, bytes | (count << 16));
    return snd_ioctl_return ((int *) arg, bytes | (count << 16));
  else
  else
    return 0;
    return 0;
}
}
 
 
static int
static int
get_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap)
get_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap)
{
{
  int             pos;
  int             pos;
  unsigned long   flags;
  unsigned long   flags;
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  if (!(dmap->flags & DMA_ACTIVE))
  if (!(dmap->flags & DMA_ACTIVE))
    pos = 0;
    pos = 0;
  else
  else
    {
    {
      clear_dma_ff (chan);
      clear_dma_ff (chan);
      disable_dma (chan);
      disable_dma (chan);
      pos = get_dma_residue (chan);
      pos = get_dma_residue (chan);
      enable_dma (chan);
      enable_dma (chan);
    }
    }
  restore_flags (flags);
  restore_flags (flags);
  /* printk ("%04x ", pos); */
  /* printk ("%04x ", pos); */
 
 
  if (audio_devs[dev]->flags & DMA_AUTOMODE)
  if (audio_devs[dev]->flags & DMA_AUTOMODE)
    return dmap->bytes_in_use - pos;
    return dmap->bytes_in_use - pos;
  else
  else
    {
    {
      pos = dmap->fragment_size - pos;
      pos = dmap->fragment_size - pos;
      if (pos < 0)
      if (pos < 0)
        return 0;
        return 0;
      return pos;
      return pos;
    }
    }
}
}
 
 
 
 
int
int
DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
{
{
  struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
  struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
  struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
  struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
  long            larg = (long) arg;
  long            larg = (long) arg;
 
 
  switch (cmd)
  switch (cmd)
    {
    {
    case SOUND_PCM_WRITE_RATE:
    case SOUND_PCM_WRITE_RATE:
      if (local)
      if (local)
        return audio_devs[dev]->d->set_speed (dev, larg);
        return audio_devs[dev]->d->set_speed (dev, larg);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_user ((int *) arg)));
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_user ((int *) arg)));
 
 
    case SOUND_PCM_READ_RATE:
    case SOUND_PCM_READ_RATE:
      if (local)
      if (local)
        return audio_devs[dev]->d->set_speed (dev, 0);
        return audio_devs[dev]->d->set_speed (dev, 0);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0));
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0));
 
 
    case SNDCTL_DSP_STEREO:
    case SNDCTL_DSP_STEREO:
      if (local)
      if (local)
        return audio_devs[dev]->d->set_channels (dev, larg + 1) - 1;
        return audio_devs[dev]->d->set_channels (dev, larg + 1) - 1;
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg) + 1) - 1);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg) + 1) - 1);
 
 
    case SOUND_PCM_WRITE_CHANNELS:
    case SOUND_PCM_WRITE_CHANNELS:
      if (local)
      if (local)
        return audio_devs[dev]->d->set_channels (dev, (short) larg);
        return audio_devs[dev]->d->set_channels (dev, (short) larg);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg)));
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg)));
 
 
    case SOUND_PCM_READ_CHANNELS:
    case SOUND_PCM_READ_CHANNELS:
      if (local)
      if (local)
        return audio_devs[dev]->d->set_channels (dev, 0);
        return audio_devs[dev]->d->set_channels (dev, 0);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0));
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0));
 
 
    case SNDCTL_DSP_SAMPLESIZE:
    case SNDCTL_DSP_SAMPLESIZE:
      if (local)
      if (local)
        return audio_devs[dev]->d->set_bits (dev, larg);
        return audio_devs[dev]->d->set_bits (dev, larg);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_user ((int *) arg)));
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_user ((int *) arg)));
 
 
    case SOUND_PCM_READ_BITS:
    case SOUND_PCM_READ_BITS:
      if (local)
      if (local)
        return audio_devs[dev]->d->set_bits (dev, 0);
        return audio_devs[dev]->d->set_bits (dev, 0);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0));
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0));
 
 
    case SNDCTL_DSP_RESET:
    case SNDCTL_DSP_RESET:
      dma_reset (dev);
      dma_reset (dev);
      return 0;
      return 0;
      break;
      break;
 
 
    case SNDCTL_DSP_SYNC:
    case SNDCTL_DSP_SYNC:
      dma_sync (dev);
      dma_sync (dev);
      dma_reset (dev);
      dma_reset (dev);
      return 0;
      return 0;
      break;
      break;
 
 
    case SNDCTL_DSP_GETBLKSIZE:
    case SNDCTL_DSP_GETBLKSIZE:
      if (!(dmap_out->flags & DMA_ALLOC_DONE))
      if (!(dmap_out->flags & DMA_ALLOC_DONE))
        {
        {
          reorganize_buffers (dev, dmap_out,
          reorganize_buffers (dev, dmap_out,
                              (audio_devs[dev]->open_mode == OPEN_READ));
                              (audio_devs[dev]->open_mode == OPEN_READ));
          if (audio_devs[dev]->flags & DMA_DUPLEX &&
          if (audio_devs[dev]->flags & DMA_DUPLEX &&
              audio_devs[dev]->open_mode & OPEN_READ)
              audio_devs[dev]->open_mode & OPEN_READ)
            reorganize_buffers (dev, dmap_in,
            reorganize_buffers (dev, dmap_in,
                                (audio_devs[dev]->open_mode == OPEN_READ));
                                (audio_devs[dev]->open_mode == OPEN_READ));
        }
        }
 
 
      return snd_ioctl_return ((int *) arg, dmap_out->fragment_size);
      return snd_ioctl_return ((int *) arg, dmap_out->fragment_size);
      break;
      break;
 
 
    case SNDCTL_DSP_SUBDIVIDE:
    case SNDCTL_DSP_SUBDIVIDE:
      {
      {
        int             fact = get_user ((int *) arg);
        int             fact = get_user ((int *) arg);
        int             ret;
        int             ret;
 
 
        ret = dma_subdivide (dev, dmap_out, arg, fact);
        ret = dma_subdivide (dev, dmap_out, arg, fact);
        if (ret < 0)
        if (ret < 0)
          return ret;
          return ret;
 
 
        if (audio_devs[dev]->flags & DMA_DUPLEX &&
        if (audio_devs[dev]->flags & DMA_DUPLEX &&
            audio_devs[dev]->open_mode & OPEN_READ)
            audio_devs[dev]->open_mode & OPEN_READ)
          ret = dma_subdivide (dev, dmap_in, arg, fact);
          ret = dma_subdivide (dev, dmap_in, arg, fact);
 
 
        return ret;
        return ret;
      }
      }
      break;
      break;
 
 
    case SNDCTL_DSP_SETDUPLEX:
    case SNDCTL_DSP_SETDUPLEX:
      if (audio_devs[dev]->flags & DMA_DUPLEX)
      if (audio_devs[dev]->flags & DMA_DUPLEX)
        return 0;
        return 0;
      else
      else
        return -(EIO);
        return -(EIO);
      break;
      break;
 
 
    case SNDCTL_DSP_SETFRAGMENT:
    case SNDCTL_DSP_SETFRAGMENT:
      {
      {
        int             fact = get_user ((int *) arg);
        int             fact = get_user ((int *) arg);
        int             ret;
        int             ret;
 
 
        ret = dma_set_fragment (dev, dmap_out, arg, fact);
        ret = dma_set_fragment (dev, dmap_out, arg, fact);
        if (ret < 0)
        if (ret < 0)
          return ret;
          return ret;
 
 
        if (audio_devs[dev]->flags & DMA_DUPLEX &&
        if (audio_devs[dev]->flags & DMA_DUPLEX &&
            audio_devs[dev]->open_mode & OPEN_READ)
            audio_devs[dev]->open_mode & OPEN_READ)
          ret = dma_set_fragment (dev, dmap_in, arg, fact);
          ret = dma_set_fragment (dev, dmap_in, arg, fact);
 
 
        return ret;
        return ret;
      }
      }
      break;
      break;
 
 
    case SNDCTL_DSP_GETISPACE:
    case SNDCTL_DSP_GETISPACE:
    case SNDCTL_DSP_GETOSPACE:
    case SNDCTL_DSP_GETOSPACE:
      if (!local)
      if (!local)
        return -(EINVAL);
        return -(EINVAL);
      else
      else
        {
        {
          struct dma_buffparms *dmap = dmap_out;
          struct dma_buffparms *dmap = dmap_out;
 
 
          audio_buf_info *info = (audio_buf_info *) arg;
          audio_buf_info *info = (audio_buf_info *) arg;
 
 
          if (cmd == SNDCTL_DSP_GETISPACE &&
          if (cmd == SNDCTL_DSP_GETISPACE &&
              !(audio_devs[dev]->open_mode & OPEN_READ))
              !(audio_devs[dev]->open_mode & OPEN_READ))
            return -(EINVAL);
            return -(EINVAL);
 
 
          if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
          if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
            dmap = dmap_in;
            dmap = dmap_in;
 
 
          if (dmap->mapping_flags & DMA_MAP_MAPPED)
          if (dmap->mapping_flags & DMA_MAP_MAPPED)
            return -(EINVAL);
            return -(EINVAL);
 
 
          if (!(dmap->flags & DMA_ALLOC_DONE))
          if (!(dmap->flags & DMA_ALLOC_DONE))
            reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
            reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
 
 
          info->fragstotal = dmap->nbufs;
          info->fragstotal = dmap->nbufs;
 
 
          if (cmd == SNDCTL_DSP_GETISPACE)
          if (cmd == SNDCTL_DSP_GETISPACE)
            info->fragments = dmap->qlen;
            info->fragments = dmap->qlen;
          else
          else
            {
            {
              if (!space_in_queue (dev))
              if (!space_in_queue (dev))
                info->fragments = 0;
                info->fragments = 0;
              else
              else
                {
                {
                  info->fragments = dmap->nbufs - dmap->qlen;
                  info->fragments = dmap->nbufs - dmap->qlen;
                  if (audio_devs[dev]->d->local_qlen)
                  if (audio_devs[dev]->d->local_qlen)
                    {
                    {
                      int             tmp = audio_devs[dev]->d->local_qlen (dev);
                      int             tmp = audio_devs[dev]->d->local_qlen (dev);
 
 
                      if (tmp && info->fragments)
                      if (tmp && info->fragments)
                        tmp--;  /*
                        tmp--;  /*
                                   * This buffer has been counted twice
                                   * This buffer has been counted twice
                                 */
                                 */
                      info->fragments -= tmp;
                      info->fragments -= tmp;
                    }
                    }
                }
                }
            }
            }
 
 
          if (info->fragments < 0)
          if (info->fragments < 0)
            info->fragments = 0;
            info->fragments = 0;
          else if (info->fragments > dmap->nbufs)
          else if (info->fragments > dmap->nbufs)
            info->fragments = dmap->nbufs;
            info->fragments = dmap->nbufs;
 
 
          info->fragsize = dmap->fragment_size;
          info->fragsize = dmap->fragment_size;
          info->bytes = info->fragments * dmap->fragment_size;
          info->bytes = info->fragments * dmap->fragment_size;
 
 
          if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
          if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
            info->bytes -= dmap->counts[dmap->qhead];
            info->bytes -= dmap->counts[dmap->qhead];
        }
        }
      return 0;
      return 0;
 
 
    case SNDCTL_DSP_SETTRIGGER:
    case SNDCTL_DSP_SETTRIGGER:
      {
      {
        unsigned long   flags;
        unsigned long   flags;
 
 
        int             bits = get_user ((int *) arg) & audio_devs[dev]->open_mode;
        int             bits = get_user ((int *) arg) & audio_devs[dev]->open_mode;
        int             changed;
        int             changed;
 
 
        if (audio_devs[dev]->d->trigger == NULL)
        if (audio_devs[dev]->d->trigger == NULL)
          return -(EINVAL);
          return -(EINVAL);
 
 
        if (!(audio_devs[dev]->flags & DMA_DUPLEX))
        if (!(audio_devs[dev]->flags & DMA_DUPLEX))
          if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
          if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
            {
            {
              printk ("Sound: Device doesn't have full duplex capability\n");
              printk ("Sound: Device doesn't have full duplex capability\n");
              return -(EINVAL);
              return -(EINVAL);
            }
            }
 
 
        save_flags (flags);
        save_flags (flags);
        cli ();
        cli ();
        changed = audio_devs[dev]->enable_bits ^ bits;
        changed = audio_devs[dev]->enable_bits ^ bits;
 
 
        if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
        if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
          {
          {
            int             err;
            int             err;
 
 
            if (!(dmap_in->flags & DMA_ALLOC_DONE))
            if (!(dmap_in->flags & DMA_ALLOC_DONE))
              {
              {
                reorganize_buffers (dev, dmap_in, 1);
                reorganize_buffers (dev, dmap_in, 1);
              }
              }
 
 
            if ((err = audio_devs[dev]->d->prepare_for_input (dev,
            if ((err = audio_devs[dev]->d->prepare_for_input (dev,
                               dmap_in->fragment_size, dmap_in->nbufs)) < 0)
                               dmap_in->fragment_size, dmap_in->nbufs)) < 0)
              return -(err);
              return -(err);
 
 
            audio_devs[dev]->enable_bits = bits;
            audio_devs[dev]->enable_bits = bits;
            activate_recording (dev, dmap_in);
            activate_recording (dev, dmap_in);
          }
          }
 
 
        if ((changed & bits) & PCM_ENABLE_OUTPUT &&
        if ((changed & bits) & PCM_ENABLE_OUTPUT &&
            dmap_out->mapping_flags & DMA_MAP_MAPPED &&
            dmap_out->mapping_flags & DMA_MAP_MAPPED &&
            audio_devs[dev]->go)
            audio_devs[dev]->go)
          {
          {
            int             err;
            int             err;
 
 
            if (!(dmap_out->flags & DMA_ALLOC_DONE))
            if (!(dmap_out->flags & DMA_ALLOC_DONE))
              {
              {
                reorganize_buffers (dev, dmap_out, 0);
                reorganize_buffers (dev, dmap_out, 0);
              }
              }
 
 
            if ((err = audio_devs[dev]->d->prepare_for_output (dev,
            if ((err = audio_devs[dev]->d->prepare_for_output (dev,
                             dmap_out->fragment_size, dmap_out->nbufs)) < 0)
                             dmap_out->fragment_size, dmap_out->nbufs)) < 0)
              return -(err);
              return -(err);
 
 
            dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
            dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
            DMAbuf_start_output (dev, 0, dmap_out->fragment_size);
            DMAbuf_start_output (dev, 0, dmap_out->fragment_size);
          }
          }
 
 
        audio_devs[dev]->enable_bits = bits;
        audio_devs[dev]->enable_bits = bits;
        if (changed && audio_devs[dev]->d->trigger)
        if (changed && audio_devs[dev]->d->trigger)
          {
          {
            audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go);
            audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go);
          }
          }
        restore_flags (flags);
        restore_flags (flags);
      }
      }
    case SNDCTL_DSP_GETTRIGGER:
    case SNDCTL_DSP_GETTRIGGER:
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits);
      return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits);
      break;
      break;
 
 
    case SNDCTL_DSP_SETSYNCRO:
    case SNDCTL_DSP_SETSYNCRO:
 
 
      if (!audio_devs[dev]->d->trigger)
      if (!audio_devs[dev]->d->trigger)
        return -(EINVAL);
        return -(EINVAL);
 
 
      audio_devs[dev]->d->trigger (dev, 0);
      audio_devs[dev]->d->trigger (dev, 0);
      audio_devs[dev]->go = 0;
      audio_devs[dev]->go = 0;
      return 0;
      return 0;
      break;
      break;
 
 
    case SNDCTL_DSP_GETIPTR:
    case SNDCTL_DSP_GETIPTR:
      {
      {
        count_info      info;
        count_info      info;
        unsigned long   flags;
        unsigned long   flags;
 
 
        if (!(audio_devs[dev]->open_mode & OPEN_READ))
        if (!(audio_devs[dev]->open_mode & OPEN_READ))
          return -(EINVAL);
          return -(EINVAL);
 
 
        save_flags (flags);
        save_flags (flags);
        cli ();
        cli ();
        info.bytes = audio_devs[dev]->dmap_in->byte_counter;
        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.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);
        info.blocks = audio_devs[dev]->dmap_in->qlen;
        info.blocks = audio_devs[dev]->dmap_in->qlen;
        info.bytes += info.ptr;
        info.bytes += info.ptr;
        memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
        memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
 
 
        if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
        if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
          audio_devs[dev]->dmap_in->qlen = 0;    /* Acknowledge interrupts */
          audio_devs[dev]->dmap_in->qlen = 0;    /* Acknowledge interrupts */
        restore_flags (flags);
        restore_flags (flags);
        return 0;
        return 0;
      }
      }
      break;
      break;
 
 
    case SNDCTL_DSP_GETOPTR:
    case SNDCTL_DSP_GETOPTR:
      {
      {
        count_info      info;
        count_info      info;
        unsigned long   flags;
        unsigned long   flags;
 
 
        if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
        if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
          return -(EINVAL);
          return -(EINVAL);
 
 
        save_flags (flags);
        save_flags (flags);
        cli ();
        cli ();
        info.bytes = audio_devs[dev]->dmap_out->byte_counter;
        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.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);
        info.blocks = audio_devs[dev]->dmap_out->qlen;
        info.blocks = audio_devs[dev]->dmap_out->qlen;
        info.bytes += info.ptr;
        info.bytes += info.ptr;
        memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
        memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
 
 
        if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
        if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
          audio_devs[dev]->dmap_out->qlen = 0;   /* Acknowledge interrupts */
          audio_devs[dev]->dmap_out->qlen = 0;   /* Acknowledge interrupts */
        restore_flags (flags);
        restore_flags (flags);
        return 0;
        return 0;
      }
      }
      break;
      break;
 
 
 
 
    default:
    default:
      return audio_devs[dev]->d->ioctl (dev, cmd, arg, local);
      return audio_devs[dev]->d->ioctl (dev, cmd, arg, local);
    }
    }
 
 
}
}
 
 
/*
/*
 * DMAbuf_start_devices() is called by the /dev/music driver to start
 * DMAbuf_start_devices() is called by the /dev/music driver to start
 * one or more audio devices at desired moment.
 * one or more audio devices at desired moment.
 */
 */
 
 
void
void
DMAbuf_start_devices (unsigned int devmask)
DMAbuf_start_devices (unsigned int devmask)
{
{
  int             dev;
  int             dev;
 
 
  for (dev = 0; dev < num_audiodevs; dev++)
  for (dev = 0; dev < num_audiodevs; dev++)
    if (devmask & (1 << dev))
    if (devmask & (1 << dev))
      if (audio_devs[dev]->open_mode != 0)
      if (audio_devs[dev]->open_mode != 0)
        if (!audio_devs[dev]->go)
        if (!audio_devs[dev]->go)
          {
          {
            /* OK to start the device */
            /* OK to start the device */
            audio_devs[dev]->go = 1;
            audio_devs[dev]->go = 1;
 
 
            if (audio_devs[dev]->d->trigger)
            if (audio_devs[dev]->d->trigger)
              audio_devs[dev]->d->trigger (dev,
              audio_devs[dev]->d->trigger (dev,
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
          }
          }
}
}
 
 
static int
static int
space_in_queue (int dev)
space_in_queue (int dev)
{
{
  int             len, max, tmp;
  int             len, max, tmp;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
 
  if (dmap->qlen >= dmap->nbufs)        /* No space at all */
  if (dmap->qlen >= dmap->nbufs)        /* No space at all */
    return 0;
    return 0;
 
 
  /*
  /*
     * Verify that there are no more pending buffers than the limit
     * Verify that there are no more pending buffers than the limit
     * defined by the process.
     * defined by the process.
   */
   */
 
 
  max = dmap->max_fragments;
  max = dmap->max_fragments;
  len = dmap->qlen;
  len = dmap->qlen;
 
 
  if (audio_devs[dev]->d->local_qlen)
  if (audio_devs[dev]->d->local_qlen)
    {
    {
      tmp = audio_devs[dev]->d->local_qlen (dev);
      tmp = audio_devs[dev]->d->local_qlen (dev);
      if (tmp && len)
      if (tmp && len)
        tmp--;                  /*
        tmp--;                  /*
                                   * This buffer has been counted twice
                                   * This buffer has been counted twice
                                 */
                                 */
      len += tmp;
      len += tmp;
    }
    }
 
 
  if (len >= max)
  if (len >= max)
    return 0;
    return 0;
  return 1;
  return 1;
}
}
 
 
int
int
DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
{
{
  unsigned long   flags;
  unsigned long   flags;
  int             abort, err = EIO;
  int             abort, err = EIO;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
 
  dmap->flags &= ~DMA_CLEAN;
  dmap->flags &= ~DMA_CLEAN;
 
 
  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
    {
    {
      printk ("Sound: Can't write to mmapped device (3)\n");
      printk ("Sound: Can't write to mmapped device (3)\n");
      return -(EINVAL);
      return -(EINVAL);
    }
    }
 
 
  if (dmap->dma_mode == DMODE_INPUT)    /* Direction change */
  if (dmap->dma_mode == DMODE_INPUT)    /* Direction change */
    {
    {
      dma_reset (dev);
      dma_reset (dev);
      dmap->dma_mode = DMODE_NONE;
      dmap->dma_mode = DMODE_NONE;
    }
    }
  else if (dmap->flags & DMA_RESTART)   /* Restart buffering */
  else if (dmap->flags & DMA_RESTART)   /* Restart buffering */
    {
    {
      dma_sync (dev);
      dma_sync (dev);
      dma_reset_output (dev);
      dma_reset_output (dev);
    }
    }
 
 
  dmap->flags &= ~(DMA_RESTART | DMA_EMPTY);
  dmap->flags &= ~(DMA_RESTART | DMA_EMPTY);
 
 
  if (!(dmap->flags & DMA_ALLOC_DONE))
  if (!(dmap->flags & DMA_ALLOC_DONE))
    reorganize_buffers (dev, dmap, 0);
    reorganize_buffers (dev, dmap, 0);
 
 
  if (!dmap->dma_mode)
  if (!dmap->dma_mode)
    {
    {
      int             err;
      int             err;
 
 
      dmap->dma_mode = DMODE_OUTPUT;
      dmap->dma_mode = DMODE_OUTPUT;
      if ((err = audio_devs[dev]->d->prepare_for_output (dev,
      if ((err = audio_devs[dev]->d->prepare_for_output (dev,
                                     dmap->fragment_size, dmap->nbufs)) < 0)
                                     dmap->fragment_size, dmap->nbufs)) < 0)
        return err;
        return err;
    }
    }
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
 
 
  abort = 0;
  abort = 0;
  while (!space_in_queue (dev) &&
  while (!space_in_queue (dev) &&
         !abort)
         !abort)
    {
    {
      int             tmout;
      int             tmout;
 
 
      if (dontblock)
      if (dontblock)
        {
        {
          restore_flags (flags);
          restore_flags (flags);
          return -(EAGAIN);
          return -(EAGAIN);
        }
        }
 
 
      if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
      if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
          audio_devs[dev]->go)
          audio_devs[dev]->go)
        {
        {
          restore_flags (flags);
          restore_flags (flags);
          return -(EAGAIN);
          return -(EAGAIN);
        }
        }
 
 
      /*
      /*
       * Wait for free space
       * Wait for free space
       */
       */
      if (!audio_devs[dev]->go)
      if (!audio_devs[dev]->go)
        tmout = 0;
        tmout = 0;
      else
      else
        tmout = 10 * HZ;
        tmout = 10 * HZ;
 
 
 
 
      {
      {
        unsigned long   tlimit;
        unsigned long   tlimit;
 
 
        if (tmout)
        if (tmout)
          current_set_timeout (tlimit = jiffies + (tmout));
          current_set_timeout (tlimit = jiffies + (tmout));
        else
        else
          tlimit = (unsigned long) -1;
          tlimit = (unsigned long) -1;
        out_sleep_flag[dev].flags = WK_SLEEP;
        out_sleep_flag[dev].flags = WK_SLEEP;
        module_interruptible_sleep_on (&out_sleeper[dev]);
        module_interruptible_sleep_on (&out_sleeper[dev]);
        if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
        if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
          {
          {
            if (jiffies >= tlimit)
            if (jiffies >= tlimit)
              out_sleep_flag[dev].flags |= WK_TIMEOUT;
              out_sleep_flag[dev].flags |= WK_TIMEOUT;
          }
          }
        out_sleep_flag[dev].flags &= ~WK_SLEEP;
        out_sleep_flag[dev].flags &= ~WK_SLEEP;
      };
      };
      if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
      if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
        {
        {
          printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
          printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
          err = EIO;
          err = EIO;
          abort = 1;
          abort = 1;
          ;
          ;
          if (audio_devs[dev]->flags & DMA_AUTOMODE)
          if (audio_devs[dev]->flags & DMA_AUTOMODE)
            dmap->flags |= DMA_RESTART;
            dmap->flags |= DMA_RESTART;
          else
          else
            dmap->flags &= ~DMA_RESTART;
            dmap->flags &= ~DMA_RESTART;
          audio_devs[dev]->d->reset (dev);
          audio_devs[dev]->d->reset (dev);
        }
        }
      else if (current_got_fatal_signal ())
      else if (current_got_fatal_signal ())
        {
        {
          err = EINTR;
          err = EINTR;
          abort = 1;
          abort = 1;
        }
        }
    }
    }
  restore_flags (flags);
  restore_flags (flags);
 
 
  if (!space_in_queue (dev))
  if (!space_in_queue (dev))
    {
    {
      return -(err);            /* Caught a signal ? */
      return -(err);            /* Caught a signal ? */
    }
    }
 
 
  *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
  *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
  *size = dmap->fragment_size;
  *size = dmap->fragment_size;
  dmap->counts[dmap->qtail] = 0;
  dmap->counts[dmap->qtail] = 0;
 
 
  return dmap->qtail;
  return dmap->qtail;
}
}
 
 
int
int
DMAbuf_get_curr_buffer (int dev, int *buf_no, char **dma_buf, int *buf_ptr, int *buf_size)
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_out;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
 
  if (dmap->cfrag < 0)
  if (dmap->cfrag < 0)
    return -1;
    return -1;
 
 
  *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
  *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
  *buf_ptr = dmap->counts[dmap->qtail];
  *buf_ptr = dmap->counts[dmap->qtail];
  *buf_size = dmap->fragment_size;
  *buf_size = dmap->fragment_size;
  return *buf_no = dmap->cfrag;
  return *buf_no = dmap->cfrag;
}
}
 
 
int
int
DMAbuf_set_count (int dev, int buff_no, int l)
DMAbuf_set_count (int dev, int buff_no, int l)
{
{
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
 
  if (buff_no == dmap->qtail)
  if (buff_no == dmap->qtail)
    {
    {
      dmap->cfrag = buff_no;
      dmap->cfrag = buff_no;
      dmap->counts[buff_no] = l;
      dmap->counts[buff_no] = l;
    }
    }
  else
  else
    dmap->cfrag = -1;
    dmap->cfrag = -1;
  return 0;
  return 0;
}
}
 
 
int
int
DMAbuf_start_output (int dev, int buff_no, int l)
DMAbuf_start_output (int dev, int buff_no, int l)
{
{
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  int             restart = 0;
  int             restart = 0;
 
 
  dmap->cfrag = -1;
  dmap->cfrag = -1;
  if (dmap->flags & DMA_RESTART)
  if (dmap->flags & DMA_RESTART)
    restart = 1;
    restart = 1;
 
 
/*
/*
 * Bypass buffering if using mmapped access
 * Bypass buffering if using mmapped access
 */
 */
 
 
  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
    {
    {
      l = dmap->fragment_size;
      l = dmap->fragment_size;
      dmap->counts[dmap->qtail] = l;
      dmap->counts[dmap->qtail] = l;
      dmap->flags &= ~DMA_RESTART;
      dmap->flags &= ~DMA_RESTART;
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
    }
    }
  else
  else
    {
    {
 
 
      dmap->qlen++;
      dmap->qlen++;
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
        printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
        printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
                dev, dmap->qlen, dmap->nbufs);
                dev, dmap->qlen, dmap->nbufs);
 
 
      dmap->counts[dmap->qtail] = l;
      dmap->counts[dmap->qtail] = l;
      if (l < dmap->fragment_size)
      if (l < dmap->fragment_size)
        {
        {
          int             p = dmap->fragment_size * dmap->qtail;
          int             p = dmap->fragment_size * dmap->qtail;
 
 
          dmap->neutral_byte = dmap->raw_buf[p + l - 1];
          dmap->neutral_byte = dmap->raw_buf[p + l - 1];
 
 
          memset (dmap->raw_buf + p + l,
          memset (dmap->raw_buf + p + l,
                  dmap->neutral_byte,
                  dmap->neutral_byte,
                  dmap->fragment_size - l);
                  dmap->fragment_size - l);
        }
        }
      else
      else
        dmap->neutral_byte =
        dmap->neutral_byte =
          dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1];
          dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1];
 
 
      if ((l != dmap->fragment_size) &&
      if ((l != dmap->fragment_size) &&
          ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
          ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
           audio_devs[dev]->flags & NEEDS_RESTART))
           audio_devs[dev]->flags & NEEDS_RESTART))
        dmap->flags |= DMA_RESTART;
        dmap->flags |= DMA_RESTART;
      else
      else
        dmap->flags &= ~DMA_RESTART;
        dmap->flags &= ~DMA_RESTART;
 
 
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
    }
    }
 
 
  if (!(dmap->flags & DMA_ACTIVE))
  if (!(dmap->flags & DMA_ACTIVE))
    {
    {
      dmap->flags |= DMA_ACTIVE;
      dmap->flags |= DMA_ACTIVE;
 
 
      if (restart)
      if (restart)
        audio_devs[dev]->d->prepare_for_output (dev,
        audio_devs[dev]->d->prepare_for_output (dev,
                                          dmap->fragment_size, dmap->nbufs);
                                          dmap->fragment_size, dmap->nbufs);
 
 
      audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
      audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
                                        dmap->qhead * dmap->fragment_size,
                                        dmap->qhead * dmap->fragment_size,
                                        dmap->counts[dmap->qhead], 0,
                                        dmap->counts[dmap->qhead], 0,
                                 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
                                 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
                                        !(dmap->flags & DMA_STARTED));
                                        !(dmap->flags & DMA_STARTED));
      dmap->flags |= DMA_STARTED;
      dmap->flags |= DMA_STARTED;
      if (audio_devs[dev]->d->trigger)
      if (audio_devs[dev]->d->trigger)
        audio_devs[dev]->d->trigger (dev,
        audio_devs[dev]->d->trigger (dev,
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
int
int
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
{
{
  int             chan;
  int             chan;
  struct dma_buffparms *dmap;
  struct dma_buffparms *dmap;
  unsigned long   flags;
  unsigned long   flags;
 
 
  if (dma_mode == DMA_MODE_WRITE)
  if (dma_mode == DMA_MODE_WRITE)
    {
    {
      chan = audio_devs[dev]->dmachan1;
      chan = audio_devs[dev]->dmachan1;
      dmap = audio_devs[dev]->dmap_out;
      dmap = audio_devs[dev]->dmap_out;
    }
    }
  else
  else
    {
    {
      chan = audio_devs[dev]->dmachan2;
      chan = audio_devs[dev]->dmachan2;
      dmap = audio_devs[dev]->dmap_in;
      dmap = audio_devs[dev]->dmap_in;
    }
    }
 
 
  if (dmap->raw_buf_phys == 0)
  if (dmap->raw_buf_phys == 0)
    {
    {
      printk ("sound: DMA buffer == NULL\n");
      printk ("sound: DMA buffer == NULL\n");
      return 0;
      return 0;
    }
    }
 
 
  /*
  /*
   * The count must be one less than the actual size. This is handled by
   * The count must be one less than the actual size. This is handled by
   * set_dma_addr()
   * set_dma_addr()
   */
   */
 
 
  if (audio_devs[dev]->flags & DMA_AUTOMODE)
  if (audio_devs[dev]->flags & DMA_AUTOMODE)
    {                           /*
    {                           /*
                                 * Auto restart mode. Transfer the whole *
                                 * Auto restart mode. Transfer the whole *
                                 * buffer
                                 * buffer
                                 */
                                 */
      save_flags (flags);
      save_flags (flags);
      cli ();
      cli ();
      disable_dma (chan);
      disable_dma (chan);
      clear_dma_ff (chan);
      clear_dma_ff (chan);
      set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
      set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
      set_dma_addr (chan, dmap->raw_buf_phys);
      set_dma_addr (chan, dmap->raw_buf_phys);
      set_dma_count (chan, dmap->bytes_in_use);
      set_dma_count (chan, dmap->bytes_in_use);
      enable_dma (chan);
      enable_dma (chan);
      restore_flags (flags);
      restore_flags (flags);
    }
    }
  else
  else
    {
    {
      save_flags (flags);
      save_flags (flags);
      cli ();
      cli ();
      disable_dma (chan);
      disable_dma (chan);
      clear_dma_ff (chan);
      clear_dma_ff (chan);
      set_dma_mode (chan, dma_mode);
      set_dma_mode (chan, dma_mode);
      set_dma_addr (chan, physaddr);
      set_dma_addr (chan, physaddr);
      set_dma_count (chan, count);
      set_dma_count (chan, count);
      enable_dma (chan);
      enable_dma (chan);
      restore_flags (flags);
      restore_flags (flags);
    }
    }
 
 
  return count;
  return count;
}
}
 
 
void
void
DMAbuf_init (void)
DMAbuf_init (void)
{
{
  int             dev;
  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++)
  for (dev = 0; dev < num_audiodevs; dev++)
    if (audio_devs[dev]->dmap_out == NULL)
    if (audio_devs[dev]->dmap_out == NULL)
      {
      {
        audio_devs[dev]->dmap_out =
        audio_devs[dev]->dmap_out =
          audio_devs[dev]->dmap_in =
          audio_devs[dev]->dmap_in =
          &dmaps[ndmaps++];
          &dmaps[ndmaps++];
 
 
        if (audio_devs[dev]->flags & DMA_DUPLEX)
        if (audio_devs[dev]->flags & DMA_DUPLEX)
          audio_devs[dev]->dmap_in =
          audio_devs[dev]->dmap_in =
            &dmaps[ndmaps++];
            &dmaps[ndmaps++];
      }
      }
}
}
 
 
static void
static void
polish_buffers (struct dma_buffparms *dmap)
polish_buffers (struct dma_buffparms *dmap)
{
{
  int             i;
  int             i;
  int             p, l;
  int             p, l;
 
 
  i = dmap->qhead;
  i = dmap->qhead;
 
 
  p = dmap->fragment_size * i;
  p = dmap->fragment_size * i;
 
 
  if (i == dmap->cfrag)
  if (i == dmap->cfrag)
    {
    {
      l = dmap->fragment_size - dmap->counts[i];
      l = dmap->fragment_size - dmap->counts[i];
    }
    }
  else
  else
    l = dmap->fragment_size;
    l = dmap->fragment_size;
 
 
  if (l)
  if (l)
    {
    {
      memset (dmap->raw_buf + p,
      memset (dmap->raw_buf + p,
              dmap->neutral_byte,
              dmap->neutral_byte,
              l);
              l);
    }
    }
}
}
 
 
static void
static void
force_restart (int dev, struct dma_buffparms *dmap)
force_restart (int dev, struct dma_buffparms *dmap)
{
{
  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
      audio_devs[dev]->d->halt_output)
      audio_devs[dev]->d->halt_output)
    audio_devs[dev]->d->halt_output (dev);
    audio_devs[dev]->d->halt_output (dev);
  else
  else
    audio_devs[dev]->d->halt_xfer (dev);
    audio_devs[dev]->d->halt_xfer (dev);
 
 
  dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED);
  dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED);
  if (audio_devs[dev]->flags & DMA_AUTOMODE)
  if (audio_devs[dev]->flags & DMA_AUTOMODE)
    dmap->flags |= DMA_RESTART;
    dmap->flags |= DMA_RESTART;
  else
  else
    dmap->flags &= ~DMA_RESTART;
    dmap->flags &= ~DMA_RESTART;
}
}
 
 
void
void
DMAbuf_outputintr (int dev, int event_type)
DMAbuf_outputintr (int dev, int event_type)
{
{
  /*
  /*
     * Event types:
     * Event types:
     *  0 = DMA transfer done. Device still has more data in the local
     *  0 = DMA transfer done. Device still has more data in the local
     *      buffer.
     *      buffer.
     *  1 = DMA transfer done. Device doesn't have local buffer or it's
     *  1 = DMA transfer done. Device doesn't have local buffer or it's
     *      empty now.
     *      empty now.
     *  2 = No DMA transfer but the device has now more space in it's local
     *  2 = No DMA transfer but the device has now more space in it's local
     *      buffer.
     *      buffer.
   */
   */
 
 
  unsigned long   flags;
  unsigned long   flags;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  int             this_fragment;
  int             this_fragment;
 
 
  dmap->byte_counter += dmap->counts[dmap->qhead];
  dmap->byte_counter += dmap->counts[dmap->qhead];
 
 
#ifdef OS_DMA_INTR
#ifdef OS_DMA_INTR
  sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
  sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
#endif
#endif
 
 
  if (dmap->raw_buf == NULL)
  if (dmap->raw_buf == NULL)
    {
    {
      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
      return;
      return;
    }
    }
 
 
  if (dmap->mapping_flags & DMA_MAP_MAPPED)
  if (dmap->mapping_flags & DMA_MAP_MAPPED)
    {
    {
      /* mmapped access */
      /* mmapped access */
      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
      dmap->qlen++;             /* Yes increment it (don't decrement) */
      dmap->qlen++;             /* Yes increment it (don't decrement) */
      dmap->flags &= ~DMA_ACTIVE;
      dmap->flags &= ~DMA_ACTIVE;
      dmap->counts[dmap->qhead] = dmap->fragment_size;
      dmap->counts[dmap->qhead] = dmap->fragment_size;
 
 
      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
        {
        {
          audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
          audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
                                          dmap->qhead * dmap->fragment_size,
                                          dmap->qhead * dmap->fragment_size,
                                            dmap->counts[dmap->qhead], 1,
                                            dmap->counts[dmap->qhead], 1,
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
          if (audio_devs[dev]->d->trigger)
          if (audio_devs[dev]->d->trigger)
            audio_devs[dev]->d->trigger (dev,
            audio_devs[dev]->d->trigger (dev,
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
        }
        }
      dmap->flags |= DMA_ACTIVE;
      dmap->flags |= DMA_ACTIVE;
    }
    }
  else if (event_type != 2)
  else if (event_type != 2)
    {
    {
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
        {
        {
          printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
          printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
                  dev, dmap->qlen, dmap->nbufs);
                  dev, dmap->qlen, dmap->nbufs);
          return;
          return;
        }
        }
 
 
      dmap->qlen--;
      dmap->qlen--;
      this_fragment = dmap->qhead;
      this_fragment = dmap->qhead;
      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
      dmap->flags &= ~DMA_ACTIVE;
      dmap->flags &= ~DMA_ACTIVE;
 
 
      if (event_type == 1 && dmap->qlen < 1)
      if (event_type == 1 && dmap->qlen < 1)
        {
        {
          dmap->underrun_count++;
          dmap->underrun_count++;
 
 
          if ((!(dmap->flags & DMA_CLEAN) &&
          if ((!(dmap->flags & DMA_CLEAN) &&
               (audio_devs[dev]->dmap_out->flags & DMA_SYNCING ||
               (audio_devs[dev]->dmap_out->flags & DMA_SYNCING ||
                dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) ||
                dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) ||
              audio_devs[dev]->flags & DMA_HARDSTOP)
              audio_devs[dev]->flags & DMA_HARDSTOP)
 
 
            {
            {
              dmap->qlen = 0;
              dmap->qlen = 0;
              force_restart (dev, dmap);
              force_restart (dev, dmap);
            }
            }
          else
          else
            /* Ignore underrun. Just move the tail pointer forward and go */
            /* Ignore underrun. Just move the tail pointer forward and go */
          if (dmap->closing)
          if (dmap->closing)
            {
            {
              polish_buffers (dmap);
              polish_buffers (dmap);
              audio_devs[dev]->d->halt_xfer (dev);
              audio_devs[dev]->d->halt_xfer (dev);
            }
            }
          else
          else
            {
            {
              dmap->qlen++;
              dmap->qlen++;
              dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
              dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
 
 
              if (!(dmap->flags & DMA_EMPTY))
              if (!(dmap->flags & DMA_EMPTY))
                polish_buffers (dmap);
                polish_buffers (dmap);
 
 
              dmap->cfrag = -1;
              dmap->cfrag = -1;
              dmap->flags |= DMA_EMPTY;
              dmap->flags |= DMA_EMPTY;
              dmap->counts[dmap->qtail] = dmap->fragment_size;
              dmap->counts[dmap->qtail] = dmap->fragment_size;
            }
            }
        }
        }
 
 
      if (dmap->qlen)
      if (dmap->qlen)
        {
        {
          if (dmap->flags & DMA_CLEAN)
          if (dmap->flags & DMA_CLEAN)
            {
            {
              int             p = dmap->fragment_size * this_fragment;
              int             p = dmap->fragment_size * this_fragment;
 
 
              memset (dmap->raw_buf + p,
              memset (dmap->raw_buf + p,
                      dmap->neutral_byte,
                      dmap->neutral_byte,
                      dmap->fragment_size);
                      dmap->fragment_size);
            }
            }
 
 
          if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
          if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
            {
            {
 
 
              if (dmap->counts[dmap->qhead] == 0)
              if (dmap->counts[dmap->qhead] == 0)
                dmap->counts[dmap->qhead] = dmap->fragment_size;
                dmap->counts[dmap->qhead] = dmap->fragment_size;
 
 
              audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
              audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
                                          dmap->qhead * dmap->fragment_size,
                                          dmap->qhead * dmap->fragment_size,
                                                dmap->counts[dmap->qhead], 1,
                                                dmap->counts[dmap->qhead], 1,
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
              if (audio_devs[dev]->d->trigger)
              if (audio_devs[dev]->d->trigger)
                audio_devs[dev]->d->trigger (dev,
                audio_devs[dev]->d->trigger (dev,
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
            }
            }
          dmap->flags |= DMA_ACTIVE;
          dmap->flags |= DMA_ACTIVE;
        }
        }
    }                           /* event_type != 2 */
    }                           /* event_type != 2 */
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  if ((out_sleep_flag[dev].flags & WK_SLEEP))
  if ((out_sleep_flag[dev].flags & WK_SLEEP))
    {
    {
      {
      {
        out_sleep_flag[dev].flags = WK_WAKEUP;
        out_sleep_flag[dev].flags = WK_WAKEUP;
        module_wake_up (&out_sleeper[dev]);
        module_wake_up (&out_sleeper[dev]);
      };
      };
    }
    }
  restore_flags (flags);
  restore_flags (flags);
}
}
 
 
void
void
DMAbuf_inputintr (int dev)
DMAbuf_inputintr (int dev)
{
{
  unsigned long   flags;
  unsigned long   flags;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
 
 
  dmap->byte_counter += dmap->fragment_size;
  dmap->byte_counter += dmap->fragment_size;
 
 
#ifdef OS_DMA_INTR
#ifdef OS_DMA_INTR
  sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
  sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
#endif
#endif
 
 
  if (dmap->raw_buf == NULL)
  if (dmap->raw_buf == NULL)
    {
    {
      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
      return;
      return;
    }
    }
 
 
  if (dmap->mapping_flags & DMA_MAP_MAPPED)
  if (dmap->mapping_flags & DMA_MAP_MAPPED)
    {
    {
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
      dmap->qlen++;
      dmap->qlen++;
 
 
      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
        {
        {
          audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
          audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
                                           dmap->qtail * dmap->fragment_size,
                                           dmap->qtail * dmap->fragment_size,
                                           dmap->fragment_size, 1,
                                           dmap->fragment_size, 1,
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
          if (audio_devs[dev]->d->trigger)
          if (audio_devs[dev]->d->trigger)
            audio_devs[dev]->d->trigger (dev,
            audio_devs[dev]->d->trigger (dev,
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
        }
        }
 
 
      dmap->flags |= DMA_ACTIVE;
      dmap->flags |= DMA_ACTIVE;
    }
    }
  else if (dmap->qlen == (dmap->nbufs - 1))
  else if (dmap->qlen == (dmap->nbufs - 1))
    {
    {
      printk ("Sound: Recording overrun\n");
      printk ("Sound: Recording overrun\n");
      dmap->underrun_count++;
      dmap->underrun_count++;
 
 
      if (audio_devs[dev]->flags & DMA_AUTOMODE)
      if (audio_devs[dev]->flags & DMA_AUTOMODE)
        {
        {
          /* Force restart on next read */
          /* Force restart on next read */
          if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
          if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
              audio_devs[dev]->d->halt_input)
              audio_devs[dev]->d->halt_input)
            audio_devs[dev]->d->halt_input (dev);
            audio_devs[dev]->d->halt_input (dev);
          else
          else
            audio_devs[dev]->d->halt_xfer (dev);
            audio_devs[dev]->d->halt_xfer (dev);
 
 
          dmap->flags &= ~DMA_ACTIVE;
          dmap->flags &= ~DMA_ACTIVE;
          if (audio_devs[dev]->flags & DMA_AUTOMODE)
          if (audio_devs[dev]->flags & DMA_AUTOMODE)
            dmap->flags |= DMA_RESTART;
            dmap->flags |= DMA_RESTART;
          else
          else
            dmap->flags &= ~DMA_RESTART;
            dmap->flags &= ~DMA_RESTART;
        }
        }
    }
    }
  else
  else
    {
    {
      dmap->qlen++;
      dmap->qlen++;
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
        printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
        printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
                dev, dmap->qlen, dmap->nbufs);
                dev, dmap->qlen, dmap->nbufs);
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
    }
    }
 
 
  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
    {
    {
      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
                                       dmap->qtail * dmap->fragment_size,
                                       dmap->qtail * dmap->fragment_size,
                                       dmap->fragment_size, 1,
                                       dmap->fragment_size, 1,
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
                                  !(audio_devs[dev]->flags & DMA_AUTOMODE));
      if (audio_devs[dev]->d->trigger)
      if (audio_devs[dev]->d->trigger)
        audio_devs[dev]->d->trigger (dev,
        audio_devs[dev]->d->trigger (dev,
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
                        audio_devs[dev]->enable_bits * audio_devs[dev]->go);
    }
    }
 
 
  dmap->flags |= DMA_ACTIVE;
  dmap->flags |= DMA_ACTIVE;
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  if ((in_sleep_flag[dev].flags & WK_SLEEP))
  if ((in_sleep_flag[dev].flags & WK_SLEEP))
    {
    {
      {
      {
        in_sleep_flag[dev].flags = WK_WAKEUP;
        in_sleep_flag[dev].flags = WK_WAKEUP;
        module_wake_up (&in_sleeper[dev]);
        module_wake_up (&in_sleeper[dev]);
      };
      };
    }
    }
  restore_flags (flags);
  restore_flags (flags);
}
}
 
 
int
int
DMAbuf_open_dma (int dev)
DMAbuf_open_dma (int dev)
{
{
/*
/*
 *    NOTE!  This routine opens only the primary DMA channel (output).
 *    NOTE!  This routine opens only the primary DMA channel (output).
 */
 */
 
 
  int             chan = audio_devs[dev]->dmachan1;
  int             chan = audio_devs[dev]->dmachan1;
  int             err;
  int             err;
  unsigned long   flags;
  unsigned long   flags;
 
 
  if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0)
  if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0)
    {
    {
      return -(EBUSY);
      return -(EBUSY);
    }
    }
  dma_init_buffers (dev, audio_devs[dev]->dmap_out);
  dma_init_buffers (dev, audio_devs[dev]->dmap_out);
  audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE;
  audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE;
  audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize;
  audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize;
 
 
  save_flags (flags);
  save_flags (flags);
  cli ();
  cli ();
  disable_dma (chan);
  disable_dma (chan);
  clear_dma_ff (chan);
  clear_dma_ff (chan);
  restore_flags (flags);
  restore_flags (flags);
 
 
  return 0;
  return 0;
}
}
 
 
void
void
DMAbuf_close_dma (int dev)
DMAbuf_close_dma (int dev)
{
{
  DMAbuf_reset_dma (dev);
  DMAbuf_reset_dma (dev);
  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
}
}
 
 
void
void
DMAbuf_reset_dma (int dev)
DMAbuf_reset_dma (int dev)
{
{
}
}
 
 
int
int
DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
{
{
  struct dma_buffparms *dmap;
  struct dma_buffparms *dmap;
  unsigned long   flags;
  unsigned long   flags;
 
 
  switch (sel_type)
  switch (sel_type)
    {
    {
    case SEL_IN:
    case SEL_IN:
      dmap = audio_devs[dev]->dmap_in;
      dmap = audio_devs[dev]->dmap_in;
 
 
      if (dmap->mapping_flags & DMA_MAP_MAPPED)
      if (dmap->mapping_flags & DMA_MAP_MAPPED)
        {
        {
          if (dmap->qlen)
          if (dmap->qlen)
            return 1;
            return 1;
 
 
          save_flags (flags);
          save_flags (flags);
          cli ();
          cli ();
 
 
          in_sleep_flag[dev].flags = WK_SLEEP;
          in_sleep_flag[dev].flags = WK_SLEEP;
          module_select_wait (&in_sleeper[dev], wait);
          module_select_wait (&in_sleeper[dev], wait);
          restore_flags (flags);
          restore_flags (flags);
          return 0;
          return 0;
        }
        }
 
 
      if (dmap->dma_mode != DMODE_INPUT)
      if (dmap->dma_mode != DMODE_INPUT)
        {
        {
          if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen &&
          if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen &&
              audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
              audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
              audio_devs[dev]->go)
              audio_devs[dev]->go)
            {
            {
              unsigned long   flags;
              unsigned long   flags;
 
 
              save_flags (flags);
              save_flags (flags);
              cli ();
              cli ();
              activate_recording (dev, dmap);
              activate_recording (dev, dmap);
              restore_flags (flags);
              restore_flags (flags);
            }
            }
          return 0;
          return 0;
        }
        }
 
 
      if (!dmap->qlen)
      if (!dmap->qlen)
        {
        {
          save_flags (flags);
          save_flags (flags);
          cli ();
          cli ();
 
 
          in_sleep_flag[dev].flags = WK_SLEEP;
          in_sleep_flag[dev].flags = WK_SLEEP;
          module_select_wait (&in_sleeper[dev], wait);
          module_select_wait (&in_sleeper[dev], wait);
          restore_flags (flags);
          restore_flags (flags);
          return 0;
          return 0;
        }
        }
      return 1;
      return 1;
      break;
      break;
 
 
    case SEL_OUT:
    case SEL_OUT:
      dmap = audio_devs[dev]->dmap_out;
      dmap = audio_devs[dev]->dmap_out;
 
 
      if (dmap->mapping_flags & DMA_MAP_MAPPED)
      if (dmap->mapping_flags & DMA_MAP_MAPPED)
        {
        {
          if (dmap->qlen)
          if (dmap->qlen)
            return 1;
            return 1;
 
 
          save_flags (flags);
          save_flags (flags);
          cli ();
          cli ();
 
 
          out_sleep_flag[dev].flags = WK_SLEEP;
          out_sleep_flag[dev].flags = WK_SLEEP;
          module_select_wait (&out_sleeper[dev], wait);
          module_select_wait (&out_sleeper[dev], wait);
          restore_flags (flags);
          restore_flags (flags);
          return 0;
          return 0;
        }
        }
 
 
      if (dmap->dma_mode == DMODE_INPUT)
      if (dmap->dma_mode == DMODE_INPUT)
        {
        {
          return 0;
          return 0;
        }
        }
 
 
      if (dmap->dma_mode == DMODE_NONE)
      if (dmap->dma_mode == DMODE_NONE)
        {
        {
          return 1;
          return 1;
        }
        }
 
 
      if (!space_in_queue (dev))
      if (!space_in_queue (dev))
        {
        {
          save_flags (flags);
          save_flags (flags);
          cli ();
          cli ();
 
 
          out_sleep_flag[dev].flags = WK_SLEEP;
          out_sleep_flag[dev].flags = WK_SLEEP;
          module_select_wait (&out_sleeper[dev], wait);
          module_select_wait (&out_sleeper[dev], wait);
          restore_flags (flags);
          restore_flags (flags);
          return 0;
          return 0;
        }
        }
      return 1;
      return 1;
      break;
      break;
 
 
    case SEL_EX:
    case SEL_EX:
      return 0;
      return 0;
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
 
 
#else /* CONFIG_AUDIO */
#else /* CONFIG_AUDIO */
/*
/*
 * Stub versions if audio services not included
 * Stub versions if audio services not included
 */
 */
 
 
int
int
DMAbuf_open (int dev, int mode)
DMAbuf_open (int dev, int mode)
{
{
  return -(ENXIO);
  return -(ENXIO);
}
}
 
 
int
int
DMAbuf_release (int dev, int mode)
DMAbuf_release (int dev, int mode)
{
{
  return 0;
  return 0;
}
}
 
 
int
int
DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
{
{
  return -(EIO);
  return -(EIO);
}
}
 
 
int
int
DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
{
{
  return -(EIO);
  return -(EIO);
}
}
 
 
int
int
DMAbuf_rmchars (int dev, int buff_no, int c)
DMAbuf_rmchars (int dev, int buff_no, int c)
{
{
  return -(EIO);
  return -(EIO);
}
}
 
 
int
int
DMAbuf_start_output (int dev, int buff_no, int l)
DMAbuf_start_output (int dev, int buff_no, int l)
{
{
  return -(EIO);
  return -(EIO);
}
}
 
 
int
int
DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
{
{
  return -(EIO);
  return -(EIO);
}
}
 
 
void
void
DMAbuf_init (void)
DMAbuf_init (void)
{
{
}
}
 
 
int
int
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
{
{
  return -(EIO);
  return -(EIO);
}
}
 
 
int
int
DMAbuf_open_dma (int dev)
DMAbuf_open_dma (int dev)
{
{
  return -(ENXIO);
  return -(ENXIO);
}
}
 
 
void
void
DMAbuf_close_dma (int dev)
DMAbuf_close_dma (int dev)
{
{
  return;
  return;
}
}
 
 
void
void
DMAbuf_reset_dma (int dev)
DMAbuf_reset_dma (int dev)
{
{
  return;
  return;
}
}
 
 
void
void
DMAbuf_inputintr (int dev)
DMAbuf_inputintr (int dev)
{
{
  return;
  return;
}
}
 
 
void
void
DMAbuf_outputintr (int dev, int underrun_flag)
DMAbuf_outputintr (int dev, int underrun_flag)
{
{
  return;
  return;
}
}
#endif
#endif
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.