[ALSA] snd:emu10k1: E-Mu updates. Fixes to firmware loading and support for 0404.


Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index fb66a94..8a0c3c1 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1628,7 +1628,7 @@
 	unsigned char spdif_bug;    /* Has Spdif phasing bug */
 	unsigned char ac97_chip;    /* Has an AC97 chip: 1 = mandatory, 2 = optional */
 	unsigned char ecard;        /* APS EEPROM */
-	unsigned char emu1010;     /* EMU 1010m card */
+	unsigned char emu_model;     /* EMU model type */
 	unsigned char spi_dac;      /* SPI interface for DAC */
 	unsigned char i2c_adc;      /* I2C interface for ADC */
 	unsigned char adc_1361t;    /* Use Philips 1361T ADC */
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 69f342c..da66067 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -54,12 +54,14 @@
 #define DOCK_FILENAME "emu/audio_dock.fw"
 #define EMU1010B_FILENAME "emu/emu1010b.fw"
 #define MICRO_DOCK_FILENAME "emu/micro_dock.fw"
+#define EMU0404_FILENAME "emu/emu0404.fw"
 #define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"
 
 MODULE_FIRMWARE(HANA_FILENAME);
 MODULE_FIRMWARE(DOCK_FILENAME);
 MODULE_FIRMWARE(EMU1010B_FILENAME);
 MODULE_FIRMWARE(MICRO_DOCK_FILENAME);
+MODULE_FIRMWARE(EMU0404_FILENAME);
 MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
 
 
@@ -287,7 +289,7 @@
 		snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
 	}
 
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		outl(HCFG_AUTOMUTE_ASYNC |
 			HCFG_EMU32_SLAVE |
 			HCFG_AUDIOENABLE, emu->port + HCFG);
@@ -317,7 +319,7 @@
 		outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
 
 	if (enable_ir) {	/* enable IR for SB Live */
-		if (emu->card_capabilities->emu1010) {
+		if (emu->card_capabilities->emu_model) {
 			;  /* Disable all access to A_IOCFG for the emu1010 */
 		} else if (emu->card_capabilities->i2c_adc) {
 			;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
@@ -338,7 +340,7 @@
  		}
 	}
 	
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		;  /* Disable all access to A_IOCFG for the emu1010 */
 	} else if (emu->card_capabilities->i2c_adc) {
 		;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
@@ -358,7 +360,7 @@
 	outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
 
 	/* Enable analog/digital outs on audigy */
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		;  /* Disable all access to A_IOCFG for the emu1010 */
 	} else if (emu->card_capabilities->i2c_adc) {
 		;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
@@ -660,6 +662,8 @@
 	int n, i;
 	int reg;
 	int value;
+	unsigned int write_post;
+	unsigned long flags;
 	const struct firmware *fw_entry;
 
 	if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) {
@@ -667,12 +671,6 @@
 		return err;
 	}
 	snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
-#if 0
-	if (fw_entry->size != 0x133a4) {
-		snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
-		return -EINVAL;
-	}
-#endif
 
 	/* The FPGA is a Xilinx Spartan IIE XC2S50E */
 	/* GPIO7 -> FPGA PGMN
@@ -680,9 +678,12 @@
 	 * GPIO5 -> FPGA DIN
 	 * FPGA CONFIG OFF -> FPGA PGMN
 	 */
+	spin_lock_irqsave(&emu->emu_lock, flags);
 	outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */
-	udelay(1);
+	write_post = inl(emu->port + A_IOCFG);
+	udelay(100);
 	outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */
+	write_post = inl(emu->port + A_IOCFG);
 	udelay(100); /* Allow FPGA memory to clean */
 	for(n = 0; n < fw_entry->size; n++) {
 		value=fw_entry->data[n];	
@@ -692,12 +693,15 @@
 				reg = reg | 0x20;
 			value = value >> 1;   
 			outl(reg, emu->port + A_IOCFG);
+			write_post = inl(emu->port + A_IOCFG);
 			outl(reg | 0x40, emu->port + A_IOCFG);
+			write_post = inl(emu->port + A_IOCFG);
 		}
 	}
 	/* After programming, set GPIO bit 4 high again. */
 	outl(0x10, emu->port + A_IOCFG);
-	
+	write_post = inl(emu->port + A_IOCFG);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
 
         release_firmware(fw_entry);
 	return 0;
@@ -711,7 +715,7 @@
 
 	for (;;) {
 		/* Delay to allow Audio Dock to settle */
-		msleep(1000);
+		msleep_interruptible(1000);
 		if (kthread_should_stop())
 			break;
 		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
@@ -721,17 +725,17 @@
 			/* Return to Audio Dock programming mode */
 			snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
 			snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
-			if (emu->card_capabilities->emu1010 == 1) {
+			if (emu->card_capabilities->emu_model == 1) {
 				if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
-					return err;
+					continue;
 				}
-			} else if (emu->card_capabilities->emu1010 == 2) {
+			} else if (emu->card_capabilities->emu_model == 2) {
 				if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
-					return err;
+					continue;
 				}
-			} else if (emu->card_capabilities->emu1010 == 3) {
+			} else if (emu->card_capabilities->emu_model == 3) {
 				if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
-					return err;
+					continue;
 				}
 			}
 
@@ -744,8 +748,7 @@
 			if ((reg & 0x1f) != 0x15) {
 				/* FPGA failed to be programmed */
 				snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
-				return 0;
-				return -ENODEV;
+				continue;
 			}
 			snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
 			snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
@@ -756,9 +759,9 @@
 			msleep(10);
 			/* Unmute all. Default is muted after a firmware load */
 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
-			break;
 		}
 	}
+	snd_printk(KERN_INFO "emu1010: firmware thread stopping\n");
 	return 0;
 }
 
@@ -799,6 +802,7 @@
 	int tmp,tmp2;
 	int reg;
 	int err;
+	const char *filename = NULL;
 
 	snd_printk(KERN_INFO "emu1010: Special config.\n");
 	/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
@@ -840,21 +844,31 @@
 		return -ENODEV;
 	}
 	snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
-	if (emu->card_capabilities->emu1010 == 1) {
-		if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
-			snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
-			return err;
-		}
-	} else if (emu->card_capabilities->emu1010 == 2) {
-		if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) {
-			snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME);
-			return err;
-		}
-	} else if (emu->card_capabilities->emu1010 == 3) {
-		if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) {
-			snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME);
-			return err;
-		}
+	switch (emu->card_capabilities->emu_model) {
+	case 1:
+		filename = HANA_FILENAME;
+		break;
+	case 2:
+		filename = EMU1010B_FILENAME;
+		break;
+	case 3:
+		filename = EMU1010_NOTEBOOK_FILENAME;
+		break;
+	case 4:
+		filename = EMU0404_FILENAME;
+		break;
+	default:
+		filename = NULL;
+		return -ENODEV;
+		break;
+	}
+	snd_printk(KERN_INFO "emu1010: filename %s testing\n", filename);
+	err = snd_emu1010_load_firmware(emu, filename);
+	if (err != 0) {
+		snd_printk(
+			KERN_INFO "emu1010: Loading Firmware file %s failed\n",
+			filename);
+		return err;
 	}
 
 	/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
@@ -1201,11 +1215,12 @@
 		}
 		snd_emu10k1_free_efx(emu);
        	}
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model == 1) {
 		/* Disable 48Volt power to Audio Dock */
 		snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  0 );
-		kthread_stop(emu->emu1010.firmware_thread);
 	}
+	if (emu->card_capabilities->emu_model)
+		kthread_stop(emu->emu1010.firmware_thread);
 	if (emu->memhdr)
 		snd_util_memhdr_free(emu->memhdr);
 	if (emu->silent_page.area)
@@ -1337,6 +1352,15 @@
 	 .spi_dac = 1,
 	 .i2c_adc = 1,
 	 .spk71 = 1} ,
+	/* Tested by James@superbug.co.uk 20-3-2007. */
+	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102,
+	 .driver = "Audigy2", .name = "E-mu 0404 [4002]",
+	 .id = "EMU0404",
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .spk71 = 1,
+	 .emu_model = 4} , /* EMU 0404 */
+	/* Tested by James@superbug.co.uk 4th Nov 2007. */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102,
 	 .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", 
 	 .id = "EMU1010",
@@ -1344,28 +1368,30 @@
 	 .ca0108_chip = 1,
 	 .ca_cardbus_chip = 1,
 	 .spk71 = 1 ,
-	 .emu1010 = 3} ,
+	 .emu_model = 3} ,
+	/* Tested by James@superbug.co.uk 4th Nov 2007. */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
 	 .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", 
 	 .id = "EMU1010",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
-	 .spk71 = 1 ,
-	 .emu1010 = 2} ,
+	 .spk71 = 1,
+	 .emu_model = 2} ,
+	/* Tested by James@superbug.co.uk 8th July 2005. */
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
+	 .driver = "Audigy2", .name = "E-mu 1010 [4001]",
+	 .id = "EMU1010",
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .spk71 = 1,
+	 .emu_model = 1} , /* Emu 1010 */
+	/* Audigy4 (Not PRO) SB0610 */
 	{.vendor = 0x1102, .device = 0x0008, 
 	 .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
 	 .ac97_chip = 1} ,
-	/* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */
-	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
-	 .driver = "Audigy2", .name = "E-mu 1010 [4001]", 
-	 .id = "EMU1010",
-	 .emu10k2_chip = 1,
-	 .ca0102_chip = 1,
-	 .spk71 = 1,
-	 .emu1010 = 1} ,
 	/* Tested by James@superbug.co.uk 3rd July 2005 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
 	 .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", 
@@ -1793,7 +1819,7 @@
 	if (emu->card_capabilities->ecard) {
 		if ((err = snd_emu10k1_ecard_init(emu)) < 0)
 			goto error;
- 	} else if (emu->card_capabilities->emu1010) {
+	} else if (emu->card_capabilities->emu_model) {
  		if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
  			snd_emu10k1_free(emu);
  			return err;
@@ -1942,7 +1968,7 @@
 		snd_emu10k1_cardbus_init(emu);
 	if (emu->card_capabilities->ecard)
 		snd_emu10k1_ecard_init(emu);
-	else if (emu->card_capabilities->emu1010)
+	else if (emu->card_capabilities->emu_model)
  		snd_emu10k1_emu1010_init(emu);
 	else
 		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 354a892..71dc4c8 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1261,7 +1261,7 @@
 A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
 	/* emu1212 DSP 0 and DSP 1 Capture */
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		if (emu->card_capabilities->ca0108_chip) {
 			/* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
 			A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
@@ -1515,7 +1515,7 @@
 
 	/* digital outputs */
 	/* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		/* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
 		snd_printk("EMU outputs on\n");
 		for (z = 0; z < 8; z++) {
@@ -1563,7 +1563,7 @@
 	A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
 #endif
 
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		if (emu->card_capabilities->ca0108_chip) {
 			snd_printk("EMU2 inputs on\n");
 			for (z = 0; z < 0x10; z++) {
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 5a38fe7..83acfa6 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -1792,7 +1792,7 @@
 			return err;
 	}
 
-	if ( emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		;  /* Disable the snd_audigy_spdif_shared_spdif */
 	} else if (emu->audigy) {
 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
@@ -1817,7 +1817,7 @@
 			return err;
 	}
 
-	if ( emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		int i;
 
 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index cf4e3ec..cf9276d 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -357,7 +357,7 @@
 	snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
 	snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
 	snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
-	if (emu->card_capabilities->emu1010)
+	if (emu->card_capabilities->emu_model)
 		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
 	else 
 		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
@@ -700,7 +700,7 @@
 	voice = evoice->number;
 
 	pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
-	if (emu->card_capabilities->emu1010)
+	if (emu->card_capabilities->emu_model)
 		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
 	else 
 		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
@@ -1231,7 +1231,7 @@
 	runtime->hw.rates = SNDRV_PCM_RATE_48000;
 	runtime->hw.rate_min = runtime->hw.rate_max = 48000;
 	spin_lock_irq(&emu->reg_lock);
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		/*  Nb. of channels has been increased to 16 */
 		/* TODO
 		 * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
@@ -1790,7 +1790,7 @@
 	/* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
 	if (emu->audigy) {
 		emu->efx_voices_mask[0] = 0;
-		if (emu->card_capabilities->emu1010)
+		if (emu->card_capabilities->emu_model)
 			/* Pavel Hofman - 32 voices will be used for
 			 * capture (write mode) -
 			 * each bit = corresponding voice
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index bd8a471..f3caa3f 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -244,7 +244,7 @@
 	unsigned long flags;
 	u32 rate;
 
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		spin_lock_irqsave(&emu->emu_lock, flags);
 		snd_emu1010_fpga_read(emu, 0x38, &value);
 		spin_unlock_irqrestore(&emu->emu_lock, flags);
@@ -584,7 +584,7 @@
 {
 	struct snd_info_entry *entry;
 #ifdef CONFIG_SND_DEBUG
-	if (emu->card_capabilities->emu1010) {
+	if (emu->card_capabilities->emu_model) {
 		if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) 
 			snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read);
 	}
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 2862e17..a026383 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -227,11 +227,14 @@
 
 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
 {
+	unsigned long flags;
+
 	if (reg > 0x3f)
 		return 1;
 	reg += 0x40; /* 0x40 upwards are registers. */
 	if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
 		return 1;
+	spin_lock_irqsave(&emu->emu_lock, flags);
 	outl(reg, emu->port + A_IOCFG);
 	udelay(10);
 	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
@@ -239,20 +242,24 @@
 	outl(value, emu->port + A_IOCFG);
 	udelay(10);
 	outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
 
 	return 0;
 }
 
 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
 {
+	unsigned long flags;
 	if (reg > 0x3f)
 		return 1;
 	reg += 0x40; /* 0x40 upwards are registers. */
+	spin_lock_irqsave(&emu->emu_lock, flags);
 	outl(reg, emu->port + A_IOCFG);
 	udelay(10);
 	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
 	udelay(10);
 	*value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
 
 	return 0;
 }