Commit 102fa906 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Jaroslav Kysela
Browse files

[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: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent e40a0b2e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -357,6 +357,8 @@ struct snd_ymfpci {
	wait_queue_head_t interrupt_sleep;
	atomic_t interrupt_sleep_count;
	struct snd_info_entry *proc_entry;
	const struct firmware *dsp_microcode;
	const struct firmware *controller_microcode;

#ifdef CONFIG_PM
	u32 *saved_regs;
+1 −0
Original line number Diff line number Diff line
@@ -735,6 +735,7 @@ config SND_VX222
config SND_YMFPCI
	tristate "Yamaha YMF724/740/744/754"
	depends on SND
	select FW_LOADER
	select SND_OPL3_LIB
	select SND_MPU401_UART
	select SND_AC97_CODEC
+3 −3
Original line number Diff line number Diff line
#ifndef _HWMCODE_
#define _HWMCODE_

static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
	0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
	0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
	0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
@@ -12,7 +12,7 @@ static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
	0x00000000, 0x00000000, 0x00000000, 0x00000000
};

static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
	0x000007, 0x240007, 0x0C0007, 0x1C0007,
	0x060007, 0x700002, 0x000020, 0x030040,
	0x007104, 0x004286, 0x030040, 0x000F0D,
@@ -791,7 +791,7 @@ static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
// 04/09  creat
// 04/12  stop nise fix
// 06/21  WorkingOff timming
static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
	0x000007, 0x240007, 0x0C0007, 0x1C0007,
	0x060007, 0x700002, 0x000020, 0x030040,
	0x007104, 0x004286, 0x030040, 0x000F0D,
+102 −23
Original line number Diff line number Diff line
@@ -2,12 +2,6 @@
 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
 *  Routines for control of YMF724/740/744/754 chips
 *
 *  BUGS:
 *    --
 *
 *  TODO:
 *    --
 *
 *   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
 *   the Free Software Foundation; either version 2 of the License, or
@@ -26,6 +20,7 @@

#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
@@ -42,10 +37,7 @@
#include <sound/mpu401.h>

#include <asm/io.h>

/*
 *  constants
 */
#include <asm/byteorder.h>

/*
 *  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"

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)
{
	int i;
	u16 ctrl;
	unsigned long *inst;
	u32 *inst;

	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
	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);

	/* setup DSP instruction code */
	inst = (u32 *)chip->dsp_microcode->data;
	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 */
	switch (chip->device_id) {
	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;
	}
	inst = (u32 *)chip->controller_microcode->data;
	for (i = 0; i < YDSXG_CTRLLENGTH / 4; 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_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);
	return 0;
}
@@ -2315,6 +2388,12 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
		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);

	udelay(100); /* seems we need a delay after downloading image.. */