aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@suse.cz>2005-01-03 16:08:33 +0100
committerJaroslav Kysela <perex@suse.cz>2005-01-03 16:08:33 +0100
commit58b298b1479b8a5616a03a42d2c279d66c8e669c (patch)
tree2efb3465bd6d3f607294874a8dc42a262ecba243 /sound
parent6cf4f6b38423a97c7cfad20cd4b5292f704861db (diff)
downloadhistory-58b298b1479b8a5616a03a42d2c279d66c8e669c.tar.gz
[ALSA] Add hotplug firmware loader support
RME HDSP driver Added the hotplug firmware loader support without hdsploader. The firmware data must be installed beforehand in the proper place from the latest alsa-firmware package. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/rme9652/hdsp.c107
1 files changed, 102 insertions, 5 deletions
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 50cf7f7896f1e4..af15edd4274526 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/firmware.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
@@ -399,6 +400,13 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
#define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES)
#define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024)
+/* use hotplug firmeare loader? */
+#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
+#ifndef HDSP_USE_HWDEP_LOADER
+#define HDSP_FW_LOADER
+#endif
+#endif
+
typedef struct _hdsp hdsp_t;
typedef struct _hdsp_midi hdsp_midi_t;
typedef struct _hdsp_9632_meters hdsp_9632_meters_t;
@@ -585,8 +593,8 @@ static struct pci_device_id snd_hdsp_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_hdsp_ids);
/* prototypes */
-static int __devinit snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp);
-static int __devinit snd_hdsp_create_pcm(snd_card_t *card, hdsp_t *hdsp);
+static int snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp);
+static int snd_hdsp_create_pcm(snd_card_t *card, hdsp_t *hdsp);
static int snd_hdsp_enable_io (hdsp_t *hdsp);
static void snd_hdsp_initialize_midi_flush (hdsp_t *hdsp);
static void snd_hdsp_initialize_channels (hdsp_t *hdsp);
@@ -4653,6 +4661,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int
}
break;
}
+#ifndef HDSP_FW_LOADER
case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: {
hdsp_firmware_t __user *firmware;
u32 __user *firmware_data;
@@ -4662,6 +4671,9 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int
/* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */
if (hdsp->io_type == Undefined) return -EINVAL;
+ if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
+ return -EBUSY;
+
snd_printk("initializing firmware upload\n");
firmware = (hdsp_firmware_t __user *)argp;
@@ -4695,6 +4707,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int
}
break;
}
+#endif
case SNDRV_HDSP_IOCTL_GET_MIXER: {
hdsp_mixer_t __user *mixer = (hdsp_mixer_t __user *)argp;
if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE))
@@ -4750,8 +4763,7 @@ static int __devinit snd_hdsp_create_hwdep(snd_card_t *card,
return 0;
}
-static int __devinit snd_hdsp_create_pcm(snd_card_t *card,
- hdsp_t *hdsp)
+static int snd_hdsp_create_pcm(snd_card_t *card, hdsp_t *hdsp)
{
snd_pcm_t *pcm;
int err;
@@ -4842,7 +4854,7 @@ static void snd_hdsp_initialize_midi_flush (hdsp_t *hdsp)
snd_hdsp_flush_midi_input (hdsp, 1);
}
-static int __devinit snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp)
+static int snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp)
{
int err;
@@ -4895,6 +4907,86 @@ static int __devinit snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp
return 0;
}
+#ifdef HDSP_FW_LOADER
+/* load firmware via hotplug fw loader */
+static int __devinit hdsp_request_fw_loader(hdsp_t *hdsp)
+{
+ const char *fwfile;
+ const struct firmware *fw;
+ int err;
+
+ if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
+ return 0;
+ if (hdsp->io_type == Undefined) {
+ if ((err = hdsp_get_iobox_version(hdsp)) < 0)
+ return err;
+ if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
+ return 0;
+ }
+ if (hdsp_check_for_iobox (hdsp))
+ return -EIO;
+
+ /* caution: max length of firmware filename is 30! */
+ switch (hdsp->io_type) {
+ case Multiface:
+ if (hdsp->firmware_rev == 0xa)
+ fwfile = "multiface_firmware.bin";
+ else
+ fwfile = "multiface_firmware_rev11.bin";
+ break;
+ case Digiface:
+ if (hdsp->firmware_rev == 0xa)
+ fwfile = "digiface_firmware.bin";
+ else
+ fwfile = "digiface_firmware_rev11.bin";
+ break;
+ default:
+ snd_printk(KERN_ERR "hdsp: invalid io_type %d\n", hdsp->io_type);
+ return -EINVAL;
+ }
+
+ if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) {
+ snd_printk(KERN_ERR "hdsp: cannot load firmware %s\n", fwfile);
+ return -ENOENT;
+ }
+ if (fw->size < sizeof(hdsp->firmware_cache)) {
+ snd_printk(KERN_ERR "hdsp: too short firmware size %d (expected %d)\n",
+ (int)fw->size, (int)sizeof(hdsp->firmware_cache));
+ release_firmware(fw);
+ return -EINVAL;
+ }
+#ifdef SNDRV_BIG_ENDIAN
+ {
+ int i;
+ u32 *src = hdsp->data;
+ for (i = 0; i < ARRAY_SIZE(hdsp->firmware_cache); i++, src++)
+ hdsp->firmware_cache[i] = ((*src & 0x000000ff) << 16) |
+ ((*src & 0x0000ff00) << 8) |
+ ((*src & 0x00ff0000) >> 8) |
+ ((*src & 0xff000000) >> 16);
+ }
+#else
+ memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache));
+#endif
+ release_firmware(fw);
+
+ hdsp->state |= HDSP_FirmwareCached;
+
+ if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
+ return err;
+
+ if (!(hdsp->state & HDSP_InitializationComplete)) {
+ snd_hdsp_initialize_channels(hdsp);
+ snd_hdsp_initialize_midi_flush(hdsp);
+ if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
+ snd_printk("error creating alsa devices\n");
+ return err;
+ }
+ }
+ return 0;
+}
+#endif
+
static int __devinit snd_hdsp_create(snd_card_t *card,
hdsp_t *hdsp,
int precise_ptr)
@@ -5003,11 +5095,16 @@ static int __devinit snd_hdsp_create(snd_card_t *card,
}
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
+#ifdef HDSP_FW_LOADER
+ if ((err = hdsp_request_fw_loader(hdsp)) < 0)
+ return err;
+#else
snd_printk("card initialization pending : waiting for firmware\n");
if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
return err;
}
return 0;
+#endif
}
snd_printk("Firmware already loaded, initializing card.\n");