Commit 14b87c6e authored by Jaroslav Kysela's avatar Jaroslav Kysela

[ALSA] Hotplug firmware loader support

Digigram VX core,MIXART driver,Digigram VX222 driver
Digigram VX Pocket driver
The hogplut fw loader is supported by vxpocket, vxp440, vx2222 and mixart
drivers.  The old ALSA fw loader is still supported for built-in kernels.
To use the hotplug, the new firmware data must be installed beforehand
from the latest alsa-tools package.

The experimental suspend/resume for vxpocket, vxp440 and vx222 are added,
too.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent d137aed3
...@@ -27,6 +27,15 @@ ...@@ -27,6 +27,15 @@
#include <sound/hwdep.h> #include <sound/hwdep.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
#if !defined(CONFIG_USE_VXLOADER) && !defined(CONFIG_SND_VX_LIB) /* built-in kernel */
#define SND_VX_FW_LOADER /* use the standard firmware loader */
#endif
#endif
struct firmware;
struct device;
typedef struct snd_vx_core vx_core_t; typedef struct snd_vx_core vx_core_t;
typedef struct vx_pipe vx_pipe_t; typedef struct vx_pipe vx_pipe_t;
...@@ -100,7 +109,7 @@ struct snd_vx_ops { ...@@ -100,7 +109,7 @@ struct snd_vx_ops {
void (*change_audio_source)(vx_core_t *chip, int src); void (*change_audio_source)(vx_core_t *chip, int src);
void (*set_clock_source)(vx_core_t *chp, int src); void (*set_clock_source)(vx_core_t *chp, int src);
/* chip init */ /* chip init */
int (*load_dsp)(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp); int (*load_dsp)(vx_core_t *chip, int idx, const struct firmware *fw);
void (*reset_dsp)(vx_core_t *chip); void (*reset_dsp)(vx_core_t *chip);
void (*reset_board)(vx_core_t *chip, int cold_reset); void (*reset_board)(vx_core_t *chip, int cold_reset);
int (*add_controls)(vx_core_t *chip); int (*add_controls)(vx_core_t *chip);
...@@ -169,6 +178,7 @@ struct snd_vx_core { ...@@ -169,6 +178,7 @@ struct snd_vx_core {
unsigned int chip_status; unsigned int chip_status;
unsigned int pcm_running; unsigned int pcm_running;
struct device *dev;
snd_hwdep_t *hwdep; snd_hwdep_t *hwdep;
struct vx_rmh irq_rmh; /* RMH used in interrupts */ struct vx_rmh irq_rmh; /* RMH used in interrupts */
...@@ -198,6 +208,8 @@ struct snd_vx_core { ...@@ -198,6 +208,8 @@ struct snd_vx_core {
unsigned char audio_monitor_active[4]; /* playback hw-monitor mute/unmute */ unsigned char audio_monitor_active[4]; /* playback hw-monitor mute/unmute */
struct semaphore mixer_mutex; struct semaphore mixer_mutex;
const struct firmware *firmware[4]; /* loaded firmware data */
}; };
...@@ -206,25 +218,18 @@ struct snd_vx_core { ...@@ -206,25 +218,18 @@ struct snd_vx_core {
*/ */
vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw, vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw,
struct snd_vx_ops *ops, int extra_size); struct snd_vx_ops *ops, int extra_size);
int snd_vx_hwdep_new(vx_core_t *chip); int snd_vx_setup_firmware(vx_core_t *chip);
int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot); int snd_vx_load_boot_image(vx_core_t *chip, const struct firmware *dsp);
int snd_vx_dsp_boot(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot); int snd_vx_dsp_boot(vx_core_t *chip, const struct firmware *dsp);
int snd_vx_dsp_load(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp); int snd_vx_dsp_load(vx_core_t *chip, const struct firmware *dsp);
void snd_vx_free_firmware(vx_core_t *chip);
/* /*
* interrupt handler; exported for pcmcia * interrupt handler; exported for pcmcia
*/ */
irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs); irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs);
/*
* power-management routines
*/
#ifdef CONFIG_PM
void snd_vx_suspend(vx_core_t *chip);
void snd_vx_resume(vx_core_t *chip);
#endif
/* /*
* lowlevel functions * lowlevel functions
*/ */
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/firmware.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/asoundef.h> #include <sound/asoundef.h>
...@@ -430,20 +431,19 @@ int vx_send_rih(vx_core_t *chip, int cmd) ...@@ -430,20 +431,19 @@ int vx_send_rih(vx_core_t *chip, int cmd)
* snd_vx_boot_xilinx - boot up the xilinx interface * snd_vx_boot_xilinx - boot up the xilinx interface
* @boot: the boot record to load * @boot: the boot record to load
*/ */
int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) int snd_vx_load_boot_image(vx_core_t *chip, const struct firmware *boot)
{ {
unsigned int i; unsigned int i;
int no_fillup = vx_has_new_dsp(chip); int no_fillup = vx_has_new_dsp(chip);
/* check the length of boot image */ /* check the length of boot image */
snd_assert(boot->length > 0, return -EINVAL); snd_assert(boot->size > 0, return -EINVAL);
snd_assert(boot->length % 3 == 0, return -EINVAL); snd_assert(boot->size % 3 == 0, return -EINVAL);
snd_assert(boot->image, return -EINVAL);
#if 0 #if 0
{ {
/* more strict check */ /* more strict check */
unsigned int c = ((u32)boot->image[0] << 16) | ((u32)boot->image[1] << 8) | boot->image[2]; unsigned int c = ((u32)boot->data[0] << 16) | ((u32)boot->data[1] << 8) | boot->data[2];
snd_assert(boot->length == (c + 2) * 3, return -EINVAL); snd_assert(boot->size == (c + 2) * 3, return -EINVAL);
} }
#endif #endif
...@@ -454,7 +454,7 @@ int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) ...@@ -454,7 +454,7 @@ int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot)
/* download boot strap */ /* download boot strap */
for (i = 0; i < 0x600; i += 3) { for (i = 0; i < 0x600; i += 3) {
if (i >= boot->length) { if (i >= boot->size) {
if (no_fillup) if (no_fillup)
break; break;
if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) {
...@@ -465,9 +465,7 @@ int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) ...@@ -465,9 +465,7 @@ int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot)
vx_outb(chip, TXM, 0); vx_outb(chip, TXM, 0);
vx_outb(chip, TXL, 0); vx_outb(chip, TXL, 0);
} else { } else {
unsigned char image[3]; unsigned char *image = boot->data + i;
if (copy_from_user(image, boot->image + i, 3))
return -EFAULT;
if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) {
snd_printk(KERN_ERR "dsp boot failed at %d\n", i); snd_printk(KERN_ERR "dsp boot failed at %d\n", i);
return -EIO; return -EIO;
...@@ -653,7 +651,7 @@ static void vx_proc_init(vx_core_t *chip) ...@@ -653,7 +651,7 @@ static void vx_proc_init(vx_core_t *chip)
/** /**
* snd_vx_dsp_boot - load the DSP boot * snd_vx_dsp_boot - load the DSP boot
*/ */
int snd_vx_dsp_boot(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) int snd_vx_dsp_boot(vx_core_t *chip, const struct firmware *boot)
{ {
int err; int err;
int cold_reset = !(chip->chip_status & VX_STAT_DEVICE_INIT); int cold_reset = !(chip->chip_status & VX_STAT_DEVICE_INIT);
...@@ -671,21 +669,20 @@ int snd_vx_dsp_boot(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) ...@@ -671,21 +669,20 @@ int snd_vx_dsp_boot(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot)
/** /**
* snd_vx_dsp_load - load the DSP image * snd_vx_dsp_load - load the DSP image
*/ */
int snd_vx_dsp_load(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp) int snd_vx_dsp_load(vx_core_t *chip, const struct firmware *dsp)
{ {
unsigned int i; unsigned int i;
int err; int err;
unsigned int csum = 0; unsigned int csum = 0;
unsigned char image[3], *cptr; unsigned char *image, *cptr;
snd_assert(dsp->length % 3 == 0, return -EINVAL); snd_assert(dsp->size % 3 == 0, return -EINVAL);
vx_toggle_dac_mute(chip, 1); vx_toggle_dac_mute(chip, 1);
/* Transfert data buffer from PC to DSP */ /* Transfert data buffer from PC to DSP */
for (i = 0; i < dsp->length; i += 3) { for (i = 0; i < dsp->size; i += 3) {
if (copy_from_user(image, dsp->image + i, 3)) image = dsp->data + i;
return -EFAULT;
/* Wait DSP ready for a new read */ /* Wait DSP ready for a new read */
if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) { if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
printk("dsp loading error at position %d\n", i); printk("dsp loading error at position %d\n", i);
...@@ -717,6 +714,54 @@ int snd_vx_dsp_load(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp) ...@@ -717,6 +714,54 @@ int snd_vx_dsp_load(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp)
return 0; return 0;
} }
#ifdef CONFIG_PM
/*
* suspend
*/
static int snd_vx_suspend(snd_card_t *card, unsigned int state)
{
vx_core_t *chip = card->pm_private_data;
unsigned int i;
snd_assert(chip, return -EINVAL);
chip->chip_status |= VX_STAT_IN_SUSPEND;
for (i = 0; i < chip->hw->num_codecs; i++)
snd_pcm_suspend_all(chip->pcm[i]);
return 0;
}
/*
* resume
*/
static int snd_vx_resume(snd_card_t *card, unsigned int state)
{
vx_core_t *chip = card->pm_private_data;
int i, err;
snd_assert(chip, return -EINVAL);
chip->chip_status &= ~VX_STAT_CHIP_INIT;
for (i = 0; i < 4; i++) {
if (! chip->firmware[i])
continue;
err = chip->ops->load_dsp(chip, i, chip->firmware[i]);
if (err < 0) {
snd_printk(KERN_ERR "vx: firmware resume error at DSP %d\n", i);
return -EIO;
}
}
chip->chip_status |= VX_STAT_CHIP_INIT;
chip->chip_status &= ~VX_STAT_IN_SUSPEND;
return 0;
}
#endif
/** /**
* snd_vx_create - constructor for vx_core_t * snd_vx_create - constructor for vx_core_t
* @hw: hardware specific record * @hw: hardware specific record
...@@ -753,37 +798,13 @@ vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw, ...@@ -753,37 +798,13 @@ vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw,
strcpy(card->driver, hw->name); strcpy(card->driver, hw->name);
sprintf(card->shortname, "Digigram %s", hw->name); sprintf(card->shortname, "Digigram %s", hw->name);
snd_card_set_pm_callback(card, snd_vx_suspend, snd_vx_resume, chip);
vx_proc_init(chip); vx_proc_init(chip);
return chip; return chip;
} }
#ifdef CONFIG_PM
/*
* suspend
*/
void snd_vx_suspend(vx_core_t *chip)
{
unsigned int i;
chip->chip_status |= VX_STAT_IN_SUSPEND;
for (i = 0; i < chip->hw->num_codecs; i++)
snd_pcm_suspend_all(chip->pcm[i]);
if (chip->hwdep)
chip->hwdep->dsp_loaded = 0;
}
/*
* resume
*/
void snd_vx_resume(vx_core_t *chip)
{
/* clear all stuff... */
chip->chip_status &= ~(VX_STAT_IN_SUSPEND|VX_STAT_CHIP_INIT);
}
#endif
/* /*
* module entries * module entries
*/ */
...@@ -804,13 +825,10 @@ module_exit(alsa_vx_core_exit) ...@@ -804,13 +825,10 @@ module_exit(alsa_vx_core_exit)
*/ */
EXPORT_SYMBOL(snd_vx_check_reg_bit); EXPORT_SYMBOL(snd_vx_check_reg_bit);
EXPORT_SYMBOL(snd_vx_create); EXPORT_SYMBOL(snd_vx_create);
EXPORT_SYMBOL(snd_vx_hwdep_new); EXPORT_SYMBOL(snd_vx_setup_firmware);
EXPORT_SYMBOL(snd_vx_free_firmware);
EXPORT_SYMBOL(snd_vx_irq_handler); EXPORT_SYMBOL(snd_vx_irq_handler);
EXPORT_SYMBOL(snd_vx_delay); EXPORT_SYMBOL(snd_vx_delay);
EXPORT_SYMBOL(snd_vx_dsp_boot); EXPORT_SYMBOL(snd_vx_dsp_boot);
EXPORT_SYMBOL(snd_vx_dsp_load); EXPORT_SYMBOL(snd_vx_dsp_load);
EXPORT_SYMBOL(snd_vx_load_boot_image); EXPORT_SYMBOL(snd_vx_load_boot_image);
#ifdef CONFIG_PM
EXPORT_SYMBOL(snd_vx_suspend);
EXPORT_SYMBOL(snd_vx_resume);
#endif
/* /*
* Driver for Digigram VX soundcards * Driver for Digigram VX soundcards
* *
* hwdep device manager * DSP firmware management
* *
* Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
* *
...@@ -21,10 +21,89 @@ ...@@ -21,10 +21,89 @@
*/ */
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/firmware.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/hwdep.h> #include <sound/hwdep.h>
#include <sound/vx_core.h> #include <sound/vx_core.h>
#ifdef SND_VX_FW_LOADER
int snd_vx_setup_firmware(vx_core_t *chip)
{
static char *fw_files[VX_TYPE_NUMS][4] = {
[VX_TYPE_BOARD] = {
NULL, "x1_1_vx2.xlx", "bd56002.boot", "l_1_vx2.d56",
},
[VX_TYPE_V2] = {
NULL, "x1_2_v22.xlx", "bd563v2.boot", "l_1_v22.d56",
},
[VX_TYPE_MIC] = {
NULL, "x1_2_v22.xlx", "bd563v2.boot", "l_1_v22.d56",
},
[VX_TYPE_VXPOCKET] = {
"bx_1_vxp.b56", "x1_1_vxp.xlx", "bd563s3.boot", "l_1_vxp.d56"
},
[VX_TYPE_VXP440] = {
"bx_1_vp4.b56", "x1_1_vp4.xlx", "bd563s3.boot", "l_1_vp4.d56"
},
};
int i, err;
for (i = 0; i < 4; i++) {
char path[32];
const struct firmware *fw;
if (! fw_files[chip->type][i])
continue;
sprintf(path, "vx/%s", fw_files[chip->type][i]);
if (request_firmware(&fw, path, chip->dev)) {
snd_printk(KERN_ERR "vx: can't load firmware %s\n", path);
return -ENOENT;
}
err = chip->ops->load_dsp(chip, i, fw);
if (err < 0) {
release_firmware(fw);
return err;
}
if (i == 1)
chip->chip_status |= VX_STAT_XILINX_LOADED;
#ifdef CONFIG_PM
chip->firmware[i] = fw;
#else
release_firmware(fw);
#endif
}
/* ok, we reached to the last one */
/* create the devices if not built yet */
if ((err = snd_vx_pcm_new(chip)) < 0)
return err;
if ((err = snd_vx_mixer_new(chip)) < 0)
return err;
if (chip->ops->add_controls)
if ((err = chip->ops->add_controls(chip)) < 0)
return err;
chip->chip_status |= VX_STAT_DEVICE_INIT;
chip->chip_status |= VX_STAT_CHIP_INIT;
return snd_card_register(chip->card);
}
/* exported */
void snd_vx_free_firmware(vx_core_t *chip)
{
#ifdef CONFIG_PM
int i;
for (i = 0; i < 4; i++)
release_firmware(chip->firmware[i]);
#endif
}
#else /* old style firmware loading */
static int vx_hwdep_open(snd_hwdep_t *hw, struct file *file) static int vx_hwdep_open(snd_hwdep_t *hw, struct file *file)
{ {
return 0; return 0;
...@@ -58,19 +137,54 @@ static int vx_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info) ...@@ -58,19 +137,54 @@ static int vx_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
return 0; return 0;
} }
static void free_fw(struct firmware *fw)
{
if (fw) {
vfree(fw->data);
kfree(fw);
}
}
static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
{ {
vx_core_t *vx = hw->private_data; vx_core_t *vx = hw->private_data;
int index, err; int index, err;
struct firmware *fw;
snd_assert(vx->ops->load_dsp, return -ENXIO); snd_assert(vx->ops->load_dsp, return -ENXIO);
err = vx->ops->load_dsp(vx, dsp);
if (err < 0) fw = kmalloc(sizeof(*fw), GFP_KERNEL);
return err; if (! fw) {
snd_printk(KERN_ERR "cannot allocate firmware\n");
return -ENOMEM;
}
fw->size = dsp->length;
fw->data = vmalloc(fw->size);
if (! fw->data) {
snd_printk(KERN_ERR "cannot allocate firmware image (length=%d)\n",
(int)fw->size);
kfree(fw);
return -ENOMEM;
}
if (copy_from_user(fw->data, dsp->image, dsp->length)) {
free_fw(fw);
return -EFAULT;
}
index = dsp->index; index = dsp->index;
if (! vx_is_pcmcia(vx)) if (! vx_is_pcmcia(vx))
index++; index++;
err = vx->ops->load_dsp(vx, index, fw);
if (err < 0) {
free_fw(fw);
return err;
}
#ifdef CONFIG_PM
chip->firmware[index] = fw;
#else
free_fw(fw);
#endif
if (index == 1) if (index == 1)
vx->chip_status |= VX_STAT_XILINX_LOADED; vx->chip_status |= VX_STAT_XILINX_LOADED;
if (index < 3) if (index < 3)
...@@ -100,7 +214,7 @@ static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -100,7 +214,7 @@ static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
/* exported */ /* exported */
int snd_vx_hwdep_new(vx_core_t *chip) int snd_vx_setup_firmware(vx_core_t *chip)
{ {
int err; int err;
snd_hwdep_t *hw; snd_hwdep_t *hw;
...@@ -118,5 +232,17 @@ int snd_vx_hwdep_new(vx_core_t *chip) ...@@ -118,5 +232,17 @@ int snd_vx_hwdep_new(vx_core_t *chip)
sprintf(hw->name, "VX Loader (%s)", chip->card->driver); sprintf(hw->name, "VX Loader (%s)", chip->card->driver);
chip->hwdep = hw; chip->hwdep = hw;
return 0; return snd_card_register(chip->card);
} }
/* exported */
void snd_vx_free_firmware(vx_core_t *chip)
{
#ifdef CONFIG_PM
int i;
for (i = 0; i < 4; i++)
free_fw(chip->firmware[i]);
#endif
}
#endif /* SND_VX_FW_LOADER */
...@@ -549,7 +549,8 @@ static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe) ...@@ -549,7 +549,8 @@ static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe)
static snd_pcm_hardware_t vx_pcm_playback_hw = { static snd_pcm_hardware_t vx_pcm_playback_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME),
.formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE, .formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000, .rate_min = 5000,
...@@ -802,6 +803,7 @@ static int vx_pcm_trigger(snd_pcm_substream_t *subs, int cmd) ...@@ -802,6 +803,7 @@ static int vx_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (! pipe->is_capture) if (! pipe->is_capture)
vx_pcm_playback_transfer(chip, subs, pipe, 2); vx_pcm_playback_transfer(chip, subs, pipe, 2);
/* FIXME: /* FIXME:
...@@ -813,6 +815,7 @@ static int vx_pcm_trigger(snd_pcm_substream_t *subs, int cmd) ...@@ -813,6 +815,7 @@ static int vx_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
pipe->running = 1; pipe->running = 1;
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
vx_toggle_pipe(chip, pipe, 0); vx_toggle_pipe(chip, pipe, 0);
vx_stop_pipe(chip, pipe); vx_stop_pipe(chip, pipe);
vx_stop_stream(chip, pipe); vx_stop_stream(chip, pipe);
...@@ -946,7 +949,8 @@ static snd_pcm_ops_t vx_pcm_playback_ops = { ...@@ -946,7 +949,8 @@ static snd_pcm_ops_t vx_pcm_playback_ops = {
static snd_pcm_hardware_t vx_pcm_capture_hw = { static snd_pcm_hardware_t vx_pcm_capture_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME),
.formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE, .formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000, .rate_min = 5000,
......
...@@ -1019,13 +1019,6 @@ static int __devinit snd_mixart_create(mixart_mgr_t *mgr, snd_card_t *card, int ...@@ -1019,13 +1019,6 @@ static int __devinit snd_mixart_create(mixart_mgr_t *mgr, snd_card_t *card, int
return err; return err;
} }
if (idx == 0) {
/* create a DSP loader only on first cardX*/
err = snd_mixart_hwdep_new(mgr);
if (err < 0)
return err;
}
snd_card_set_dev(card, &mgr->pci->dev); snd_card_set_dev(card, &mgr->pci->dev);
return 0; return 0;
...@@ -1411,6 +1404,13 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, ...@@ -1411,6 +1404,13 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci,
/* init bufferinfo_array */ /* init bufferinfo_array */
memset(mgr->bufferinfo.area, 0, size); memset(mgr->bufferinfo.area, 0, size);
/* set up firmware */
err = snd_mixart_setup_firmware(mgr);
if (err < 0) {
snd_mixart_free(mgr);
return err;
}
pci_set_drvdata(pci, mgr); pci_set_drvdata(pci, mgr);
dev++; dev++;
return 0; return 0;
......
/* /*
* Driver for Digigram miXart soundcards * Driver for Digigram miXart soundcards
* *
* hwdep device manager * DSP firmware management
* *
* Copyright (c) 2003 by Digigram <alsa@digigram.com> * Copyright (c) 2003 by Digigram <alsa@digigram.com>
* *
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <asm/io.h> #include <asm/io.h>
#include <sound/core.h> #include <sound/core.h>
#include "mixart.h" #include "mixart.h"
...@@ -30,19 +32,6 @@ ...@@ -30,19 +32,6 @@
#include "mixart_hwdep.h" #include "mixart_hwdep.h"
/* miXart hwdep interface id string */
#define SND_MIXART_HWDEP_ID "miXart Loader"
static int mixart_hwdep_open(snd_hwdep_t *hw, struct file *file)
{
return 0;
}
static int mixart_hwdep_release(snd_hwdep_t *hw, struct file *file)
{
return 0;
}
/** /**
* wait for a value on a peudo register, exit with a timeout * wait for a value on a peudo register, exit with a timeout
* *
...@@ -109,34 +98,30 @@ struct snd_mixart_elf32_phdr { ...@@ -109,34 +98,30 @@ struct snd_mixart_elf32_phdr {
u32 p_align; u32 p_align;
}; };
static int mixart_load_elf(mixart_mgr_t *mgr, snd_hwdep_dsp_image_t *dsp ) static int mixart_load_elf(mixart_mgr_t *mgr, const struct firmware *dsp )
{ {
char elf32_magic_number[4] = {0x7f,'E','L','F'}; char elf32_magic_number[4] = {0x7f,'E','L','F'};
snd_mixart_elf32_ehdr_t elf_header; snd_mixart_elf32_ehdr_t *elf_header;
int i; int i;
if ( copy_from_user(&elf_header, dsp->image , sizeof(snd_mixart_elf32_ehdr_t)) ) elf_header = (snd_mixart_elf32_ehdr_t *)dsp->data;
return -EFAULT;
for( i=0; i<4; i++ ) for( i=0; i<4; i++ )
if ( elf32_magic_number[i] != elf_header.e_ident[i] ) if ( elf32_magic_number[i] != elf_header->e_ident[i] )
return -EINVAL; return -EINVAL;
if( elf_header.e_phoff != 0 ) { if( elf_header->e_phoff != 0 ) {
snd_mixart_elf32_phdr_t elf_programheader; snd_mixart_elf32_phdr_t elf_programheader;
for( i=0; i < be16_to_cpu(elf_header.e_phnum); i++ ) { for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
u32 pos = be32_to_cpu(elf_header.e_phoff) + (u32)(i * be16_to_cpu(elf_header.e_phentsize)); u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
if( copy_from_user( &elf_programheader, dsp->image + pos, sizeof(elf_programheader) ) ) memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
return -EFAULT;
if(elf_programheader.p_type != 0) { if(elf_programheader.p_type != 0) {
if( elf_programheader.p_filesz != 0 ) { if( elf_programheader.p_filesz != 0 ) {
if(copy_from_user_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)), memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
dsp->image + be32_to_cpu( elf_programheader.p_offset ), dsp->data + be32_to_cpu( elf_programheader.p_offset ),
be32_to_cpu( elf_programheader.p_filesz ))) be32_to_cpu( elf_programheader.p_filesz ));
return -EFAULT;
} }
} }
} }
...@@ -144,20 +129,6 @@ static int mixart_load_elf(mixart_mgr_t *mgr, snd_hwdep_dsp_image_t *dsp ) ...@@ -144,20 +129,6 @@ static int mixart_load_elf(mixart_mgr_t *mgr, snd_hwdep_dsp_image_t *dsp )
return 0; return 0;
} }
static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
{
mixart_mgr_t *mgr = hw->private_data;
strcpy(info->id, "miXart");
info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
if (mgr->hwdep->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX))
info->chip_ready = 1;
info->version = MIXART_DRIVER_VERSION;
return 0;
}
/* /*
* get basic information and init miXart * get basic information and init miXart
*/ */
...@@ -344,9 +315,8 @@ static int mixart_first_init(mixart_mgr_t *mgr) ...@@ -344,9 +315,8 @@ static int mixart_first_init(mixart_mgr_t *mgr)
/* firmware base addresses (when hard coded) */ /* firmware base addresses (when hard coded) */
#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS 0x00600000 #define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS 0x00600000
static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) static int mixart_dsp_load(mixart_mgr_t* mgr, int index, const struct firmware *dsp)
{ {
mixart_mgr_t* mgr = hw->private_data;
int err, card_index; int err, card_index;
u32 status_xilinx, status_elf, status_daught; u32 status_xilinx, status_elf, status_daught;
u32 val; u32 val;
...@@ -364,7 +334,7 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -364,7 +334,7 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
return -EAGAIN; /* try again later */ return -EAGAIN; /* try again later */
} }
switch (dsp->index) { switch (index) {
case MIXART_MOTHERBOARD_XLX_INDEX: case MIXART_MOTHERBOARD_XLX_INDEX:
/* xilinx already loaded ? */ /* xilinx already loaded ? */
...@@ -379,8 +349,8 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -379,8 +349,8 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
} }
/* check xilinx validity */ /* check xilinx validity */
snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL); snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
snd_assert(dsp->length % 4 == 0, return -EINVAL); snd_assert(dsp->size % 4 == 0, return -EINVAL);
/* set xilinx status to copying */ /* set xilinx status to copying */
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET )); writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
...@@ -388,11 +358,10 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -388,11 +358,10 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
/* setup xilinx base address */ /* setup xilinx base address */
writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET )); writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
/* setup code size for xilinx file */ /* setup code size for xilinx file */
writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET )); writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
/* copy xilinx code */ /* copy xilinx code */
if (copy_from_user_toio( MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS), dsp->image, dsp->length)) memcpy_toio( MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS), dsp->data, dsp->size);
return -EFAULT;
/* set xilinx status to copy finished */ /* set xilinx status to copy finished */
writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET )); writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
...@@ -428,7 +397,7 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -428,7 +397,7 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET )); writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
/* process the copying of the elf packets */ /* process the copying of the elf packets */
err = mixart_load_elf( mgr, dsp); err = mixart_load_elf( mgr, dsp );
if (err < 0) return err; if (err < 0) return err;
/* set elf status to copy finished */ /* set elf status to copy finished */
...@@ -479,11 +448,11 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -479,11 +448,11 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
} }
/* check daughterboard xilinx validity */ /* check daughterboard xilinx validity */
snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL); snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
snd_assert(dsp->length % 4 == 0, return -EINVAL); snd_assert(dsp->size % 4 == 0, return -EINVAL);
/* inform mixart about the size of the file */ /* inform mixart about the size of the file */
writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET )); writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
/* set daughterboard status to 1 */ /* set daughterboard status to 1 */
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET )); writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
...@@ -500,8 +469,7 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -500,8 +469,7 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
snd_assert(val != 0, return -EINVAL); snd_assert(val != 0, return -EINVAL);
/* copy daughterboard xilinx code */ /* copy daughterboard xilinx code */
if (copy_from_user_toio( MIXART_MEM( mgr, val), dsp->image, dsp->length)) memcpy_toio( MIXART_MEM( mgr, val), dsp->data, dsp->size);
return -EFAULT;
/* set daughterboard status to 4 */ /* set daughterboard status to 4 */
writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET )); writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
...@@ -549,7 +517,94 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) ...@@ -549,7 +517,94 @@ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
} }
int snd_mixart_hwdep_new(mixart_mgr_t *mgr) #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
#if !defined(CONFIG_USE_MIXARTLOADER) && !defined(CONFIG_SND_MIXART) /* built-in kernel */
#define SND_MIXART_FW_LOADER /* use the standard firmware loader */
#endif
#endif
#ifdef SND_MIXART_FW_LOADER
#include <linux/firmware.h>
int snd_mixart_setup_firmware(mixart_mgr_t *mgr)
{
static char *fw_files[3] = {
"miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
};
char path[32];
const struct firmware *fw_entry;
int i, err;
for (i = 0; i < 3; i++) {
sprintf(path, "mixart/%s", fw_files[i]);
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
snd_printk(KERN_ERR "miXart: can't load firmware %s\n", path);
return -ENOENT;
}
/* fake hwdep dsp record */
err = mixart_dsp_load(mgr, i, fw_entry);
release_firmware(fw_entry);
if (err < 0)
return err;
}
return 0;
}
#else /* old style firmware loading */
/* miXart hwdep interface id string */
#define SND_MIXART_HWDEP_ID "miXart Loader"
static int mixart_hwdep_open(snd_hwdep_t *hw, struct file *file)
{
return 0;
}
static int mixart_hwdep_release(snd_hwdep_t *hw, struct file *file)
{
return 0;
}
static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
{
mixart_mgr_t *mgr = hw->private_data;
strcpy(info->id, "miXart");
info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
if (mgr->hwdep->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX))
info->chip_ready = 1;
info->version = MIXART_DRIVER_VERSION;
return 0;
}
static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
{
mixart_mgr_t* mgr = hw->private_data;
struct firmware fw;
int err;
fw->size = dsp->length;
fw->data = vmalloc(dsp->length);
if (! fw->data) {
snd_printk(KERN_ERR "miXart: cannot allocate image size %d\n",
(int)dsp->length);
return -ENOMEM;
}
if (copy_from_user(fw->data, dsp->image, dsp->length)) {
vfree(fw->data);
return -EFAULT;
}
err = mixart_dsp_load(mgr, dsp->index, &fw);
vfree(fw->data);
return err;
}
int snd_mixart_setup_firmware(mixart_mgr_t *mgr)
{ {
int err; int err;
snd_hwdep_t *hw; snd_hwdep_t *hw;
...@@ -568,5 +623,8 @@ int snd_mixart_hwdep_new(mixart_mgr_t *mgr) ...@@ -568,5 +623,8 @@ int snd_mixart_hwdep_new(mixart_mgr_t *mgr)
sprintf(hw->name, SND_MIXART_HWDEP_ID); sprintf(hw->name, SND_MIXART_HWDEP_ID);
mgr->hwdep = hw; mgr->hwdep = hw;
mgr->hwdep->dsp_loaded = 0; mgr->hwdep->dsp_loaded = 0;
return 0;
return snd_card_register(mgr->chip[0]->card);
} }
#endif /* SND_MIXART_FW_LOADER */
...@@ -140,7 +140,6 @@ ...@@ -140,7 +140,6 @@
#define MIXART_OIDI 0x008 /* 0000 0000 1000 */ #define MIXART_OIDI 0x008 /* 0000 0000 1000 */
/* exported */ int snd_mixart_setup_firmware(mixart_mgr_t *mgr);
int snd_mixart_hwdep_new(mixart_mgr_t *mgr);
#endif /* __SOUND_MIXART_HWDEP_H */ #endif /* __SOUND_MIXART_HWDEP_H */
...@@ -225,7 +225,11 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci, ...@@ -225,7 +225,11 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci,
snd_printdd("%s at 0x%lx & 0x%lx, irq %i\n", snd_printdd("%s at 0x%lx & 0x%lx, irq %i\n",
card->shortname, vx->port[0], vx->port[1], vx->core.irq); card->shortname, vx->port[0], vx->port[1], vx->core.irq);
if ((err = snd_vx_hwdep_new(&vx->core)) < 0) { #ifdef SND_VX_FW_LOADER
vx->core.dev = &pci->dev;
#endif
if ((err = snd_vx_setup_firmware(&vx->core)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
...@@ -251,6 +255,7 @@ static struct pci_driver driver = { ...@@ -251,6 +255,7 @@ static struct pci_driver driver = {
.id_table = snd_vx222_ids, .id_table = snd_vx222_ids,
.probe = snd_vx222_probe, .probe = snd_vx222_probe,
.remove = __devexit_p(snd_vx222_remove), .remove = __devexit_p(snd_vx222_remove),
SND_PCI_PM_CALLBACKS
}; };
static int __init alsa_card_vx222_init(void) static int __init alsa_card_vx222_init(void)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/firmware.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -351,12 +352,11 @@ static int put_xilinx_data(vx_core_t *chip, unsigned int port, unsigned int coun ...@@ -351,12 +352,11 @@ static int put_xilinx_data(vx_core_t *chip, unsigned int port, unsigned int coun
/* /*
* load the xilinx image * load the xilinx image
*/ */
static int vx2_load_xilinx_binary(vx_core_t *chip, const snd_hwdep_dsp_image_t *xilinx) static int vx2_load_xilinx_binary(vx_core_t *chip, const struct firmware *xilinx)
{ {
unsigned int i; unsigned int i;
unsigned int port; unsigned int port;
unsigned char data; unsigned char *image;
unsigned char __user *image;
/* XILINX reset (wait at least 1 milisecond between reset on and off). */ /* XILINX reset (wait at least 1 milisecond between reset on and off). */
vx_outl(chip, CNTRL, VX_CNTRL_REGISTER_VALUE | VX_XILINX_RESET_MASK); vx_outl(chip, CNTRL, VX_CNTRL_REGISTER_VALUE | VX_XILINX_RESET_MASK);
...@@ -371,10 +371,9 @@ static int vx2_load_xilinx_binary(vx_core_t *chip, const snd_hwdep_dsp_image_t * ...@@ -371,10 +371,9 @@ static int vx2_load_xilinx_binary(vx_core_t *chip, const snd_hwdep_dsp_image_t *
else else
port = VX_GPIOC; /* VX222 V2 and VX222_MIC_BOARD with new PLX9030 use this register */ port = VX_GPIOC; /* VX222 V2 and VX222_MIC_BOARD with new PLX9030 use this register */
image = xilinx->image; image = xilinx->data;
for (i = 0; i < xilinx->length; i++, image++) { for (i = 0; i < xilinx->size; i++, image++) {
__get_user(data, image); if (put_xilinx_data(chip, port, 8, *image) < 0)
if (put_xilinx_data(chip, port, 8, data) < 0)
return -EINVAL; return -EINVAL;
/* don't take too much time in this loop... */ /* don't take too much time in this loop... */
cond_resched(); cond_resched();
...@@ -400,25 +399,22 @@ static int vx2_load_xilinx_binary(vx_core_t *chip, const snd_hwdep_dsp_image_t * ...@@ -400,25 +399,22 @@ static int vx2_load_xilinx_binary(vx_core_t *chip, const snd_hwdep_dsp_image_t *
/* /*
* load the boot/dsp images * load the boot/dsp images
*/ */
static int vx2_load_dsp(vx_core_t *vx, const snd_hwdep_dsp_image_t *dsp) static int vx2_load_dsp(vx_core_t *vx, int index, const struct firmware *dsp)
{ {
int err; int err;
if (*dsp->name) switch (index) {
snd_printdd("loading dsp [%d] %s, size = %Zd\n", case 1:
dsp->index, dsp->name, dsp->length);
switch (dsp->index) {
case 0:
/* xilinx image */ /* xilinx image */
if ((err = vx2_load_xilinx_binary(vx, dsp)) < 0) if ((err = vx2_load_xilinx_binary(vx, dsp)) < 0)
return err; return err;
if ((err = vx2_test_xilinx(vx)) < 0) if ((err = vx2_test_xilinx(vx)) < 0)
return err; return err;
return 0; return 0;
case 1: case 2:
/* DSP boot */ /* DSP boot */
return snd_vx_dsp_boot(vx, dsp); return snd_vx_dsp_boot(vx, dsp);
case 2: case 3:
/* DSP image */ /* DSP image */
return snd_vx_dsp_load(vx, dsp); return snd_vx_dsp_load(vx, dsp);
default: default:
......
...@@ -68,7 +68,10 @@ static int snd_vxpocket_free(vx_core_t *chip) ...@@ -68,7 +68,10 @@ static int snd_vxpocket_free(vx_core_t *chip)
if (hw) if (hw)
hw->card_list[vxp->index] = NULL; hw->card_list[vxp->index] = NULL;
chip->card = NULL; chip->card = NULL;
if (chip->dev)
kfree(chip->dev);
snd_vx_free_firmware(chip);
kfree(chip); kfree(chip);
return 0; return 0;
} }
...@@ -120,6 +123,19 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw) ...@@ -120,6 +123,19 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw)
if (! chip) if (! chip)
return NULL; return NULL;
#ifdef SND_VX_FW_LOADER
/* fake a device here since pcmcia doesn't give a valid device... */
chip->dev = kcalloc(1, sizeof(*chip->dev), GFP_KERNEL);
if (! chip->dev) {
snd_printk(KERN_ERR "vxp: can't malloc chip->dev\n");
kfree(chip);
snd_card_free(card);
return NULL;
}
device_initialize(chip->dev);
sprintf(chip->dev->bus_id, "vxpocket%d", i);
#endif
if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) { if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) {
kfree(chip); kfree(chip);
snd_card_free(card); snd_card_free(card);
...@@ -156,11 +172,8 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw) ...@@ -156,11 +172,8 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw)
link->conf.ConfigIndex = 1; link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION; link->conf.Present = PRESENT_OPTION;
/* Chain drivers */
link->next = hw->dev_list;
hw->dev_list = link;
/* Register with Card Services */ /* Register with Card Services */
memset(&client_reg, 0, sizeof(client_reg));
client_reg.dev_info = hw->dev_info; client_reg.dev_info = hw->dev_info;
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
client_reg.EventMask = client_reg.EventMask =
...@@ -177,10 +190,16 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw) ...@@ -177,10 +190,16 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw)
ret = pcmcia_register_client(&link->handle, &client_reg); ret = pcmcia_register_client(&link->handle, &client_reg);
if (ret != CS_SUCCESS) { if (ret != CS_SUCCESS) {
cs_error(link->handle, RegisterClient, ret); cs_error(link->handle, RegisterClient, ret);
snd_vxpocket_detach(hw, link); snd_card_free(card);
return NULL; return NULL;
} }
/* Chain drivers */
link->next = hw->dev_list;
hw->dev_list = link;
/* snd_card_set_pm_callback(card, snd_vxpocket_suspend, snd_vxpocket_resume, chip); */
return link; return link;
} }
...@@ -208,12 +227,9 @@ static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq) ...@@ -208,12 +227,9 @@ static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq)
sprintf(card->longname, "%s at 0x%x, irq %i", sprintf(card->longname, "%s at 0x%x, irq %i",
card->shortname, port, irq); card->shortname, port, irq);
if ((err = snd_vx_hwdep_new(chip)) < 0)
return err;
chip->irq = irq; chip->irq = irq;
if ((err = snd_card_register(chip->card)) < 0) if ((err = snd_vx_setup_firmware(chip)) < 0)
return err; return err;
return 0; return 0;
...@@ -226,7 +242,12 @@ static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq) ...@@ -226,7 +242,12 @@ static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq)
*/ */
void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link) void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link)
{ {
vx_core_t *chip = link->priv; vx_core_t *chip;
if (! link)
return;
chip = link->priv;
snd_printdd(KERN_DEBUG "vxpocket_detach called\n"); snd_printdd(KERN_DEBUG "vxpocket_detach called\n");
/* Remove the interface data from the linked list */ /* Remove the interface data from the linked list */
...@@ -234,10 +255,10 @@ void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link) ...@@ -234,10 +255,10 @@ void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link)
dev_link_t **linkp; dev_link_t **linkp;
/* Locate device structure */ /* Locate device structure */
for (linkp = &hw->dev_list; *linkp; linkp = &(*linkp)->next) for (linkp = &hw->dev_list; *linkp; linkp = &(*linkp)->next)
if (*linkp == link) if (*linkp == link) {
break;
if (*linkp)
*linkp = link->next; *linkp = link->next;
break;
}
} }
chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */
snd_card_disconnect(chip->card); snd_card_disconnect(chip->card);
...@@ -266,13 +287,16 @@ static void vxpocket_config(dev_link_t *link) ...@@ -266,13 +287,16 @@ static void vxpocket_config(dev_link_t *link)
vx_core_t *chip = link->priv; vx_core_t *chip = link->priv;
struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
tuple_t tuple; tuple_t tuple;
cisparse_t parse; cisparse_t *parse = NULL;
config_info_t conf;
u_short buf[32]; u_short buf[32];
int last_fn, last_ret; int last_fn, last_ret;
snd_printdd(KERN_DEBUG "vxpocket_config called\n"); snd_printdd(KERN_DEBUG "vxpocket_config called\n");
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; parse = kmalloc(sizeof(*parse), GFP_KERNEL);
if (! parse) {
snd_printk(KERN_ERR "vx: cannot allocate\n");
return;
}
tuple.Attributes = 0; tuple.Attributes = 0;
tuple.TupleData = (cisdata_t *)buf; tuple.TupleData = (cisdata_t *)buf;
tuple.TupleDataMax = sizeof(buf); tuple.TupleDataMax = sizeof(buf);
...@@ -280,12 +304,9 @@ static void vxpocket_config(dev_link_t *link) ...@@ -280,12 +304,9 @@ static void vxpocket_config(dev_link_t *link)
tuple.DesiredTuple = CISTPL_CONFIG; tuple.DesiredTuple = CISTPL_CONFIG;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
link->conf.ConfigBase = parse.config.base; link->conf.ConfigBase = parse->config.base;
link->conf.ConfigIndex = 1; link->conf.Present = parse->config.rmask[0];
CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
link->conf.Vcc = conf.Vcc;
/* Configure card */ /* Configure card */
link->state |= DEV_CONFIG; link->state |= DEV_CONFIG;
...@@ -299,6 +320,7 @@ static void vxpocket_config(dev_link_t *link) ...@@ -299,6 +320,7 @@ static void vxpocket_config(dev_link_t *link)
link->dev = &vxp->node; link->dev = &vxp->node;
link->state &= ~DEV_CONFIG_PENDING; link->state &= ~DEV_CONFIG_PENDING;
kfree(parse);
return; return;
cs_failed: cs_failed:
...@@ -307,6 +329,8 @@ static void vxpocket_config(dev_link_t *link) ...@@ -307,6 +329,8 @@ static void vxpocket_config(dev_link_t *link)
pcmcia_release_configuration(link->handle); pcmcia_release_configuration(link->handle);
pcmcia_release_io(link->handle, &link->io); pcmcia_release_io(link->handle, &link->io);
pcmcia_release_irq(link->handle, &link->irq); pcmcia_release_irq(link->handle, &link->irq);
link->state &= ~DEV_CONFIG;
kfree(parse);
} }
...@@ -328,16 +352,16 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar ...@@ -328,16 +352,16 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar
break; break;
case CS_EVENT_CARD_INSERTION: case CS_EVENT_CARD_INSERTION:
snd_printdd(KERN_DEBUG "CARD_INSERTION..\n"); snd_printdd(KERN_DEBUG "CARD_INSERTION..\n");
link->state |= DEV_PRESENT; link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
vxpocket_config(link); vxpocket_config(link);
break; break;
#ifdef CONFIG_PM #ifdef CONFIG_PM
case CS_EVENT_PM_SUSPEND: case CS_EVENT_PM_SUSPEND:
snd_printdd(KERN_DEBUG "SUSPEND\n"); snd_printdd(KERN_DEBUG "SUSPEND\n");
link->state |= DEV_SUSPEND; link->state |= DEV_SUSPEND;
if (chip) { if (chip && chip->card->pm_suspend) {
snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n"); snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
snd_vx_suspend(chip); chip->card->pm_suspend(chip->card, 0);
} }
/* Fall through... */ /* Fall through... */
case CS_EVENT_RESET_PHYSICAL: case CS_EVENT_RESET_PHYSICAL:
...@@ -355,9 +379,9 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar ...@@ -355,9 +379,9 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar
//struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
snd_printdd(KERN_DEBUG "requestconfig...\n"); snd_printdd(KERN_DEBUG "requestconfig...\n");
pcmcia_request_configuration(link->handle, &link->conf); pcmcia_request_configuration(link->handle, &link->conf);
if (chip) { if (chip && chip->card->pm_resume) {
snd_printdd(KERN_DEBUG "calling snd_vx_resume\n"); snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
snd_vx_resume(chip); chip->card->pm_resume(chip->card, 0);
} }
} }
snd_printdd(KERN_DEBUG "resume done!\n"); snd_printdd(KERN_DEBUG "resume done!\n");
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/firmware.h>
#include <sound/core.h> #include <sound/core.h>
#include <asm/io.h> #include <asm/io.h>
#include "vxpocket.h" #include "vxpocket.h"
...@@ -144,13 +145,13 @@ static void vxp_reset_codec(vx_core_t *_chip) ...@@ -144,13 +145,13 @@ static void vxp_reset_codec(vx_core_t *_chip)
* vx_load_xilinx_binary - load the xilinx binary image * vx_load_xilinx_binary - load the xilinx binary image
* the binary image is the binary array converted from the bitstream file. * the binary image is the binary array converted from the bitstream file.
*/ */
static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t *xilinx) static int vxp_load_xilinx_binary(vx_core_t *_chip, const struct firmware *fw)
{ {
struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
unsigned int i; unsigned int i;
int c; int c;
int regCSUER, regRUER; int regCSUER, regRUER;
unsigned char __user *image; unsigned char *image;
unsigned char data; unsigned char data;
/* Switch to programmation mode */ /* Switch to programmation mode */
...@@ -171,9 +172,9 @@ static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t ...@@ -171,9 +172,9 @@ static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t
/* set HF1 for loading xilinx binary */ /* set HF1 for loading xilinx binary */
vx_outb(chip, ICR, ICR_HF1); vx_outb(chip, ICR, ICR_HF1);
image = xilinx->image; image = fw->data;
for (i = 0; i < xilinx->length; i++, image++) { for (i = 0; i < fw->size; i++, image++) {
__get_user(data, image); data = *image;
if (vx_wait_isr_bit(_chip, ISR_TX_EMPTY) < 0) if (vx_wait_isr_bit(_chip, ISR_TX_EMPTY) < 0)
goto _error; goto _error;
vx_outb(chip, TXL, data); vx_outb(chip, TXL, data);
...@@ -200,7 +201,7 @@ static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t ...@@ -200,7 +201,7 @@ static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t
c |= (int)vx_inb(chip, RXM) << 8; c |= (int)vx_inb(chip, RXM) << 8;
c |= vx_inb(chip, RXL); c |= vx_inb(chip, RXL);
snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%x\n", c, xilinx->length); snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%x\n", c, fw->size);
vx_outb(chip, ICR, ICR_HF0); vx_outb(chip, ICR, ICR_HF0);
...@@ -242,30 +243,27 @@ static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t ...@@ -242,30 +243,27 @@ static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t
/* /*
* vxp_load_dsp - load_dsp callback * vxp_load_dsp - load_dsp callback
*/ */
static int vxp_load_dsp(vx_core_t *vx, const snd_hwdep_dsp_image_t *dsp) static int vxp_load_dsp(vx_core_t *vx, int index, const struct firmware *fw)
{ {
int err; int err;
if (*dsp->name) switch (index) {
snd_printdd("loading dsp [%d] %s, size = %d\n", dsp->index, dsp->name, dsp->length);
switch (dsp->index) {
case 0: case 0:
/* xilinx boot */ /* xilinx boot */
if ((err = vx_check_magic(vx)) < 0) if ((err = vx_check_magic(vx)) < 0)
return err; return err;
if ((err = snd_vx_load_boot_image(vx, dsp)) < 0) if ((err = snd_vx_load_boot_image(vx, fw)) < 0)
return err; return err;
return 0; return 0;
case 1: case 1:
/* xilinx image */ /* xilinx image */
return vxp_load_xilinx_binary(vx, dsp); return vxp_load_xilinx_binary(vx, fw);
case 2: case 2:
/* DSP boot */ /* DSP boot */
return snd_vx_dsp_boot(vx, dsp); return snd_vx_dsp_boot(vx, fw);
case 3: case 3:
/* DSP image */ /* DSP image */
return snd_vx_dsp_load(vx, dsp); return snd_vx_dsp_load(vx, fw);
default: default:
snd_BUG(); snd_BUG();
return -EINVAL; return -EINVAL;
......
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