Commit 58b298b1 authored by Jaroslav Kysela's avatar Jaroslav Kysela

[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: default avatarTakashi Iwai <tiwai@suse.de>
parent 6cf4f6b3
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <sound/core.h> #include <sound/core.h>
...@@ -399,6 +400,13 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," ...@@ -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_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES)
#define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) #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 hdsp_t;
typedef struct _hdsp_midi hdsp_midi_t; typedef struct _hdsp_midi hdsp_midi_t;
typedef struct _hdsp_9632_meters hdsp_9632_meters_t; typedef struct _hdsp_9632_meters hdsp_9632_meters_t;
...@@ -585,8 +593,8 @@ static struct pci_device_id snd_hdsp_ids[] = { ...@@ -585,8 +593,8 @@ static struct pci_device_id snd_hdsp_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_hdsp_ids); MODULE_DEVICE_TABLE(pci, snd_hdsp_ids);
/* prototypes */ /* prototypes */
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);
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);
static int snd_hdsp_enable_io (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_midi_flush (hdsp_t *hdsp);
static void snd_hdsp_initialize_channels (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 ...@@ -4653,6 +4661,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int
} }
break; break;
} }
#ifndef HDSP_FW_LOADER
case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: { case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: {
hdsp_firmware_t __user *firmware; hdsp_firmware_t __user *firmware;
u32 __user *firmware_data; u32 __user *firmware_data;
...@@ -4662,6 +4671,9 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int ...@@ -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 */ /* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */
if (hdsp->io_type == Undefined) return -EINVAL; if (hdsp->io_type == Undefined) return -EINVAL;
if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
return -EBUSY;
snd_printk("initializing firmware upload\n"); snd_printk("initializing firmware upload\n");
firmware = (hdsp_firmware_t __user *)argp; 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 ...@@ -4695,6 +4707,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int
} }
break; break;
} }
#endif
case SNDRV_HDSP_IOCTL_GET_MIXER: { case SNDRV_HDSP_IOCTL_GET_MIXER: {
hdsp_mixer_t __user *mixer = (hdsp_mixer_t __user *)argp; 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)) 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, ...@@ -4750,8 +4763,7 @@ static int __devinit snd_hdsp_create_hwdep(snd_card_t *card,
return 0; return 0;
} }
static int __devinit snd_hdsp_create_pcm(snd_card_t *card, static int snd_hdsp_create_pcm(snd_card_t *card, hdsp_t *hdsp)
hdsp_t *hdsp)
{ {
snd_pcm_t *pcm; snd_pcm_t *pcm;
int err; int err;
...@@ -4842,7 +4854,7 @@ static void snd_hdsp_initialize_midi_flush (hdsp_t *hdsp) ...@@ -4842,7 +4854,7 @@ static void snd_hdsp_initialize_midi_flush (hdsp_t *hdsp)
snd_hdsp_flush_midi_input (hdsp, 1); 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; int err;
...@@ -4895,6 +4907,86 @@ static int __devinit snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp ...@@ -4895,6 +4907,86 @@ static int __devinit snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp
return 0; 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, static int __devinit snd_hdsp_create(snd_card_t *card,
hdsp_t *hdsp, hdsp_t *hdsp,
int precise_ptr) int precise_ptr)
...@@ -5003,11 +5095,16 @@ static int __devinit snd_hdsp_create(snd_card_t *card, ...@@ -5003,11 +5095,16 @@ static int __devinit snd_hdsp_create(snd_card_t *card,
} }
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { 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"); snd_printk("card initialization pending : waiting for firmware\n");
if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) { if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
return err; return err;
} }
return 0; return 0;
#endif
} }
snd_printk("Firmware already loaded, initializing card.\n"); snd_printk("Firmware already loaded, initializing card.\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment