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

Next file: linux/drivers/sound/configure.c
Previous file: linux/drivers/sound/aedsp16.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.8/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
@@ -33,11 +33,13 @@
 #ifndef EXCLUDE_AUDIO
 
 #include "ulaw.h"
+#include "coproc.h"
 
 #define ON		1
 #define OFF		0
 
 static int      wr_buff_no[MAX_AUDIO_DEV];	/*
+
 						 * != -1, if there is
 						 * a incomplete output
 						 * block in the queue.
@@ -45,6 +47,7 @@
 static int      wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
 
 static int      audio_mode[MAX_AUDIO_DEV];
+static int      dev_nblock[MAX_AUDIO_DEV];	/* 1 if in noblocking mode */
 
 #define		AM_NONE		0
 #define		AM_WRITE	1
@@ -98,6 +101,16 @@
   if ((ret = DMAbuf_open (dev, mode)) < 0)
     return ret;
 
+  if (audio_devs[dev]->coproc)
+    if ((ret = audio_devs[dev]->coproc->
+	 open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
+      {
+	audio_release (dev, file);
+	printk ("Sound: Can't access coprocessor device\n");
+
+	return ret;
+      }
+
   local_conversion[dev] = 0;
 
   if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
@@ -115,6 +128,8 @@
 
   wr_buff_no[dev] = -1;
   audio_mode[dev] = AM_NONE;
+  wr_buff_size[dev] = wr_buff_ptr[dev] = 0;
+  dev_nblock[dev] = 0;
 
   return ret;
 }
@@ -134,6 +149,8 @@
       wr_buff_no[dev] = -1;
     }
 
+  if (audio_devs[dev]->coproc)
+    audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM);
   DMAbuf_release (dev, mode);
 }
 
@@ -155,9 +172,9 @@
 	   "1:\tlodsb\n\t"
 	   "xlatb\n\t"
 	   "stosb\n\t"
-	   "loop 1b\n\t":
-	   :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
-	   :"bx", "cx", "di", "si", "ax");
+"loop 1b\n\t":
+:	   "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
+:	   "bx", "cx", "di", "si", "ax");
 }
 
 #endif
@@ -203,8 +220,13 @@
 				 * There is no incomplete buffers
 				 */
 	{
-	  if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
+	  if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev],
+						     &wr_buff_size[dev],
+						     dev_nblock[dev])) < 0)
 	    {
+	      /* Handle nonblocking mode */
+	      if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EAGAIN))
+		return p;	/* No more space. Return # of accepted bytes */
 	      return wr_buff_no[dev];
 	    }
 	  wr_buff_ptr[dev] = 0;
@@ -284,8 +306,16 @@
 
   while (c)
     {
-      if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
-	return buff_no;
+      if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
+					 dev_nblock[dev])) < 0)
+	{
+	  /* Nonblocking mode handling. Return current # of bytes */
+
+	  if (dev_nblock[dev] && buff_no == RET_ERROR (EAGAIN))
+	    return p;
+
+	  return buff_no;
+	}
 
       if (l > c)
 	l = c;
@@ -324,56 +354,149 @@
 
   dev = dev >> 4;
 
-  switch (cmd)
+  if (((cmd >> 8) & 0xff) == 'C')
     {
-    case SNDCTL_DSP_SYNC:
-      if (wr_buff_no[dev] >= 0)
+      if (audio_devs[dev]->coproc)	/* Coprocessor ioctl */
+	return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0);
+      else
+	printk ("/dev/dsp%d: No coprocessor for this device\n", dev);
+
+      return RET_ERROR (EREMOTEIO);
+    }
+  else
+    switch (cmd)
+      {
+      case SNDCTL_DSP_SYNC:
+	if (wr_buff_no[dev] >= 0)
+	  {
+	    DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+	    wr_buff_no[dev] = -1;
+	  }
+	return DMAbuf_ioctl (dev, cmd, arg, 0);
+	break;
+
+      case SNDCTL_DSP_POST:
+	if (wr_buff_no[dev] >= 0)
+	  {
+	    DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+	    wr_buff_no[dev] = -1;
+	  }
+	return 0;
+	break;
+
+      case SNDCTL_DSP_RESET:
+	wr_buff_no[dev] = -1;
+	return DMAbuf_ioctl (dev, cmd, arg, 0);
+	break;
+
+      case SNDCTL_DSP_GETFMTS:
+	return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
+	break;
+
+      case SNDCTL_DSP_SETFMT:
+	return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+
+      case SNDCTL_DSP_GETISPACE:
+	if (audio_mode[dev] == AM_WRITE)
+	  return RET_ERROR (EBUSY);
+
 	{
-	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+	  audio_buf_info  info;
 
-	  wr_buff_no[dev] = -1;
+	  int             err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
+
+	  if (err < 0)
+	    return err;
+
+	  if (wr_buff_no[dev] != -1)
+	    info.bytes += wr_buff_ptr[dev];
+
+	  IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
+	  return 0;
 	}
-      return DMAbuf_ioctl (dev, cmd, arg, 0);
-      break;
 
-    case SNDCTL_DSP_POST:
-      if (wr_buff_no[dev] >= 0)
+      case SNDCTL_DSP_GETOSPACE:
+	if (audio_mode[dev] == AM_READ)
+	  return RET_ERROR (EBUSY);
+
 	{
-	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+	  audio_buf_info  info;
 
-	  wr_buff_no[dev] = -1;
-	}
-      return 0;
-      break;
+	  int             err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
 
-    case SNDCTL_DSP_RESET:
-      wr_buff_no[dev] = -1;
-      return DMAbuf_ioctl (dev, cmd, arg, 0);
-      break;
+	  if (err < 0)
+	    return err;
 
-    case SNDCTL_DSP_GETFMTS:
-      return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
-      break;
+	  if (wr_buff_no[dev] != -1)
+	    info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
 
-    case SNDCTL_DSP_SETFMT:
-      return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+	  IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
+	  return 0;
+	}
 
-    default:
-      return DMAbuf_ioctl (dev, cmd, arg, 0);
-      break;
-    }
+      case SNDCTL_DSP_NONBLOCK:
+	dev_nblock[dev] = 1;
+	return 0;
+	break;
+
+      default:
+	return DMAbuf_ioctl (dev, cmd, arg, 0);
+      }
 }
 
 long
 audio_init (long mem_start)
 {
   /*
- * NOTE! This routine could be called several times during boot.
- */
+     * NOTE! This routine could be called several times during boot.
+   */
   return mem_start;
 }
 
-#else
+#ifdef ALLOW_SELECT
+int
+audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+  int             l;
+  char           *dmabuf;
+
+  dev = dev >> 4;
+
+  switch (sel_type)
+    {
+    case SEL_IN:
+      if (audio_mode[dev] != AM_READ)	/* Wrong direction */
+	return 0;
+
+      if (DMAbuf_getrdbuffer (dev, &dmabuf, &l,
+			      1 /* Don't block */ ) >= 0)
+	return 1;		/* We have data */
+
+      return DMAbuf_select (dev, file, sel_type, wait);
+      break;
+
+    case SEL_OUT:
+      if (audio_mode[dev] != AM_WRITE)	/* Wrong direction */
+	return 0;
+
+      if (wr_buff_no[dev] != -1)
+	return 1;		/* There is space in the current buffer */
+
+      return DMAbuf_select (dev, file, sel_type, wait);
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
+}
+
+#endif /* ALLOW_SELECT */
+
+#else /* EXCLUDE_AUDIO */
 /*
  * Stub versions
  */

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