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

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

diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
@@ -3,7 +3,7 @@
  *
  * The DMA buffer manager for digitized voice applications
  *
- * Copyright by Hannu Savolainen 1993, 1994
+ * Copyright by Hannu Savolainen 1993, 1994, 1995
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -38,11 +38,13 @@
 DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
 
 static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
-{{0}};		/*
-		 * Primitive way to allocate
-		 * such a large array.
-		 * Needs dynamic run-time allocation.
-		 */
+{
+  {0}};				/*
+
+				   * Primitive way to allocate
+				   * such a large array.
+				   * Needs dynamic run-time alloction.
+				 */
 
 static void
 reorganize_buffers (int dev)
@@ -78,10 +80,10 @@
       sz = sr * nc * sz;
 
       /*
-   * Compute a buffer size for time not exceeding 1 second.
-   * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
-   * of sound (using the current speed, sample size and #channels).
-   */
+         * Compute a buffer size for time not exeeding 1 second.
+         * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
+         * of sound (using the current speed, sample size and #channels).
+       */
 
       bsz = dsp_dev->buffsize;
       while (bsz > sz)
@@ -106,9 +108,9 @@
   else
     {
       /*
- * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
- * the buffer size computation has already been done.
- */
+         * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
+         * the buffer sice computation has already been done.
+       */
       if (dmap->fragment_size > audio_devs[dev]->buffsize)
 	dmap->fragment_size = audio_devs[dev]->buffsize;
       bsz = dmap->fragment_size;
@@ -157,7 +159,6 @@
   dmap->flags = DMA_BUSY;	/* Other flags off */
   dmap->qlen = dmap->qhead = dmap->qtail = 0;
 
-  dmap->qlen = dmap->qtail = dmap->qhead = 0;
   dmap->dma_mode = DMODE_NONE;
 }
 
@@ -250,7 +251,7 @@
 
       /*
        * Some devices such as GUS have huge amount of on board RAM for the
-       * audio data. We have to wait util the device has finished playing.
+       * audio data. We have to wait until the device has finished playing.
        */
 
       DISABLE_INTR (flags);
@@ -295,7 +296,7 @@
 }
 
 int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
 {
   unsigned long   flags;
   int             err = EIO;
@@ -342,6 +343,12 @@
 	  dmap->flags |= DMA_ACTIVE | DMA_STARTED;
 	}
 
+      if (dontblock)
+	{
+	  RESTORE_INTR (flags);
+	  return RET_ERROR (EAGAIN);
+	}
+
       /* Wait for the next block */
 
       DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
@@ -425,7 +432,7 @@
 	  }
 
 	if (dmap->subdivision != 0 ||
-	    dmap->fragment_size)/* Too late to change */
+	    dmap->fragment_size)	/* Loo late to change */
 	  return RET_ERROR (EINVAL);
 
 	if (fact > MAX_REALTIME_FACTOR)
@@ -448,7 +455,7 @@
 	  return RET_ERROR (EIO);
 
 	if (dmap->subdivision != 0 ||
-	    dmap->fragment_size)/* Too late to change */
+	    dmap->fragment_size)	/* Loo late to change */
 	  return RET_ERROR (EINVAL);
 
 	bytes = fact & 0xffff;
@@ -478,11 +485,24 @@
       }
       break;
 
+    case SNDCTL_DSP_GETISPACE:
+    case SNDCTL_DSP_GETOSPACE:
+      if (!local)
+	return RET_ERROR (EINVAL);
+
+      {
+	audio_buf_info *info = (audio_buf_info *) arg;
+
+	info->fragments = dmap->qlen;
+	info->fragsize = dmap->fragment_size;
+	info->bytes = dmap->qlen * dmap->fragment_size;
+      }
+      return 0;
+
     default:
       return audio_devs[dev]->ioctl (dev, cmd, arg, local);
     }
 
-  return RET_ERROR (EIO);
 }
 
 static int
@@ -491,13 +511,13 @@
   int             len, max, tmp;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  if (dmap->qlen == dmap->nbufs)/* No space at all */
+  if (dmap->qlen == dmap->nbufs)	/* No space at all */
     return 0;
 
   /*
-  * Verify that there are no more pending buffers than the limit
-  * defined by the process.
-  */
+     * Verify that there are no more pending buffers than the limit
+     * defined by the process.
+   */
 
   max = dmap->max_fragments;
   len = dmap->qlen;
@@ -507,8 +527,8 @@
       tmp = audio_devs[dev]->local_qlen (dev);
       if (tmp & len)
 	tmp--;			/*
-			 * This buffer has been counted twice
-			 */
+				   * This buffer has been counted twice
+				 */
       len += tmp;
     }
 
@@ -518,7 +538,7 @@
 }
 
 int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
 {
   unsigned long   flags;
   int             abort, err = EIO;
@@ -551,6 +571,9 @@
     }
 
 
+  if (dontblock)
+    return RET_ERROR (EAGAIN);
+
   DISABLE_INTR (flags);
 
   abort = 0;
@@ -669,13 +692,24 @@
 #ifndef DMAMODE_AUTO
       printk ("sound: Invalid DMA mode for device %d\n", dev);
 #endif
+#if defined(SVR42)
+
+      /*
+         ** send full count to snd_dma_prog, it will take care of subtracting
+         ** one if it is required.
+       */
+      snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use,
+		    dma_mode, TRUE);
+
+#else /* !SVR42 */
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
 #ifdef DMAMODE_AUTO
 		 | DMAMODE_AUTO
 #endif
 		 ,
-		 dmap->raw_buf_phys[0], dmap->bytes_in_use);
+		 dmap->raw_buf_phys[0], dmap->bytes_in_use - 1);
       dma_enable (chan);
+#endif /*  ! SVR42 */
 #else
 #error This routine is not valid for this OS.
 #endif
@@ -703,9 +737,15 @@
 #else
 
 #if defined(GENERIC_SYSV)
+#if defined(SVR42)
+
+      snd_dma_prog (chan, physaddr, count, dma_mode, FALSE);
+
+#else /* ! SVR42 */
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
 		 physaddr, count);
       dma_enable (chan);
+#endif /* SVR42 */
 #else
 #error This routine is not valid for this OS.
 #endif /* GENERIC_SYSV */
@@ -722,9 +762,13 @@
 {
   int             dev;
 
+#if defined(SVR42)
+  snd_dma_init ();
+#endif /* SVR42 */
+
   /*
- * NOTE! This routine could be called several times.
- */
+     * NOTE! This routine could be called several times.
+   */
 
   for (dev = 0; dev < num_audiodevs; dev++)
     audio_devs[dev]->dmap = &dmaps[dev];
@@ -735,18 +779,22 @@
 DMAbuf_outputintr (int dev, int event_type)
 {
   /*
- * Event types:
- *	0 = DMA transfer done. Device still has more data in the local
- *	    buffer.
- *	1 = DMA transfer done. Device doesn't have local buffer or it's
- *	    empty now.
- *	2 = No DMA transfer but the device has now more space in its local
- *	    buffer.
- */
+     * Event types:
+     *  0 = DMA transfer done. Device still has more data in the local
+     *      buffer.
+     *  1 = DMA transfer done. Device doesn't have local buffer or it's
+     *      empty now.
+     *  2 = No DMA transfer but the device has now more space in it's local
+     *      buffer.
+   */
 
   unsigned long   flags;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
+#if defined(SVR42)
+  snd_dma_intr (audio_devs[dev]->dmachan);
+#endif /* SVR42 */
+
   if (event_type != 2)
     {
       if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
@@ -793,6 +841,10 @@
   unsigned long   flags;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
+#if defined(SVR42)
+  snd_dma_intr (audio_devs[dev]->dmachan);
+#endif /* SVR42 */
+
   if (dmap->qlen == (dmap->nbufs - 1))
     {
       printk ("Sound: Recording overrun\n");
@@ -832,7 +884,7 @@
   unsigned long   flags;
   int             chan = audio_devs[dev]->dmachan;
 
-  if (ALLOC_DMA_CHN (chan,"audio"))
+  if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name))
     {
       printk ("Unable to grab DMA%d for the audio driver\n", chan);
       return RET_ERROR (EBUSY);
@@ -853,24 +905,72 @@
 {
   int             chan = audio_devs[dev]->dmachan;
 
-  DMAbuf_reset_dma (chan);
+  DMAbuf_reset_dma (dev);
   RELEASE_DMA_CHN (chan);
 }
 
 void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma (int dev)
 {
+#if 0
+  int             chan = audio_devs[dev]->dmachan;
+
+  disable_dma (chan);
+#endif
 }
 
-/*
- * The sound_mem_init() is called by mem_init() immediately after mem_map is
- * initialized and before free_page_list is created.
- *
- * This routine allocates DMA buffers at the end of available physical memory (
- * <16M) and marks pages reserved at mem_map.
- */
+#ifdef ALLOW_SELECT
+int
+DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+  unsigned long   flags;
 
-#else
+  switch (sel_type)
+    {
+    case SEL_IN:
+      if (dmap->dma_mode != DMODE_INPUT)
+	return 0;
+
+      if (!dmap->qlen)
+	{
+	  DISABLE_INTR (flags);
+	  dev_sleep_flag[dev].mode = WK_SLEEP;
+	  select_wait (&dev_sleeper[dev], wait);
+	  RESTORE_INTR (flags);
+	  return 0;
+	}
+      return 1;
+      break;
+
+    case SEL_OUT:
+      if (dmap->dma_mode == DMODE_INPUT)
+	return 0;
+
+      if (dmap->dma_mode == DMODE_NONE)
+	return 1;
+
+      if (!space_in_queue (dev))
+	{
+	  DISABLE_INTR (flags);
+	  dev_sleep_flag[dev].mode = WK_SLEEP;
+	  select_wait (&dev_sleeper[dev], wait);
+	  RESTORE_INTR (flags);
+	  return 0;
+	}
+      return 1;
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
+}
+
+#endif /* ALLOW_SELECT */
+
+#else /* EXCLUDE_AUDIO */
 /*
  * Stub versions if audio services not included
  */
@@ -888,13 +988,13 @@
 }
 
 int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
 {
   return RET_ERROR (EIO);
 }
 
 int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
 {
   return RET_ERROR (EIO);
 }
@@ -930,19 +1030,19 @@
 }
 
 int
-DMAbuf_open_dma (int chan)
+DMAbuf_open_dma (int dev)
 {
   return RET_ERROR (ENXIO);
 }
 
 void
-DMAbuf_close_dma (int chan)
+DMAbuf_close_dma (int dev)
 {
   return;
 }
 
 void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma (int dev)
 {
   return;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this