patch-2.1.28 linux/drivers/sound/dmabuf.c

Next file: linux/drivers/sound/finetune.h
Previous file: linux/drivers/sound/dev_table.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.27/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
@@ -4,14 +4,15 @@
  * The DMA buffer manager for digitized voice applications
  */
 /*
- * Copyright (C) by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
 #include <linux/config.h>
-#include <linux/poll.h>
+
+#undef  BE_CONSERVATIVE
 
 #include "sound_config.h"
 
@@ -28,9 +29,6 @@
 {
   {0}};
 
-#define NEUTRAL8	0x80
-#define NEUTRAL16	0x00
-
 static int      ndmaps = 0;
 
 #define MAX_DMAP (MAX_AUDIO_DEV*2)
@@ -39,130 +37,9 @@
 {
   {0}};
 
-static int      space_in_queue (int dev);
-
 static void     dma_reset_output (int dev);
 static void     dma_reset_input (int dev);
-static int      dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact);
-
-static void
-reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording)
-{
-  /*
-   * This routine breaks the physical device buffers to logical ones.
-   */
-
-  struct audio_operations *dsp_dev = audio_devs[dev];
-
-  unsigned        i, n;
-  unsigned        sr, nc, sz, bsz;
-
-  sr = dsp_dev->d->set_speed (dev, 0);
-  nc = dsp_dev->d->set_channels (dev, 0);
-  sz = dsp_dev->d->set_bits (dev, 0);
-
-  if (sz == 8)
-    dmap->neutral_byte = NEUTRAL8;
-  else
-    dmap->neutral_byte = NEUTRAL16;
-
-  if (sr < 1 || nc < 1 || sz < 1)
-    {
-      printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
-	      dev, sr, nc, sz);
-      sr = DSP_DEFAULT_SPEED;
-      nc = 1;
-      sz = 8;
-    }
-
-  sz = sr * nc * sz;
-
-  sz /= 8;			/* #bits -> #bytes */
-  dmap->data_rate = sz;
-
-  if (dmap->fragment_size == 0)
-    {				/* Compute the fragment size using the default algorithm */
-
-      /*
-         * Compute a buffer size for time not exceeding 1 second.
-         * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
-         * of sound (using the current speed, sample size and #channels).
-       */
-
-      bsz = dsp_dev->buffsize;
-      while (bsz > sz)
-	bsz /= 2;
-
-      if (bsz == dsp_dev->buffsize)
-	bsz /= 2;		/* Needs at least 2 buffers */
-
-/*
- *    Split the computed fragment to smaller parts. After 3.5a9
- *      the default subdivision is 4 which should give better
- *      results when recording.
- */
-
-      if (dmap->subdivision == 0)	/* Not already set */
-	{
-	  dmap->subdivision = 4;	/* Init to the default value */
-
-	  if ((bsz / dmap->subdivision) > 4096)
-	    dmap->subdivision *= 2;
-	  if ((bsz / dmap->subdivision) < 4096)
-	    dmap->subdivision = 1;
-	}
-
-      bsz /= dmap->subdivision;
-
-      if (bsz < 16)
-	bsz = 16;		/* Just a sanity check */
-
-      dmap->fragment_size = bsz;
-    }
-  else
-    {
-      /*
-         * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
-         * the buffer size computation has already been done.
-       */
-      if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
-	dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
-      bsz = dmap->fragment_size;
-    }
-
-  bsz &= ~0x03;			/* Force size which is multiple of 4 bytes */
-#ifdef OS_DMA_ALIGN_CHECK
-  OS_DMA_ALIGN_CHECK (bsz);
-#endif
-
-  n = dsp_dev->buffsize / bsz;
-  if (n > MAX_SUB_BUFFERS)
-    n = MAX_SUB_BUFFERS;
-  if (n > dmap->max_fragments)
-    n = dmap->max_fragments;
-
-  if (n < 2)
-    {
-      n = 2;
-      bsz /= 2;
-    }
-
-  dmap->nbufs = n;
-  dmap->bytes_in_use = n * bsz;
-  dmap->fragment_size = bsz;
-
-  if (dmap->raw_buf)
-    memset (dmap->raw_buf,
-	    dmap->neutral_byte,
-	    dmap->bytes_in_use);
-
-  for (i = 0; i < dmap->nbufs; i++)
-    {
-      dmap->counts[i] = 0;
-    }
-
-  dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
-}
+static int      local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
 
 static void
 dma_init_buffers (int dev, struct dma_buffparms *dmap)
@@ -176,17 +53,18 @@
       in_sleep_flag[dev].opts = WK_NONE;
     }
 
-  dmap->flags = DMA_BUSY;	/* Other flags off */
-  dmap->qlen = dmap->qhead = dmap->qtail = 0;
-  dmap->nbufs = 1;
+  dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
+  dmap->byte_counter = 0;
   dmap->bytes_in_use = audio_devs[dev]->buffsize;
 
   dmap->dma_mode = DMODE_NONE;
   dmap->mapping_flags = 0;
-  dmap->neutral_byte = NEUTRAL8;
+  dmap->neutral_byte = 0x80;
   dmap->data_rate = 8000;
   dmap->cfrag = -1;
   dmap->closing = 0;
+  dmap->nbufs = 1;
+  dmap->flags = DMA_BUSY;	/* Other flags off */
 }
 
 static int
@@ -219,6 +97,8 @@
   dmap->fragment_size = 0;
   dmap->max_fragments = 65536;	/* Just a large value */
   dmap->byte_counter = 0;
+  dmap->applic_profile = APF_NORMAL;
+  dmap->needs_reorg = 1;
 
 
   dma_init_buffers (dev, dmap);
@@ -235,20 +115,20 @@
     dmap->dma_mode = DMODE_NONE;
   dmap->flags &= ~DMA_BUSY;
 
-  disable_dma (chan);
-  sound_free_dmap (dev, dmap, chan);
+  disable_dma (dmap->dma);
 }
 
+
 static unsigned int
 default_set_bits (int dev, unsigned int bits)
 {
-  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1);
+  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits);
 }
 
 static int
 default_set_speed (int dev, int speed)
 {
-  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) speed, 1);
+  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) & speed);
 }
 
 static short
@@ -256,7 +136,7 @@
 {
   int             c = channels;
 
-  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) c, 1);
+  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c);
 }
 
 static void
@@ -279,50 +159,66 @@
 
   if (dev >= num_audiodevs)
     {
-      /*  printk ("PCM device %d not installed.\n", dev); */
       return -ENXIO;
     }
 
   if (!audio_devs[dev])
     {
-      /* printk ("PCM device %d not initialized\n", dev); */
       return -ENXIO;
     }
 
   if (!(audio_devs[dev]->flags & DMA_DUPLEX))
     {
       audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
-      audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
+      audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma;
     }
 
+  check_driver (audio_devs[dev]->d);
+
   if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0)
     return retval;
 
-  check_driver (audio_devs[dev]->d);
-
   dmap_out = audio_devs[dev]->dmap_out;
   dmap_in = audio_devs[dev]->dmap_in;
 
-  if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0)
+  if (dmap_in == dmap_out)
+    audio_devs[dev]->flags &= ~DMA_DUPLEX;
+
+  if (mode & OPEN_WRITE)
     {
-      audio_devs[dev]->d->close (dev);
-      return retval;
+      if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0)
+	{
+	  audio_devs[dev]->d->close (dev);
+	  return retval;
+	}
     }
 
   audio_devs[dev]->enable_bits = mode;
-  if (mode & OPEN_READ &&
-      audio_devs[dev]->flags & DMA_DUPLEX &&
-      dmap_out != dmap_in)
-    if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0)
-      {
-	audio_devs[dev]->d->close (dev);
-	close_dmap (dev, dmap_out, audio_devs[dev]->dmachan1);
-	return retval;
-      }
+
+  if (mode == OPEN_READ || (mode != OPEN_WRITE &&
+			    audio_devs[dev]->flags & DMA_DUPLEX))
+    {
+      if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0)
+	{
+	  audio_devs[dev]->d->close (dev);
+
+	  if (mode & OPEN_WRITE)
+	    {
+	      close_dmap (dev, dmap_out, audio_devs[dev]->dmap_out->dma);
+	    }
+
+	  return retval;
+	}
+    }
+
   audio_devs[dev]->open_mode = mode;
   audio_devs[dev]->go = 1;
-  in_sleep_flag[dev].opts = WK_NONE;
-  out_sleep_flag[dev].opts = WK_NONE;
+
+  if (mode & OPEN_READ)
+    in_sleep_flag[dev].opts = WK_NONE;
+
+  if (mode & OPEN_WRITE)
+    out_sleep_flag[dev].opts = WK_NONE;
 
   audio_devs[dev]->d->set_bits (dev, 8);
   audio_devs[dev]->d->set_channels (dev, 1);
@@ -334,17 +230,10 @@
 void
 DMAbuf_reset (int dev)
 {
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-  audio_devs[dev]->d->reset (dev);
-  restore_flags (flags);
-
-  dma_reset_output (dev);
+  if (audio_devs[dev]->open_mode & OPEN_WRITE)
+    dma_reset_output (dev);
 
-  if (audio_devs[dev]->flags & DMA_DUPLEX &&
-      audio_devs[dev]->open_mode & OPEN_READ)
+  if (audio_devs[dev]->open_mode & OPEN_READ)
     dma_reset_input (dev);
 }
 
@@ -356,8 +245,6 @@
 
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
-  if (dmap->dma_mode != DMODE_OUTPUT)
-    return;
 
   if (!(dmap->flags & DMA_STARTED))	/* DMA is not active */
     return;
@@ -404,7 +291,6 @@
       };
     }
   audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
-  audio_devs[dev]->dmap_out->flags |= DMA_RESTART;
 
 /*
  * Finally shut the device off
@@ -412,68 +298,74 @@
 
   if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
       !audio_devs[dev]->d->halt_output)
-    audio_devs[dev]->d->reset (dev);
+    audio_devs[dev]->d->halt_io (dev);
   else
     audio_devs[dev]->d->halt_output (dev);
   audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED;
   restore_flags (flags);
 
-  dma_init_buffers (dev, audio_devs[dev]->dmap_out);
+  clear_dma_ff (dmap->dma);
+  disable_dma (dmap->dma);
+  dmap->byte_counter = 0;
   reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0);
+  dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
 }
 
 static void
 dma_reset_input (int dev)
 {
   unsigned long   flags;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
 
   save_flags (flags);
   cli ();
   if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
       !audio_devs[dev]->d->halt_input)
-    audio_devs[dev]->d->reset (dev);
+    audio_devs[dev]->d->halt_io (dev);
   else
     audio_devs[dev]->d->halt_input (dev);
   audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED;
   restore_flags (flags);
 
-  dma_init_buffers (dev, audio_devs[dev]->dmap_in);
+  dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
+  dmap->byte_counter = 0;
   reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1);
 }
 
-static void
-launch_output (int dev, struct dma_buffparms *dmap)
+void
+DMAbuf_launch_output (int dev, struct dma_buffparms *dmap)
 {
-  dmap->flags |= DMA_ACTIVE;
-
-  if (dmap->dma_mode == DMODE_NONE || dmap->flags & DMA_RESTART)
+  if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE))
     {
-      reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0);
-      audio_devs[dev]->d->prepare_for_output (dev,
-					  dmap->fragment_size, dmap->nbufs);
-    }
+      if (!(dmap->flags & DMA_STARTED))
+	{
+	  reorganize_buffers (dev, dmap, 0);
 
-  dmap->dma_mode |= DMODE_OUTPUT;
+	  if (audio_devs[dev]->d->prepare_for_output (dev,
+					  dmap->fragment_size, dmap->nbufs))
+	    return;
 
-  if (dmap->counts[dmap->qhead] == 0)
-    dmap->counts[dmap->qhead] = dmap->fragment_size;
+	  local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
+			   DMA_MODE_WRITE);
+	}
+      if (dmap->counts[dmap->qhead] == 0)
+	dmap->counts[dmap->qhead] = dmap->fragment_size;
 
-  audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
-				    dmap->qhead * dmap->fragment_size,
-				    dmap->counts[dmap->qhead], 0,
-				 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
-				    !(dmap->flags & DMA_STARTED));
-  dmap->flags |= DMA_STARTED;
-  if (audio_devs[dev]->d->trigger)
-    audio_devs[dev]->d->trigger (dev,
+      audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
+					dmap->qhead * dmap->fragment_size,
+					dmap->counts[dmap->qhead], 1);
+      if (audio_devs[dev]->d->trigger)
+	audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+    }
+  dmap->flags |= DMA_ACTIVE;
 }
 
 int
 DMAbuf_sync (int dev)
 {
   unsigned long   flags;
-  int             tmout;
+  int             tmout, n = 0;
 
   if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
     return 0;
@@ -499,13 +391,14 @@
       ;
       if (dmap->qlen > 0)
 	if (!(dmap->flags & DMA_ACTIVE))
-	  launch_output (dev, dmap);
+	  DMAbuf_launch_output (dev, dmap);
       ;
 
       audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
 
       audio_devs[dev]->dmap_out->underrun_count = 0;
       while (!(current->signal & ~current->blocked)
+	     && n++ <= audio_devs[dev]->dmap_out->nbufs
 	     && audio_devs[dev]->dmap_out->qlen
 	     && audio_devs[dev]->dmap_out->underrun_count == 0)
 	{
@@ -534,7 +427,6 @@
 	    }
 	}
       audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
-      audio_devs[dev]->dmap_out->flags |= DMA_RESTART;
       restore_flags (flags);
       /*
        * Some devices such as GUS have huge amount of on board RAM for the
@@ -578,32 +470,39 @@
 {
   unsigned long   flags;
 
-  audio_devs[dev]->dmap_out->closing = 1;
-  audio_devs[dev]->dmap_in->closing = 1;
+  if (audio_devs[dev]->open_mode & OPEN_WRITE)
+    audio_devs[dev]->dmap_out->closing = 1;
+  if (audio_devs[dev]->open_mode & OPEN_READ)
+    audio_devs[dev]->dmap_in->closing = 1;
+
+  if (audio_devs[dev]->open_mode & OPEN_WRITE)
+    if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED))
+      if (!((current->signal & ~current->blocked))
+	  && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
+	{
+	  DMAbuf_sync (dev);
+	}
 
-  if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED))
-  if (!((current->signal & ~current->blocked))
-      && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
+  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
     {
-      DMAbuf_sync (dev);
+      memset (audio_devs[dev]->dmap_out->raw_buf,
+	      audio_devs[dev]->dmap_out->neutral_byte,
+	      audio_devs[dev]->dmap_out->bytes_in_use);
     }
 
-  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
-    memset (audio_devs[dev]->dmap_out->raw_buf,
-	    audio_devs[dev]->dmap_out->neutral_byte,
-	    audio_devs[dev]->dmap_out->bytes_in_use);
-
   save_flags (flags);
   cli ();
 
-  audio_devs[dev]->d->halt_xfer (dev);
+  DMAbuf_reset (dev);
   audio_devs[dev]->d->close (dev);
 
-  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
+  if (audio_devs[dev]->open_mode & OPEN_WRITE)
+    close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma);
 
-  if (audio_devs[dev]->open_mode & OPEN_READ &&
-      audio_devs[dev]->flags & DMA_DUPLEX)
-    close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+  if (audio_devs[dev]->open_mode == OPEN_READ ||
+      (audio_devs[dev]->open_mode != OPEN_WRITE &&
+       audio_devs[dev]->flags & DMA_DUPLEX))
+    close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma);
   audio_devs[dev]->open_mode = 0;
 
   restore_flags (flags);
@@ -611,21 +510,15 @@
   return 0;
 }
 
-static int
-activate_recording (int dev, struct dma_buffparms *dmap)
+int
+DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap)
 {
-  int             prepare = 0;
+  if (!(audio_devs[dev]->open_mode & OPEN_READ))
+    return 0;
 
   if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
     return 0;
 
-  if (dmap->flags & DMA_RESTART)
-    {
-      dma_reset_input (dev);
-      dmap->flags &= ~DMA_RESTART;
-      prepare = 1;
-    }
-
   if (dmap->dma_mode == DMODE_OUTPUT)	/* Direction change */
     {
       DMAbuf_sync (dev);
@@ -633,8 +526,7 @@
       dmap->dma_mode = DMODE_NONE;
     }
 
-
-  if (prepare || !dmap->dma_mode)
+  if (!dmap->dma_mode)
     {
       int             err;
 
@@ -649,12 +541,14 @@
 
   if (!(dmap->flags & DMA_ACTIVE))
     {
+      if (dmap->needs_reorg)
+	reorganize_buffers (dev, dmap, 0);
+      local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
+		       DMA_MODE_READ);
       audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
 				       dmap->qtail * dmap->fragment_size,
-				       dmap->fragment_size, 0,
-				 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
-				       !(dmap->flags & DMA_STARTED));
-      dmap->flags |= DMA_ACTIVE | DMA_STARTED;
+				       dmap->fragment_size, 0);
+      dmap->flags |= DMA_ACTIVE;
       if (audio_devs[dev]->d->trigger)
 	audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
@@ -669,6 +563,11 @@
   int             err = EIO;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
 
+  if (!(audio_devs[dev]->open_mode & OPEN_READ))
+    return -EIO;
+  if (dmap->needs_reorg)
+    reorganize_buffers (dev, dmap, 0);
+
   save_flags (flags);
   cli ();
   if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
@@ -687,7 +586,7 @@
 	  return -EAGAIN;
 	}
 
-      if ((err = activate_recording (dev, dmap)) < 0)
+      if ((err = DMAbuf_activate_recording (dev, dmap)) < 0)
 	{
 	  restore_flags (flags);
 	  return err;
@@ -737,7 +636,7 @@
 	{
 	  printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
 	  err = EIO;
-	  audio_devs[dev]->d->reset (dev);
+	  dma_reset_input (dev);
 	  ;
 	}
       else
@@ -781,83 +680,8 @@
   return 0;
 }
 
-static int
-dma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
-{
-  if (fact == 0)
-    {
-      fact = dmap->subdivision;
-      if (fact == 0)
-	fact = 1;
-      return ioctl_out (arg, fact);
-    }
-
-  if (dmap->subdivision != 0 ||
-      dmap->fragment_size)	/* Too late to change */
-    return -EINVAL;
-
-  if (fact > MAX_REALTIME_FACTOR)
-    return -EINVAL;
-
-  if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
-    return -EINVAL;
-
-  dmap->subdivision = fact;
-  return ioctl_out (arg, fact);
-}
-
-static int
-dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
-{
-  int             bytes, count;
-
-  if (fact == 0)
-    return -EIO;
-
-  if (dmap->subdivision != 0 ||
-      dmap->fragment_size)	/* Too late to change */
-    return -EINVAL;
-
-  bytes = fact & 0xffff;
-  count = (fact >> 16) & 0x7fff;
-
-  if (count == 0)
-    count = MAX_SUB_BUFFERS;
-
-  if (bytes < 4 || bytes > 17)	/* <16 || > 512k */
-    return -EINVAL;
-
-  if (count < 2)
-    return -EINVAL;
-
-  if (audio_devs[dev]->min_fragment > 0)
-    if (bytes < audio_devs[dev]->min_fragment)
-      bytes = audio_devs[dev]->min_fragment;
-
-#ifdef OS_DMA_MINBITS
-  if (bytes < OS_DMA_MINBITS)
-    bytes = OS_DMA_MINBITS;
-#endif
-
-  dmap->fragment_size = (1 << bytes);
-  dmap->max_fragments = count;
-
-  if (dmap->fragment_size > audio_devs[dev]->buffsize)
-    dmap->fragment_size = audio_devs[dev]->buffsize;
-
-  if (dmap->fragment_size == audio_devs[dev]->buffsize &&
-      audio_devs[dev]->flags & DMA_AUTOMODE)
-    dmap->fragment_size /= 2;	/* Needs at least 2 buffers */
-
-  dmap->subdivision = 1;	/* Disable SNDCTL_DSP_SUBDIVIDE */
-  if (arg)
-    return ioctl_out (arg, bytes | (count << 16));
-  else
-    return 0;
-}
-
-static int
-get_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap)
+int
+DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap)
 {
 /*
  * Try to approximate the active byte position of the DMA pointer within the
@@ -865,6 +689,7 @@
  */
   int             pos;
   unsigned long   flags;
+  int             chan = dmap->dma;
 
   save_flags (flags);
   cli ();
@@ -873,16 +698,26 @@
   else
     {
       clear_dma_ff (chan);
-      disable_dma (chan);
+      disable_dma (dmap->dma);
       pos = get_dma_residue (chan);
-      if (chan > 3)		/* Word count */
-	pos *= 2;
-      pos = dmap->bytes_in_use - pos - 1;
+      pos = dmap->bytes_in_use - pos;
+
+      if (dmap->flags & DMODE_OUTPUT)
+	{
+	  if (dmap->qhead == 0)
+	    pos %= dmap->bytes_in_use;
+	}
+      else
+	{
+	  if (dmap->qtail == 0)
+	    pos %= dmap->bytes_in_use;
+	}
+
       if (pos < 0)
 	pos = 0;
       if (pos > dmap->bytes_in_use)
 	pos = dmap->bytes_in_use;
-      enable_dma (chan);
+      enable_dma (dmap->dma);
     }
   restore_flags (flags);
   /* printk ("%04x ", pos); */
@@ -890,353 +725,200 @@
   return pos;
 }
 
-
-int
-DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+/*
+ * DMAbuf_start_devices() is called by the /dev/music driver to start
+ * one or more audio devices at desired moment.
+ */
+static void
+DMAbuf_start_device (int dev)
 {
-  struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
-  struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
-
-  switch (cmd)
-    {
-    case SNDCTL_DSP_GETBLKSIZE:
-      if (!(dmap_out->flags & DMA_ALLOC_DONE))
-	{
-	  reorganize_buffers (dev, dmap_out,
-			      (audio_devs[dev]->open_mode == OPEN_READ));
-	  if (audio_devs[dev]->flags & DMA_DUPLEX &&
-	      audio_devs[dev]->open_mode & OPEN_READ)
-	    reorganize_buffers (dev, dmap_in,
-				(audio_devs[dev]->open_mode == OPEN_READ));
-	}
+  if (audio_devs[dev]->open_mode != 0)
+    if (!audio_devs[dev]->go)
+      {
+	/* OK to start the device */
+	audio_devs[dev]->go = 1;
 
-      if (local)
-	return dmap_out->fragment_size;
-      else
-	return ioctl_out (arg, dmap_out->fragment_size);
-      break;
+	if (audio_devs[dev]->d->trigger)
+	  audio_devs[dev]->d->trigger (dev,
+			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+      }
+}
 
-    case SNDCTL_DSP_SUBDIVIDE:
-      {
-	int             fact;
-	int             ret;
+void
+DMAbuf_start_devices (unsigned int devmask)
+{
+  int             dev;
 
-	get_user (fact, (int *) arg);
+  for (dev = 0; dev < num_audiodevs; dev++)
+    if (devmask & (1 << dev))
+      DMAbuf_start_device (dev);
+}
 
-	ret = dma_subdivide (dev, dmap_out, arg, fact);
-	if (ret < 0)
-	  return ret;
+int
+DMAbuf_space_in_queue (int dev)
+{
+  int             len, max, tmp;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
-	if (audio_devs[dev]->flags & DMA_DUPLEX &&
-	    audio_devs[dev]->open_mode & OPEN_READ)
-	  ret = dma_subdivide (dev, dmap_in, arg, fact);
+  /* Don't allow touching pages too close to the playing ones */
+  int             lim = dmap->nbufs - 1;
 
-	return ret;
-      }
-      break;
+  if (lim < 2)
+    lim = 2;
 
-    case SNDCTL_DSP_SETFRAGMENT:
-      {
-	int             fact;
-	int             ret;
+  if (dmap->qlen >= lim)	/* No space at all */
+    return 0;
 
-	get_user (fact, (int *) arg);
-	ret = dma_set_fragment (dev, dmap_out, arg, fact);
-	if (ret < 0)
-	  return ret;
-
-	if (audio_devs[dev]->flags & DMA_DUPLEX &&
-	    audio_devs[dev]->open_mode & OPEN_READ)
-	  ret = dma_set_fragment (dev, dmap_in, arg, fact);
+  /*
+   * Verify that there are no more pending buffers than the limit
+   * defined by the process.
+   */
 
-	return ret;
-      }
-      break;
+  max = dmap->max_fragments;
+  len = dmap->qlen;
 
-    case SNDCTL_DSP_GETISPACE:
-    case SNDCTL_DSP_GETOSPACE:
-      if (!local)
-	return -EINVAL;
-      else
-	{
-	  struct dma_buffparms *dmap = dmap_out;
+  if (audio_devs[dev]->d->local_qlen)
+    {
+      tmp = audio_devs[dev]->d->local_qlen (dev);
+      if (tmp && len)
+	tmp--;			/*
+				 * This buffer has been counted twice
+				 */
+      len += tmp;
+    }
 
-	  audio_buf_info *info = (audio_buf_info *) arg;
+  if (len >= max)
+    return 0;
+  return 1;
+}
 
-	  if (cmd == SNDCTL_DSP_GETISPACE &&
-	      !(audio_devs[dev]->open_mode & OPEN_READ))
-	    return -EINVAL;
+static int
+output_sleep (int dev, int dontblock)
+{
+  int             tmout;
+  int             err = 0;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
-	  if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
-	    dmap = dmap_in;
+  if (dontblock)
+    {
+      return -EAGAIN;
+    }
 
-	  if (dmap->mapping_flags & DMA_MAP_MAPPED)
-	    return -EINVAL;
+  if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
+    {
+      return -EAGAIN;
+    }
 
-	  if (!(dmap->flags & DMA_ALLOC_DONE))
-	    reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
+  /*
+   * Wait for free space
+   */
+  if (!audio_devs[dev]->go)
+    tmout = 0;
+  else
+    {
+      tmout =
+	(dmap->fragment_size * HZ) / dmap->data_rate;
 
-	  info->fragstotal = dmap->nbufs;
+      tmout += HZ / 10;		/* Some safety distance */
 
-	  if (cmd == SNDCTL_DSP_GETISPACE)
-	    info->fragments = dmap->qlen;
-	  else
-	    {
-	      if (!space_in_queue (dev))
-		info->fragments = 0;
-	      else
-		{
-		  info->fragments = dmap->nbufs - dmap->qlen;
-		  if (audio_devs[dev]->d->local_qlen)
-		    {
-		      int             tmp = audio_devs[dev]->d->local_qlen (dev);
-
-		      if (tmp && info->fragments)
-			tmp--;	/*
-				   * This buffer has been counted twice
-				 */
-		      info->fragments -= tmp;
-		    }
-		}
-	    }
+      if (tmout < (HZ / 2))
+	tmout = HZ / 2;
+      if (tmout > 20 * HZ)
+	tmout = 20 * HZ;
+    }
 
-	  if (info->fragments < 0)
-	    info->fragments = 0;
-	  else if (info->fragments > dmap->nbufs)
-	    info->fragments = dmap->nbufs;
+  if ((current->signal & ~current->blocked))
+    return -EIO;
 
-	  info->fragsize = dmap->fragment_size;
-	  info->bytes = info->fragments * dmap->fragment_size;
 
-	  if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
-	    info->bytes -= dmap->counts[dmap->qhead];
-	}
-      return 0;
+  {
+    unsigned long   tlimit;
 
-    case SNDCTL_DSP_SETTRIGGER:
+    if (tmout)
+      current->timeout = tlimit = jiffies + (tmout);
+    else
+      tlimit = (unsigned long) -1;
+    out_sleep_flag[dev].opts = WK_SLEEP;
+    interruptible_sleep_on (&out_sleeper[dev]);
+    if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
       {
-	unsigned long   flags;
-
-	int             bits;
-	int             changed;
-
-	get_user (bits, (int *) arg);
-	bits &= audio_devs[dev]->open_mode;
-
-	if (audio_devs[dev]->d->trigger == NULL)
-	  return -EINVAL;
-
-	if (!(audio_devs[dev]->flags & DMA_DUPLEX))
-	  if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
-	    {
-	      printk ("Sound: Device doesn't have full duplex capability\n");
-	      return -EINVAL;
-	    }
-
-	save_flags (flags);
-	cli ();
-	changed = audio_devs[dev]->enable_bits ^ bits;
-
-	if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
-	  {
-	    int             err;
-
-	    reorganize_buffers (dev, dmap_in, 1);
-
-	    if ((err = audio_devs[dev]->d->prepare_for_input (dev,
-			       dmap_in->fragment_size, dmap_in->nbufs)) < 0)
-	      return -err;
-
-	    audio_devs[dev]->enable_bits = bits;
-	    activate_recording (dev, dmap_in);
-	  }
-
-
-	if ((changed & bits) & PCM_ENABLE_OUTPUT &&
-	    dmap_out->mapping_flags & DMA_MAP_MAPPED &&
-	    audio_devs[dev]->go)
-	  {
-
-	    if (!(dmap_out->flags & DMA_ALLOC_DONE))
-	      {
-		reorganize_buffers (dev, dmap_out, 0);
-	      }
-
-	    ;
-	    dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
-	    launch_output (dev, dmap_out);
-	    ;
-	  }
-
-	audio_devs[dev]->enable_bits = bits;
-	if (changed && audio_devs[dev]->d->trigger)
-	  {
-	    audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go);
-	  }
-	restore_flags (flags);
-      }
-    case SNDCTL_DSP_GETTRIGGER:
-      return ioctl_out (arg, audio_devs[dev]->enable_bits);
-      break;
-
-    case SNDCTL_DSP_SETSYNCRO:
-
-      if (!audio_devs[dev]->d->trigger)
-	return -EINVAL;
-
-      audio_devs[dev]->d->trigger (dev, 0);
-      audio_devs[dev]->go = 0;
-      return 0;
-      break;
-
-    case SNDCTL_DSP_GETIPTR:
-      {
-	count_info      info;
-	unsigned long   flags;
-
-	if (!(audio_devs[dev]->open_mode & OPEN_READ))
-	  return -EINVAL;
-
-	save_flags (flags);
-	cli ();
-	info.bytes = audio_devs[dev]->dmap_in->byte_counter;
-	info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);
-	info.blocks = audio_devs[dev]->dmap_in->qlen;
-	info.bytes += info.ptr;
-	{
-	  char           *fixit = (char *) &info;
-
-	  copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
-	};
-
-	if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
-	  audio_devs[dev]->dmap_in->qlen = 0;	/* Acknowledge interrupts */
-	restore_flags (flags);
-	return 0;
+	if (jiffies >= tlimit)
+	  out_sleep_flag[dev].opts |= WK_TIMEOUT;
       }
-      break;
-
-    case SNDCTL_DSP_GETOPTR:
-      {
-	count_info      info;
-	unsigned long   flags;
-
-	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-	  return -EINVAL;
-
-	save_flags (flags);
-	cli ();
-	info.bytes = audio_devs[dev]->dmap_out->byte_counter;
-	info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);
-	info.blocks = audio_devs[dev]->dmap_out->qlen;
-	info.bytes += info.ptr;
-	{
-	  char           *fixit = (char *) &info;
-
-	  copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
-	};
-
-	if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
-	  audio_devs[dev]->dmap_out->qlen = 0;	/* Acknowledge interrupts */
-	restore_flags (flags);
-	return 0;
-      }
-      break;
-
-
-    case SNDCTL_DSP_POST:
-      ;
-      if (audio_devs[dev]->dmap_out->qlen > 0)
-	if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
-	  launch_output (dev, audio_devs[dev]->dmap_out);
+    out_sleep_flag[dev].opts &= ~WK_SLEEP;
+  };
+  if ((out_sleep_flag[dev].opts & WK_TIMEOUT))
+    {
+      printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
+      err = EIO;
       ;
-      return 0;
-      break;
-
-    default:
-      return audio_devs[dev]->d->ioctl (dev, cmd, arg, local);
+      dma_reset_output (dev);
+    }
+  else if ((current->signal & ~current->blocked))
+    {
+      err = EINTR;
     }
 
-}
-
-/*
- * DMAbuf_start_devices() is called by the /dev/music driver to start
- * one or more audio devices at desired moment.
- */
-
-void
-DMAbuf_start_device (int dev)
-{
-  if (audio_devs[dev]->open_mode != 0)
-    if (!audio_devs[dev]->go)
-      {
-	/* OK to start the device */
-	audio_devs[dev]->go = 1;
-
-	if (audio_devs[dev]->d->trigger)
-	  audio_devs[dev]->d->trigger (dev,
-			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-      }
-}
-
-void
-DMAbuf_start_devices (unsigned int devmask)
-{
-  int             dev;
-
-  for (dev = 0; dev < num_audiodevs; dev++)
-    if (devmask & (1 << dev))
-      DMAbuf_start_device (dev);
+  return err;
 }
 
 static int
-space_in_queue (int dev)
+find_output_space (int dev, char **buf, int *size)
 {
-  int             len, max, tmp;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+  unsigned long   flags;
+  unsigned long   offs, active_offs;
+  long            len;
 
-  /* Don't allow touching pages too close to the playing ones */
-  int             lim = dmap->nbufs - 1;
+  if (!DMAbuf_space_in_queue (dev))
+    return 0;
 
-  if (lim < 2)
-    lim = 2;
+  save_flags (flags);
+  cli ();
 
-  if (dmap->qlen >= lim)	/* No space at all */
-    return 0;
+#ifdef BE_CONSERVATIVE
+  active_offs = dmap->byte_counter + (dmap->qhead + 1) * dmap->fragment_size;
+#else
+  active_offs = ((dmap->byte_counter + DMAbuf_get_buffer_pointer (dev, dmap)));
+  /* / dmap->fragment_size) * dmap->fragment_size; */
 
-  /*
-   * Verify that there are no more pending buffers than the limit
-   * defined by the process.
-   */
+#endif
 
-  max = dmap->max_fragments;
-  len = dmap->qlen;
+  offs = (dmap->user_counter % dmap->bytes_in_use) & ~3;
+  *buf = dmap->raw_buf + offs;
 
-  if (audio_devs[dev]->d->local_qlen)
+  len = active_offs + dmap->bytes_in_use - dmap->user_counter;	/* Number of unused bytes in buffer */
+
+  if ((offs + len) > dmap->bytes_in_use)
+    len = dmap->bytes_in_use - offs;
+
+  if (len < 0)
     {
-      tmp = audio_devs[dev]->d->local_qlen (dev);
-      if (tmp && len)
-	tmp--;			/*
-				 * This buffer has been counted twice
-				 */
-      len += tmp;
+      restore_flags (flags);
+      return 0;
     }
 
-  if (len >= max)
-    return 0;
-  return 1;
+  if ((offs + len) > dmap->bytes_in_use)
+    len = dmap->bytes_in_use - offs;
+
+  *size = len & ~3;
+
+  restore_flags (flags);
+
+  return (len > 0);
 }
 
 int
 DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
 {
   unsigned long   flags;
-  int             abort, err = EIO;
+  int             err = EIO;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
-  dmap->flags &= ~DMA_CLEAN;
+  if (dmap->needs_reorg)
+    reorganize_buffers (dev, dmap, 0);
 
-  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+  if (dmap->mapping_flags & DMA_MAP_MAPPED)
     {
       printk ("Sound: Can't write to mmapped device (3)\n");
       return -EINVAL;
@@ -1247,204 +929,77 @@
       DMAbuf_reset (dev);
       dmap->dma_mode = DMODE_NONE;
     }
-  else if (dmap->flags & DMA_RESTART)	/* Restart buffering */
-    {
-      DMAbuf_sync (dev);
-      dma_reset_output (dev);
-      dmap->dma_mode = DMODE_NONE;
-    }
-
-  dmap->flags &= ~(DMA_RESTART | DMA_EMPTY);
 
-  if (!dmap->dma_mode)
-    {
-      int             err;
-
-      reorganize_buffers (dev, dmap, 0);
-      dmap->dma_mode = DMODE_OUTPUT;
-      if ((err = audio_devs[dev]->d->prepare_for_output (dev,
-				     dmap->fragment_size, dmap->nbufs)) < 0)
-	return err;
-    }
+  dmap->dma_mode = DMODE_OUTPUT;
 
   save_flags (flags);
   cli ();
 
-  abort = 0;
-  while (!space_in_queue (dev) &&
-	 !abort)
+  while (!find_output_space (dev, buf, size))
     {
-      int             tmout;
-
-      if (dontblock)
+      if ((err = output_sleep (dev, dontblock)) < 0)
 	{
 	  restore_flags (flags);
-	  return -EAGAIN;
-	}
-
-      if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
-	{
-	  restore_flags (flags);
-	  return -EAGAIN;
-	}
-
-      /*
-       * Wait for free space
-       */
-      if (!audio_devs[dev]->go)
-	tmout = 0;
-      else
-	{
-	  tmout =
-	    (dmap->fragment_size * HZ) / dmap->data_rate;
-
-	  tmout += HZ / 10;	/* Some safety distance */
-
-	  if (tmout < (HZ / 2))
-	    tmout = HZ / 2;
-	  if (tmout > 20 * HZ)
-	    tmout = 20 * HZ;
-	}
-
-
-      {
-	unsigned long   tlimit;
-
-	if (tmout)
-	  current->timeout = tlimit = jiffies + (tmout);
-	else
-	  tlimit = (unsigned long) -1;
-	out_sleep_flag[dev].opts = WK_SLEEP;
-	interruptible_sleep_on (&out_sleeper[dev]);
-	if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
-	  {
-	    if (jiffies >= tlimit)
-	      out_sleep_flag[dev].opts |= WK_TIMEOUT;
-	  }
-	out_sleep_flag[dev].opts &= ~WK_SLEEP;
-      };
-      if ((out_sleep_flag[dev].opts & WK_TIMEOUT))
-	{
-	  printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
-	  err = EIO;
-	  abort = 1;
-	  ;
-	  if (audio_devs[dev]->flags & DMA_AUTOMODE)
-	    dmap->flags |= DMA_RESTART;
-	  else
-	    dmap->flags &= ~DMA_RESTART;
-	  audio_devs[dev]->d->reset (dev);
-	}
-      else if ((current->signal & ~current->blocked))
-	{
-	  err = EINTR;
-	  abort = 1;
+	  return err;
 	}
     }
-  restore_flags (flags);
 
-  if (!space_in_queue (dev))
+  if (!find_output_space (dev, buf, size))
     {
-      return -err;		/* Caught a signal ? */
+      restore_flags (flags);
+      return -EIO;		/* Caught a signal ? */
     }
+  restore_flags (flags);
 
-  *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
-  *size = dmap->fragment_size;
-  dmap->counts[dmap->qtail] = 0;
-
-  return dmap->qtail;
-}
-
-int
-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;
-
-  if (dmap->cfrag < 0)
-    return -1;
-
-  *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
-  *buf_ptr = dmap->counts[dmap->qtail];
-  *buf_size = dmap->fragment_size;
-  return *buf_no = dmap->cfrag;
-}
-
-int
-DMAbuf_set_count (int dev, int buff_no, int l)
-{
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-  if (buff_no == dmap->qtail)
-    {
-      dmap->cfrag = buff_no;
-      dmap->counts[buff_no] = l;
-    }
-  else
-    dmap->cfrag = -1;
+  dmap->flags |= DMA_DIRTY;
   return 0;
 }
 
 int
-DMAbuf_start_output (int dev, int buff_no, int l)
+DMAbuf_move_wrpointer (int dev, int l)
 {
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-  int             restart = 0;
-  int             post = dmap->flags & DMA_POST;
+  unsigned long   ptr = (dmap->user_counter / dmap->fragment_size)
+  * dmap->fragment_size;
+
+  unsigned long   end_ptr, p, prev_count;
+  int             post = (dmap->flags & DMA_POST);
 
   ;
 
   dmap->flags &= ~DMA_POST;
 
   dmap->cfrag = -1;
-  if (dmap->flags & DMA_RESTART)
-    restart = 1;
 
-/*
- * Bypass buffering if using mmapped access
- */
+  prev_count = dmap->user_counter;
+  dmap->user_counter += l;
 
-  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
-    {
-      l = dmap->fragment_size;
-      dmap->counts[dmap->qtail] = l;
-      dmap->flags &= ~DMA_RESTART;
-      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+  if (dmap->user_counter < prev_count)	/* Wrap? */
+    {				/* Wrap the device counter too */
+      dmap->byte_counter %= dmap->bytes_in_use;
     }
-  else
-    {
 
-      dmap->qlen++;
+  end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size;
 
-      dmap->counts[dmap->qtail] = l;
-      if (l < dmap->fragment_size)
-	{
-	  int             p = dmap->fragment_size * dmap->qtail;
-
-#if defined(PPC) || defined(sparc) || defined(HPPA)
-	  dmap->neutral_byte = dmap->raw_buf[p + l - 2];
-#else
-	  dmap->neutral_byte = dmap->raw_buf[p + l - 1];
-#endif
-
-	  memset (dmap->raw_buf + p + l,
-		  dmap->neutral_byte,
-		  dmap->fragment_size - l);
-	}
-      else
-	dmap->neutral_byte =
-	  dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1];
+  p = (dmap->user_counter - 1) % dmap->bytes_in_use;
+  dmap->neutral_byte = dmap->raw_buf[p];
 
+  /* Update the fragment based bookkeeping too */
+  while (ptr < end_ptr)
+    {
+      dmap->counts[dmap->qtail] = dmap->fragment_size;
       dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+      dmap->qlen++;
+      ptr += dmap->fragment_size;
     }
 
-  /* Delay playback until there are at least two fragments (to prevent hiccup) */
-  if (dmap->qlen > 1 || post ||
-      (dmap->qlen > 0 && dmap->nbufs <= 2) ||
-      (dmap->qlen > 0 && dmap->flags & DMA_SYNCING) ||
-      restart || l != dmap->fragment_size)
-    if (!(dmap->flags & DMA_ACTIVE))
+  dmap->counts[dmap->qtail] = dmap->user_counter - ptr;
+
+  if (!(dmap->flags & DMA_ACTIVE))
+    if (dmap->qlen > 1 ||
+	(dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1)))
       {
-	launch_output (dev, dmap);
+	DMAbuf_launch_output (dev, dmap);
       }
 
   ;
@@ -1459,26 +1014,23 @@
 
   if (dma_mode == DMA_MODE_WRITE)
     {
-      chan = audio_devs[dev]->dmachan1;
+      chan = audio_devs[dev]->dmap_out->dma;
       dmap = audio_devs[dev]->dmap_out;
     }
   else
     {
-      chan = audio_devs[dev]->dmachan2;
+      chan = audio_devs[dev]->dmap_in->dma;
       dmap = audio_devs[dev]->dmap_in;
     }
 
   if (dmap->raw_buf == NULL)
     {
-      printk ("sound: DMA buffer == NULL\n");
+      printk ("sound: DMA buffer(1) == NULL\n");
+      printk ("Device %d, chn=%s\n", dev,
+	      (dmap == audio_devs[dev]->dmap_out) ? "out" : "in");
       return 0;
     }
 
-  /* Handle cards with non automode DMA in new way */
-  if (physaddr != dmap->raw_buf_phys)	/* Not fragment 0 */
-    return count;
-  count = dmap->bytes_in_use;
-
   if (chan < 0)
     return 0;
 
@@ -1487,79 +1039,55 @@
    * set_dma_addr()
    */
 
-  if (audio_devs[dev]->flags & DMA_AUTOMODE)
-    {				/*
-				 * Auto restart mode. Transfer the whole *
-				 * buffer
-				 */
-      unsigned long   flags;
+  sound_start_dma (dev, dmap, chan, physaddr, count, dma_mode, 0);
 
-      save_flags (flags);
-      cli ();
-      disable_dma (chan);
-      clear_dma_ff (chan);
-      set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
-      set_dma_addr (chan, dmap->raw_buf_phys);
-      set_dma_count (chan, dmap->bytes_in_use);
-      enable_dma (chan);
-      restore_flags (flags);
+  return count;
+}
+
+static int
+local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+{
+  int             chan;
+  struct dma_buffparms *dmap;
+
+  if (dma_mode == DMA_MODE_WRITE)
+    {
+      chan = audio_devs[dev]->dmap_out->dma;
+      dmap = audio_devs[dev]->dmap_out;
     }
   else
     {
-      unsigned long   flags;
-
-      save_flags (flags);
-      cli ();
-      disable_dma (chan);
-      clear_dma_ff (chan);
-      set_dma_mode (chan, dma_mode);
-      set_dma_addr (chan, physaddr);
-      set_dma_count (chan, count);
-      enable_dma (chan);
-      restore_flags (flags);
+      chan = audio_devs[dev]->dmap_in->dma;
+      dmap = audio_devs[dev]->dmap_in;
     }
 
-  return count;
-}
-
-void
-DMAbuf_init (void)
-{
-  int             dev;
+  if (dmap->raw_buf == NULL)
+    {
+      printk ("sound: DMA buffer(2) == NULL\n");
+      printk ("Device %d, chn=%s\n", dev,
+	      (dmap == audio_devs[dev]->dmap_out) ? "out" : "in");
+      return 0;
+    }
 
+  if (chan < 0)
+    return 0;
 
   /*
-     * NOTE! This routine could be called several times.
+   * The count must be one less than the actual size. This is handled by
+   * set_dma_addr()
    */
 
-  for (dev = 0; dev < num_audiodevs; dev++)
-    if (audio_devs[dev]->dmap_out == NULL)
-      {
-	audio_devs[dev]->dmap_out =
-	  audio_devs[dev]->dmap_in =
-	  &dmaps[ndmaps++];
-
-	if (audio_devs[dev]->flags & DMA_DUPLEX)
-	  audio_devs[dev]->dmap_in =
-	    &dmaps[ndmaps++];
-      }
+  sound_start_dma (dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1);
+  dmap->flags |= DMA_STARTED;
+
+  return count;
 }
 
 static void
-force_restart (int dev, struct dma_buffparms *dmap)
+finish_output_interrupt (int dev, struct dma_buffparms *dmap)
 {
   unsigned long   flags;
 
-  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
-      audio_devs[dev]->d->halt_output)
-    audio_devs[dev]->d->halt_output (dev);
-  else
-    audio_devs[dev]->d->halt_xfer (dev);
-
-  dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED);
-  dmap->flags |= DMA_RESTART;
-  dmap->qlen = dmap->qhead = dmap->qtail = 0;
-
   save_flags (flags);
   cli ();
   if ((out_sleep_flag[dev].opts & WK_SLEEP))
@@ -1590,111 +1118,98 @@
   int             this_fragment;
 
 #ifdef OS_DMA_INTR
-  if (audio_devs[dev]->dmachan1 >= 0)
-    sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
+  if (audio_devs[dev]->dmap_out->dma >= 0)
+    sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma);
 #endif
 
   if (dmap->raw_buf == NULL)
     {
-      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
+      printk ("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev);
       return;
     }
 
   if (dmap->mapping_flags & DMA_MAP_MAPPED)
     {
+      unsigned long   prev_counter = dmap->byte_counter;
+
       /* mmapped access */
       dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
       if (dmap->qhead == 0)	/* Wrapped */
-	dmap->byte_counter += dmap->bytes_in_use;
-      dmap->qlen++;		/* Yes increment it (don't decrement) */
-      dmap->flags &= ~DMA_ACTIVE;
-      dmap->counts[dmap->qhead] = dmap->fragment_size;
+	{
+	  dmap->byte_counter += dmap->bytes_in_use;
+	  if (dmap->byte_counter < prev_counter)	/* Overflow */
+	    {
+	      dmap->user_counter %= dmap->bytes_in_use;
+	    }
+	}
 
+      dmap->qlen++;		/* Yes increment it (don't decrement) */
       if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
-	{
-	  if (dmap->counts[dmap->qhead] == 0)
-	    dmap->counts[dmap->qhead] = dmap->fragment_size;
+	dmap->flags &= ~DMA_ACTIVE;
+      dmap->counts[dmap->qhead] = dmap->fragment_size;
 
-	  audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
-					  dmap->qhead * dmap->fragment_size,
-					    dmap->counts[dmap->qhead], 1,
-				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
-	  if (audio_devs[dev]->d->trigger)
-	    audio_devs[dev]->d->trigger (dev,
-			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-	}
-      dmap->flags |= DMA_ACTIVE;
+      DMAbuf_launch_output (dev, dmap);
+      finish_output_interrupt (dev, dmap);
+      return;
     }
-  else if (event_type != 2)
+
+  if (event_type == 2)
     {
-      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
-	{
-	  printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
-		  dev, dmap->qlen, dmap->nbufs);
-	  force_restart (dev, dmap);
-	  return;
-	}
+      finish_output_interrupt (dev, dmap);
+      return;
+    }
 
-      save_flags (flags);
-      cli ();
+  if (dmap->qlen > dmap->nbufs)
+    dmap->qlen = dmap->nbufs;
 
-      dmap->qlen--;
-      this_fragment = dmap->qhead;
-      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+  if (dmap->qlen <= 0)
+    {
+      finish_output_interrupt (dev, dmap);
+      return;
+    }
 
-      if (dmap->qhead == 0)	/* Wrapped */
-	dmap->byte_counter += dmap->bytes_in_use;
-      dmap->flags &= ~DMA_ACTIVE;
+  save_flags (flags);
+  cli ();
 
-      if (event_type == 1 && dmap->qlen < 1)
-	{
-	  dmap->underrun_count++;
+  dmap->qlen--;
+  this_fragment = dmap->qhead;
+  dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
 
-	  dmap->qlen = 0;
-	  force_restart (dev, dmap);
-	}
+  if (dmap->qhead == 0)		/* Wrapped */
+    {
+      unsigned long   prev_counter = dmap->byte_counter;
 
-      if (dmap->qlen)
+      dmap->byte_counter += dmap->bytes_in_use;
+      if (dmap->byte_counter < prev_counter)	/* Overflow */
 	{
-	  if (dmap->flags & DMA_CLEAN)
-	    {
-	      int             p = dmap->fragment_size * this_fragment;
-
-	      memset (dmap->raw_buf + p,
-		      dmap->neutral_byte,
-		      dmap->fragment_size);
-	    }
+	  dmap->user_counter %= dmap->bytes_in_use;
+	}
+    }
 
-	  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
-	    {
+  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+    dmap->flags &= ~DMA_ACTIVE;
 
-	      if (dmap->counts[dmap->qhead] == 0)
-		dmap->counts[dmap->qhead] = dmap->fragment_size;
+  if (event_type == 1 && dmap->qlen < 1)
+    {
+      dmap->underrun_count++;
 
-	      audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
-					  dmap->qhead * dmap->fragment_size,
-						dmap->counts[dmap->qhead], 1,
-				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
-	      if (audio_devs[dev]->d->trigger)
-		audio_devs[dev]->d->trigger (dev,
-			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-	    }
-	  dmap->flags |= DMA_ACTIVE;
+      dmap->qlen = 0;
+      if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS)
+	{
+	  dmap->flags &= ~DMA_DIRTY;
+	  memset (audio_devs[dev]->dmap_out->raw_buf,
+		  audio_devs[dev]->dmap_out->neutral_byte,
+		  audio_devs[dev]->dmap_out->bytes_in_use);
 	}
+      dmap->user_counter += dmap->fragment_size;
+      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+    }
 
-      restore_flags (flags);
-    }				/* event_type != 2 */
+  if (dmap->qlen > 0)
+    DMAbuf_launch_output (dev, dmap);
 
-  save_flags (flags);
-  cli ();
-  if ((out_sleep_flag[dev].opts & WK_SLEEP))
-    {
-      {
-	out_sleep_flag[dev].opts = WK_WAKEUP;
-	wake_up (&out_sleeper[dev]);
-      };
-    }
   restore_flags (flags);
+  finish_output_interrupt (dev, dmap);
 }
 
 void
@@ -1704,8 +1219,8 @@
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
 
 #ifdef OS_DMA_INTR
-  if (audio_devs[dev]->dmachan2 >= 0)
-    sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+  if (audio_devs[dev]->dmap_in->dma >= 0)
+    sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma);
 #endif
 
   if (dmap->raw_buf == NULL)
@@ -1718,15 +1233,26 @@
     {
       dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
       if (dmap->qtail == 0)	/* Wrapped */
-	dmap->byte_counter += dmap->bytes_in_use;
+	{
+	  unsigned long   prev_counter = dmap->byte_counter;
+
+	  dmap->byte_counter += dmap->bytes_in_use;
+	  if (dmap->byte_counter < prev_counter)	/* Overflow */
+	    {
+	      dmap->user_counter %= dmap->bytes_in_use;
+	    }
+	}
       dmap->qlen++;
 
       if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
 	{
+	  if (dmap->needs_reorg)
+	    reorganize_buffers (dev, dmap, 0);
+	  local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
+			   DMA_MODE_READ);
 	  audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
 					   dmap->qtail * dmap->fragment_size,
-					   dmap->fragment_size, 1,
-				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
+					   dmap->fragment_size, 1);
 	  if (audio_devs[dev]->d->trigger)
 	    audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
@@ -1734,26 +1260,13 @@
 
       dmap->flags |= DMA_ACTIVE;
     }
-  else if (dmap->qlen == (dmap->nbufs - 1))
+  else if (dmap->qlen >= (dmap->nbufs - 1))
     {
       /* printk ("Sound: Recording overrun\n"); */
       dmap->underrun_count++;
 
-      if (audio_devs[dev]->flags & DMA_AUTOMODE)
-	{
-	  /* Force restart on next read */
-	  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
-	      audio_devs[dev]->d->halt_input)
-	    audio_devs[dev]->d->halt_input (dev);
-	  else
-	    audio_devs[dev]->d->halt_xfer (dev);
-
-	  dmap->flags &= ~DMA_ACTIVE;
-	  if (audio_devs[dev]->flags & DMA_AUTOMODE)
-	    dmap->flags |= DMA_RESTART;
-	  else
-	    dmap->flags &= ~DMA_RESTART;
-	}
+      /* Just throw away the oldest fragment but keep the engine running */
+      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
     }
   else
     {
@@ -1763,15 +1276,26 @@
 		dev, dmap->qlen, dmap->nbufs);
       dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
       if (dmap->qtail == 0)	/* Wrapped */
-	dmap->byte_counter += dmap->bytes_in_use;
+	{
+	  unsigned long   prev_counter = dmap->byte_counter;
+
+	  dmap->byte_counter += dmap->bytes_in_use;
+	  if (dmap->byte_counter < prev_counter)	/* Overflow */
+	    {
+	      dmap->user_counter %= dmap->bytes_in_use;
+	    }
+	}
     }
 
   if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
     {
+      if (dmap->needs_reorg)
+	reorganize_buffers (dev, dmap, 0);
+      local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
+		       DMA_MODE_READ);
       audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
 				       dmap->qtail * dmap->fragment_size,
-				       dmap->fragment_size, 1,
-				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
+				       dmap->fragment_size, 1);
       if (audio_devs[dev]->d->trigger)
 	audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
@@ -1798,9 +1322,8 @@
  *    NOTE!  This routine opens only the primary DMA channel (output).
  */
 
-  int             chan = audio_devs[dev]->dmachan1;
+  int             chan = audio_devs[dev]->dmap_out->dma;
   int             err;
-  unsigned long   flags;
 
   if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0)
     {
@@ -1812,6 +1335,8 @@
 
   if (chan >= 0)
     {
+      unsigned long   flags;
+
       save_flags (flags);
       cli ();
       disable_dma (chan);
@@ -1825,167 +1350,147 @@
 void
 DMAbuf_close_dma (int 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]->dmap_out->dma);
 }
 
 void
-DMAbuf_reset_dma (int dev)
+DMAbuf_init (void)
 {
+  int             dev;
+
+  /*
+     * NOTE! This routine could be called several times.
+   */
+
+  for (dev = 0; dev < num_audiodevs; dev++)
+    if (audio_devs[dev]->dmap_out == NULL)
+      {
+	if (audio_devs[dev]->d == NULL)
+	  panic ("OSS: audio_devs[%d]->d == NULL\n", dev);
+	if (audio_devs[dev]->parent_dev)
+	  {			/* Use DMA map of the parent dev */
+	    int             parent = audio_devs[dev]->parent_dev - 1;
+
+	    audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out;
+	    audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in;
+	  }
+	else
+	  {
+	    audio_devs[dev]->dmap_out =
+	      audio_devs[dev]->dmap_in =
+	      &dmaps[ndmaps++];
+
+	    if (audio_devs[dev]->flags & DMA_DUPLEX)
+	      audio_devs[dev]->dmap_in =
+		&dmaps[ndmaps++];
+	  }
+      }
 }
 
-unsigned int
-DMAbuf_poll (kdev_t dev, struct fileinfo *file, poll_table * wait)
+int
+DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait)
 {
-  unsigned int mask = 0;
   struct dma_buffparms *dmap;
   unsigned long   flags;
 
-  save_flags (flags);
-  cli ();
-
-  in_sleep_flag[dev].opts = WK_SLEEP;
-  poll_wait (&in_sleeper[dev], wait);
-  out_sleep_flag[dev].opts = WK_SLEEP;
-  poll_wait (&out_sleeper[dev], wait);
-
-  restore_flags (flags);
-
-/* sel_in */
-  dmap = audio_devs[dev]->dmap_in;
-  if (!(audio_devs[dev]->open_mode))
-    goto sel_out;
-  if (dmap->mapping_flags & DMA_MAP_MAPPED) {
-    if (dmap->qlen)
-      mask |= POLLIN | POLLRDNORM;
-    goto sel_out;
-  }
-  if (dmap->dma_mode != DMODE_INPUT) {
-    if (dmap->dma_mode == DMODE_NONE &&
-	audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
-	!dmap->qlen &&
-	audio_devs[dev]->go) {
-      unsigned long   flags;
+  switch (sel_type)
+    {
+    case SEL_IN:
+      if (!(audio_devs[dev]->open_mode))
+	return 0;
 
-      save_flags (flags);
-      cli ();
-      activate_recording (dev, dmap);
-      restore_flags (flags);
-    }
-    goto sel_out;
-  }
-  if (!dmap->qlen)
-    goto sel_out;
-  mask |= POLLIN | POLLRDNORM;
+      dmap = audio_devs[dev]->dmap_in;
 
- sel_out:
-  dmap = audio_devs[dev]->dmap_out;
+      if (dmap->mapping_flags & DMA_MAP_MAPPED)
+	{
+	  if (dmap->qlen)
+	    return 1;
 
-  if (dmap->mapping_flags & DMA_MAP_MAPPED) {
-    if (dmap->qlen)
-      mask |= POLLOUT | POLLWRNORM;
-    goto sel_ex;
-  }
-  if (dmap->dma_mode == DMODE_INPUT)
-    goto sel_ex;
-  if (dmap->dma_mode == DMODE_NONE) {
-    mask |= POLLOUT | POLLWRNORM;
-    goto sel_ex;
-  }
-  if (!space_in_queue (dev))
-    goto sel_ex;
-  mask |= POLLOUT | POLLWRNORM;
+	  save_flags (flags);
+	  cli ();
 
-sel_ex:
-  return mask;
-}
+	  in_sleep_flag[dev].opts = WK_SLEEP;
+	  poll_wait (&in_sleeper[dev], wait);
+	  restore_flags (flags);
+	  return 0;
+	}
 
+      if (dmap->dma_mode != DMODE_INPUT)
+	{
+	  if (dmap->dma_mode == DMODE_NONE &&
+	      audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
+	      !dmap->qlen &&
+	      audio_devs[dev]->go)
+	    {
+	      unsigned long   flags;
 
-#else /* CONFIG_AUDIO */
-/*
- * Stub versions if audio services not included
- */
+	      save_flags (flags);
+	      cli ();
+	      DMAbuf_activate_recording (dev, dmap);
+	      restore_flags (flags);
+	    }
+	  return 0;
+	}
 
-int
-DMAbuf_open (int dev, int mode)
-{
-  return -ENXIO;
-}
+      if (!dmap->qlen)
+	{
+	  save_flags (flags);
+	  cli ();
 
-int
-DMAbuf_release (int dev, int mode)
-{
-  return 0;
-}
+	  in_sleep_flag[dev].opts = WK_SLEEP;
+	  poll_wait (&in_sleeper[dev], wait);
+	  restore_flags (flags);
+	  return 0;
+	}
+      return 1;
+      break;
 
-int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
-{
-  return -EIO;
-}
+    case SEL_OUT:
+      dmap = audio_devs[dev]->dmap_out;
 
-int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
-{
-  return -EIO;
-}
+      if (dmap->mapping_flags & DMA_MAP_MAPPED)
+	{
+	  if (dmap->qlen)
+	    return 1;
 
-int
-DMAbuf_rmchars (int dev, int buff_no, int c)
-{
-  return -EIO;
-}
+	  save_flags (flags);
+	  cli ();
 
-int
-DMAbuf_start_output (int dev, int buff_no, int l)
-{
-  return -EIO;
-}
+	  out_sleep_flag[dev].opts = WK_SLEEP;
+	  poll_wait (&out_sleeper[dev], wait);
+	  restore_flags (flags);
+	  return 0;
+	}
 
-int
-DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
-{
-  return -EIO;
-}
+      if (dmap->dma_mode == DMODE_INPUT)
+	{
+	  return 0;
+	}
 
-void
-DMAbuf_init (void)
-{
-}
+      if (dmap->dma_mode == DMODE_NONE)
+	{
+	  return 1;
+	}
 
-int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
-{
-  return -EIO;
-}
+      if (!DMAbuf_space_in_queue (dev))
+	{
+	  save_flags (flags);
+	  cli ();
 
-int
-DMAbuf_open_dma (int dev)
-{
-  return -ENXIO;
-}
+	  out_sleep_flag[dev].opts = WK_SLEEP;
+	  poll_wait (&out_sleeper[dev], wait);
+	  restore_flags (flags);
+	  return 0;
+	}
+      return 1;
+      break;
 
-void
-DMAbuf_close_dma (int dev)
-{
-  return;
-}
+    case SEL_EX:
+      return 0;
+    }
 
-void
-DMAbuf_reset_dma (int dev)
-{
-  return;
+  return 0;
 }
 
-void
-DMAbuf_inputintr (int dev)
-{
-  return;
-}
 
-void
-DMAbuf_outputintr (int dev, int underrun_flag)
-{
-  return;
-}
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov