patch-2.4.21 linux-2.4.21/drivers/sound/i810_audio.c

Next file: linux-2.4.21/drivers/sound/kahlua.c
Previous file: linux-2.4.21/drivers/sound/gus_wave.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/sound/i810_audio.c linux-2.4.21/drivers/sound/i810_audio.c
@@ -65,6 +65,20 @@
  *	If you need to force a specific rate set the clocking= option
  *
  *	This driver is cursed. (Ben LaHaise)
+ *
+ *  ICH 3 caveats
+ *	Intel errata #7 for ICH3 IO. We need to disable SMI stuff
+ *	when codec probing. [Not Yet Done]
+ *
+ *  ICH 4 caveats
+ *
+ *      The ICH4 has the feature, that the codec ID doesn't have to be 
+ *      congruent with the IO connection.
+ * 
+ *      Therefore, from driver version 0.23 on, there is a "codec ID" <->
+ *      "IO register base offset" mapping (card->ac97_id_map) field.
+ *   
+ *      Juergen "George" Sawinski (jsaw) 
  */
  
 #include <linux/module.h>
@@ -122,6 +136,9 @@
 #ifndef PCI_DEVICE_ID_AMD_768_AUDIO
 #define PCI_DEVICE_ID_AMD_768_AUDIO	0x7445
 #endif
+#ifndef PCI_DEVICE_ID_AMD_8111_AC97
+#define PCI_DEVICE_ID_AMD_8111_AC97	0x746d
+#endif
 
 static int ftsodell=0;
 static int strict_clocking=0;
@@ -132,6 +149,7 @@
 //#define DEBUG2
 //#define DEBUG_INTERRUPTS
 //#define DEBUG_MMAP
+//#define DEBUG_MMIO
 
 #define ADC_RUNNING	1
 #define DAC_RUNNING	2
@@ -174,6 +192,11 @@
  * each dma engine has controlling registers.  These goofy
  * names are from the datasheet, but make it easy to write
  * code while leafing through it.
+ *
+ * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, 
+ * mic in 2, s/pdif.   Of special interest is the fact that
+ * the upper 3 DMA engines on the ICH4 *must* be accessed
+ * via mmio access instead of pio access.
  */
 
 #define ENUM_ENGINE(PRE,DIG) 									\
@@ -198,6 +221,14 @@
 	CAS	 = 	0x34			/* Codec Write Semaphore Register */
 };
 
+ENUM_ENGINE(MC2,4);     /* Mic In 2 */
+ENUM_ENGINE(PI2,5);     /* PCM In 2 */
+ENUM_ENGINE(SP,6);      /* S/PDIF */
+
+enum {
+	SDM =           0x80                    /* SDATA_IN Map Register */
+};
+
 /* interrupts for a dma engine */
 #define DMA_INT_FIFO		(1<<4)  /* fifo under/over flow */
 #define DMA_INT_COMPLETE	(1<<3)  /* buffer read/write complete and ioc set */
@@ -217,8 +248,7 @@
 #define INT_GPI		(1<<0)
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
-
-#define DRIVER_VERSION "0.21"
+#define DRIVER_VERSION "0.24"
 
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
@@ -227,7 +257,7 @@
 #define NR_HW_CH		3
 
 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97		2
+#define NR_AC97                 4
 
 /* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
 /* stream at a minimum for this card to be happy */
@@ -262,6 +292,25 @@
 	"AMD-8111 IOHub"
 };
 
+/* These are capabilities (and bugs) the chipsets _can_ have */
+static struct {
+	int16_t      nr_ac97;
+#define CAP_MMIO                 0x0001
+#define CAP_20BIT_AUDIO_SUPPORT  0x0002
+	u_int16_t flags;
+} card_cap[] = {
+	{  1, 0x0000 }, /* ICH82801AA */
+	{  1, 0x0000 }, /* ICH82901AB */
+	{  1, 0x0000 }, /* INTEL440MX */
+	{  1, 0x0000 }, /* INTELICH2 */
+	{  2, 0x0000 }, /* INTELICH3 */
+        {  3, 0x0003 }, /* INTELICH4 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* SI7012 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* NVIDIA_NFORCE */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* AMD768 */
+	/*@FIXME to be verified*/	{  3, 0x0001 }, /* AMD8111 */
+};
+
 static struct pci_device_id i810_pci_tbl [] __initdata = {
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
@@ -363,7 +412,6 @@
 
 
 struct i810_card {
-	struct i810_channel channel[3];
 	unsigned int magic;
 
 	/* We keep i810 cards in a linked list */
@@ -376,6 +424,7 @@
 	/* PCI device stuff */
 	struct pci_dev * pci_dev;
 	u16 pci_id;
+	u16 pci_id_internal; /* used to access card_cap[] */
 #ifdef CONFIG_PM	
 	u16 pm_suspended;
 	u32 pm_save_state[64/sizeof(u32)];
@@ -385,17 +434,27 @@
 	int dev_audio;
 
 	/* structures for abstraction of hardware facilities, codecs, banks and channels*/
+	u16    ac97_id_map[NR_AC97];
 	struct ac97_codec *ac97_codec[NR_AC97];
 	struct i810_state *states[NR_HW_CH];
+	struct i810_channel *channel;	/* 1:1 to states[] but diff. lifetime */
+	dma_addr_t chandma;
 
 	u16 ac97_features;
 	u16 ac97_status;
 	u16 channels;
 	
 	/* hardware resources */
-	unsigned long iobase;
 	unsigned long ac97base;
+	unsigned long iobase;
 	u32 irq;
+
+	unsigned long ac97base_mmio_phys;
+	unsigned long iobase_mmio_phys;
+	u_int8_t *ac97base_mmio;
+	u_int8_t *iobase_mmio;
+
+	int           use_mmio;
 	
 	/* Function support */
 	struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
@@ -408,6 +467,12 @@
 	int initializing;
 };
 
+/* extract register offset from codec struct */
+#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
+
+/* set LVI from CIV */
+#define CIV_TO_LVI(port, off) outb((inb(port+OFF_CIV)+off) & 31, port+OFF_LVI)
+
 static struct i810_card *devs = NULL;
 
 static int i810_open_mixdev(struct inode *inode, struct file *file);
@@ -415,6 +480,10 @@
 			     unsigned int cmd, unsigned long arg);
 static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
 static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
 
 static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
 {
@@ -574,6 +643,11 @@
 {
 	int	aud_reg;
 	struct ac97_codec *codec = state->card->ac97_codec[0];
+	
+	/* No codec, no setup */
+	
+	if(codec == NULL)
+		return;
 
 	aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
 	aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
@@ -766,7 +840,8 @@
 	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {
 		dmabuf->enable |= ADC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PI_CR);
 	}
 }
 
@@ -815,7 +890,8 @@
 	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
 		dmabuf->enable |= DAC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PO_CR);
 	}
 }
 static void start_dac(struct i810_state *state)
@@ -967,7 +1043,7 @@
 	  
 		for(i=0;i<dmabuf->numfrag;i++)
 		{
-			sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i);
+			sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
 			// the card will always be doing 16bit stereo
 			sg->control=dmabuf->fragsamples;
 			if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
@@ -982,9 +1058,11 @@
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-		outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-		outb(0, state->card->iobase+c->port+OFF_CIV);
-		outb(0, state->card->iobase+c->port+OFF_LVI);
+		while( inb(state->card->iobase+c->port+OFF_CR) & 0x02 ) ;
+		outl((u32)state->card->chandma +
+		    c->num*sizeof(struct i810_channel),
+		    state->card->iobase+c->port+OFF_BDBAR);
+		CIV_TO_LVI(state->card->iobase+c->port, 0);
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -1030,13 +1108,13 @@
 		if(rec && dmabuf->count < dmabuf->dmasize &&
 		   (dmabuf->trigger & PCM_ENABLE_INPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_adc(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		} else if (!rec && dmabuf->count &&
 			   (dmabuf->trigger & PCM_ENABLE_OUTPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_dac(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		}
@@ -1304,7 +1382,6 @@
 				if (dmabuf->enable & ADC_RUNNING)
 					__stop_adc(state);
 				dmabuf->enable = 0;
-				wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
 				printk(" STOP ");
 #endif
@@ -1750,9 +1827,11 @@
 		}
 		if (c != NULL) {
 			outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-			outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-			outb(0, state->card->iobase+c->port+OFF_CIV);
-			outb(0, state->card->iobase+c->port+OFF_LVI);
+			while ( inb(state->card->iobase+c->port+OFF_CR) & 2 );
+			outl((u32)state->card->chandma +
+			    c->num*sizeof(struct i810_channel),
+			    state->card->iobase+c->port+OFF_BDBAR);
+			CIV_TO_LVI(state->card->iobase+c->port, 0);
 		}
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1874,7 +1953,8 @@
 		}
 
 		/* ICH and ICH0 only support 2 channels */
-		if ( state->card->pci_id == 0x2415 || state->card->pci_id == 0x2425 ) 
+		if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801 
+		     || state->card->pci_id == PCI_DEVICE_ID_INTEL_82901) 
 			return put_user(2, (int *)arg);
 	
 		/* Multi-channel support was added with ICH2. Bits in */
@@ -1893,12 +1973,14 @@
 
 		switch ( val ) {
 			case 2: /* 2 channels is always supported */
-				outl(state->card->iobase + GLOB_CNT, (i_glob_cnt & 0xcfffff));
+				outl(i_glob_cnt & 0xffcfffff,
+				     state->card->iobase + GLOB_CNT);
 				/* Do we need to change mixer settings????  */
 				break;
 			case 4: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 4 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0100000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x100000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -1906,7 +1988,8 @@
 				break;
 			case 6: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 6 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0200000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x200000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -2111,14 +2194,14 @@
 #if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
 #endif
-		if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
+		if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
 			stop_adc(state);
 		}
-		if( !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
+		if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
 			stop_dac(state);
 		}
 		dmabuf->trigger = val;
-		if(val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
+		if((file->f_mode & FMODE_WRITE) && (val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
 			if (!dmabuf->write_channel) {
 				dmabuf->ready = 0;
 				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
@@ -2139,7 +2222,7 @@
 			} else
 				start_dac(state);
 		}
-		if(val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
+		if((file->f_mode & FMODE_READ) && (val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
 			if (!dmabuf->read_channel) {
 				dmabuf->ready = 0;
 				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
@@ -2411,6 +2494,9 @@
 	}
 	if(file->f_mode & FMODE_WRITE) {
 		if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
+			/* make sure we free the record channel allocated above */
+			if(file->f_mode & FMODE_READ)
+				card->free_pcm_channel(card,dmabuf->read_channel->num);
 			kfree (card->states[i]);
 			card->states[i] = NULL;;
 			return -EBUSY;
@@ -2424,6 +2510,9 @@
 			i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
 		} else {
 			i810_set_dac_rate(state, 8000);
+			/* Put the ACLink in 2 channel mode by default */
+			i = inl(card->iobase + GLOB_CNT);
+			outl(i & 0xffcfffff, card->iobase + GLOB_CNT);
 		}
 	}
 		
@@ -2488,27 +2577,86 @@
 
 /* Write AC97 codec registers */
 
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+#ifdef DEBUG_MMIO
+	{
+		u16 ans = readw(card->ac97base_mmio + reg_set);
+		printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
+		return ans;
+	}
+#else
+	return readw(card->ac97base_mmio + reg_set);
+#endif
+}
 
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
 	
 	return inw(card->ac97base + reg_set);
 }
 
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+	writew(data, card->ac97base_mmio + reg_set);
+
+#ifdef DEBUG_MMIO
+	printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
+#endif
+}
 
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
-	outw(data, card->ac97base + reg_set);
+	
+        outw(data, card->ac97base + reg_set);
+}
+
+static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		return i810_ac97_get_mmio(dev, reg);
+	}
+	else {
+		return i810_ac97_get_io(dev, reg);
+	}
+}
+
+static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		i810_ac97_set_mmio(dev, reg, data);
+	}
+	else {
+		i810_ac97_set_io(dev, reg, data);
+	}
 }
 
 
@@ -2533,7 +2681,7 @@
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(HZ/20);
 		}
-		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++) 
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor) {
 				file->private_data = card->ac97_codec[i];
@@ -2561,10 +2709,18 @@
 /* AC97 codec initialisation.  These small functions exist so we don't
    duplicate code between module init and apm resume */
 
-static inline int i810_ac97_exists(struct i810_card *card,int ac97_number)
+static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
 {
 	u32 reg = inl(card->iobase + GLOB_STA);
-	return (reg & (0x100 << ac97_number));
+	switch (ac97_number) {
+	case 0:
+		return reg & (1<<8);
+	case 1: 
+		return reg & (1<<9);
+	case 2:
+		return reg & (1<<28);
+	}
+	return 0;
 }
 
 static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
@@ -2587,10 +2743,9 @@
 	/* power it all up */
 	i810_ac97_set(codec, AC97_POWER_CONTROL,
 		      i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+
 	/* wait for analog ready */
-	for (i=10;
-	     i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf);
-	     i--)
+	for (i=10; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
 	{
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(HZ/20);
@@ -2598,11 +2753,18 @@
 	return i;
 }
 
-/* if I knew what this did, I'd give it a better name */
-static int i810_ac97_random_init_stuff(struct i810_card *card)
+/**
+ *	i810_ac97_power_up_bus	-	bring up AC97 link
+ *	@card : ICH audio device to power up
+ *
+ *	Bring up the ACLink AC97 codec bus
+ */
+ 
+static int i810_ac97_power_up_bus(struct i810_card *card)
 {	
 	u32 reg = inl(card->iobase + GLOB_CNT);
 	int i;
+	int primary_codec_id = 0;
 
 	if((reg&2)==0)	/* Cold required */
 		reg|=2;
@@ -2610,8 +2772,13 @@
 		reg|=4;	/* Warm */
 		
 	reg&=~8;	/* ACLink on */
-	outl(reg , card->iobase + GLOB_CNT);
 	
+	/* At this point we deassert AC_RESET # */
+	outl(reg , card->iobase + GLOB_CNT);
+
+	/* We must now allow time for the Codec initialisation.
+	   600mS is the specified time */
+	   	
 	for(i=0;i<10;i++)
 	{
 		if((inl(card->iobase+GLOB_CNT)&4)==0)
@@ -2628,7 +2795,31 @@
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ/2);
-	reg = inl(card->iobase + GLOB_STA);
+
+	/*
+	 *	See if the primary codec comes ready. This must happen
+	 *	before we start doing DMA stuff
+	 */	
+	/* see i810_ac97_init for the next 7 lines (jsaw) */
+	inw(card->ac97base);
+	if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+	    && (card->use_mmio)) {
+		primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+		printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
+		       primary_codec_id);
+	}
+
+	if(! i810_ac97_exists(card, primary_codec_id))
+	{
+		printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ);	/* actually 600mS by the spec */
+
+		if(i810_ac97_exists(card, primary_codec_id))
+			printk("OK\n");
+		else 
+			printk("no response.\n");
+	}
 	inw(card->ac97base);
 	return 1;
 }
@@ -2636,12 +2827,14 @@
 static int __init i810_ac97_init(struct i810_card *card)
 {
 	int num_ac97 = 0;
+	int ac97_id;
 	int total_channels = 0;
+	int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
 	struct ac97_codec *codec;
 	u16 eid;
 	u32 reg;
 
-	if(!i810_ac97_random_init_stuff(card)) return 0;
+	if(!i810_ac97_power_up_bus(card)) return 0;
 
 	/* Number of channels supported */
 	/* What about the codec?  Just because the ICH supports */
@@ -2657,26 +2850,47 @@
 		card->channels = 6;
 	else if ( reg & 0x0100000 )
 		card->channels = 4;
-	printk("i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
+	reg = inl(card->iobase + GLOB_CNT);
+	outl(reg & 0xffcfffff, card->iobase + GLOB_CNT);
 		
-	inw(card->ac97base);
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) 
+		card->ac97_codec[num_ac97] = NULL;
 
-	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+	/*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
+	if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
 
-		/* Assume codec isn't available until we go through the
-		 * gauntlet below */
-		card->ac97_codec[num_ac97] = NULL;
+	for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
+		/* codec reset */
+		printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
+		if (card->use_mmio) readw(card->ac97base_mmio + 0x80*num_ac97);
+		else inw(card->ac97base + 0x80*num_ac97);
+
+		/* If we have the SDATA_IN Map Register, as on ICH4, we
+		   do not loop thru all possible codec IDs but thru all 
+		   possible IO channels. Bit 0:1 of SDM then holds the 
+		   last codec ID spoken to. 
+		*/
+		if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+		    && (card->use_mmio)) {
+			ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+			printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
+			       num_ac97, ac97_id);
+		}
+		else {
+			ac97_id = num_ac97;
+		}
 
 		/* The ICH programmer's reference says you should   */
 		/* check the ready status before probing. So we chk */
 		/*   What do we do if it's not ready?  Wait and try */
 		/*   again, or abort?                               */
-		if (!i810_ac97_exists(card,num_ac97)) {
+		if (!i810_ac97_exists(card, ac97_id)) {
 			if(num_ac97 == 0)
 				printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
-			break; /* I think this works, if not ready stop */
 		}
-
+		
 		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
 			return -ENOMEM;
 		memset(codec, 0, sizeof(struct ac97_codec));
@@ -2684,13 +2898,20 @@
 		/* initialize some basic codec information, other fields will be filled
 		   in ac97_probe_codec */
 		codec->private_data = card;
-		codec->id = num_ac97;
+		codec->id = ac97_id;
+		card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
 
-		codec->codec_read = i810_ac97_get;
-		codec->codec_write = i810_ac97_set;
+		if (card->use_mmio) {	
+			codec->codec_read = i810_ac97_get_mmio;
+			codec->codec_write = i810_ac97_set_mmio;
+		}
+		else {
+			codec->codec_read = i810_ac97_get_io;
+			codec->codec_write = i810_ac97_set_io;
+		}
 	
 		if(!i810_ac97_probe_and_powerup(card,codec)) {
-			printk("i810_audio: timed out waiting for codec %d analog ready.\n", num_ac97);
+			printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
 			kfree(codec);
 			break;	/* it didn't work */
 		}
@@ -2699,7 +2920,7 @@
 		
 		/* Don't attempt to get eid until powerup is complete */
 		eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-		
+
 		if(eid==0xFFFFFF)
 		{
 			printk(KERN_WARNING "i810_audio: no codec attached ?\n");
@@ -2707,16 +2928,17 @@
 			break;
 		}
 		
-		codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-		if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID))
+		/* Check for an AC97 1.0 soft modem (ID1) */
+		
+		if(codec->modem)
 		{
-			printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", num_ac97);
+			printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id);
 			kfree(codec);
 			continue;
 		}
-	
+		
 		card->ac97_features = eid;
-				
+
 		/* Now check the codec for useful features to make up for
 		   the dumbness of the 810 hardware engine */
 
@@ -2730,6 +2952,11 @@
 			}			
 		}
    		
+		/* Turn on the amplifier */
+
+		codec->codec_write(codec, AC97_POWER_CONTROL, 
+			 codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
+				
 		/* Determine how many channels the codec(s) support   */
 		/*   - The primary codec always supports 2            */
 		/*   - If the codec supports AMAP, surround DACs will */
@@ -2755,7 +2982,7 @@
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
 		} else if (eid & 0x0400) {  /* this only works on 2.2 compliant codecs */
 			eid &= 0xffcf;
 			if((eid & 0xc000) != 0)	{
@@ -2777,14 +3004,14 @@
 			}
 			i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
 			eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", num_ac97, eid);
+			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
 			if (eid & 0x0080) /* L/R Surround channels */
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
 		} else {
-			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
 		}
 
 		if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
@@ -2833,6 +3060,8 @@
 		init_MUTEX(&state->open_sem);
 		dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
 		dmabuf->trigger = PCM_ENABLE_OUTPUT;
+		i810_set_spdif_output(state, -1, 0);
+		i810_set_dac_channels(state, 2);
 		i810_set_dac_rate(state, 48000);
 		if(prog_dmabuf(state, 0) != 0) {
 			goto config_out_nodmabuf;
@@ -2841,7 +3070,7 @@
 			goto config_out;
 		}
 		dmabuf->count = dmabuf->dmasize;
-		outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI);
+		CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, 31);
 		save_flags(flags);
 		cli();
 		start_dac(state);
@@ -2849,10 +3078,9 @@
 		mdelay(50);
 		new_offset = i810_get_dma_addr(state, 0);
 		stop_dac(state);
-		outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR);
 		restore_flags(flags);
 		i = new_offset - offset;
-#ifdef DEBUG
+#ifdef DEBUG_INTERRUPTS
 		printk("i810_audio: %d bytes in 50 milliseconds\n", i);
 #endif
 		if(i == 0)
@@ -2894,10 +3122,25 @@
 	memset(card, 0, sizeof(*card));
 
 	card->initializing = 1;
-	card->iobase = pci_resource_start (pci_dev, 1);
-	card->ac97base = pci_resource_start (pci_dev, 0);
 	card->pci_dev = pci_dev;
 	card->pci_id = pci_id->device;
+	card->ac97base = pci_resource_start (pci_dev, 0);
+	card->iobase = pci_resource_start (pci_dev, 1);
+
+	/* if chipset could have mmio capability, check it */ 
+	if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
+		card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
+		card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
+
+		if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
+			card->use_mmio = 1;
+		}
+		else {
+			card->ac97base_mmio_phys = 0;
+			card->iobase_mmio_phys = 0;
+		}
+	}
+
 	card->irq = pci_dev->irq;
 	card->next = devs;
 	card->magic = I810_CARD_MAGIC;
@@ -2909,23 +3152,37 @@
 
 	pci_set_master(pci_dev);
 
-	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n",
-	       card_names[pci_id->driver_data], card->iobase, card->ac97base, 
+	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
+	       "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
+	       card_names[pci_id->driver_data], 
+	       card->iobase, card->ac97base, 
+	       card->ac97base_mmio_phys, card->iobase_mmio_phys,
 	       card->irq);
 
 	card->alloc_pcm_channel = i810_alloc_pcm_channel;
 	card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
 	card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
 	card->free_pcm_channel = i810_free_pcm_channel;
-	card->channel[0].offset = 0;
-	card->channel[0].port = 0x00;
-	card->channel[0].num=0;
-	card->channel[1].offset = 0;
-	card->channel[1].port = 0x10;
-	card->channel[1].num=1;
-	card->channel[2].offset = 0;
-	card->channel[2].port = 0x20;
-	card->channel[2].num=2;
+
+	if ((card->channel = pci_alloc_consistent(pci_dev,
+	    sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
+		printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
+		goto out_mem;
+	}
+
+	{ /* We may dispose of this altogether some time soon, so... */
+		struct i810_channel *cp = card->channel;
+
+		cp[0].offset = 0;
+		cp[0].port = 0x00;
+		cp[0].num = 0;
+		cp[1].offset = 0;
+		cp[1].port = 0x10;
+		cp[1].num = 1;
+		cp[2].offset = 0;
+		cp[2].port = 0x20;
+		cp[2].num = 2;
+	}
 
 	/* claim our iospace and irq */
 	request_region(card->iobase, 64, card_names[pci_id->driver_data]);
@@ -2934,19 +3191,42 @@
 	if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
 			card_names[pci_id->driver_data], card)) {
 		printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
-		kfree(card);
-		return -ENODEV;
+		goto out_pio;
+	}
+
+	if (card->use_mmio) {
+		if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
+			if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
+				if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
+					if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
+						printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
+						       card_names[pci_id->driver_data], 
+						       (unsigned long) card->ac97base_mmio, 
+						       (unsigned long) card->iobase_mmio); 
+					}
+					else {
+						iounmap(card->ac97base_mmio);
+						release_mem_region(card->ac97base_mmio_phys, 512);
+						release_mem_region(card->iobase_mmio_phys, 512);
+						card->use_mmio = 0;
+					}
+				}
+				else {
+					iounmap(card->ac97base_mmio);
+					release_mem_region(card->ac97base_mmio_phys, 512);
+					card->use_mmio = 0;
+				}
+			}
+		}
+		else {
+			card->use_mmio = 0;
+		}
 	}
 
 	/* initialize AC97 codec and register /dev/mixer */
 	if (i810_ac97_init(card) <= 0) {
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
 	pci_set_drvdata(pci_dev, card);
 
@@ -2959,19 +3239,34 @@
 	if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
 		int i;
 		printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
 		for (i = 0; i < NR_AC97; i++)
 		if (card->ac97_codec[i] != NULL) {
 			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
 			kfree (card->ac97_codec[i]);
 		}
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
+
  	card->initializing = 0;
 	return 0;
+
+out_iospace:
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
+out_pio:	
+	release_region(card->iobase, 64);
+	release_region(card->ac97base, 256);
+out_chan:
+	pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
+	    card->channel, card->chandma);
+out_mem:
+	kfree(card);
+	return -ENODEV;
 }
 
 static void __devexit i810_remove(struct pci_dev *pci_dev)
@@ -2982,6 +3277,12 @@
 	free_irq(card->irq, devs);
 	release_region(card->iobase, 64);
 	release_region(card->ac97base, 256);
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
 
 	/* unregister audio devices */
 	for (i = 0; i < NR_AC97; i++)
@@ -3064,7 +3365,7 @@
 	   hardware has to be more or less completely reinitialized from
 	   scratch after an apm suspend.  Works For Me.   -dan */
 
-	i810_ac97_random_init_stuff(card);
+	i810_ac97_power_up_bus(card);
 
 	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
 		struct ac97_codec *codec = card->ac97_codec[num_ac97];

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