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

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

diff -u --recursive --new-file v2.1.74/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
@@ -11,13 +11,12 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
-#include <linux/config.h>
 
+#include <linux/config.h>
 
 #include "sound_config.h"
 
 #if defined(CONFIG_AUDIO) || defined(MODULE)
-
 #include "ulaw.h"
 #include "coproc.h"
 
@@ -37,36 +36,38 @@
 static int      local_conversion[MAX_AUDIO_DEV];
 
 #define CNV_MU_LAW	0x00000001
-static int
-set_format(int dev, int fmt)
+
+static int set_format(int dev, int fmt)
 {
 	if (fmt != AFMT_QUERY)
-	  {
-		  local_conversion[dev] = 0;
+	{
+		local_conversion[dev] = 0;
 
-		  if (!(audio_devs[dev]->format_mask & fmt))	/* Not supported */
-			  if (fmt == AFMT_MU_LAW)
-			    {
-				    fmt = AFMT_U8;
-				    local_conversion[dev] = CNV_MU_LAW;
-			  } else
-				  fmt = AFMT_U8;	/* This is always supported */
-
-		  audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt);
-		  local_format[dev] = fmt;
-	} else
+		if (!(audio_devs[dev]->format_mask & fmt))	/* Not supported */
+		{
+			if (fmt == AFMT_MU_LAW)
+			{
+				fmt = AFMT_U8;
+				local_conversion[dev] = CNV_MU_LAW;
+			}
+			else
+				fmt = AFMT_U8;	/* This is always supported */
+		}
+		audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt);
+		local_format[dev] = fmt;
+	}
+	else
 		return local_format[dev];
 
 	return local_format[dev];
 }
 
-int
-audio_open(int dev, struct fileinfo *file)
+int audio_open(int dev, struct fileinfo *file)
 {
-	int             ret;
-	int             bits;
-	int             dev_type = dev & 0x0f;
-	int             mode = file->mode & O_ACCMODE;
+	int ret;
+	int bits;
+	int dev_type = dev & 0x0f;
+	int mode = file->mode & O_ACCMODE;
 
 	dev = dev >> 4;
 
@@ -82,20 +83,21 @@
 		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;
-		  }
+			open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
+		{
+			audio_release(dev, file);
+			printk(KERN_WARNING "Sound: Can't access coprocessor device\n");
+			return ret;
+		}
+	}
+	
 	local_conversion[dev] = 0;
 
 	if (dev_type == SND_DEV_AUDIO)
-	  {
 		  set_format(dev, AFMT_MU_LAW);
-	} else
+	else 
 		set_format(dev, bits);
 
 	audio_mode[dev] = AM_NONE;
@@ -105,8 +107,7 @@
 	return ret;
 }
 
-static void
-sync_output(int dev)
+static void sync_output(int dev)
 {
 	int             p, i;
 	int             l;
@@ -117,39 +118,40 @@
 	dmap->flags |= DMA_POST;
 
 	/* Align the write pointer with fragment boundaries */
+	
 	if ((l = dmap->user_counter % dmap->fragment_size) > 0)
-	  {
-		  int             len;
-		  unsigned long   offs = dmap->user_counter % dmap->bytes_in_use;
-
-		  len = dmap->fragment_size - l;
-		  memset(dmap->raw_buf + offs, dmap->neutral_byte, len);
-		  DMAbuf_move_wrpointer(dev, len);
-	  }
-/*
- * Clean all unused buffer fragments.
- */
+	{
+		int len;
+		unsigned long offs = dmap->user_counter % dmap->bytes_in_use;
+
+		len = dmap->fragment_size - l;
+		memset(dmap->raw_buf + offs, dmap->neutral_byte, len);
+		DMAbuf_move_wrpointer(dev, len);
+	}
+	
+	/*
+	 * Clean all unused buffer fragments.
+	 */
 
 	p = dmap->qtail;
 	dmap->flags |= DMA_POST;
 
 	for (i = dmap->qlen + 1; i < dmap->nbufs; i++)
-	  {
-		  p = (p + 1) % dmap->nbufs;
-		  if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >
-		      (dmap->raw_buf + dmap->buffsize))
-			  printk("audio: Buffer error 2\n");
-
-		  memset(dmap->raw_buf + p * dmap->fragment_size,
-			 dmap->neutral_byte,
-			 dmap->fragment_size);
-	  }
+	{
+		p = (p + 1) % dmap->nbufs;
+		if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >
+			(dmap->raw_buf + dmap->buffsize))
+				printk(KERN_ERR "audio: Buffer error 2\n");
+
+		memset(dmap->raw_buf + p * dmap->fragment_size,
+			dmap->neutral_byte,
+			dmap->fragment_size);
+	}
 
 	dmap->flags |= DMA_DIRTY;
 }
 
-void
-audio_release(int dev, struct fileinfo *file)
+void audio_release(int dev, struct fileinfo *file)
 {
 	int             mode;
 
@@ -167,8 +169,8 @@
 }
 
 #if defined(NO_INLINE_ASM) || !defined(i386)
-static void
-translate_bytes(const unsigned char *table, unsigned char *buff, int n)
+
+static void translate_bytes(const unsigned char *table, unsigned char *buff, int n)
 {
 	unsigned long   i;
 
@@ -184,25 +186,24 @@
 translate_bytes(const void *table, void *buff, int n)
 {
 	if (n > 0)
-	  {
-		  __asm__("cld\n"
-			  "1:\tlodsb\n\t"
-			  "xlatb\n\t"
-			  "stosb\n\t"
+	{
+		__asm__("cld\n"
+			"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");
-	  }
+	}
 }
 
 #endif
 
-int
-audio_write(int dev, struct fileinfo *file, const char *buf, int count)
+int audio_write(int dev, struct fileinfo *file, const char *buf, int count)
 {
-	int             c, p, l, buf_size;
-	int             err;
-	char           *dma_buf;
+	int c, p, l, buf_size;
+	int err;
+	char *dma_buf;
 
 	dev = dev >> 4;
 
@@ -218,61 +219,61 @@
 		audio_mode[dev] = AM_WRITE;
 
 	if (!count)		/* Flush output */
-	  {
+	{
 		  sync_output(dev);
 		  return 0;
-	  }
+	}
+	
 	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)
-				    return p;	/* No more space. Return # of accepted bytes */
-			    return err;
-		    }
-		  l = c;
-
-		  if (l > buf_size)
-			  l = buf_size;
-
-		  if (!audio_devs[dev]->d->copy_user)
-		    {
-			    if ((dma_buf + l) >
+			if (dev_nblock[dev] && err == -EAGAIN)
+				return p;	/* No more space. Return # of accepted bytes */
+			return err;
+		}
+		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]->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]->dmap_out->buffsize);
-				      return -EDOM;
-			      }
-			    if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)
-			      {
-				      printk("audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf);
-				      return -EDOM;
-			      }
-			    copy_from_user(dma_buf, &(buf)[p], l);
-		  } else
-			  audio_devs[dev]->d->copy_user(dev,
-						  dma_buf, 0, buf, p, l);
-
-		  if (local_conversion[dev] & CNV_MU_LAW)
-		    {
-			    /*
-			     * This just allows interrupts while the conversion is running
-			     */
-			    sti();
-			    translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
-		    }
-		  c -= l;
-		  p += l;
-		  DMAbuf_move_wrpointer(dev, l);
+			{
+				printk(KERN_ERR "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]->dmap_out->buffsize);
+				return -EDOM;
+			}
+			if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)
+			{
+				printk(KERN_ERR "audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf);
+				return -EDOM;
+			}
+			if(copy_from_user(dma_buf, &(buf)[p], l))
+				return -EFAULT;
+		} 
+		else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l);
+
+		if (local_conversion[dev] & CNV_MU_LAW)
+		{
+			/*
+			 * This just allows interrupts while the conversion is running
+			 */
+			sti();
+			translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
+		}
+		c -= l;
+		p += l;
+		DMAbuf_move_wrpointer(dev, l);
 
-	  }
+	}
 
 	return count;
 }
 
-int
-audio_read(int dev, struct fileinfo *file, char *buf, int count)
+int audio_read(int dev, struct fileinfo *file, char *buf, int count)
 {
 	int             c, p, l;
 	char           *dmabuf;
@@ -286,251 +287,268 @@
 		return -EPERM;
 
 	if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-	  {
-		  sync_output(dev);
-	  }
+		sync_output(dev);
+
 	if (audio_devs[dev]->flags & DMA_DUPLEX)
 		audio_mode[dev] |= AM_READ;
 	else
 		audio_mode[dev] = AM_READ;
 
-	while (c)
-	  {
-		  if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
-						   dev_nblock[dev])) < 0)
-		    {
-			    /* Nonblocking mode handling. Return current # of bytes */
+	while(c)
+	{
+		if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
+			dev_nblock[dev])) < 0)
+		{
+			/*
+			 *	Nonblocking mode handling. Return current # of bytes
+			 */
 
-			    if (dev_nblock[dev] && buf_no == -EAGAIN)
-				    return p;
+			if (dev_nblock[dev] && buf_no == -EAGAIN)
+				return p;
 
-			    if (p > 0) 		/* Avoid throwing away data */
+			if (p > 0) 		/* Avoid throwing away data */
 				return p;	/* Return it instead */
 
-			    return buf_no;
-		    }
-		  if (l > c)
-			  l = c;
-
-		  /*
-		   * Insert any local processing here.
-		   */
-
-		  if (local_conversion[dev] & CNV_MU_LAW)
-		    {
-			    /*
-			     * This just allows interrupts while the conversion is running
-			     */
-			    sti();
-
-			    translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);
-		    }
-		  {
-			  char           *fixit = dmabuf;
-
-			  copy_to_user(&(buf)[p], fixit, l);
-		  };
-
-		  DMAbuf_rmchars(dev, buf_no, l);
-
-		  p += l;
-		  c -= l;
-	  }
+			return buf_no;
+		}
+		if (l > c)
+			l = c;
+
+		/*
+		 * Insert any local processing here.
+		 */
+
+		if (local_conversion[dev] & CNV_MU_LAW)
+		{
+			/*
+			 * This just allows interrupts while the conversion is running
+			 */
+			sti();
+
+			translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);
+		}
+		
+		{
+			char           *fixit = dmabuf;
+
+			if(copy_to_user(&(buf)[p], fixit, l))
+				return -EFAULT;
+		};
+
+		DMAbuf_rmchars(dev, buf_no, l);
+
+		p += l;
+		c -= l;
+	}
 
 	return count - c;
 }
 
-int
-audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
+int audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
 	    unsigned int cmd, caddr_t arg)
 {
-	int             val;
-
-	/* printk( "audio_ioctl(%x, %x)\n",  (int)cmd,  (int)arg); */
+	int val;
 
 	dev = dev >> 4;
 
 	if (((cmd >> 8) & 0xff) == 'C')
-	  {
-		  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 -ENXIO;
-	} else
-		switch (cmd)
-		  {
-		  case SNDCTL_DSP_SYNC:
-			  if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-				  return 0;
-
-			  if (audio_devs[dev]->dmap_out->fragment_size == 0)
-				  return 0;
-			  sync_output(dev);
-			  DMAbuf_sync(dev);
-			  DMAbuf_reset(dev);
-			  return 0;
-			  break;
-
-		  case SNDCTL_DSP_POST:
-			  if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-				  return 0;
-			  if (audio_devs[dev]->dmap_out->fragment_size == 0)
-				  return 0;
-			  audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
-			  sync_output(dev);
-			  dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
-			  return 0;
-			  break;
-
-		  case SNDCTL_DSP_RESET:
-			  audio_mode[dev] = AM_NONE;
-			  DMAbuf_reset(dev);
-			  return 0;
-			  break;
-
-		  case SNDCTL_DSP_GETFMTS:
-			  return (*(int *) arg = audio_devs[dev]->format_mask);
-			  break;
-
-		  case SNDCTL_DSP_SETFMT:
-			  val = *(int *) arg;
-			  return (*(int *) arg = set_format(dev, val));
-
-		  case SNDCTL_DSP_GETISPACE:
-			  if (!(audio_devs[dev]->open_mode & OPEN_READ))
-				  return 0;
-			  if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-				  return -EBUSY;
-
-			  {
-				  audio_buf_info  info;
-
-				  int             err = dma_ioctl(dev, cmd, (caddr_t) & info);
-
-				  if (err < 0)
-					  return err;
-
-				  memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-				  return 0;
-			  }
+	{
+		if (audio_devs[dev]->coproc)	/* Coprocessor ioctl */
+			return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
+		/* else
+			printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */
+		return -ENXIO;
+	}
+	else switch (cmd)
+	{
+		case SNDCTL_DSP_SYNC:
+			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+				return 0;
+
+			if (audio_devs[dev]->dmap_out->fragment_size == 0)
+				return 0;
+			sync_output(dev);
+			DMAbuf_sync(dev);
+			DMAbuf_reset(dev);
+			return 0;
+
+		case SNDCTL_DSP_POST:
+			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+				return 0;
+			if (audio_devs[dev]->dmap_out->fragment_size == 0)
+				return 0;
+			audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
+			sync_output(dev);
+			dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
+			return 0;
+
+		case SNDCTL_DSP_RESET:
+			audio_mode[dev] = AM_NONE;
+			DMAbuf_reset(dev);
+			return 0;
+
+		case SNDCTL_DSP_GETFMTS:
+			return (*(int *) arg = audio_devs[dev]->format_mask);
+
+		case SNDCTL_DSP_SETFMT:
+			val = *(int *) arg;
+			return (*(int *) arg = set_format(dev, val));
+
+		case SNDCTL_DSP_GETISPACE:
+			if (!(audio_devs[dev]->open_mode & OPEN_READ))
+				return 0;
+			if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+				return -EBUSY;
+
+			{
+				audio_buf_info  info;
+
+				int err = dma_ioctl(dev, cmd, (caddr_t) & info);
+
+				if (err < 0)
+					return err;
+
+				memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+				return 0;
+			}
 
-		  case SNDCTL_DSP_GETOSPACE:
-			  if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+		case SNDCTL_DSP_GETOSPACE:
+			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
 				  return -EPERM;
-			  if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+			if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
 				  return -EBUSY;
 
-			  {
-				  audio_buf_info  info;
-
-				  int             err = dma_ioctl(dev, cmd, (caddr_t) & info);
-
-				  if (err < 0)
-					  return err;
-
-				  memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-				  return 0;
-			  }
-
-		  case SNDCTL_DSP_NONBLOCK:
-			  dev_nblock[dev] = 1;
-			  return 0;
-			  break;
-
-		  case SNDCTL_DSP_GETCAPS:
-			  {
-				  int             info = 1;	/* Revision level of this ioctl() */
-
-				  if (audio_devs[dev]->flags & DMA_DUPLEX &&
-				      audio_devs[dev]->open_mode == OPEN_READWRITE)
-					  info |= DSP_CAP_DUPLEX;
-
-				  if (audio_devs[dev]->coproc)
-					  info |= DSP_CAP_COPROC;
-
-				  if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */
-					  info |= DSP_CAP_BATCH;
-
-				  if (audio_devs[dev]->d->trigger)	/* Supports SETTRIGGER */
-					  info |= DSP_CAP_TRIGGER;
+			{
+				audio_buf_info  info;
 
-				  info |= DSP_CAP_MMAP;
+				int err = dma_ioctl(dev, cmd, (caddr_t) & info);
 
-				  memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-				  return 0;
-			  }
-			  break;
+				if (err < 0)
+					return err;
 
-		  case SOUND_PCM_WRITE_RATE:
-			  val = *(int *) arg;
-			  return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val));
-
-		  case SOUND_PCM_READ_RATE:
-			  return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0));
-
-		  case SNDCTL_DSP_STEREO:
-			  {
-				  int             n;
-
-				  n = *(int *) arg;
-				  if (n > 1)
-				    {
-					    printk("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n);
-					    return -EINVAL;
-				    }
-				  if (n < 0)
-					  return -EINVAL;
-
-				  return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1);
-			  }
-
-		  case SOUND_PCM_WRITE_CHANNELS:
-			  val = *(int *) arg;
-			  return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val));
-
-		  case SOUND_PCM_READ_CHANNELS:
-			  return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0));
-
-		  case SOUND_PCM_READ_BITS:
-			  return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0));
-
-		  case SNDCTL_DSP_SETDUPLEX:
-			  if (audio_devs[dev]->open_mode != OPEN_READWRITE)
-				  return -EPERM;
-			  if (audio_devs[dev]->flags & DMA_DUPLEX)
-				  return 0;
-			  else
-				  return -EIO;
-			  break;
-
-		  case SNDCTL_DSP_PROFILE:
-			  if (audio_devs[dev]->open_mode & OPEN_WRITE)
-				  audio_devs[dev]->dmap_out->applic_profile = *(int *) arg;
-			  if (audio_devs[dev]->open_mode & OPEN_READ)
-				  audio_devs[dev]->dmap_in->applic_profile = *(int *) arg;
-			  return 0;
-			  break;
-
-		  default:
-			  return dma_ioctl(dev, cmd, arg);
-		  }
+				memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+				return 0;
+			}
+
+		case SNDCTL_DSP_NONBLOCK:
+			dev_nblock[dev] = 1;
+			return 0;
+
+		case SNDCTL_DSP_GETCAPS:
+		{
+			int info = 1;	/* Revision level of this ioctl() */
+
+			if (audio_devs[dev]->flags & DMA_DUPLEX &&
+				audio_devs[dev]->open_mode == OPEN_READWRITE)
+					info |= DSP_CAP_DUPLEX;
+
+			if (audio_devs[dev]->coproc)
+				info |= DSP_CAP_COPROC;
+
+			if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */
+				info |= DSP_CAP_BATCH;
+
+			if (audio_devs[dev]->d->trigger)	/* Supports SETTRIGGER */
+				info |= DSP_CAP_TRIGGER;
+
+			info |= DSP_CAP_MMAP;
+
+			memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+			return 0;
+		}
+
+		case SOUND_PCM_WRITE_RATE:
+			val = *(int *) arg;
+			return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val));
+
+		case SOUND_PCM_READ_RATE:
+			return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0));
+
+		case SNDCTL_DSP_STEREO:
+		{
+			int n;
+
+			n = *(int *) arg;
+			if (n > 1)
+			{
+/*				printk(KERN_DENUG "sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n);*/
+				return -EINVAL;
+			}
+			if (n < 0)
+				return -EINVAL;
+
+			return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1);
+		}
+
+		case SOUND_PCM_WRITE_CHANNELS:
+			val = *(int *) arg;
+			return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val));
+
+		case SOUND_PCM_READ_CHANNELS:
+			return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0));
+
+		case SOUND_PCM_READ_BITS:
+			return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0));
+
+		case SNDCTL_DSP_SETDUPLEX:
+			if (audio_devs[dev]->open_mode != OPEN_READWRITE)
+				return -EPERM;
+			if (audio_devs[dev]->flags & DMA_DUPLEX)
+				return 0;
+			else
+				return -EIO;
+
+		case SNDCTL_DSP_PROFILE:
+			if (audio_devs[dev]->open_mode & OPEN_WRITE)
+				audio_devs[dev]->dmap_out->applic_profile = *(int *) arg;
+			if (audio_devs[dev]->open_mode & OPEN_READ)
+				audio_devs[dev]->dmap_in->applic_profile = *(int *) arg;
+			return 0;
+
+		case SNDCTL_DSP_GETODELAY:
+		{
+			int count;
+			unsigned long   flags;
+			struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+				return -EINVAL;
+			if (!(dmap->flags & DMA_ALLOC_DONE))
+				return *(int *) arg = 0;
+
+			save_flags (flags);
+			cli ();
+			/* Compute number of bytes that have been played */
+			count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
+			if (count < dmap->fragment_size && dmap->qhead != 0)
+				count += dmap->bytes_in_use;	/* Pointer wrap not handled yet */
+			count += dmap->byte_counter;
+
+			/* Substract current count from the number of bytes written by app */
+			count = dmap->user_counter - count;
+			if (count < 0)
+				count = 0;
+			restore_flags (flags);
+
+			return *(int *) arg = count;
+		}
+		break;
+
+		default:
+			return dma_ioctl(dev, cmd, arg);
+	}
 }
 
-void
-audio_init_devices(void)
+void audio_init_devices(void)
 {
 	/*
 	 * NOTE! This routine could be called several times during boot.
 	 */
 }
 
-
 #endif
 
-void
-reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
+void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
 {
 	/*
 	 * This routine breaks the physical device buffers to logical ones.
@@ -538,8 +556,8 @@
 
 	struct audio_operations *dsp_dev = audio_devs[dev];
 
-	unsigned        i, n;
-	unsigned        sr, nc, sz, bsz;
+	unsigned i, n;
+	unsigned sr, nc, sz, bsz;
 
 	sr = dsp_dev->d->set_speed(dev, 0);
 	nc = dsp_dev->d->set_channels(dev, 0);
@@ -551,12 +569,13 @@
 		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;
-	  }
+	{
+/*		printk(KERN_DEBUG "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 */
@@ -567,52 +586,54 @@
 	dmap->needs_reorg = 0;
 
 	if (dmap->fragment_size == 0)
-	  {			/* Compute the fragment size using the default algorithm */
+	{	
+		/* 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 = dmap->buffsize;
+		while (bsz > sz)
+			bsz /= 2;
+
+		if (bsz == dmap->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;
 
-		  /*
-		     * 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 = dmap->buffsize;
-		  while (bsz > sz)
-			  bsz /= 2;
-
-		  if (bsz == dmap->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 > (dmap->buffsize / 2))
-			  dmap->fragment_size = (dmap->buffsize / 2);
-		  bsz = dmap->fragment_size;
-	  }
+		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 > (dmap->buffsize / 2))
+			dmap->fragment_size = (dmap->buffsize / 2);
+		bsz = dmap->fragment_size;
+	}
 
 	if (audio_devs[dev]->min_fragment)
 		if (bsz < (1 << audio_devs[dev]->min_fragment))
@@ -632,42 +653,39 @@
 		n = dmap->max_fragments;
 
 	if (n < 2)
-	  {
-		  n = 2;
-		  bsz /= 2;
-	  }
+	{
+		n = 2;
+		bsz /= 2;
+	}
 	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 */
+			dmap->bytes_in_use;	/* Approximately one hour */
 
 	if (dmap->raw_buf)
-	  {
-		  memset(dmap->raw_buf,
-			 dmap->neutral_byte,
-			 dmap->bytes_in_use);
-	  }
+	{
+		memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use);
+	}
+	
 	for (i = 0; i < dmap->nbufs; i++)
-	  {
-		  dmap->counts[i] = 0;
-	  }
+	{
+		dmap->counts[i] = 0;
+	}
 
 	dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
 }
 
-static int
-dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+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 (*(int *) arg = fact);
-	  }
-	if (dmap->subdivision != 0 ||
-	    dmap->fragment_size)	/* Too late to change */
+	{
+		fact = dmap->subdivision;
+		if (fact == 0)
+			fact = 1;
+		return (*(int *) arg = fact);
+	}
+	if (dmap->subdivision != 0 || dmap->fragment_size)	/* Too late to change */
 		return -EINVAL;
 
 	if (fact > MAX_REALTIME_FACTOR)
@@ -680,10 +698,9 @@
 	return (*(int *) arg = fact);
 }
 
-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)
 {
-	int             bytes, count;
+	int bytes, count;
 
 	if (fact == 0)
 		return -EIO;
@@ -736,309 +753,305 @@
 		return 0;
 }
 
-int
-dma_ioctl(int dev, unsigned int cmd, caddr_t arg)
+int dma_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
 
 	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_SUBDIVIDE:
-		  {
-			  int             fact;
-			  int             ret = 0;
-
-			  fact = *(int *) arg;
-
-			  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]->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;
-		  }
-		  break;
-
-	  case SNDCTL_DSP_GETISPACE:
-	  case SNDCTL_DSP_GETOSPACE:
-		  {
-			  struct dma_buffparms *dmap = dmap_out;
-
-			  audio_buf_info *info = (audio_buf_info *) arg;
-
-			  if (cmd == SNDCTL_DSP_GETISPACE &&
-			      !(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;
-
-			  if (dmap->mapping_flags & DMA_MAP_MAPPED)
-				  return -EINVAL;
-
-			  if (!(dmap->flags & DMA_ALLOC_DONE))
-				  reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
-
-			  info->fragstotal = dmap->nbufs;
-
-			  if (cmd == SNDCTL_DSP_GETISPACE)
-				  info->fragments = dmap->qlen;
-			  else
-			    {
-				    if (!DMAbuf_space_in_queue(dev))
-					    info->fragments = 0;
-				    else
-				      {
-					      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
-									 */
-							info->fragments -= tmp;
-						}
-				      }
-			    }
-
-			  if (info->fragments < 0)
-				  info->fragments = 0;
-			  else if (info->fragments > dmap->nbufs)
-				  info->fragments = dmap->nbufs;
-
-			  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];
-			  else
-			    {
-				    info->fragments = info->bytes / dmap->fragment_size;
-				    info->bytes -= dmap->user_counter % dmap->fragment_size;
-			    }
-		  }
-		  return 0;
-
-	  case SNDCTL_DSP_SETTRIGGER:
-		  {
-			  unsigned long   flags;
-
-			  int             bits;
-			  int             changed;
-
-			  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;
-
-				    dmap_in->dma_mode = DMODE_INPUT;
-				    audio_devs[dev]->enable_bits = bits;
-				    DMAbuf_activate_recording(dev, dmap_in);
-			    }
-			  if ((changed & bits) & PCM_ENABLE_OUTPUT &&
-			      (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
-			      audio_devs[dev]->go)
-			    {
-
-				    if (!(dmap_out->flags & DMA_ALLOC_DONE))
-				      {
-					      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);
-				    ;
-			    }
-			  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 (*(int *) 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;
-			  struct dma_buffparms *dmap = dmap_in;
-
-			  if (!(audio_devs[dev]->open_mode & OPEN_READ))
-				  return -EINVAL;
-
-			  save_flags(flags);
-			  cli();
-			  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 (dmap->mapping_flags & DMA_MAP_MAPPED)
-				  dmap->qlen = 0;	/* Reset interrupt counter */
-			  restore_flags(flags);
-			  return 0;
-		  }
-		  break;
-
-	  case SNDCTL_DSP_GETOPTR:
-		  {
-			  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 = 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 (dmap->mapping_flags & DMA_MAP_MAPPED)
-				  dmap->qlen = 0;	/* Reset interrupt counter */
-
-			  restore_flags(flags);
-			  return 0;
-		  }
-		  break;
-
-    case SNDCTL_DSP_GETODELAY:
-      {
-	int count;
-	unsigned long   flags;
-	struct dma_buffparms *dmap = dmap_out;
-
-	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-	   return -EINVAL;
-	if (!(dmap->flags & DMA_ALLOC_DONE))
-	   return (*(int *) arg = 0);
-
-	save_flags (flags);
-	cli ();
-	/* Compute number of bytes that have been played */
-	count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
-	if (count < dmap->fragment_size && dmap->qhead != 0)
-	   count += dmap->bytes_in_use;	/* Pointer wrap not handled yet */
-	count += dmap->byte_counter;
-
-	/* Substract current count from the number of bytes written by app */
-	count = dmap->user_counter - count;
-	if (count < 0)
-           count = 0;
-	restore_flags (flags);
-
-	return (*(int *) arg = count);
-      }
-      break;
-
-	  case SNDCTL_DSP_POST:
-		  ;
-		  if (audio_devs[dev]->dmap_out->qlen > 0)
-			  if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
-				  DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
-		  ;
-		  return 0;
-		  break;
-
-	  case SNDCTL_DSP_GETBLKSIZE:
-		  {
-			  int             fragment_size;
-			  struct dma_buffparms *dmap = dmap_out;
-
-			  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:
-		  {
-			  int             fact;
-			  int             ret;
-
-			  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);
-
-			  return ret;
-		  }
-		  break;
-
-	  default:
-		  return audio_devs[dev]->d->ioctl(dev, cmd, arg);
-	  }
+		case SNDCTL_DSP_SUBDIVIDE:
+		{
+			int             fact;
+			int             ret = 0;
+
+			fact = *(int *) arg;
+
+			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]->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;
+		}
+		break;
+
+		case SNDCTL_DSP_GETISPACE:
+		case SNDCTL_DSP_GETOSPACE:
+		{
+			struct dma_buffparms *dmap = dmap_out;
+
+			audio_buf_info *info = (audio_buf_info *) arg;
+
+			if (cmd == SNDCTL_DSP_GETISPACE &&
+				!(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;
+
+			if (dmap->mapping_flags & DMA_MAP_MAPPED)
+				return -EINVAL;
+
+			if (!(dmap->flags & DMA_ALLOC_DONE))
+				reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
+
+			info->fragstotal = dmap->nbufs;
+
+			if (cmd == SNDCTL_DSP_GETISPACE)
+				info->fragments = dmap->qlen;
+			else
+			{
+				if (!DMAbuf_space_in_queue(dev))
+					info->fragments = 0;
+				else
+				{
+					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
+								 */
+						info->fragments -= tmp;
+					}
+				}
+			}
+
+			if (info->fragments < 0)
+				info->fragments = 0;
+			else if (info->fragments > dmap->nbufs)
+				info->fragments = dmap->nbufs;
+
+			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];
+			else
+			{
+				info->fragments = info->bytes / dmap->fragment_size;
+				info->bytes -= dmap->user_counter % dmap->fragment_size;
+			}
+		}
+		return 0;
 
+		case SNDCTL_DSP_SETTRIGGER:
+		{
+			unsigned long flags;
+
+			int bits;
+			int changed;
+
+			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(KERN_WARNING "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;
+
+				dmap_in->dma_mode = DMODE_INPUT;
+				audio_devs[dev]->enable_bits = bits;
+				DMAbuf_activate_recording(dev, dmap_in);
+			}
+			
+			if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+				(dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
+				audio_devs[dev]->go)
+			{
+
+				if (!(dmap_out->flags & DMA_ALLOC_DONE))
+				{
+					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);
+			}
+			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);
+		}
+		/* Falls through... */
+
+		case SNDCTL_DSP_GETTRIGGER:
+			return (*(int *) arg = audio_devs[dev]->enable_bits);
+
+		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;
+			struct dma_buffparms *dmap = dmap_in;
+
+			if (!(audio_devs[dev]->open_mode & OPEN_READ))
+				return -EINVAL;
+
+			save_flags(flags);
+			cli();
+			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 (dmap->mapping_flags & DMA_MAP_MAPPED)
+				dmap->qlen = 0;	/* Reset interrupt counter */
+			restore_flags(flags);
+			return 0;
+		}
+		break;
+
+		case SNDCTL_DSP_GETOPTR:
+		{
+			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 = 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 (dmap->mapping_flags & DMA_MAP_MAPPED)
+				dmap->qlen = 0;	/* Reset interrupt counter */
+
+			restore_flags(flags);
+			return 0;
+		}
+		break;
+
+		case SNDCTL_DSP_GETODELAY:
+		{
+			int count;
+			unsigned long   flags;
+			struct dma_buffparms *dmap = dmap_out;
+
+			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+				return -EINVAL;
+			if (!(dmap->flags & DMA_ALLOC_DONE))
+				return (*(int *) arg = 0);
+
+			save_flags(flags);
+			cli();
+			/* Compute number of bytes that have been played */
+			count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
+			if (count < dmap->fragment_size && dmap->qhead != 0)
+				count += dmap->bytes_in_use;	/* Pointer wrap not handled yet */
+			count += dmap->byte_counter;
+
+			/* Substract current count from the number of bytes written by app */
+			count = dmap->user_counter - count;
+			if (count < 0)
+        			count = 0;
+			restore_flags (flags);
+
+			return (*(int *) arg = count);
+		}
+
+		case SNDCTL_DSP_POST:
+			if (audio_devs[dev]->dmap_out->qlen > 0)
+				if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
+					DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
+			return 0;
+
+		case SNDCTL_DSP_GETBLKSIZE:
+		{
+			int             fragment_size;
+			struct dma_buffparms *dmap = dmap_out;
+
+			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);
+		}
+
+		case SNDCTL_DSP_SETFRAGMENT:
+		{
+			int  fact;
+			int  ret = 0;
+
+			fact = *(int *) arg;
+			if (audio_devs[dev]->open_mode & OPEN_WRITE)
+				ret = dma_set_fragment(dev, dmap_out, arg, fact);
+			if (ret < 0)
+				return ret;
+
+			if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+				(audio_devs[dev]->flags & DMA_DUPLEX &&
+				audio_devs[dev]->open_mode & OPEN_READ))
+				ret = dma_set_fragment(dev, dmap_in, arg, fact);
+
+			return ret;
+		}
+		break;
+
+		default:
+			return audio_devs[dev]->d->ioctl(dev, cmd, arg);
+	}
 }

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