[ALSA] snd-emu10k1:Improves firmware loading for E-Mu cards.

Details:
Fixes http://bugzilla.kernel.org/show_bug.cgi?id=8176

Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 868f3bd..d6c8c54 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1456,6 +1456,7 @@
 	unsigned int adc_pads; /* bit mask */
 	unsigned int dac_pads; /* bit mask */
 	unsigned int internal_clock; /* 44100 or 48000 */
+	struct task_struct *firmware_thread;
 };
 
 struct snd_emu10k1 {
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 404ae1b..800d634 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <linux/sched.h>
+#include <linux/kthread.h>
 #include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -702,6 +704,59 @@
 	return 0;
 }
 
+int emu1010_firmware_thread(void *data) {
+	struct snd_emu10k1 * emu = data;
+	int tmp,tmp2;
+	int reg;
+	int err;
+
+	for (;;) {
+		/* Delay to allow Audio Dock to settle */
+		msleep(1000);
+		if (kthread_should_stop())
+			break;
+		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
+		snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg ); /* OPTIONS: Which cards are attached to the EMU */
+		if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
+			/* Audio Dock attached */
+			/* 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 ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
+					return err;
+				}
+			} else if (emu->card_capabilities->emu1010 == 2) {
+				if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+					return err;
+				}
+			} else if (emu->card_capabilities->emu1010 == 3) {
+				if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+					return err;
+				}
+			}
+
+			snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0 );
+			snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
+			snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
+			/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+			snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+			snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
+			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;
+			}
+			snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
+			snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
+			snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 );
+			snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2);
+		}
+	}
+	return 0;
+}
+
 /*
  * EMU-1010 - details found out from this driver, official MS Win drivers,
  * testing the card:
@@ -1004,49 +1059,12 @@
 	snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); 
 	snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif  (or 0x11 for aes/ebu) */
 
-	/* Delay to allow Audio Dock to settle */
-	msleep(100);
-	snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
-	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg ); /* OPTIONS: Which cards are attached to the EMU */
-	/* FIXME: The loading of this should be able to happen any time,
-	 * as the user can plug/unplug it at any time
-	 */
-	if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) {
-		/* Audio Dock attached */
-		/* 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 ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
-				return err;
-			}
-		} else if (emu->card_capabilities->emu1010 == 2) {
-			if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
-				return err;
-			}
-		} else if (emu->card_capabilities->emu1010 == 3) {
-			if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
-				return err;
-			}
-		}
+	/* Start Micro/Audio Dock firmware loader thread */
+	emu->emu1010.firmware_thread = kthread_create(&emu1010_firmware_thread,
+                                   emu,
+                                   "emu1010_firmware");
+	wake_up_process(emu->emu1010.firmware_thread);
 
-		snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0 );
-		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
-		snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
-		/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
-		snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
-		snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
-		if ((reg & 0x3f) != 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;
-		}
-		snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
-		snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
-		snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 );
-		snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2);
-	}
 #if 0
 	snd_emu1010_fpga_link_dst_src_write(emu,
 		EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */
@@ -1173,6 +1191,7 @@
 	if (emu->card_capabilities->emu1010) {
 		/* Disable 48Volt power to Audio Dock */
 		snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  0 );
+		kthread_stop(emu->emu1010.firmware_thread);
 	}
 	if (emu->memhdr)
 		snd_util_memhdr_free(emu->memhdr);