[ALSA] ymfpci: add request_firmware()
Load the DSP and controller microcode using request_firmware(), if possible, instead of using the built-in firmware. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
This commit is contained in:
committed by
Jaroslav Kysela
parent
e40a0b2e9d
commit
102fa9060e
@@ -357,6 +357,8 @@ struct snd_ymfpci {
|
|||||||
wait_queue_head_t interrupt_sleep;
|
wait_queue_head_t interrupt_sleep;
|
||||||
atomic_t interrupt_sleep_count;
|
atomic_t interrupt_sleep_count;
|
||||||
struct snd_info_entry *proc_entry;
|
struct snd_info_entry *proc_entry;
|
||||||
|
const struct firmware *dsp_microcode;
|
||||||
|
const struct firmware *controller_microcode;
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
u32 *saved_regs;
|
u32 *saved_regs;
|
||||||
|
@@ -735,6 +735,7 @@ config SND_VX222
|
|||||||
config SND_YMFPCI
|
config SND_YMFPCI
|
||||||
tristate "Yamaha YMF724/740/744/754"
|
tristate "Yamaha YMF724/740/744/754"
|
||||||
depends on SND
|
depends on SND
|
||||||
|
select FW_LOADER
|
||||||
select SND_OPL3_LIB
|
select SND_OPL3_LIB
|
||||||
select SND_MPU401_UART
|
select SND_MPU401_UART
|
||||||
select SND_AC97_CODEC
|
select SND_AC97_CODEC
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#ifndef _HWMCODE_
|
#ifndef _HWMCODE_
|
||||||
#define _HWMCODE_
|
#define _HWMCODE_
|
||||||
|
|
||||||
static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
|
static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
|
||||||
0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
|
0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
|
||||||
0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
|
0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
|
||||||
0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
|
0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
|
||||||
@@ -12,7 +12,7 @@ static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
|
|||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000
|
0x00000000, 0x00000000, 0x00000000, 0x00000000
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
|
static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
|
||||||
0x000007, 0x240007, 0x0C0007, 0x1C0007,
|
0x000007, 0x240007, 0x0C0007, 0x1C0007,
|
||||||
0x060007, 0x700002, 0x000020, 0x030040,
|
0x060007, 0x700002, 0x000020, 0x030040,
|
||||||
0x007104, 0x004286, 0x030040, 0x000F0D,
|
0x007104, 0x004286, 0x030040, 0x000F0D,
|
||||||
@@ -791,7 +791,7 @@ static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
|
|||||||
// 04/09 creat
|
// 04/09 creat
|
||||||
// 04/12 stop nise fix
|
// 04/12 stop nise fix
|
||||||
// 06/21 WorkingOff timming
|
// 06/21 WorkingOff timming
|
||||||
static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
|
static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
|
||||||
0x000007, 0x240007, 0x0C0007, 0x1C0007,
|
0x000007, 0x240007, 0x0C0007, 0x1C0007,
|
||||||
0x060007, 0x700002, 0x000020, 0x030040,
|
0x060007, 0x700002, 0x000020, 0x030040,
|
||||||
0x007104, 0x004286, 0x030040, 0x000F0D,
|
0x007104, 0x004286, 0x030040, 0x000F0D,
|
||||||
|
@@ -2,12 +2,6 @@
|
|||||||
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
|
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
|
||||||
* Routines for control of YMF724/740/744/754 chips
|
* Routines for control of YMF724/740/744/754 chips
|
||||||
*
|
*
|
||||||
* BUGS:
|
|
||||||
* --
|
|
||||||
*
|
|
||||||
* TODO:
|
|
||||||
* --
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
@@ -26,6 +20,7 @@
|
|||||||
|
|
||||||
#include <sound/driver.h>
|
#include <sound/driver.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
@@ -42,10 +37,7 @@
|
|||||||
#include <sound/mpu401.h>
|
#include <sound/mpu401.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
#include <asm/byteorder.h>
|
||||||
/*
|
|
||||||
* constants
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* common I/O routines
|
* common I/O routines
|
||||||
@@ -1971,13 +1963,94 @@ static void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FIRMWARE_IN_THE_KERNEL
|
||||||
|
|
||||||
|
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||||
|
|
||||||
#include "ymfpci_image.h"
|
#include "ymfpci_image.h"
|
||||||
|
|
||||||
|
static struct firmware snd_ymfpci_dsp_microcode = {
|
||||||
|
.size = YDSXG_DSPLENGTH,
|
||||||
|
.data = (u8 *)DspInst,
|
||||||
|
};
|
||||||
|
static struct firmware snd_ymfpci_controller_microcode = {
|
||||||
|
.size = YDSXG_CTRLLENGTH,
|
||||||
|
.data = (u8 *)CntrlInst,
|
||||||
|
};
|
||||||
|
static struct firmware snd_ymfpci_controller_1e_microcode = {
|
||||||
|
.size = YDSXG_CTRLLENGTH,
|
||||||
|
.data = (u8 *)CntrlInst1E,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __LITTLE_ENDIAN
|
||||||
|
static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { }
|
||||||
|
#else
|
||||||
|
static void snd_ymfpci_convert_from_le(const struct firmware *fw)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 *data = (u32 *)fw->data;
|
||||||
|
|
||||||
|
for (i = 0; i < fw->size / 4; ++i)
|
||||||
|
le32_to_cpus(&data[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
|
||||||
|
{
|
||||||
|
int err, is_1e;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw",
|
||||||
|
&chip->pci->dev);
|
||||||
|
if (err >= 0) {
|
||||||
|
if (chip->dsp_microcode->size == YDSXG_DSPLENGTH)
|
||||||
|
snd_ymfpci_convert_from_le(chip->dsp_microcode);
|
||||||
|
else {
|
||||||
|
snd_printk(KERN_ERR "DSP microcode has wrong size\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err < 0) {
|
||||||
|
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||||
|
chip->dsp_microcode = &snd_ymfpci_dsp_microcode;
|
||||||
|
#else
|
||||||
|
return err;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F ||
|
||||||
|
chip->device_id == PCI_DEVICE_ID_YAMAHA_740C ||
|
||||||
|
chip->device_id == PCI_DEVICE_ID_YAMAHA_744 ||
|
||||||
|
chip->device_id == PCI_DEVICE_ID_YAMAHA_754;
|
||||||
|
name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw";
|
||||||
|
err = request_firmware(&chip->controller_microcode, name,
|
||||||
|
&chip->pci->dev);
|
||||||
|
if (err >= 0) {
|
||||||
|
if (chip->controller_microcode->size == YDSXG_CTRLLENGTH)
|
||||||
|
snd_ymfpci_convert_from_le(chip->controller_microcode);
|
||||||
|
else {
|
||||||
|
snd_printk(KERN_ERR "controller microcode"
|
||||||
|
" has wrong size\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err < 0) {
|
||||||
|
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||||
|
chip->controller_microcode =
|
||||||
|
is_1e ? &snd_ymfpci_controller_1e_microcode
|
||||||
|
: &snd_ymfpci_controller_microcode;
|
||||||
|
#else
|
||||||
|
return err;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
|
static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u16 ctrl;
|
u16 ctrl;
|
||||||
unsigned long *inst;
|
u32 *inst;
|
||||||
|
|
||||||
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
|
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
|
||||||
snd_ymfpci_disable_dsp(chip);
|
snd_ymfpci_disable_dsp(chip);
|
||||||
@@ -1992,21 +2065,12 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
|
|||||||
snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
|
snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
|
||||||
|
|
||||||
/* setup DSP instruction code */
|
/* setup DSP instruction code */
|
||||||
|
inst = (u32 *)chip->dsp_microcode->data;
|
||||||
for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
|
for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
|
||||||
snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
|
snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]);
|
||||||
|
|
||||||
/* setup control instruction code */
|
/* setup control instruction code */
|
||||||
switch (chip->device_id) {
|
inst = (u32 *)chip->controller_microcode->data;
|
||||||
case PCI_DEVICE_ID_YAMAHA_724F:
|
|
||||||
case PCI_DEVICE_ID_YAMAHA_740C:
|
|
||||||
case PCI_DEVICE_ID_YAMAHA_744:
|
|
||||||
case PCI_DEVICE_ID_YAMAHA_754:
|
|
||||||
inst = CntrlInst1E;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
inst = CntrlInst;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
|
for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
|
||||||
snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]);
|
snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]);
|
||||||
|
|
||||||
@@ -2160,6 +2224,15 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
|
|||||||
pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
|
pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
|
||||||
|
|
||||||
pci_disable_device(chip->pci);
|
pci_disable_device(chip->pci);
|
||||||
|
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||||
|
if (chip->dsp_microcode != &snd_ymfpci_dsp_microcode)
|
||||||
|
#endif
|
||||||
|
release_firmware(chip->dsp_microcode);
|
||||||
|
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||||
|
if (chip->controller_microcode != &snd_ymfpci_controller_microcode &&
|
||||||
|
chip->controller_microcode != &snd_ymfpci_controller_1e_microcode)
|
||||||
|
#endif
|
||||||
|
release_firmware(chip->controller_microcode);
|
||||||
kfree(chip);
|
kfree(chip);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2315,6 +2388,12 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = snd_ymfpci_request_firmware(chip);
|
||||||
|
if (err < 0) {
|
||||||
|
snd_printk(KERN_ERR "firmware request failed: %d\n", err);
|
||||||
|
snd_ymfpci_free(chip);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
snd_ymfpci_download_image(chip);
|
snd_ymfpci_download_image(chip);
|
||||||
|
|
||||||
udelay(100); /* seems we need a delay after downloading image.. */
|
udelay(100); /* seems we need a delay after downloading image.. */
|
||||||
|
Reference in New Issue
Block a user