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

Next file: linux/drivers/sound/gus_card.c
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.87/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
@@ -9,6 +9,15 @@
  * 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.
+ *
+ * Thomas Sailer   : moved several static variables into struct audio_operations
+ *                   (which is grossly misnamed btw.) because they have the same
+ *                   lifetime as the rest in there and dynamic allocation saves
+ *                   12k or so
+ * Thomas Sailer   : remove {in,out}_sleep_flag. It was used for the sleeper to
+ *                   determine if it was woken up by the expiring timeout or by
+ *                   an explicit wake_up. current->timeout can be used instead;
+ *                   if 0, the wakeup was due to the timeout.
  */
 #include <linux/config.h>
 
@@ -17,37 +26,132 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW)
+#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
 
-static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = {
-	NULL
-};
 
-static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = {
-	{0}
-};
+static void dma_reset_output(int dev);
+static void dma_reset_input(int dev);
+static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode);
+
 
-static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = {
-	NULL
-};
 
-static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = {
-	{0}
-};
+static int debugmem = 0;	/* switched off by default */
+static int dma_buffsize = DSP_BUFFSIZE;
+
+static void dmabuf_set_timeout(struct dma_buffparms *dmap)
+{
+	unsigned long tmout;
 
-static int ndmaps = 0;
+	tmout = (dmap->fragment_size * HZ) / dmap->data_rate;
+	tmout += HZ / 5;	/* Some safety distance */
+	if (tmout < (HZ / 2))
+		tmout = HZ / 2;
+	if (tmout > 20 * HZ)
+		tmout = 20 * HZ;
+	current->timeout = jiffies + tmout;
+}
 
-#define MAX_DMAP (MAX_AUDIO_DEV*2)
+static int sound_alloc_dmap(struct dma_buffparms *dmap)
+{
+	char *start_addr, *end_addr;
+	int i, dma_pagesize;
+	int sz, size;
+
+	dmap->mapping_flags &= ~DMA_MAP_MAPPED;
+
+	if (dmap->raw_buf != NULL)
+		return 0;	/* Already done */
+	if (dma_buffsize < 4096)
+		dma_buffsize = 4096;
+	dma_pagesize = (dmap->dma < 4) ? (64 * 1024) : (128 * 1024);
+	dmap->raw_buf = NULL;
+	dmap->buffsize = dma_buffsize;
+	if (dmap->buffsize > dma_pagesize)
+		dmap->buffsize = dma_pagesize;
+	start_addr = NULL;
+	/*
+	 * Now loop until we get a free buffer. Try to get smaller buffer if
+	 * it fails. Don't accept smaller than 8k buffer for performance
+	 * reasons.
+	 */
+	while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) {
+		for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1);
+		dmap->buffsize = PAGE_SIZE * (1 << sz);
+		start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz);
+		if (start_addr == NULL)
+			dmap->buffsize /= 2;
+	}
+
+	if (start_addr == NULL) {
+		printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n");
+		return -ENOMEM;
+	} else {
+		/* make some checks */
+		end_addr = start_addr + dmap->buffsize - 1;
 
-static struct dma_buffparms dmaps[MAX_DMAP] = {
-	{0}
-};
+		if (debugmem)
+			printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr);
+		
+		/* now check if it fits into the same dma-pagesize */
 
-static void dma_reset_output(int dev);
-static void dma_reset_input(int dev);
-static int local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode);
+		if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1))
+		    || end_addr >= (char *) (MAX_DMA_ADDRESS)) {
+			printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize);
+			return -EFAULT;
+		}
+	}
+	dmap->raw_buf = start_addr;
+	dmap->raw_buf_phys = virt_to_bus(start_addr);
+
+	for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
+		set_bit(PG_reserved, &mem_map[i].flags);;
+	return 0;
+}
+
+static void sound_free_dmap(struct dma_buffparms *dmap)
+{
+	int sz, size, i;
+	unsigned long start_addr, end_addr;
+
+	if (dmap->raw_buf == NULL)
+		return;
+	if (dmap->mapping_flags & DMA_MAP_MAPPED)
+		return;		/* Don't free mmapped buffer. Will use it next time */
+	for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1);
+
+	start_addr = (unsigned long) dmap->raw_buf;
+	end_addr = start_addr + dmap->buffsize;
+
+	for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
+		clear_bit(PG_reserved, &mem_map[i].flags);;
+
+	free_pages((unsigned long) dmap->raw_buf, sz);
+	dmap->raw_buf = NULL;
+}
+
+
+/* Intel version !!!!!!!!! */
 
-static void dma_init_buffers(int dev, struct dma_buffparms *dmap)
+static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, int count, int dma_mode)
+{
+	unsigned long flags;
+	int chan = dmap->dma;
+
+	/* printk( "Start DMA%d %d, %d\n",  chan,  (int)(physaddr-dmap->raw_buf_phys),  count); */
+	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);
+
+	return 0;
+}
+
+static void dma_init_buffers(struct dma_buffparms *dmap)
 {
 	dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
 	dmap->byte_counter = 0;
@@ -64,26 +168,24 @@
 	dmap->flags = DMA_BUSY;	/* Other flags off */
 }
 
-static int open_dmap(int dev, int mode, struct dma_buffparms *dmap, int chan)
+static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffparms *dmap)
 {
 	int err;
 	
 	if (dmap->flags & DMA_BUSY)
 		return -EBUSY;
-	if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0)
+	if ((err = sound_alloc_dmap(dmap)) < 0)
 		return err;
 
-	if (dmap->raw_buf == NULL)
-	{
+	if (dmap->raw_buf == NULL) {
 		printk(KERN_WARNING "Sound: DMA buffers not available\n");
 		return -ENOSPC;	/* Memory allocation failed during boot */
 	}
-	if (sound_open_dma(chan, audio_devs[dev]->name))
-	{
-		printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", chan);
+	if (sound_open_dma(dmap->dma, adev->name)) {
+		printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", dmap->dma);
 		return -EBUSY;
 	}
-	dma_init_buffers(dev, dmap);
+	dma_init_buffers(dmap);
 	dmap->open_mode = mode;
 	dmap->subdivision = dmap->underrun_count = 0;
 	dmap->fragment_size = 0;
@@ -94,19 +196,12 @@
 	dmap->needs_reorg = 1;
 	dmap->audio_callback = NULL;
 	dmap->callback_parm = 0;
-
-
-	if (dmap->dma_mode & DMODE_OUTPUT)
-		out_sleep_flag[dev].opts = WK_NONE;
-	else
-		in_sleep_flag[dev].opts = WK_NONE;
 	return 0;
 }
 
-static void close_dmap(int dev, struct dma_buffparms *dmap, int chan)
+static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap)
 {
-	sound_close_dma(chan);
-
+	sound_close_dma(dmap->dma);
 	if (dmap->flags & DMA_BUSY)
 		dmap->dma_mode = DMODE_NONE;
 	dmap->flags &= ~DMA_BUSY;
@@ -157,74 +252,49 @@
 
 int DMAbuf_open(int dev, int mode)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	int retval;
 	struct dma_buffparms *dmap_in = NULL;
 	struct dma_buffparms *dmap_out = NULL;
 
-	if (dev >= num_audiodevs || audio_devs[dev] == NULL)
-		return -ENXIO;
-
-	if (!audio_devs[dev])
+	if (!adev)
 		  return -ENXIO;
+	if (!(adev->flags & DMA_DUPLEX))
+		adev->dmap_in = adev->dmap_out;
+	check_driver(adev->d);
 
-	if (!(audio_devs[dev]->flags & DMA_DUPLEX))
-	{
-		audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
-		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)
+	if ((retval = adev->d->open(dev, mode)) < 0)
 		return retval;
-
-	dmap_out = audio_devs[dev]->dmap_out;
-	dmap_in = audio_devs[dev]->dmap_in;
-
+	dmap_out = adev->dmap_out;
+	dmap_in = adev->dmap_in;
 	if (dmap_in == dmap_out)
-		audio_devs[dev]->flags &= ~DMA_DUPLEX;
+		adev->flags &= ~DMA_DUPLEX;
 
-	if (mode & OPEN_WRITE)
-	{
-		if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0)
-		{
-			audio_devs[dev]->d->close(dev);
+	if (mode & OPEN_WRITE) {
+		if ((retval = open_dmap(adev, mode, dmap_out)) < 0) {
+			adev->d->close(dev);
 			return retval;
 		}
 	}
-	audio_devs[dev]->enable_bits = mode;
+	adev->enable_bits = mode;
 
-	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_READ || (mode != OPEN_WRITE && adev->flags & DMA_DUPLEX)) {
+		if ((retval = open_dmap(adev, mode, dmap_in)) < 0) {
+			adev->d->close(dev);
 			if (mode & OPEN_WRITE)
-			{
-				close_dmap(dev, dmap_out, audio_devs[dev]->dmap_out->dma);
-			}
+				close_dmap(adev, dmap_out);
 			return retval;
 		}
 	}
-	audio_devs[dev]->open_mode = mode;
-	audio_devs[dev]->go = 1;
-
-	if (mode & OPEN_READ)
-		in_sleep_flag[dev].opts = WK_NONE;
+	adev->open_mode = mode;
+	adev->go = 1;
 
-	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);
-	audio_devs[dev]->d->set_speed(dev, DSP_DEFAULT_SPEED);
-
-	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);
-	}
+	adev->d->set_bits(dev, 8);
+	adev->d->set_channels(dev, 1);
+	adev->d->set_speed(dev, DSP_DEFAULT_SPEED);
+	if (adev->dmap_out->dma_mode == DMODE_OUTPUT) 
+		memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte,
+		       adev->dmap_out->bytes_in_use);
 	return 0;
 }
 
@@ -239,9 +309,9 @@
 
 static void dma_reset_output(int dev)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	unsigned long flags;
-	int tmout;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	struct dma_buffparms *dmap = adev->dmap_out;
 
 	if (!(dmap->flags & DMA_STARTED))	/* DMA is not active */
 		return;
@@ -251,162 +321,111 @@
 	 */
 	save_flags(flags);
 	cli();
+	adev->dmap_out->flags |= DMA_SYNCING;
 
-	tmout = (dmap->fragment_size * HZ) / dmap->data_rate;
-
-	tmout += HZ / 5;	/* Some safety distance */
-	if (tmout < (HZ / 2))
-		tmout = HZ / 2;
-	if (tmout > 20 * HZ)
-		tmout = 20 * HZ;
-
-	audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
-
-	audio_devs[dev]->dmap_out->underrun_count = 0;
-	if (!signal_pending(current)
-	    && audio_devs[dev]->dmap_out->qlen
-	    && audio_devs[dev]->dmap_out->underrun_count == 0)
-	{
-		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;
+	adev->dmap_out->underrun_count = 0;
+	if (!signal_pending(current) && adev->dmap_out->qlen && 
+	    adev->dmap_out->underrun_count == 0) {
+		dmabuf_set_timeout(dmap);
+		interruptible_sleep_on(&adev->out_sleeper);
+		current->timeout = 0;
 	}
-	audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
+	adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
 
 	/*
 	 *	Finally shut the device off
 	 */
-
-	if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
-			!audio_devs[dev]->d->halt_output)
-		audio_devs[dev]->d->halt_io(dev);
+	if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_output)
+		adev->d->halt_io(dev);
 	else
-		audio_devs[dev]->d->halt_output(dev);
-	audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED;
-	restore_flags(flags);
-
+		adev->d->halt_output(dev);
+	adev->dmap_out->flags &= ~DMA_STARTED;
 	clear_dma_ff(dmap->dma);
 	disable_dma(dmap->dma);
+	restore_flags(flags);
 	dmap->byte_counter = 0;
-	reorganize_buffers(dev, audio_devs[dev]->dmap_out, 0);
+	reorganize_buffers(dev, adev->dmap_out, 0);
 	dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
 }
 
 static void dma_reset_input(int dev)
 {
+        struct audio_operations *adev = audio_devs[dev];
 	unsigned long flags;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+	struct dma_buffparms *dmap = adev->dmap_in;
 
 	save_flags(flags);
 	cli();
-	if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
-		!audio_devs[dev]->d->halt_input)
-		audio_devs[dev]->d->halt_io(dev);
+	if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input)
+		adev->d->halt_io(dev);
 	else
-		audio_devs[dev]->d->halt_input(dev);
-	audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED;
+		adev->d->halt_input(dev);
+	adev->dmap_in->flags &= ~DMA_STARTED;
 	restore_flags(flags);
 
 	dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
 	dmap->byte_counter = 0;
-	reorganize_buffers(dev, audio_devs[dev]->dmap_in, 1);
+	reorganize_buffers(dev, adev->dmap_in, 1);
 }
 
 void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap)
 {
-	if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT))
+	struct audio_operations *adev = audio_devs[dev];
+
+	if (!((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT))
 		return;		/* Don't start DMA yet */
 	dmap->dma_mode = DMODE_OUTPUT;
 
-	if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA)
-	{
-		if (!(dmap->flags & DMA_STARTED))
-		{
+	if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) {
+		if (!(dmap->flags & DMA_STARTED)) {
 			reorganize_buffers(dev, dmap, 0);
-			if (audio_devs[dev]->d->prepare_for_output(dev,
-					dmap->fragment_size, dmap->nbufs))
+			if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs))
 				return;
 			if (!(dmap->flags & DMA_NODMA))
-				local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE);
+				local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE);
 			dmap->flags |= DMA_STARTED;
 		}
 		if (dmap->counts[dmap->qhead] == 0)
 			dmap->counts[dmap->qhead] = dmap->fragment_size;
-
 		dmap->dma_mode = DMODE_OUTPUT;
-		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);
+		adev->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size,
+				      dmap->counts[dmap->qhead], 1);
+		if (adev->d->trigger)
+			adev->d->trigger(dev,adev->enable_bits * adev->go);
 	}
 	dmap->flags |= DMA_ACTIVE;
 }
 
 int DMAbuf_sync(int dev)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	unsigned long flags;
-	int tmout, n = 0;
+	int n = 0;
+	struct dma_buffparms *dmap;
 
-	if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
+	if (!adev->go && (!adev->enable_bits & PCM_ENABLE_OUTPUT))
 		return 0;
 
-	if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
-	{
-		struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	if (adev->dmap_out->dma_mode == DMODE_OUTPUT) {
+		dmap = adev->dmap_out;
 		save_flags(flags);
 		cli();
-
-		tmout = (dmap->fragment_size * HZ) / dmap->data_rate;
-		tmout += HZ / 5;	/* Some safety distance */
-
-		if (tmout < (HZ / 2))
-			tmout = HZ / 2;
-		if (tmout > 20 * HZ)
-			tmout = 20 * HZ;
-
-		if (dmap->qlen > 0)
-			if (!(dmap->flags & DMA_ACTIVE))
-				DMAbuf_launch_output(dev, dmap);
-
-		audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
-		audio_devs[dev]->dmap_out->underrun_count = 0;
-		while (!signal_pending(current) && n++ <= audio_devs[dev]->dmap_out->nbufs && audio_devs[dev]->dmap_out->qlen
-				&& audio_devs[dev]->dmap_out->underrun_count == 0)
-		{
-			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))
-			{
-				audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
+		if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE))
+			DMAbuf_launch_output(dev, dmap);
+		adev->dmap_out->flags |= DMA_SYNCING;
+		adev->dmap_out->underrun_count = 0;
+		while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && 
+		       adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) {
+			dmabuf_set_timeout(dmap);
+			interruptible_sleep_on(&adev->out_sleeper);
+			if (!current->timeout) {
+				adev->dmap_out->flags &= ~DMA_SYNCING;
 				restore_flags(flags);
-				return audio_devs[dev]->dmap_out->qlen;
+				return adev->dmap_out->qlen;
 			}
+			current->timeout = 0;
 		}
-		audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
+		adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
 		restore_flags(flags);
 		
 		/*
@@ -416,195 +435,138 @@
 
 		save_flags(flags);
 		cli();
-		if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */
-		{
-			while (!signal_pending(current) && audio_devs[dev]->d->local_qlen(dev))
-			{
-				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 (adev->d->local_qlen) {   /* Device has hidden buffers */
+			while (!signal_pending(current) && adev->d->local_qlen(dev)) {
+				dmabuf_set_timeout(dmap);
+				interruptible_sleep_on(&adev->out_sleeper);
+				current->timeout = 0;
 			}
 		}
 		restore_flags(flags);
 	}
-	audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE;
-	return audio_devs[dev]->dmap_out->qlen;
+	adev->dmap_out->dma_mode = DMODE_NONE;
+	return adev->dmap_out->qlen;
 }
 
 int DMAbuf_release(int dev, int mode)
 {
-	unsigned long   flags;
-
-	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;
+	struct audio_operations *adev = audio_devs[dev];
+	unsigned long flags;
 
-	if (audio_devs[dev]->open_mode & OPEN_WRITE)
-		if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED))
-			if (!signal_pending(current)
-			    && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
-			{
+	if (adev->open_mode & OPEN_WRITE)
+		adev->dmap_out->closing = 1;
+	if (adev->open_mode & OPEN_READ)
+		adev->dmap_in->closing = 1;
+
+	if (adev->open_mode & OPEN_WRITE)
+		if (!(adev->dmap_in->mapping_flags & DMA_MAP_MAPPED))
+			if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT))
 				DMAbuf_sync(dev);
-			}
-	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);
-	}
+	if (adev->dmap_out->dma_mode == DMODE_OUTPUT)
+		memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use);
 	save_flags(flags);
 	cli();
 
 	DMAbuf_reset(dev);
-	audio_devs[dev]->d->close(dev);
+	adev->d->close(dev);
 
-	if (audio_devs[dev]->open_mode & OPEN_WRITE)
-		close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma);
+	if (adev->open_mode & OPEN_WRITE)
+		close_dmap(adev, adev->dmap_out);
 
-	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;
+	if (adev->open_mode == OPEN_READ ||
+	    (adev->open_mode != OPEN_WRITE &&
+	     adev->flags & DMA_DUPLEX))
+		close_dmap(adev, adev->dmap_in);
+	adev->open_mode = 0;
 	restore_flags(flags);
 	return 0;
 }
 
 int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap)
 {
-	if (!(audio_devs[dev]->open_mode & OPEN_READ))
-		return 0;
+	struct audio_operations *adev = audio_devs[dev];
+	int  err;
 
-	if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
+	if (!(adev->open_mode & OPEN_READ))
 		return 0;
-
-	if (dmap->dma_mode == DMODE_OUTPUT)	/* Direction change */
-	{
+	if (!(adev->enable_bits & PCM_ENABLE_INPUT))
+		return 0;
+	if (dmap->dma_mode == DMODE_OUTPUT) {	/* Direction change */
 		DMAbuf_sync(dev);
 		DMAbuf_reset(dev);
 		dmap->dma_mode = DMODE_NONE;
 	}
-	if (!dmap->dma_mode)
-	{
-		int  err;
-
+	if (!dmap->dma_mode) {
 		reorganize_buffers(dev, dmap, 1);
-		if ((err = audio_devs[dev]->d->prepare_for_input(dev,
+		if ((err = adev->d->prepare_for_input(dev,
 				dmap->fragment_size, dmap->nbufs)) < 0)
 			return err;
 		dmap->dma_mode = DMODE_INPUT;
 	}
-	if (!(dmap->flags & DMA_ACTIVE))
-	{
+	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);
+		local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ);
+		adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size,
+				     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);
+		if (adev->d->trigger)
+			adev->d->trigger(dev, adev->enable_bits * adev->go);
 	}
 	return 0;
 }
 
 int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	unsigned long flags;
 	int err = 0, n = 0;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+	struct dma_buffparms *dmap = adev->dmap_in;
+	int go;
 
-	if (!(audio_devs[dev]->open_mode & OPEN_READ))
+	if (!(adev->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)
-	{
+	if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
 /*		  printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/
 		  restore_flags(flags);
 		  return -EINVAL;
-	}
-	else while (dmap->qlen <= 0 && n++ < 10)
-	{
-		int tmout;
-		unsigned long tlimit;
-
-		if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || !audio_devs[dev]->go)
-		{
+	} else while (dmap->qlen <= 0 && n++ < 10) {
+		if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) {
 			restore_flags(flags);
 			return -EAGAIN;
 		}
-		if ((err = DMAbuf_activate_recording(dev, dmap)) < 0)
-		{
+		if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) {
 			restore_flags(flags);
 			return err;
 		}
 		/* Wait for the next block */
 
-		if (dontblock)
-		{
+		if (dontblock) {
 			restore_flags(flags);
 			return -EAGAIN;
 		}
-		if (!audio_devs[dev]->go)
-			tmout = 0;
-		else
-		{
-			tmout = (dmap->fragment_size * HZ) / dmap->data_rate;
-			tmout += HZ / 5;	/* Some safety distance */
-
-			if (tmout < (HZ / 2))
-				tmout = HZ / 2;
-			if (tmout > 20 * HZ)
-				tmout = 20 * HZ;
-		}
-
-		if (tmout)
-			current->timeout = tlimit = jiffies + (tmout);
-		else
-			tlimit = (unsigned long) -1;
-		in_sleep_flag[dev].opts = WK_SLEEP;
-		interruptible_sleep_on(&in_sleeper[dev]);
-		if (!(in_sleep_flag[dev].opts & WK_WAKEUP))
-		{
-			if (jiffies >= tlimit)
-				in_sleep_flag[dev].opts |= WK_TIMEOUT;
-		}
-		in_sleep_flag[dev].opts &= ~WK_SLEEP;
-
-		if ((in_sleep_flag[dev].opts & WK_TIMEOUT))
-		{
+		if (!(go = adev->go))
+			current->timeout = 0;
+		else 
+			dmabuf_set_timeout(dmap);
+		interruptible_sleep_on(&adev->in_sleeper);
+		if (go && !current->timeout) {
 			/* FIXME: include device name */
 			err = -EIO;
 			printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
 			dma_reset_input(dev);
-		}
-		else
+		} else
 			err = -EINTR;
+		current->timeout = 0;
 	}
 	restore_flags(flags);
 
 	if (dmap->qlen <= 0)
-	{
-		if (err == 0)
-			err = -EINTR;
-		return err;
-	}
+		return err ? err : -EINTR;
 	*buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];
 	*len = dmap->fragment_size - dmap->counts[dmap->qhead];
 
@@ -613,7 +575,8 @@
 
 int DMAbuf_rmchars(int dev, int buff_no, int c)
 {
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = adev->dmap_in;
 	int p = dmap->counts[dmap->qhead] + c;
 
 	if (dmap->mapping_flags & DMA_MAP_MAPPED)
@@ -623,8 +586,7 @@
 	}
 	else if (dmap->qlen <= 0)
 		return -EIO;
-	else if (p >= dmap->fragment_size)
-	{			/* This buffer is completely empty */
+	else if (p >= dmap->fragment_size) {  /* This buffer is completely empty */
 		dmap->counts[dmap->qhead] = 0;
 		dmap->qlen--;
 		dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
@@ -648,24 +610,19 @@
 	cli();
 	if (!(dmap->flags & DMA_ACTIVE))
 		pos = 0;
-	else
-	{
+	else {
 		int chan = dmap->dma;
 		clear_dma_ff(chan);
 		disable_dma(dmap->dma);
 		pos = get_dma_residue(chan);
 		pos = dmap->bytes_in_use - pos;
 
-		if (!(dmap->mapping_flags & DMA_MAP_MAPPED))
-		{
-			if (direction == DMODE_OUTPUT)
-			{
+		if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) {
+			if (direction == DMODE_OUTPUT) {
 				if (dmap->qhead == 0)
 					if (pos > dmap->fragment_size)
 						pos = 0;
-			}
-			else
-			{
+			} else {
 				if (dmap->qtail == 0)
 					if (pos > dmap->fragment_size)
 						pos = 0;
@@ -687,35 +644,33 @@
  *	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)
-{
-	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)
 {
+	struct audio_operations *adev;
 	int dev;
 
-	for (dev = 0; dev < num_audiodevs; dev++)
-		if ((devmask & (1 << dev)) && audio_devs[dev] != NULL)
-			DMAbuf_start_device(dev);
+	for (dev = 0; dev < num_audiodevs; dev++) {
+		if (!(devmask & (1 << dev)))
+			continue;
+		if (!(adev = audio_devs[dev]))
+			continue;
+		if (adev->open_mode == 0)
+			continue;
+		if (adev->go)
+			continue;
+		/* OK to start the device */
+		adev->go = 1;
+		if (adev->d->trigger)
+			adev->d->trigger(dev,adev->enable_bits * adev->go);
+	}
 }
 
 int DMAbuf_space_in_queue(int dev)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	int len, max, tmp;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	struct dma_buffparms *dmap = adev->dmap_out;
 	int lim = dmap->nbufs;
 
 	if (lim < 2)
@@ -734,13 +689,10 @@
 		max = lim;
 	len = dmap->qlen;
 
-	if (audio_devs[dev]->d->local_qlen)
-	{
-		tmp = audio_devs[dev]->d->local_qlen(dev);
+	if (adev->d->local_qlen) {
+		tmp = adev->d->local_qlen(dev);
 		if (tmp && len)
-			tmp--;	/*
-				 * This buffer has been counted twice
-				 */
+			tmp--;	/* This buffer has been counted twice */
 		len += tmp;
 	}
 	if (dmap->byte_counter % dmap->fragment_size)	/* There is a partial fragment */
@@ -753,62 +705,42 @@
 
 static int output_sleep(int dev, int dontblock)
 {
-	int tmout;
+	struct audio_operations *adev = audio_devs[dev];
 	int err = 0;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-	unsigned long   tlimit;
+	struct dma_buffparms *dmap = adev->dmap_out;
+	int timeout;
 
 	if (dontblock)
 		return -EAGAIN;
-	if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
+	if (!(adev->enable_bits & PCM_ENABLE_OUTPUT))
 		return -EAGAIN;
 
 	/*
 	 * Wait for free space
 	 */
-
-	if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT)
-		tmout = 0;
-	else
-	{
-		tmout = (dmap->fragment_size * HZ) / dmap->data_rate;
-		tmout += HZ / 5;	/* Some safety distance */
-
-		if (tmout < (HZ / 2))
-			tmout = HZ / 2;
-		if (tmout > 20 * HZ)
-			tmout = 20 * HZ;
-	}
-
 	if (signal_pending(current))
 		return -EIO;
-
-	if (tmout)
-		current->timeout = tlimit = jiffies + (tmout);
+	timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT));
+	if (timeout) 
+		dmabuf_set_timeout(dmap);
 	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))
-	{
+		current->timeout = 0;
+	interruptible_sleep_on(&adev->out_sleeper);
+	if (timeout && !current->timeout) {
 		printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
 		dma_reset_output(dev);
+	} else {
+		current->timeout = 0;
+		if (signal_pending(current))
+			err = -EINTR;
 	}
-	else if (signal_pending(current))
-		err = -EINTR;
 	return err;
 }
 
 static int find_output_space(int dev, char **buf, int *size)
 {
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = adev->dmap_out;
 	unsigned long flags;
 	unsigned long active_offs;
 	long len, offs;
@@ -816,7 +748,6 @@
 	int occupied_bytes = (dmap->user_counter % dmap->fragment_size);
 
 	*buf = dmap->raw_buf;
-
 	if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes)
 		return 0;
 	save_flags(flags);
@@ -833,8 +764,7 @@
 #endif
 
 	offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP;
-	if (offs < 0 || offs >= dmap->bytes_in_use)
-	{
+	if (offs < 0 || offs >= dmap->bytes_in_use) {
 		printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs);
 		printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use);
 		return 0;
@@ -845,53 +775,45 @@
 
 	if ((offs + len) > dmap->bytes_in_use)
 		len = dmap->bytes_in_use - offs;
-	if (len < 0)
-	{
+	if (len < 0) {
 		restore_flags(flags);
 		return 0;
 	}
 	if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes))
 		len = (maxfrags * dmap->fragment_size) - occupied_bytes;
-
 	*size = len & ~SAMPLE_ROUNDUP;
-
 	restore_flags(flags);
 	return (*size > 0);
 }
 
 int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	unsigned long flags;
 	int err = -EIO;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	struct dma_buffparms *dmap = adev->dmap_out;
 
 	if (dmap->needs_reorg)
 		reorganize_buffers(dev, dmap, 0);
 
-	if (dmap->mapping_flags & DMA_MAP_MAPPED)
-	{
+	if (dmap->mapping_flags & DMA_MAP_MAPPED) {
 /*		printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/
 		return -EINVAL;
 	}
-	if (dmap->dma_mode == DMODE_INPUT)	/* Direction change */
-	{
-		  DMAbuf_reset(dev);
-		  dmap->dma_mode = DMODE_NONE;
+	if (dmap->dma_mode == DMODE_INPUT) {	/* Direction change */
+		DMAbuf_reset(dev);
+		dmap->dma_mode = DMODE_NONE;
 	}
 	dmap->dma_mode = DMODE_OUTPUT;
 
 	save_flags(flags);
 	cli();
-
-	while (find_output_space(dev, buf, size) <= 0)
-	{
-		if ((err = output_sleep(dev, dontblock)) < 0)
-		{
+	while (find_output_space(dev, buf, size) <= 0) {
+		if ((err = output_sleep(dev, dontblock)) < 0) {
 			restore_flags(flags);
 			return err;
 		}
 	}
-
 	restore_flags(flags);
 
 	return 0;
@@ -899,7 +821,8 @@
 
 int DMAbuf_move_wrpointer(int dev, int l)
 {
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = adev->dmap_out;
 	unsigned long ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size;
 	unsigned long end_ptr, p;
 	int post = (dmap->flags & DMA_POST);
@@ -909,10 +832,9 @@
 	dmap->user_counter += l;
 	dmap->flags |= DMA_DIRTY;
 
-	if (dmap->user_counter >= dmap->max_byte_counter)
-	{			/* Wrap the byte counters */
+	if (dmap->user_counter >= dmap->max_byte_counter) {
+		/* Wrap the byte counters */
 		long decr = dmap->user_counter;
-
 		dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
 		decr -= dmap->user_counter;
 		dmap->byte_counter -= decr;
@@ -923,8 +845,7 @@
 	dmap->neutral_byte = dmap->raw_buf[p];
 
 	/* Update the fragment based bookkeeping too */
-	while (ptr < end_ptr)
-	{
+	while (ptr < end_ptr) {
 		dmap->counts[dmap->qtail] = dmap->fragment_size;
 		dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
 		dmap->qlen++;
@@ -937,137 +858,85 @@
 	 *	Let the low level driver to perform some postprocessing to
 	 *	the written data.
 	 */
-	if (audio_devs[dev]->d->postprocess_write)
-		audio_devs[dev]->d->postprocess_write(dev);
+	if (adev->d->postprocess_write)
+		adev->d->postprocess_write(dev);
 
 	if (!(dmap->flags & DMA_ACTIVE))
-	{
-		if (dmap->qlen > 1 ||
-		    (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1)))
-			  DMAbuf_launch_output(dev, dmap);
-	}
+		if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1)))
+			DMAbuf_launch_output(dev, dmap);
 	return 0;
 }
 
 int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode)
 {
-	int             chan;
-	struct dma_buffparms *dmap;
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in;
 
-	if (dma_mode == DMA_MODE_WRITE)
-	{
-		chan = audio_devs[dev]->dmap_out->dma;
-		dmap = audio_devs[dev]->dmap_out;
-	}
-	else
-	{
-		chan = audio_devs[dev]->dmap_in->dma;
-		dmap = audio_devs[dev]->dmap_in;
-	}
-
-	if (dmap->raw_buf == NULL)
-	{
+	if (dmap->raw_buf == NULL) {
 		printk(KERN_ERR "sound: DMA buffer(1) == NULL\n");
-		printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in");
+		printk("Device %d, chn=%s\n", dev, (dmap == adev->dmap_out) ? "out" : "in");
 		return 0;
 	}
-	if (chan < 0)
+	if (dmap->dma < 0)
 		return 0;
-
-	sound_start_dma(dev, dmap, chan, physaddr, count, dma_mode, 0);
-
+	sound_start_dma(dmap, physaddr, count, dma_mode);
 	return count;
 }
 
-static int local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode)
+static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode)
 {
-	int chan;
-	struct dma_buffparms *dmap;
+	struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in;
 
-	if (dma_mode == DMA_MODE_WRITE)
-	{
-		chan = audio_devs[dev]->dmap_out->dma;
-		dmap = audio_devs[dev]->dmap_out;
-	}
-	else
-	{
-		chan = audio_devs[dev]->dmap_in->dma;
-		dmap = audio_devs[dev]->dmap_in;
-	}
-
-	if (dmap->raw_buf == NULL)
-	{
+	if (dmap->raw_buf == NULL) {
 		printk(KERN_ERR "sound: DMA buffer(2) == NULL\n");
-		printk(KERN_ERR "Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in");
+		printk(KERN_ERR "Device %s, chn=%s\n", adev->name, (dmap == adev->dmap_out) ? "out" : "in");
 		return 0;
 	}
 	if (dmap->flags & DMA_NODMA)
-	{
 		return 1;
-	}
-	if (chan < 0)
+	if (dmap->dma < 0)
 		return 0;
-
-	sound_start_dma(dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1);
+	sound_start_dma(dmap, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode | DMA_AUTOINIT);
 	dmap->flags |= DMA_STARTED;
-
 	return count;
 }
 
 static void finish_output_interrupt(int dev, struct dma_buffparms *dmap)
 {
-	unsigned long flags;
+	struct audio_operations *adev = audio_devs[dev];
 
 	if (dmap->audio_callback != NULL)
 		dmap->audio_callback(dev, dmap->callback_parm);
-
-	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);
+	wake_up(&adev->out_sleeper);
 }
 
 static void do_outputintr(int dev, int dummy)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	unsigned long flags;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	struct dma_buffparms *dmap = adev->dmap_out;
 	int this_fragment;
 
-#ifdef OS_DMA_INTR
-	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)
-	{
+	if (dmap->raw_buf == NULL) {
 		printk(KERN_ERR "Sound: Error. Audio interrupt (%d) after freeing buffers.\n", dev);
 		return;
 	}
-	if (dmap->mapping_flags & DMA_MAP_MAPPED)	/* Virtual memory mapped access */
-	{
+	if (dmap->mapping_flags & DMA_MAP_MAPPED) {	/* Virtual memory mapped access */
 		/* mmapped access */
 		dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
-		if (dmap->qhead == 0)		/* Wrapped */
-		{
+		if (dmap->qhead == 0) {	    /* Wrapped */
 			dmap->byte_counter += dmap->bytes_in_use;
-			if (dmap->byte_counter >= dmap->max_byte_counter)	/* Overflow */
-			{
+			if (dmap->byte_counter >= dmap->max_byte_counter) {	/* Overflow */
 				long decr = dmap->byte_counter;
-
 				dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
 				decr -= dmap->byte_counter;
 				dmap->user_counter -= decr;
 			}
 		}
 		dmap->qlen++;	/* Yes increment it (don't decrement) */
-		if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+		if (!(adev->flags & DMA_AUTOMODE))
 			dmap->flags &= ~DMA_ACTIVE;
 		dmap->counts[dmap->qhead] = dmap->fragment_size;
-
 		DMAbuf_launch_output(dev, dmap);
 		finish_output_interrupt(dev, dmap);
 		return;
@@ -1079,53 +948,43 @@
 	this_fragment = dmap->qhead;
 	dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
 
-	if (dmap->qhead == 0)	/* Wrapped */
-	{
+	if (dmap->qhead == 0) {	/* Wrapped */
 		dmap->byte_counter += dmap->bytes_in_use;
-		if (dmap->byte_counter >= dmap->max_byte_counter)	/* Overflow */
-		{
+		if (dmap->byte_counter >= dmap->max_byte_counter) {	/* Overflow */
 			long decr = dmap->byte_counter;
-
 			dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
 			decr -= dmap->byte_counter;
 			dmap->user_counter -= decr;
 		}
 	}
-	if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+	if (!(adev->flags & DMA_AUTOMODE))
 		dmap->flags &= ~DMA_ACTIVE;
-
-	while (dmap->qlen <= 0)
-	{
+	while (dmap->qlen <= 0) {
 		dmap->underrun_count++;
 		dmap->qlen++;
-		if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS)
-		{
+		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->buffsize);
+			memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte,
+			       adev->dmap_out->buffsize);
 		}
 		dmap->user_counter += dmap->fragment_size;
 		dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
 	}
-
 	if (dmap->qlen > 0)
 		DMAbuf_launch_output(dev, dmap);
-
 	restore_flags(flags);
 	finish_output_interrupt(dev, dmap);
 }
 
 void DMAbuf_outputintr(int dev, int notify_only)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	unsigned long flags;
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+	struct dma_buffparms *dmap = adev->dmap_out;
 
 	save_flags(flags);
 	cli();
-
-	if (!(dmap->flags & DMA_NODMA))
-	{
+	if (!(dmap->flags & DMA_NODMA)) {
 		int chan = dmap->dma, pos, n;
 		clear_dma_ff(chan);
 		disable_dma(dmap->dma);
@@ -1145,29 +1004,19 @@
 
 static void do_inputintr(int dev)
 {
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-	unsigned long flags;
-
-#ifdef OS_DMA_INTR
-	if (audio_devs[dev]->dmap_in->dma >= 0)
-		sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma);
-#endif
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = adev->dmap_in;
 
-	if (dmap->raw_buf == NULL)
-	{
+	if (dmap->raw_buf == NULL) {
 		printk(KERN_ERR "Sound: Fatal error. Audio interrupt after freeing buffers.\n");
 		return;
 	}
-	if (dmap->mapping_flags & DMA_MAP_MAPPED)
-	{
+	if (dmap->mapping_flags & DMA_MAP_MAPPED) {
 		dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-		if (dmap->qtail == 0)		/* Wrapped */
-		{
+		if (dmap->qtail == 0) {		/* Wrapped */
 			dmap->byte_counter += dmap->bytes_in_use;
-			if (dmap->byte_counter >= dmap->max_byte_counter)	/* Overflow */
-			{
+			if (dmap->byte_counter >= dmap->max_byte_counter) {	/* Overflow */
 				long decr = dmap->byte_counter;
-
 				dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
 				decr -= dmap->byte_counter;
 				dmap->user_counter -= decr;
@@ -1175,79 +1024,58 @@
 		}
 		dmap->qlen++;
 
-		if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
-		{
+		if (!(adev->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);
-			if (audio_devs[dev]->d->trigger)
-				audio_devs[dev]->d->trigger(dev,audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+			local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_READ);
+			adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size,
+					     dmap->fragment_size, 1);
+			if (adev->d->trigger)
+				adev->d->trigger(dev, adev->enable_bits * adev->go);
 		}
 		dmap->flags |= DMA_ACTIVE;
-	}
-	else if (dmap->qlen >= (dmap->nbufs - 1))
-	{
+	} else if (dmap->qlen >= (dmap->nbufs - 1)) {
 		printk(KERN_WARNING "Sound: Recording overrun\n");
 		dmap->underrun_count++;
 
 		/* Just throw away the oldest fragment but keep the engine running */
 		dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
 		dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-	}
-	else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs)
-	{
+	} else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) {
 		dmap->qlen++;
 		dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-		if (dmap->qtail == 0)		/* Wrapped */
-		{
+		if (dmap->qtail == 0) {		/* Wrapped */
 			dmap->byte_counter += dmap->bytes_in_use;
-			if (dmap->byte_counter >= dmap->max_byte_counter)	/* Overflow */
-			{
+			if (dmap->byte_counter >= dmap->max_byte_counter) {	/* Overflow */
 				long decr = dmap->byte_counter;
-
 				dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
 				decr -= dmap->byte_counter;
 				dmap->user_counter -= decr;
 			}
 		}
 	}
-	if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA)
-	{
-		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);
-		if (audio_devs[dev]->d->trigger)
-			audio_devs[dev]->d->trigger(dev,audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+	if (!(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) {
+		local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ);
+		adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1);
+		if (adev->d->trigger)
+			adev->d->trigger(dev,adev->enable_bits * adev->go);
 	}
 	dmap->flags |= DMA_ACTIVE;
-
-	save_flags(flags);
-	cli();
 	if (dmap->qlen > 0)
-	{
-		if ((in_sleep_flag[dev].opts & WK_SLEEP))
-		{
-			in_sleep_flag[dev].opts = WK_WAKEUP;
-			wake_up(&in_sleeper[dev]);
-		}
-	}
-	restore_flags(flags);
+		wake_up(&adev->in_sleeper);
 }
 
 void DMAbuf_inputintr(int dev)
 {
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = adev->dmap_in;
 	unsigned long flags;
 
 	save_flags(flags);
 	cli();
 
-	if (!(dmap->flags & DMA_NODMA))
-	{
+	if (!(dmap->flags & DMA_NODMA)) {
 		int chan = dmap->dma, pos, n;
-
 		clear_dma_ff(chan);
 		disable_dma(dmap->dma);
 		pos = dmap->bytes_in_use - get_dma_residue(chan);
@@ -1260,8 +1088,7 @@
 		n = 0;
 		while (dmap->qtail != pos && ++n < dmap->nbufs)
 			do_inputintr(dev);
-	}
-	else
+	} else
 		do_inputintr(dev);
 	restore_flags(flags);
 }
@@ -1271,25 +1098,22 @@
 	/*
 	 *    NOTE!  This routine opens only the primary DMA channel (output).
 	 */
-
-	int chan = audio_devs[dev]->dmap_out->dma;
+	struct audio_operations *adev = audio_devs[dev];
 	int err;
 
-	if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0)
+	if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0)
 		return -EBUSY;
-	dma_init_buffers(dev, audio_devs[dev]->dmap_out);
-	out_sleep_flag[dev].opts = WK_NONE;
-	audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE;
-	audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize;
+	dma_init_buffers(adev->dmap_out);
+	adev->dmap_out->flags |= DMA_ALLOC_DONE;
+	adev->dmap_out->fragment_size = adev->dmap_out->buffsize;
 
-	if (chan >= 0)
-	{
+	if (adev->dmap_out->dma >= 0) {
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		disable_dma(audio_devs[dev]->dmap_out->dma);
-		clear_dma_ff(chan);
+		clear_dma_ff(adev->dmap_out->dma);
+		disable_dma(adev->dmap_out->dma);
 		restore_flags(flags);
 	}
 	return 0;
@@ -1297,147 +1121,107 @@
 
 void DMAbuf_close_dma(int dev)
 {
-	close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma);
+	close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out);
 }
 
 void DMAbuf_init(int dev, int dma1, int dma2)
 {
+	struct audio_operations *adev = audio_devs[dev];
 	/*
 	 * NOTE! This routine could be called several times.
 	 */
 
-	if (audio_devs[dev] && audio_devs[dev]->dmap_out == NULL)
-	{
-		if (audio_devs[dev]->d == NULL)
+	if (adev && adev->dmap_out == NULL) {
+		if (adev->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++];
-			audio_devs[dev]->dmap_out->dma = dma1;
-
-			if (audio_devs[dev]->flags & DMA_DUPLEX)
-			{
-				audio_devs[dev]->dmap_in = &dmaps[ndmaps++];
-				audio_devs[dev]->dmap_in->dma = dma2;
+		if (adev->parent_dev) {	 /* Use DMA map of the parent dev */
+			int parent = adev->parent_dev - 1;
+			adev->dmap_out = audio_devs[parent]->dmap_out;
+			adev->dmap_in = audio_devs[parent]->dmap_in;
+		} else {
+			adev->dmap_out = adev->dmap_in = &adev->dmaps[0];
+			adev->dmap_out->dma = dma1;
+			if (adev->flags & DMA_DUPLEX) {
+				adev->dmap_in = &adev->dmaps[1];
+				adev->dmap_in->dma = dma2;
 			}
 		}
 	}
 }
 
-int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait)
+static unsigned int poll_input(int dev, poll_table *wait)
 {
-	struct dma_buffparms *dmap;
-	unsigned long   flags;
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = adev->dmap_in;
 
-	switch (sel_type)
-	{
-		case SEL_IN:
-			if (!(audio_devs[dev]->open_mode & OPEN_READ))
-				return 0;
-			dmap = audio_devs[dev]->dmap_in;
-
-			if (dmap->mapping_flags & DMA_MAP_MAPPED)
-			{
-				if (dmap->qlen)
-					return 1;
-				save_flags(flags);
-				cli();
-				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;
-					save_flags(flags);
-					cli();
-					DMAbuf_activate_recording(dev, dmap);
-					restore_flags(flags);
-				}
-				return 0;
-			}
-			if (!dmap->qlen)
-			{
-				save_flags(flags);
-				cli();
-
-				in_sleep_flag[dev].opts = WK_SLEEP;
-				poll_wait(&in_sleeper[dev], wait);
-				restore_flags(flags);
-				return 0;
-			}
-			return 1;
-
-		case SEL_OUT:
-			dmap = audio_devs[dev]->dmap_out;
-
-			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-				return 0;
-
-			if (dmap->mapping_flags & DMA_MAP_MAPPED)
-			{
-				if (dmap->qlen)
-					return 1;
-
-				save_flags(flags);
-				cli();
-
-				out_sleep_flag[dev].opts = WK_SLEEP;
-				poll_wait(&out_sleeper[dev], wait);
-				restore_flags(flags);
-				return 0;
-			}
-			    
-			if (dmap->dma_mode == DMODE_INPUT)
-				return 0;
-
-			if (dmap->dma_mode == DMODE_NONE)
-				return 1;
-
-			if (!DMAbuf_space_in_queue(dev))
-			{
-				save_flags(flags);
-				cli();
-
-				out_sleep_flag[dev].opts = WK_SLEEP;
-				poll_wait(&out_sleeper[dev], wait);
-				restore_flags(flags);
-				return 0;
-			}
-			return 1;
-			break;
+	if (!(adev->open_mode & OPEN_READ))
+		return 0;
+	if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+		poll_wait(&adev->in_sleeper, wait);
+		if (dmap->qlen)
+			return POLLIN | POLLRDNORM;
+		return 0;
+	}
+	if (dmap->dma_mode != DMODE_INPUT) {
+		if (dmap->dma_mode == DMODE_NONE &&
+		    adev->enable_bits & PCM_ENABLE_INPUT &&
+		    !dmap->qlen && adev->go) {
+			unsigned long flags;
+			
+			poll_wait(&adev->in_sleeper, wait);
+			save_flags(flags);
+			cli();
+			DMAbuf_activate_recording(dev, dmap);
+			restore_flags(flags);
+		}
+		return 0;
+	}
+	poll_wait(&adev->in_sleeper, wait);
+	if (!dmap->qlen)
+		return 0;
+	return POLLIN | POLLRDNORM;
+}
 
-		case SEL_EX:
-			return 0;
+static unsigned int poll_output(int dev, poll_table *wait)
+{
+	struct audio_operations *adev = audio_devs[dev];
+	struct dma_buffparms *dmap = adev->dmap_out;
+	
+	if (!(adev->open_mode & OPEN_WRITE))
+		return 0;
+	if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+		poll_wait(&adev->out_sleeper, wait);
+		if (dmap->qlen)
+			return POLLOUT | POLLWRNORM;
+		return 0;
 	}
+	if (dmap->dma_mode == DMODE_INPUT)
+		return 0;
+	poll_wait(&adev->out_sleeper, wait);
+	if (dmap->dma_mode == DMODE_NONE)
+		return POLLOUT | POLLWRNORM;
+	if (!DMAbuf_space_in_queue(dev))
+		return 0;
+	return POLLOUT | POLLWRNORM;
+}
 
-	return 0;
+unsigned int DMAbuf_poll(int dev, poll_table *wait)
+{
+	return poll_input(dev, wait) | poll_output(dev, wait);
 }
 
 void DMAbuf_deinit(int dev)
 {
-/* This routine is called when driver is being unloaded */
+	struct audio_operations *adev = audio_devs[dev];
+	/* This routine is called when driver is being unloaded */
+	if (!adev)
+		return;
 #ifdef RUNTIME_DMA_ALLOC
-	if (audio_devs[dev])
-		sound_free_dmap (dev, audio_devs[dev]->dmap_out, 
-				 audio_devs[dev]->dmap_out->dma);
-
-	if (audio_devs[dev] && audio_devs[dev]->flags & DMA_DUPLEX)
-		sound_free_dmap (dev, audio_devs[dev]->dmap_in, 
-				 audio_devs[dev]->dmap_in->dma);
+	sound_free_dmap(adev->dmap_out);
+
+	if (adev->flags & DMA_DUPLEX)
+		sound_free_dmap(adev->dmap_in);
 #endif
 }
 

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