patch-2.3.35 linux/drivers/sound/maestro.c

Next file: linux/drivers/usb/.indent.pro
Previous file: linux/drivers/sound/Config.in
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.34/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
@@ -1,6 +1,6 @@
 /*****************************************************************************
  *
- *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.2.x
+ *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -28,25 +28,25 @@
  *	proprietors of Hack Central for fine lodging.
  *
  *  Supported devices:
- *  /dev/dsp0-7    standard /dev/dsp device, (mostly) OSS compatible
+ *  /dev/dsp0-3    standard /dev/dsp device, (mostly) OSS compatible
  *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
  *
  *  Hardware Description
  *
  *	A working Maestro setup contains the Maestro chip wired to a 
- *	codec or 2.  In the Maestro we have the APUs, the ASP, and the
+ *	codec or 2.  In the Maestro we have the APUs, the ASSP, and the
  *	Wavecache.  The APUs can be though of as virtual audio routing
  *	channels.  They can take data from a number of sources and perform
  *	basic encodings of the data.  The wavecache is a storehouse for
  *	PCM data.  Typically it deals with PCI and interracts with the
- *	APUs.  The ASP is a wacky DSP like device that ESS is loth
+ *	APUs.  The ASSP is a wacky DSP like device that ESS is loth
  *	to release docs on.  Thankfully it isn't required on the Maestro
  *	until you start doing insane things like FM emulation and surround
  *	encoding.  The codecs are almost always AC-97 compliant codecs, 
  *	but it appears that early Maestros may have had PT101 (an ESS
  *	part?) wired to them.  The only real difference in the Maestro
  *	families is external goop like docking capability, memory for
- *	the ASP, and initialization differences.
+ *	the ASSP, and initialization differences.
  *
  *  Driver Operation
  *
@@ -55,25 +55,19 @@
  *	/dev/dsp? device.  2 channels for output, and 4 channels for
  *	input.
  *
- *	For output we maintain a ring buffer of data that we are DMAing
- *	to the card.  In mono operation this is nice and easy.  When
- *	we receive data we tack it onto the ring buffer and make sure
- *	the APU assigned to it is playing over the data.  When we fill
- *	the ring buffer we put the client to sleep until there is
- *	room again.  Easy.
+ *	Each APU can do a number of things, but we only really use
+ *	3 basic functions.  For playback we use them to convert PCM
+ *	data fetched over PCI by the wavecahche into analog data that
+ *	is handed to the codec.  One APU for mono, and a pair for stereo.
+ *	When in stereo, the combination of smarts in the APU and Wavecache
+ *	decide which wavecache gets the left or right channel.
  *
- *	However, this starts to stink when we use stereo.  The APUs
- *	supposedly can decode LRLR packed stereo data, but it
- *	doesn't work.  So we're forced to use dual mono APUs walking over
- *	mono encoded data.  This requires us to split the input from
- *	the client and complicates the buffer maths tremendously.  Ick.
- *
- *	This also pollutes the recording paths as well.  We have to use
- *	2 L/R incoming APUs that are fixed at 16bit/48khz.  We then pipe
- * 	these through 2 rate converion apus that mix them down to the
- * 	requested frequency and write them to memory through the wavecache.
- *	We also apparently need a 512byte region thats used as temp space 
- *	between the incoming APUs and the rate converters.
+ *	For record we still use the old overly mono system.  For each in
+ *	coming channel the data comes in from the codec, through a 'input'
+ *	APU, through another rate converter APU, and then into memory via
+ *	the wavecache and PCI.  If its stereo, we mash it back into LRLR in
+ *	software.  The pass between the 2 APUs is supposedly what requires us
+ *	to have a 512 byte buffer sitting around in wavecache/memory.
  *
  *	The wavecache makes our life even more fun.  First off, it can
  *	only address the first 28 bits of PCI address space, making it
@@ -113,9 +107,19 @@
  *	similar.
  *	
  * History
+ *  v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
+ *	fix nec Versas?  man would that be cool.
+ *  v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
+ *	brown bag volume max fix..
+ *  v0.11 - Nov 11 1999 - Zach Brown <zab@redhat.com>
+ *	use proper stereo apu decoding, mmap/write should work.
+ *	make volume sliders more useful, tweak rate calculation.
+ *	fix lame 8bit format reporting bug.  duh. apm apu saving buglet also
+ *	fix maestro 1 clock freq "bug", remove pt101 support
  *  v0.10 - Oct 28 1999 - Zach Brown <zab@redhat.com>
  *	aha, so, sometimes the WP writes a status word to offset 0
  *	  from one of the PCMBARs.  rearrange allocation accordingly..
+ *	  cheers again to Eric for being a good hacker in investigating this.
  *	Jeroen Hoogervorst submits 7500 fix out of nowhere.  yay.  :)
  *  v0.09 - Oct 23 1999 - Zach Brown <zab@redhat.com>
  *	added APM support.
@@ -159,16 +163,12 @@
  *
  * TODO
  *	some people get indir reg timeouts?
- *	anyone have a pt101 codec?
- *	mmap(), but beware stereo encoding nastiness.
- *	actually post pci writes
  *	fix bob frequency
+ *	endianness
  *	do smart things with ac97 2.0 bits.
- *	ugh.. non aligned writes in the middle of a data stream.. ugh
- *	sort out 0x34->0x36 crap in init
  *	docking and dual codecs and 978?
- *	pcm_sync?
- *	actually use LRLR
+ *	leave 54->61 open
+ *	resolve 2.3/2.2 stuff
  *
  *	it also would be fun to have a mode that would not use pci dma at all
  *	but would copy into the wavecache on board memory and use that 
@@ -189,12 +189,14 @@
  #define SILLY_INIT_SEM(SEM) SEM=MUTEX;
  #define init_waitqueue_head init_waitqueue
  #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
+ #define SILLY_OFFSET(VMA) ((VMA)->vm_offset)
 
 #else
 
  #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start)
  #define SILLY_INIT_SEM(SEM) init_MUTEX(&SEM)
  #define SILLY_MAKE_INIT(FUNC) __init FUNC
+ #define SILLY_OFFSET(VMA) ((VMA)->vm_pgoff)
 
 #endif
 
@@ -241,7 +243,7 @@
 #endif
 
 /* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.10"
+#define DRIVER_VERSION "0.13"
 
 #ifndef PCI_VENDOR_ESS
 #define PCI_VENDOR_ESS			0x125D
@@ -256,6 +258,10 @@
 
 #define ESS_CHAN_HARD		0x100
 
+/* NEC Versas ? */
+#define NEC_VERSA_SUBID1	0x80581033
+#define NEC_VERSA_SUBID2	0x803c1033
+
 
 /* changed so that I could actually find all the
 	references and fix them up.  its a little more readable now. */
@@ -271,8 +277,8 @@
 #define DAC_RUNNING		1
 #define ADC_RUNNING		2
 
-#define MAX_DSP_ORDER	3
-#define MAX_DSPS	(1<<3)
+#define MAX_DSP_ORDER	2
+#define MAX_DSPS	(1<<MAX_DSP_ORDER)
 #define NR_DSPS		(1<<dsps_order)
 #define NR_IDRS		32
 
@@ -296,6 +302,11 @@
 	[TYPE_MAESTRO2E] = "ESS Maestro 2E"
 };
 
+static int clock_freq[]={
+	[TYPE_MAESTRO] = (49152000L / 1024L),
+	[TYPE_MAESTRO2] = (50000000L / 1024L),
+	[TYPE_MAESTRO2E] = (50000000L / 1024L)
+};
 
 /* --------------------------------------------------------------------- */
 
@@ -521,7 +532,7 @@
 	[SOUND_MIXER_BASS] =            0x3232,
 	[SOUND_MIXER_TREBLE] =          0x3232,
 	[SOUND_MIXER_SPEAKER] =         0x3232,
-	[SOUND_MIXER_MIC] =     0x3232,
+	[SOUND_MIXER_MIC] =     0x8000, /* annoying */
 	[SOUND_MIXER_LINE] =    0x3232,
 	[SOUND_MIXER_CD] =      0x3232,
 	[SOUND_MIXER_VIDEO] =   0x3232,
@@ -599,6 +610,23 @@
 /* write the OSS encoded volume to the given OSS encoded mixer,
 	again caller's job to make sure all is well in arg land,
 	call with spinlock held */
+	
+/* linear scale -> log */
+unsigned char lin2log[101] = 
+{
+0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
+50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
+63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
+72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
+78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
+83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
+87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
+90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
+93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
+95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
+97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99 
+};
+
 static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
 {
 	u16 val=0;
@@ -614,12 +642,13 @@
 			right = (right * mh->scale) / 100;
 			left = (left * mh->scale) / 100;
 			if ((left == 0) && (right == 0))
-				val |= 0x8000; 
-		} else {
-			right = ((100 - right) * mh->scale) / 100;
-			left = ((100 - left) * mh->scale) / 100;
-			if((left == mh->scale) && (right == mh->scale))
 				val |= 0x8000;
+		} else {
+			/* log conversion for the stereo controls */
+			if((left == 0) && (right == 0))
+				val = 0x8000;
+			right = ((100 - lin2log[right]) * mh->scale) / 100;
+			left = ((100 - lin2log[left]) * mh->scale) / 100;
 		}
 
 		val |= (left << 8) | right;
@@ -772,6 +801,8 @@
 	return 0;
 }
 
+#if 0  /* there has been 1 person on the planet with a pt101 that we
+	know of.  If they care, they can put this back in :) */
 static u16 maestro_pt101_init(struct ess_card *card,int iobase)
 {
 	printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
@@ -792,6 +823,7 @@
 	maestro_ac97_set(iobase, 0x0E, 0x801F);
 	return 0;
 }
+#endif
 
 /* this is very magic, and very slow.. */
 static void 
@@ -799,6 +831,7 @@
 {
 	u16 save_68;
 	u16 w;
+	u32 vend;
 
 	outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
 	outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
@@ -808,6 +841,7 @@
 	outw(0x0000,  ioaddr+0x36);
 	save_68 = inw(ioaddr+0x68);
 	pci_read_config_word(pcidev, 0x58, &w);	/* something magical with gpio and bus arb. */
+	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);
 	if( w & 0x1)
 		save_68 |= 0x10;
 	outw(0xfffe, ioaddr + 0x64);	/* tickly gpio 0.. */
@@ -861,6 +895,12 @@
 		}
 	}
 #endif
+	if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {
+		/* turn on external amp? */
+		outw(0xf9ff, ioaddr + 0x64);
+		outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
+		outw(0x0209, ioaddr + 0x60);
+	}
 }
 /*
  *	Indirect register access. Not all registers are readable so we
@@ -1065,13 +1105,12 @@
 /* sets the play formats of these apus, should be passed the already shifted format */
 static void set_apu_fmt(struct ess_state *s, int apu, int mode)
 {
-	if(mode&ESS_FMT_16BIT) { 
-		s->apu_mode[apu] = 0x10;
-		s->apu_mode[apu+1] = 0x10;
-	} else {
-		s->apu_mode[apu] = 0x30;
-		s->apu_mode[apu+1] = 0x30;
-	}
+	int apu_fmt = 0x10;
+
+	if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; 
+	if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; 
+	s->apu_mode[apu]   = apu_fmt;
+	s->apu_mode[apu+1] = apu_fmt;
 }
 
 /* this only fixes the output apu mode to be later set by start_dac and
@@ -1082,18 +1121,21 @@
 	set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
 }
 
-static u16 compute_rate(u32 freq)
+/* this is off by a little bit.. */
+static u32 compute_rate(struct ess_state *s, u32 freq)
 {
-	if(freq==48000)
-		return 0xFFFF;
-	freq<<=16;
-	freq/=48000;
-	return freq;
+	u32 clock = clock_freq[s->card->card_type];     
+
+	if (freq == 48000) return 0x10000;
+
+	return ((freq / clock) <<16 )+  
+		(((freq % clock) << 16) / clock);
 }
 
-static void set_dac_rate(struct ess_state *s, unsigned rate)
+static void set_dac_rate(struct ess_state *s, unsigned int rate)
 {
 	u32 freq;
+	int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
 
 	if (rate > 48000)
 		rate = 48000;
@@ -1102,12 +1144,12 @@
 
 	s->ratedac = rate;
 
-	if(!((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT))
-		rate >>= 1; /* who knows */
+	if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
+		rate >>= 1;
 
 /*	M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
 
-	freq = compute_rate(rate);
+	freq = compute_rate(s, rate);
 	
 	/* Load the frequency, turn on 6dB */
 	apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
@@ -1122,14 +1164,15 @@
 {
 	u32 freq;
 
-	if (rate > 48000)
-		rate = 48000;
+	/* Sample Rate conversion APUs don't like 0x10000 for their rate */
+	if (rate > 47999)
+		rate = 47999;
 	if (rate < 4000)
 		rate = 4000;
 
 	s->rateadc = rate;
 
-	freq = compute_rate(rate);
+	freq = compute_rate(s, rate);
 	
 	/* Load the frequency, turn on 6dB */
 	apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
@@ -1234,27 +1277,21 @@
 	/* all maestro sizes are in 16bit words */
 	size >>=1;
 
-	/* we're given the full size of the buffer, but
-	in stereo each channel will only play its half */
 	if(mode&ESS_FMT_STEREO) {
-		size >>=1; 
 		high_apu++;
+		/* only 16/stereo gets size divided */
+		if(mode&ESS_FMT_16BIT)
+			size>>=1;
 	}
 	
 	for(channel=0; channel <= high_apu; channel++)
 	{
-		int i;
-		
-		if(!channel) 
-			pa = virt_to_bus(buffer);
-		else
-		/* right channel plays its split half.
-			*2 accomodates for rampant shifting earlier */
-			pa = virt_to_bus(buffer + size*2);
+		pa = virt_to_bus(buffer);
 
 		/* set the wavecache control reg */
 		tmpval = (pa - 0x10) & 0xFFF8;
-		if(!(mode & 2)) tmpval |= 4; /* 8bit */ 
+		if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
+		if(mode & ESS_FMT_STEREO) tmpval |= 2;
 		ess->apu_base[channel]=tmpval;
 		wave_set_register(ess, ess->apu[channel]<<3, tmpval);
 		
@@ -1262,14 +1299,17 @@
 		pa>>=1; /* words */
 		
 		/* base offset of dma calcs when reading the pointer
-			on this left one */
+			on the left one */
 		if(!channel) ess->dma_dac.base = pa&0xFFFF;
 		
 		pa|=0x00400000;			/* System RAM */
-		
-		/* Begin loading the APU */		
-		for(i=0;i<15;i++)		/* clear all PBRs */
-			apu_set_register(ess, channel, i, 0x0000);
+
+		/* XXX the 16bit here might not be needed.. */
+		if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
+			if(channel) 
+				pa|=0x00800000;			/* Stereo */
+			pa>>=1;
+		}
 			
 /* XXX think about endianess when writing these registers */
 		M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
@@ -1290,16 +1330,17 @@
 		/* dma on, no envelopes, filter to all 1s) */
 		apu_set_register(ess, channel, 0, 0x400F);
 		
-		if(mode&ESS_FMT_STEREO)
-			/* set panning: left or right */
-			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
-		else
-			apu_set_register(ess, channel, 10, 0x8F08);
-
 		if(mode&ESS_FMT_16BIT)
 			ess->apu_mode[channel]=0x10;
 		else
 			ess->apu_mode[channel]=0x30;
+
+		if(mode&ESS_FMT_STEREO) {
+			/* set panning: left or right */
+			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
+			ess->apu_mode[channel] += 0x10;
+		} else
+			apu_set_register(ess, channel, 10, 0x8F08);
 	}
 	
 	/* clear WP interupts */
@@ -1660,29 +1701,20 @@
 clear_advance(struct ess_state *s)
 {
 	unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+	
 	unsigned char *buf = s->dma_dac.rawbuf;
 	unsigned bsize = s->dma_dac.dmasize;
-	/* swptr is always in bytes as read from an apu.. */
 	unsigned bptr = s->dma_dac.swptr;
 	unsigned len = s->dma_dac.fragsize;
-	int i=1;
-
-	if((s->fmt >> ESS_DAC_SHIFT)  & ESS_FMT_STEREO) {
-		i++;
-		bsize >>=1;
-	}
-		
-	for ( ;i; i-- , buf += bsize) {
-
-		if (bptr + len > bsize) {
-			unsigned x = bsize - bptr;
-			memset(buf + bptr, c, x);
-			/* account for wrapping? */
-			bptr = 0;
-			len -= x;
-		}
-		memset(buf + bptr, c, len);
+	
+	if (bptr + len > bsize) {
+		unsigned x = bsize - bptr;
+		memset(buf + bptr, c, x);
+		/* account for wrapping? */
+		bptr = 0;
+		len -= x;
 	}
+	memset(buf + bptr, c, len);
 }
 
 /* call with spinlock held! */
@@ -1725,8 +1757,13 @@
 	}
 	/* update DAC pointer */
 	if (s->dma_dac.ready) {
-		/* this is so gross.  */
-		hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; 
+		hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
+		/* the apu only reports the length it has seen, not the
+			length of the memory that has been used (the WP
+			knows that */
+		if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
+			hwptr<<=1;
+
 		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
 /*		M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
 		s->dma_dac.hwptr = hwptr;
@@ -2190,42 +2227,6 @@
 	return ret;
 }
 
-/* god this is gross..*/
-/* again, the mode passed is shifted/masked */
-static int 
-split_stereo(unsigned char *real_buffer,unsigned char  *tmp_buffer, int offset, 
-	int count, int bufsize, int mode)
-{  
-	/* oh, bother.	stereo decoding APU's don't work in 16bit so we
-	use dual linear decoders.  which means we have to hack up stereo
-	buffer's we're given.  yuck.  */
-
-	unsigned char *so,*left,*right;
-	int i;
-
-	so = tmp_buffer;
-	left = real_buffer + offset;
-	right = real_buffer + bufsize/2 + offset;
-
-	if(mode & ESS_FMT_16BIT) {
-		for(i=count/4; i ; i--) {
-			*(right++) = (*(so+2));
-			*(right++) = (*(so+3));
-			*(left++) = (*so);
-			*(left++) = (*(so+1));
-			so+=4;
-		}
-	} else {
-		for(i=count/2; i ; i--) {
-			*(right++) = (*(so+1));
-			*(left++) = (*so);
-			so+=2;
-		}
-	}
-
-	return 0;
-}
-
 static ssize_t 
 ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
@@ -2233,9 +2234,7 @@
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
-	unsigned char *splitbuf = NULL;
 	int cnt;
-	int mode = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
 	
 	VALIDATE_STATE(s);
 	if (ppos != &file->f_pos)
@@ -2246,9 +2245,6 @@
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	/* XXX be more clever than this.. */
-	if (!(splitbuf = kmalloc(count,GFP_KERNEL)))
-		return -ENOMEM; 
 	ret = 0;
 
 	calc_bob_rate(s);
@@ -2262,12 +2258,8 @@
 		}
 		swptr = s->dma_dac.swptr;
 
-		if(mode & ESS_FMT_STEREO) {
-			/* in stereo we have the 'dual' buffers.. */
-			cnt = ((s->dma_dac.dmasize/2)-swptr)*2;
-		} else {
-			cnt = s->dma_dac.dmasize-swptr;
-		}
+		cnt = s->dma_dac.dmasize-swptr;
+
 		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
 			cnt = s->dma_dac.dmasize - s->dma_dac.count;
 
@@ -2276,10 +2268,6 @@
 		if (cnt > count)
 			cnt = count;
 
-		/* our goofball stereo splitter can only deal in mults of 4 */
-		if (cnt > 0) 
-			cnt &= ~3;
-
 		if (cnt <= 0) {
 			start_dac(s);
 			if (file->f_flags & O_NONBLOCK) {
@@ -2309,26 +2297,13 @@
 			}
 			continue;
 		}
-		if(mode & ESS_FMT_STEREO) {
-			if (copy_from_user(splitbuf, buffer, cnt)) {
-				if (!ret) ret = -EFAULT;
-				goto return_free;
-			}
-			split_stereo(s->dma_dac.rawbuf,splitbuf,swptr,cnt,s->dma_dac.dmasize,
-				mode);
-		} else {
-			if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-				if (!ret) ret = -EFAULT;
-				goto return_free;
-			}
+		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+			if (!ret) ret = -EFAULT;
+			goto return_free;
 		}
 
-		if(mode & ESS_FMT_STEREO) {
-			/* again with the weird pointer magic */
-			swptr = (swptr + (cnt/2)) % (s->dma_dac.dmasize/2);
-		} else {
-			swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		}
+		swptr = (swptr + cnt) % s->dma_dac.dmasize;
+
 		spin_lock_irqsave(&s->lock, flags);
 		s->dma_dac.swptr = swptr;
 		s->dma_dac.count += cnt;
@@ -2340,7 +2315,6 @@
 		start_dac(s);
 	}
 return_free:
-	if (splitbuf) kfree(splitbuf);
 	return ret;
 }
 
@@ -2374,8 +2348,6 @@
 	return mask;
 }
 
-/* this needs to be fixed to deal with the dual apus/buffers */
-#if 0
 static int ess_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct ess_state *s = (struct ess_state *)file->private_data;
@@ -2388,13 +2360,18 @@
 		if ((ret = prog_dmabuf(s, 1)) != 0)
 			return ret;
 		db = &s->dma_dac;
-	} else if (vma->vm_flags & VM_READ) {
+	} else 
+#if 0
+	/* if we can have the wp/wc do the combining
+		we can turn this back on.  */
+	      if (vma->vm_flags & VM_READ) {
 		if ((ret = prog_dmabuf(s, 0)) != 0)
 			return ret;
 		db = &s->dma_adc;
-	} else 
+	} else  
+#endif
 		return -EINVAL;
-	if (vma->vm_pgofft != 0)
+	if (SILLY_OFFSET(vma) != 0)
 		return -EINVAL;
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << db->buforder))
@@ -2404,7 +2381,6 @@
 	db->mapped = 1;
 	return 0;
 }
-#endif
 
 static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -2434,7 +2410,7 @@
 		return 0;
 
 	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER /*| DSP_CAP_MMAP*/, (int *)arg);
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
 		
         case SNDCTL_DSP_RESET:
 		if (file->f_mode & FMODE_WRITE) {
@@ -2515,7 +2491,7 @@
 					   : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
 		
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+                return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg);
 		
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
 		get_user_ret(val, (int *)arg, -EFAULT);
@@ -2548,7 +2524,7 @@
 			(ESS_FMT_16BIT << ESS_ADC_SHIFT) 
 			: (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 
 				AFMT_S16_LE : 
-				AFMT_S8, 
+				AFMT_U8, 
 			(int *)arg);
 		
 	case SNDCTL_DSP_POST:
@@ -2938,7 +2914,7 @@
 	NULL,  /* readdir */
 	&ess_poll,
 	&ess_ioctl,
-	NULL,	/* XXX &ess_mmap, */
+	&ess_mmap,
 	&ess_open,
 	NULL,	/* flush */
 	&ess_release,
@@ -3000,7 +2976,7 @@
 	w&=~(1<<7);		/* HWV off */
 	w&=~(1<<6);		/* Debounce off */
 	w&=~(1<<5);		/* GPIO 4:5 */
-	w|= (1<<4);             /* Disconnect from the CHI.  Enabling this in made a dell 7500 work. */
+	w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
 	w&=~(1<<3);		/* IDMA off (undocumented) */
 	w&=~(1<<2);		/* MIDI fix off (undoc) */
 	w&=~(1<<1);		/* reserved, always write 0 */
@@ -3303,7 +3279,8 @@
 	maestro_config(card);
 
 	if(maestro_ac97_get(iobase, 0x00)==0x0080) {
-		maestro_pt101_init(card,iobase);
+		printk(KERN_ERR "maestro: my goodness!  you seem to have a pt101 codec, which is quite rare.\n"
+				"\tyou should tell someone about this.\n");
 	} else {
 		maestro_ac97_init(card,iobase);
 	}
@@ -3451,7 +3428,7 @@
 }
 
 static int 
-maestro_apm_suspend(void)
+maestro_suspend(void)
 {
 	struct ess_card *card;
 	unsigned long flags;
@@ -3474,7 +3451,7 @@
 			stop_dac(s);
 			stop_adc(s);
 			for(j=0;j<6;j++) 
-				card->apu_map[s->apu[i]][5]=apu_get_register(s,i,5);
+				card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5);
 
 		}
 
@@ -3491,7 +3468,7 @@
 	return 0;
 }
 static int 
-maestro_apm_resume(void)
+maestro_resume(void)
 {
 	struct ess_card *card;
 	unsigned long flags;
@@ -3565,11 +3542,11 @@
 	case APM_SYS_SUSPEND: 
 	case APM_CRITICAL_SUSPEND: 
 	case APM_USER_SUSPEND: 
-		maestro_apm_suspend();break;
+		maestro_suspend();break;
 	case APM_NORMAL_RESUME: 
 	case APM_CRITICAL_RESUME: 
 	case APM_STANDBY_RESUME: 
-		maestro_apm_resume();break;
+		maestro_resume();break;
 	default: break;
 	}
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)