ALSA: sscape: convert to firmware loader framework

The conversion solves the problem that firmware size was set to 64KB
while non PnP cards have 128KB firmware files.

An additional firmware initialization code has been moved from the OSS
driver.

Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index b11c35f..1ce465c 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1,5 +1,5 @@
 /*
- *   Low-level ALSA driver for the ENSONIQ SoundScape PnP
+ *   Low-level ALSA driver for the ENSONIQ SoundScape
  *   Copyright (c) by Chris Rankin
  *
  *   This driver was written in part using information obtained from
@@ -25,22 +25,26 @@
 #include <linux/err.h>
 #include <linux/isa.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 #include <linux/pnp.h>
 #include <linux/spinlock.h>
 #include <linux/moduleparam.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#include <sound/hwdep.h>
 #include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/initval.h>
 
-#include <sound/sscape_ioctl.h>
-
 
 MODULE_AUTHOR("Chris Rankin");
-MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver");
+MODULE_DESCRIPTION("ENSONIQ SoundScape driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("sndscape.co0");
+MODULE_FIRMWARE("sndscape.co1");
+MODULE_FIRMWARE("sndscape.co2");
+MODULE_FIRMWARE("sndscape.co3");
+MODULE_FIRMWARE("sndscape.co4");
+MODULE_FIRMWARE("scope.cod");
 
 static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX;
 static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR;
@@ -142,14 +146,12 @@
 	struct resource *wss_res;
 	struct snd_wss *chip;
 	struct snd_mpu401 *mpu;
-	struct snd_hwdep *hw;
 
 	/*
 	 * The MIDI device won't work until we've loaded
 	 * its firmware via a hardware-dependent device IOCTL
 	 */
 	spinlock_t fwlock;
-	int hw_in_use;
 	unsigned long midi_usage;
 	unsigned char midi_vol;
 };
@@ -167,12 +169,6 @@
 	return (struct soundscape *) (mpu->private_data);
 }
 
-static inline struct soundscape *get_hwdep_soundscape(struct snd_hwdep * hw)
-{
-	return (struct soundscape *) (hw->private_data);
-}
-
-
 /*
  * Allocates some kernel memory that we can use for DMA.
  * I think this means that the memory has to map to
@@ -393,12 +389,12 @@
 
 	do {
 		unsigned long flags;
-		unsigned char x;
+		int x;
 
 		spin_lock_irqsave(&s->lock, flags);
-		x = inb(HOST_DATA_IO(s->io_base));
+		x = host_read_unsafe(s->io_base);
 		spin_unlock_irqrestore(&s->lock, flags);
-		if ((x & 0xfe) == 0xfe)
+		if (x == 0xfe || x == 0xff)
 			return 1;
 
 		msleep(10);
@@ -420,10 +416,10 @@
 
 	do {
 		unsigned long flags;
-		unsigned char x;
+		int x;
 
 		spin_lock_irqsave(&s->lock, flags);
-		x = inb(HOST_DATA_IO(s->io_base));
+		x = host_read_unsafe(s->io_base);
 		spin_unlock_irqrestore(&s->lock, flags);
 		if (x == 0xfe)
 			return 1;
@@ -438,14 +434,14 @@
  * Upload a byte-stream into the SoundScape using DMA channel A.
  */
 static int upload_dma_data(struct soundscape *s,
-                           const unsigned char __user *data,
+			   const unsigned char *data,
                            size_t size)
 {
 	unsigned long flags;
 	struct snd_dma_buffer dma;
 	int ret;
 
-	if (!get_dmabuf(&dma, PAGE_ALIGN(size)))
+	if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024)))
 		return -ENOMEM;
 
 	spin_lock_irqsave(&s->lock, flags);
@@ -458,7 +454,6 @@
 	/*
 	 * Enable the DMA channels and configure them ...
 	 */
-	sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50);
 	sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT);
 	sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);
 
@@ -468,35 +463,17 @@
 	sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80);
 
 	/*
-	 * Upload the user's data (firmware?) to the SoundScape
+	 * Upload the firmware to the SoundScape
 	 * board through the DMA channel ...
 	 */
 	while (size != 0) {
 		unsigned long len;
 
-		/*
-		 * Apparently, copying to/from userspace can sleep.
-		 * We are therefore forbidden from holding any
-		 * spinlocks while we copy ...
-		 */
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		/*
-		 * Remember that the data that we want to DMA
-		 * comes from USERSPACE. We have already verified
-		 * the userspace pointer ...
-		 */
 		len = min(size, dma.bytes);
-		len -= __copy_from_user(dma.area, data, len);
+		memcpy(dma.area, data, len);
 		data += len;
 		size -= len;
 
-		/*
-		 * Grab that spinlock again, now that we've
-		 * finished copying!
-		 */
-		spin_lock_irqsave(&s->lock, flags);
-
 		snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
 		sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
 		if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
@@ -512,6 +489,7 @@
 	} /* while */
 
 	set_host_mode_unsafe(s->io_base);
+	outb(0x0, s->io_base);
 
 	/*
 	 * Boot the board ... (I think)
@@ -537,7 +515,7 @@
 	/*
 	 * NOTE!!! We are NOT holding any spinlocks at this point !!!
 	 */
-	sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40));
+	sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70));
 	free_dmabuf(&dma);
 
 	return ret;
@@ -547,163 +525,70 @@
  * Upload the bootblock(?) into the SoundScape. The only
  * purpose of this block of code seems to be to tell
  * us which version of the microcode we should be using.
- *
- * NOTE: The boot-block data resides in USER-SPACE!!!
- *       However, we have already verified its memory
- *       addresses by the time we get here.
  */
-static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb)
+static int sscape_upload_bootblock(struct snd_card *card)
 {
+	struct soundscape *sscape = get_card_soundscape(card);
 	unsigned long flags;
+	const struct firmware *init_fw = NULL;
 	int data = 0;
 	int ret;
 
-	ret = upload_dma_data(sscape, bb->code, sizeof(bb->code));
+	ret = request_firmware(&init_fw, "scope.cod", card->dev);
+	if (ret < 0) {
+		snd_printk(KERN_ERR "Error loading scope.cod");
+		return ret;
+	}
+	ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
+
+	release_firmware(init_fw);
 
 	spin_lock_irqsave(&sscape->lock, flags);
-	if (ret == 0) {
+	if (ret == 0)
 		data = host_read_ctrl_unsafe(sscape->io_base, 100);
-	}
-	set_midi_mode_unsafe(sscape->io_base);
+
+	if (data & 0x10)
+		sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f);
+
 	spin_unlock_irqrestore(&sscape->lock, flags);
 
-	if (ret == 0) {
-		if (data < 0) {
-			snd_printk(KERN_ERR "sscape: timeout reading firmware version\n");
-			ret = -EAGAIN;
-		}
-		else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) {
-			ret = -EFAULT;
-		}
+	data &= 0xf;
+	if (ret == 0 && data > 7) {
+		snd_printk(KERN_ERR "timeout reading firmware version\n");
+		ret = -EAGAIN;
 	}
 
-	return ret;
+	return (ret == 0) ? data : ret;
 }
 
 /*
- * Upload the microcode into the SoundScape. The
- * microcode is 64K of data, and if we try to copy
- * it into a local variable then we will SMASH THE
- * KERNEL'S STACK! We therefore leave it in USER
- * SPACE, and save ourselves from copying it at all.
+ * Upload the microcode into the SoundScape.
  */
-static int sscape_upload_microcode(struct soundscape *sscape,
-                                   const struct sscape_microcode __user *mc)
+static int sscape_upload_microcode(struct snd_card *card, int version)
 {
-	unsigned long flags;
-	char __user *code;
+	struct soundscape *sscape = get_card_soundscape(card);
+	const struct firmware *init_fw = NULL;
+	char name[14];
 	int err;
 
-	/*
-	 * We are going to have to copy this data into a special
-	 * DMA-able buffer before we can upload it. We shall therefore
-	 * just check that the data pointer is valid for now.
-	 *
-	 * NOTE: This buffer is 64K long! That's WAY too big to
-	 *       copy into a stack-temporary anyway.
-	 */
-	if ( get_user(code, &mc->code) ||
-	     !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) )
-		return -EFAULT;
+	snprintf(name, sizeof(name), "sndscape.co%d", version);
 
-	if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) {
-		snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n");
+	err = request_firmware(&init_fw, name, card->dev);
+	if (err < 0) {
+		snd_printk(KERN_ERR "Error loading sndscape.co%d", version);
+		return err;
 	}
+	err = upload_dma_data(sscape, init_fw->data, init_fw->size);
+	if (err == 0)
+		snd_printk(KERN_INFO "MIDI firmware loaded %d KBs\n",
+				init_fw->size >> 10);
 
-	spin_lock_irqsave(&sscape->lock, flags);
-	set_midi_mode_unsafe(sscape->io_base);
-	spin_unlock_irqrestore(&sscape->lock, flags);
-
-	initialise_mpu401(sscape->mpu);
+	release_firmware(init_fw);
 
 	return err;
 }
 
 /*
- * Hardware-specific device functions, to implement special
- * IOCTLs for the SoundScape card. This is how we upload
- * the microcode into the card, for example, and so we
- * must ensure that no two processes can open this device
- * simultaneously, and that we can't open it at all if
- * someone is using the MIDI device.
- */
-static int sscape_hw_open(struct snd_hwdep * hw, struct file *file)
-{
-	register struct soundscape *sscape = get_hwdep_soundscape(hw);
-	unsigned long flags;
-	int err;
-
-	spin_lock_irqsave(&sscape->fwlock, flags);
-
-	if ((sscape->midi_usage != 0) || sscape->hw_in_use) {
-		err = -EBUSY;
-	} else {
-		sscape->hw_in_use = 1;
-		err = 0;
-	}
-
-	spin_unlock_irqrestore(&sscape->fwlock, flags);
-	return err;
-}
-
-static int sscape_hw_release(struct snd_hwdep * hw, struct file *file)
-{
-	register struct soundscape *sscape = get_hwdep_soundscape(hw);
-	unsigned long flags;
-
-	spin_lock_irqsave(&sscape->fwlock, flags);
-	sscape->hw_in_use = 0;
-	spin_unlock_irqrestore(&sscape->fwlock, flags);
-	return 0;
-}
-
-static int sscape_hw_ioctl(struct snd_hwdep * hw, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-	struct soundscape *sscape = get_hwdep_soundscape(hw);
-	int err = -EBUSY;
-
-	switch (cmd) {
-	case SND_SSCAPE_LOAD_BOOTB:
-		{
-			register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg;
-
-			/*
-			 * We are going to have to copy this data into a special
-			 * DMA-able buffer before we can upload it. We shall therefore
-			 * just check that the data pointer is valid for now ...
-			 */
-			if ( !access_ok(VERIFY_READ, bb->code, sizeof(bb->code)) )
-				return -EFAULT;
-
-			/*
-			 * Now check that we can write the firmware version number too...
-			 */
-			if ( !access_ok(VERIFY_WRITE, &bb->version, sizeof(bb->version)) )
-				return -EFAULT;
-
-			err = sscape_upload_bootblock(sscape, bb);
-		}
-		break;
-
-	case SND_SSCAPE_LOAD_MCODE:
-		{
-			register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg;
-
-			err = sscape_upload_microcode(sscape, mc);
-		}
-		break;
-
-	default:
-		err = -EINVAL;
-		break;
-	} /* switch */
-
-	return err;
-}
-
-
-/*
  * Mixer control for the SoundScape's MIDI device.
  */
 static int sscape_midi_info(struct snd_kcontrol *ctl,
@@ -920,7 +805,7 @@
 
 		spin_lock_irqsave(&sscape->fwlock, flags);
 
-		if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) {
+		if (sscape->midi_usage == ULONG_MAX) {
 			err = -EBUSY;
 		} else {
 			++(sscape->midi_usage);
@@ -1053,13 +938,6 @@
 			}
 		}
 
-		strcpy(card->driver, "SoundScape");
-		strcpy(card->shortname, pcm->name);
-		snprintf(card->longname, sizeof(card->longname),
-			 "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
-			 pcm->name, chip->port, chip->irq,
-			 chip->dma1, chip->dma2);
-
 		sscape->chip = chip;
 	}
 
@@ -1162,29 +1040,6 @@
 		return -ENXIO;
 	}
 
-	if (sscape->type != SSCAPE_VIVO) {
-		/*
-		 * Now create the hardware-specific device so that we can
-		 * load the microcode into the on-board processor.
-		 * We cannot use the MPU-401 MIDI system until this firmware
-		 * has been loaded into the card.
-		 */
-		err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw));
-		if (err < 0) {
-			printk(KERN_ERR "sscape: Failed to create "
-					"firmware device\n");
-			goto _release_dma;
-		}
-		strlcpy(sscape->hw->name, "SoundScape M68K",
-			sizeof(sscape->hw->name));
-		sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';
-		sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;
-		sscape->hw->ops.open = sscape_hw_open;
-		sscape->hw->ops.release = sscape_hw_release;
-		sscape->hw->ops.ioctl = sscape_hw_ioctl;
-		sscape->hw->private_data = sscape;
-	}
-
 	/*
 	 * Tell the on-board devices where their resources are (I think -
 	 * I can't be sure without a datasheet ... So many magic values!)
@@ -1222,28 +1077,56 @@
 		       wss_port[dev], irq[dev]);
 		goto _release_dma;
 	}
+	strcpy(card->driver, "SoundScape");
+	strcpy(card->shortname, name);
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
+		 name, sscape->chip->port, sscape->chip->irq,
+		 sscape->chip->dma1, sscape->chip->dma2);
+
 #define MIDI_DEVNUM  0
 	if (sscape->type != SSCAPE_VIVO) {
-		err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]);
-		if (err < 0) {
-			printk(KERN_ERR "sscape: Failed to create "
-					"MPU-401 device at 0x%lx\n",
-					port[dev]);
-			goto _release_dma;
+		err = sscape_upload_bootblock(card);
+		if (err >= 0)
+			err = sscape_upload_microcode(card, err);
+
+		if (err == 0) {
+			err = create_mpu401(card, MIDI_DEVNUM, port[dev],
+					    mpu_irq[dev]);
+			if (err < 0) {
+				printk(KERN_ERR "sscape: Failed to create "
+						"MPU-401 device at 0x%lx\n",
+						port[dev]);
+				goto _release_dma;
+			}
+
+			/*
+			 * Enable the master IRQ ...
+			 */
+			sscape_write(sscape, GA_INTENA_REG, 0x80);
+
+			/*
+			 * Initialize mixer
+			 */
+			spin_lock_irqsave(&sscape->lock, flags);
+			sscape->midi_vol = 0;
+			host_write_ctrl_unsafe(sscape->io_base,
+						CMD_SET_MIDI_VOL, 100);
+			host_write_ctrl_unsafe(sscape->io_base,
+						sscape->midi_vol, 100);
+			host_write_ctrl_unsafe(sscape->io_base,
+						CMD_XXX_MIDI_VOL, 100);
+			host_write_ctrl_unsafe(sscape->io_base,
+						sscape->midi_vol, 100);
+			host_write_ctrl_unsafe(sscape->io_base,
+						CMD_SET_EXTMIDI, 100);
+			host_write_ctrl_unsafe(sscape->io_base,
+						0, 100);
+			host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
+
+			set_midi_mode_unsafe(sscape->io_base);
+			spin_unlock_irqrestore(&sscape->lock, flags);
 		}
-
-		/*
-		 * Enable the master IRQ ...
-		 */
-		sscape_write(sscape, GA_INTENA_REG, 0x80);
-
-		/*
-		 * Initialize mixer
-		 */
-		sscape->midi_vol = 0;
-		host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);
-		host_write_ctrl_unsafe(sscape->io_base, 0, 100);
-		host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);
 	}
 
 	/*
@@ -1301,11 +1184,12 @@
 	sscape->type = SSCAPE;
 
 	dma[dev] &= 0x03;
+	snd_card_set_dev(card, pdev);
+
 	ret = create_sscape(dev, card);
 	if (ret < 0)
 		goto _release_card;
 
-	snd_card_set_dev(card, pdev);
 	if ((ret = snd_card_register(card)) < 0) {
 		printk(KERN_ERR "sscape: Failed to register sound card\n");
 		goto _release_card;
@@ -1426,12 +1310,12 @@
 		wss_port[idx] = pnp_port_start(dev, 1);
 		dma2[idx] = pnp_dma(dev, 1);
 	}
+	snd_card_set_dev(card, &pcard->card->dev);
 
 	ret = create_sscape(idx, card);
 	if (ret < 0)
 		goto _release_card;
 
-	snd_card_set_dev(card, &pcard->card->dev);
 	if ((ret = snd_card_register(card)) < 0) {
 		printk(KERN_ERR "sscape: Failed to register sound card\n");
 		goto _release_card;