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

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

diff -u --recursive --new-file v2.1.40/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
@@ -21,9 +21,6 @@
 #include "ulaw.h"
 #include "coproc.h"
 
-#define ON		1
-#define OFF		0
-
 #define NEUTRAL8	0x80
 #define NEUTRAL16	0x00
 
@@ -31,11 +28,12 @@
 static int      dev_nblock[MAX_AUDIO_DEV];	/* 1 if in nonblocking mode */
 
 #define		AM_NONE		0
-#define		AM_WRITE	1
-#define 	AM_READ		2
+#define		AM_WRITE	OPEN_WRITE
+#define 	AM_READ		OPEN_READ
+static int      dma_ioctl (int dev, unsigned int cmd, caddr_t arg);
 
 
-static int      audio_format[MAX_AUDIO_DEV];
+static int      local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV];
 static int      local_conversion[MAX_AUDIO_DEV];
 
 #define CNV_MU_LAW	0x00000001
@@ -44,7 +42,6 @@
 {
   if (fmt != AFMT_QUERY)
     {
-
       local_conversion[dev] = 0;
 
       if (!(audio_devs[dev]->format_mask & fmt))	/* Not supported */
@@ -57,10 +54,10 @@
 	  fmt = AFMT_U8;	/* This is always supported */
 
       audio_format[dev] = audio_devs[dev]->d->set_bits (dev, fmt);
+      local_format[dev] = fmt;
     }
-
-  if (local_conversion[dev])	/* This shadows the HW format */
-    return local_conversion[dev];
+  else
+    return local_format[dev];
 
   return audio_format[dev];
 }
@@ -98,7 +95,6 @@
 
   local_conversion[dev] = 0;
 
-
   if (dev_type == SND_DEV_AUDIO)
     {
       set_format (dev, AFMT_MU_LAW);
@@ -127,19 +123,12 @@
   /* Align the write pointer with fragment boundaries */
   if ((l = dmap->user_counter % dmap->fragment_size) > 0)
     {
-      char           *ptr;
-      int             err, dummylen, len = dmap->fragment_size - l;
+      int             len;
+      unsigned long   offs = dmap->user_counter % dmap->bytes_in_use;
 
-      if ((err = DMAbuf_getwrbuffer (dev, &ptr, &dummylen, 1)) >= 0)
-	if (dummylen >= len && ((long) ptr % dmap->fragment_size) == l)
-	  {
-	    if ((ptr + len) > (dmap->raw_buf + audio_devs[dev]->buffsize))
-	      printk ("audio: Buffer error 1\n");
-	    if (ptr < dmap->raw_buf)
-	      printk ("audio: Buffer error 11\n");
-	    memset (ptr, dmap->neutral_byte, len);
-	    DMAbuf_move_wrpointer (dev, len);
-	  }
+      len = dmap->fragment_size - l;
+      memset (dmap->raw_buf + offs, dmap->neutral_byte, len);
+      DMAbuf_move_wrpointer (dev, len);
     }
 
 /*
@@ -153,7 +142,7 @@
     {
       p = (p + 1) % dmap->nbufs;
       if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >
-	  (dmap->raw_buf + audio_devs[dev]->buffsize))
+	  (dmap->raw_buf + dmap->buffsize))
 	printk ("audio: Buffer error 2\n");
 
       memset (dmap->raw_buf + p * dmap->fragment_size,
@@ -241,7 +230,7 @@
 
   while (c)
     {
-      if ((err = DMAbuf_getwrbuffer (dev, &dma_buf, &buf_size, dev_nblock[dev]) < 0))
+      if ((err = DMAbuf_getwrbuffer (dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0)
 	{
 	  /* Handle nonblocking mode */
 	  if (dev_nblock[dev] && err == -EAGAIN)
@@ -250,17 +239,18 @@
 	}
 
       l = c;
+
       if (l > buf_size)
 	l = buf_size;
 
       if (!audio_devs[dev]->d->copy_user)
 	{
 	  if ((dma_buf + l) >
-	   (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->buffsize))
+	      (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize))
 	    printk ("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n",
 		    (long) dma_buf, l,
 		    (long) audio_devs[dev]->dmap_out->raw_buf,
-		    (int) audio_devs[dev]->buffsize);
+		    (int) audio_devs[dev]->dmap_out->buffsize);
 	  if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)
 	    printk ("audio: Buffer error 13\n");
 	  copy_from_user (dma_buf, &(buf)[p], l);
@@ -541,46 +531,10 @@
 audio_init_devices (void)
 {
   /*
-     * NOTE! This routine could be called several times during boot.
+   * NOTE! This routine could be called several times during boot.
    */
 }
 
-int
-audio_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait)
-{
-  dev = dev >> 4;
-
-  switch (sel_type)
-    {
-    case SEL_IN:
-      if (!(audio_devs[dev]->open_mode & OPEN_READ))
-	return 0;
-      if (audio_mode[dev] & AM_WRITE && !(audio_devs[dev]->flags & DMA_DUPLEX))
-	{
-	  return 0;		/* Not recording */
-	}
-
-      return DMAbuf_select (dev, file, sel_type, wait);
-      break;
-
-    case SEL_OUT:
-      if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-	return 0;
-      if (audio_mode[dev] & AM_READ && !(audio_devs[dev]->flags & DMA_DUPLEX))
-	{
-	  return 0;		/* Wrong direction */
-	}
-
-      return DMAbuf_select (dev, file, sel_type, wait);
-      break;
-
-    case SEL_EX:
-      return 0;
-    }
-
-  return 0;
-}
-
 
 #endif
 
@@ -632,11 +586,11 @@
          * of sound (using the current speed, sample size and #channels).
        */
 
-      bsz = dsp_dev->buffsize;
+      bsz = dmap->buffsize;
       while (bsz > sz)
 	bsz /= 2;
 
-      if (bsz == dsp_dev->buffsize)
+      if (bsz == dmap->buffsize)
 	bsz /= 2;		/* Needs at least 2 buffers */
 
 /*
@@ -668,17 +622,23 @@
          * 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);
+      if (dmap->fragment_size > (dmap->buffsize / 2))
+	dmap->fragment_size = (dmap->buffsize / 2);
       bsz = dmap->fragment_size;
     }
 
-  bsz &= ~0x03;			/* Force size which is multiple of 4 bytes */
+  if (audio_devs[dev]->min_fragment)
+    if (bsz < (1 << audio_devs[dev]->min_fragment))
+      bsz = 1 << audio_devs[dev]->min_fragment;
+  if (audio_devs[dev]->max_fragment)
+    if (bsz > (1 << audio_devs[dev]->max_fragment))
+      bsz = 1 << audio_devs[dev]->max_fragment;
+  bsz &= ~0x07;			/* Force size which is multiple of 8 bytes */
 #ifdef OS_DMA_ALIGN_CHECK
   OS_DMA_ALIGN_CHECK (bsz);
 #endif
 
-  n = dsp_dev->buffsize / bsz;
+  n = dmap->buffsize / bsz;
   if (n > MAX_SUB_BUFFERS)
     n = MAX_SUB_BUFFERS;
   if (n > dmap->max_fragments)
@@ -693,6 +653,8 @@
   dmap->nbufs = n;
   dmap->bytes_in_use = n * bsz;
   dmap->fragment_size = bsz;
+  dmap->max_byte_counter = (dmap->data_rate * 60 * 60) +
+    dmap->bytes_in_use;		/* Approximately one hour */
 
   if (dmap->raw_buf)
     {
@@ -751,6 +713,8 @@
 
   if (count == 0)
     count = MAX_SUB_BUFFERS;
+  else if (count < MAX_SUB_BUFFERS)
+    count++;
 
   if (bytes < 4 || bytes > 17)	/* <16 || > 512k */
     return -EINVAL;
@@ -762,6 +726,10 @@
     if (bytes < audio_devs[dev]->min_fragment)
       bytes = audio_devs[dev]->min_fragment;
 
+  if (audio_devs[dev]->max_fragment > 0)
+    if (bytes > audio_devs[dev]->max_fragment)
+      bytes = audio_devs[dev]->max_fragment;
+
 #ifdef OS_DMA_MINBITS
   if (bytes < OS_DMA_MINBITS)
     bytes = OS_DMA_MINBITS;
@@ -770,16 +738,16 @@
   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 > dmap->buffsize)
+    dmap->fragment_size = dmap->buffsize;
 
-  if (dmap->fragment_size == audio_devs[dev]->buffsize &&
+  if (dmap->fragment_size == dmap->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 (*(int *) arg = bytes | (count << 16));
+    return (*(int *) arg = bytes | ((count - 1) << 16));
   else
     return 0;
 }
@@ -797,16 +765,18 @@
     case SNDCTL_DSP_SUBDIVIDE:
       {
 	int             fact;
-	int             ret;
+	int             ret = 0;
 
 	fact = *(int *) arg;
 
-	ret = dma_subdivide (dev, dmap_out, arg, fact);
+	if (audio_devs[dev]->open_mode & OPEN_WRITE)
+	  ret = dma_subdivide (dev, dmap_out, arg, fact);
 	if (ret < 0)
 	  return ret;
 
-	if (audio_devs[dev]->flags & DMA_DUPLEX &&
-	    audio_devs[dev]->open_mode & OPEN_READ)
+	if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+	    (audio_devs[dev]->flags & DMA_DUPLEX &&
+	     audio_devs[dev]->open_mode & OPEN_READ))
 	  ret = dma_subdivide (dev, dmap_in, arg, fact);
 
 	return ret;
@@ -824,6 +794,10 @@
 	    !(audio_devs[dev]->open_mode & OPEN_READ))
 	  return -EINVAL;
 
+	if (cmd == SNDCTL_DSP_GETOSPACE &&
+	    !(audio_devs[dev]->open_mode & OPEN_WRITE))
+	  return -EINVAL;
+
 	if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
 	  dmap = dmap_in;
 
@@ -843,14 +817,14 @@
 	      info->fragments = 0;
 	    else
 	      {
-		info->fragments = dmap->nbufs - dmap->qlen;
+		info->fragments = DMAbuf_space_in_queue (dev);
 		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
+				 * This buffer has been counted twice
 				 */
 		    info->fragments -= tmp;
 		  }
@@ -904,6 +878,7 @@
 			       dmap_in->fragment_size, dmap_in->nbufs)) < 0)
 	      return -err;
 
+	    dmap_in->dma_mode = DMODE_INPUT;
 	    audio_devs[dev]->enable_bits = bits;
 	    DMAbuf_activate_recording (dev, dmap_in);
 	  }
@@ -919,7 +894,9 @@
 		reorganize_buffers (dev, dmap_out, 0);
 	      }
 
+	    dmap_out->dma_mode = DMODE_OUTPUT;
 	    ;
+	    audio_devs[dev]->enable_bits = bits;
 	    dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
 	    DMAbuf_launch_output (dev, dmap_out);
 	    ;
@@ -950,20 +927,24 @@
       {
 	count_info      info;
 	unsigned long   flags;
+	struct dma_buffparms *dmap = dmap_in;
 
 	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 = DMAbuf_get_buffer_pointer (dev, audio_devs[dev]->dmap_in) & ~3;
-	info.blocks = audio_devs[dev]->dmap_in->qlen;
+	info.bytes = dmap->byte_counter;
+	info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_INPUT) & ~3;
+	if (info.ptr < dmap->fragment_size && dmap->qtail != 0)
+	  info.bytes += dmap->bytes_in_use;	/* Pointer wrap not handled yet */
+
+	info.blocks = dmap->qlen;
 	info.bytes += info.ptr;
 	memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info));
 
-	if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
-	  audio_devs[dev]->dmap_in->qlen = 0;	/* Reset interrupt counter */
+	if (dmap->mapping_flags & DMA_MAP_MAPPED)
+	  dmap->qlen = 0;	/* Reset interrupt counter */
 	restore_flags (flags);
 	return 0;
       }
@@ -973,20 +954,23 @@
       {
 	count_info      info;
 	unsigned long   flags;
+	struct dma_buffparms *dmap = dmap_out;
 
 	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 = DMAbuf_get_buffer_pointer (dev, audio_devs[dev]->dmap_out) & ~3;
-	info.blocks = audio_devs[dev]->dmap_out->qlen;
+	info.bytes = dmap->byte_counter;
+	info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT) & ~3;
+	if (info.ptr < dmap->fragment_size && dmap->qhead != 0)
+	  info.bytes += dmap->bytes_in_use;	/* Pointer wrap not handled yet */
+	info.blocks = dmap->qlen;
 	info.bytes += info.ptr;
 	memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info));
 
-	if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
-	  audio_devs[dev]->dmap_out->qlen = 0;	/* Reset interrupt counter */
+	if (dmap->mapping_flags & DMA_MAP_MAPPED)
+	  dmap->qlen = 0;	/* Reset interrupt counter */
 
 	restore_flags (flags);
 	return 0;
@@ -1004,18 +988,23 @@
       break;
 
     case SNDCTL_DSP_GETBLKSIZE:
-      if (!(dmap_out->flags & DMA_ALLOC_DONE))
-	{
-	  if (audio_devs[dev]->open_mode & OPEN_WRITE)
-	    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));
-	}
+      {
+	int             fragment_size;
+	struct dma_buffparms *dmap = dmap_out;
 
-      return (*(int *) arg = dmap_out->fragment_size);
+	if (audio_devs[dev]->open_mode & OPEN_WRITE)
+	  reorganize_buffers (dev, dmap_out,
+			      (audio_devs[dev]->open_mode == OPEN_READ));
+	if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+	    (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 == OPEN_READ)
+	  dmap = dmap_in;
+	fragment_size = dmap->fragment_size;
+	return (*(int *) arg = fragment_size);
+      }
       break;
 
     case SNDCTL_DSP_SETFRAGMENT:

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