diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2006-10-11 06:05:59 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2007-02-09 03:00:42 -0500 |
commit | 102fa9060e114a53628a6594034b6ecf624dffc6 (patch) | |
tree | 13a7fae84cbcea996d61b011bfc99b26b39125e5 /sound | |
parent | e40a0b2e9d73c69e6b9e5d55eb56696f81fbf802 (diff) |
[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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/Kconfig | 1 | ||||
-rw-r--r-- | sound/pci/ymfpci/ymfpci_image.h | 6 | ||||
-rw-r--r-- | sound/pci/ymfpci/ymfpci_main.c | 125 |
3 files changed, 106 insertions, 26 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index ee37de940c63..fcbf9673db62 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -735,6 +735,7 @@ config SND_VX222 | |||
735 | config SND_YMFPCI | 735 | config SND_YMFPCI |
736 | tristate "Yamaha YMF724/740/744/754" | 736 | tristate "Yamaha YMF724/740/744/754" |
737 | depends on SND | 737 | depends on SND |
738 | select FW_LOADER | ||
738 | select SND_OPL3_LIB | 739 | select SND_OPL3_LIB |
739 | select SND_MPU401_UART | 740 | select SND_MPU401_UART |
740 | select SND_AC97_CODEC | 741 | select SND_AC97_CODEC |
diff --git a/sound/pci/ymfpci/ymfpci_image.h b/sound/pci/ymfpci/ymfpci_image.h index 1b0746991669..112f2fff6c8e 100644 --- a/sound/pci/ymfpci/ymfpci_image.h +++ b/sound/pci/ymfpci/ymfpci_image.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef _HWMCODE_ | 1 | #ifndef _HWMCODE_ |
2 | #define _HWMCODE_ | 2 | #define _HWMCODE_ |
3 | 3 | ||
4 | static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = { | 4 | static u32 DspInst[YDSXG_DSPLENGTH / 4] = { |
5 | 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, | 5 | 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, |
6 | 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, | 6 | 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, |
7 | 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, | 7 | 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, |
@@ -12,7 +12,7 @@ static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = { | |||
12 | 0x00000000, 0x00000000, 0x00000000, 0x00000000 | 12 | 0x00000000, 0x00000000, 0x00000000, 0x00000000 |
13 | }; | 13 | }; |
14 | 14 | ||
15 | static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = { | 15 | static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = { |
16 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, | 16 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, |
17 | 0x060007, 0x700002, 0x000020, 0x030040, | 17 | 0x060007, 0x700002, 0x000020, 0x030040, |
18 | 0x007104, 0x004286, 0x030040, 0x000F0D, | 18 | 0x007104, 0x004286, 0x030040, 0x000F0D, |
@@ -791,7 +791,7 @@ static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = { | |||
791 | // 04/09 creat | 791 | // 04/09 creat |
792 | // 04/12 stop nise fix | 792 | // 04/12 stop nise fix |
793 | // 06/21 WorkingOff timming | 793 | // 06/21 WorkingOff timming |
794 | static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { | 794 | static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { |
795 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, | 795 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, |
796 | 0x060007, 0x700002, 0x000020, 0x030040, | 796 | 0x060007, 0x700002, 0x000020, 0x030040, |
797 | 0x007104, 0x004286, 0x030040, 0x000F0D, | 797 | 0x007104, 0x004286, 0x030040, 0x000F0D, |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 7881944a1957..5bde816cd5c4 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -2,12 +2,6 @@ | |||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | 2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> |
3 | * Routines for control of YMF724/740/744/754 chips | 3 | * Routines for control of YMF724/740/744/754 chips |
4 | * | 4 | * |
5 | * BUGS: | ||
6 | * -- | ||
7 | * | ||
8 | * TODO: | ||
9 | * -- | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or |
@@ -26,6 +20,7 @@ | |||
26 | 20 | ||
27 | #include <sound/driver.h> | 21 | #include <sound/driver.h> |
28 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/firmware.h> | ||
29 | #include <linux/init.h> | 24 | #include <linux/init.h> |
30 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
31 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
@@ -42,10 +37,7 @@ | |||
42 | #include <sound/mpu401.h> | 37 | #include <sound/mpu401.h> |
43 | 38 | ||
44 | #include <asm/io.h> | 39 | #include <asm/io.h> |
45 | 40 | #include <asm/byteorder.h> | |
46 | /* | ||
47 | * constants | ||
48 | */ | ||
49 | 41 | ||
50 | /* | 42 | /* |
51 | * common I/O routines | 43 | * common I/O routines |
@@ -1971,13 +1963,94 @@ static void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip) | |||
1971 | } | 1963 | } |
1972 | } | 1964 | } |
1973 | 1965 | ||
1966 | #define FIRMWARE_IN_THE_KERNEL | ||
1967 | |||
1968 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
1969 | |||
1974 | #include "ymfpci_image.h" | 1970 | #include "ymfpci_image.h" |
1975 | 1971 | ||
1972 | static struct firmware snd_ymfpci_dsp_microcode = { | ||
1973 | .size = YDSXG_DSPLENGTH, | ||
1974 | .data = (u8 *)DspInst, | ||
1975 | }; | ||
1976 | static struct firmware snd_ymfpci_controller_microcode = { | ||
1977 | .size = YDSXG_CTRLLENGTH, | ||
1978 | .data = (u8 *)CntrlInst, | ||
1979 | }; | ||
1980 | static struct firmware snd_ymfpci_controller_1e_microcode = { | ||
1981 | .size = YDSXG_CTRLLENGTH, | ||
1982 | .data = (u8 *)CntrlInst1E, | ||
1983 | }; | ||
1984 | #endif | ||
1985 | |||
1986 | #ifdef __LITTLE_ENDIAN | ||
1987 | static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { } | ||
1988 | #else | ||
1989 | static void snd_ymfpci_convert_from_le(const struct firmware *fw) | ||
1990 | { | ||
1991 | int i; | ||
1992 | u32 *data = (u32 *)fw->data; | ||
1993 | |||
1994 | for (i = 0; i < fw->size / 4; ++i) | ||
1995 | le32_to_cpus(&data[i]); | ||
1996 | } | ||
1997 | #endif | ||
1998 | |||
1999 | static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip) | ||
2000 | { | ||
2001 | int err, is_1e; | ||
2002 | const char *name; | ||
2003 | |||
2004 | err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw", | ||
2005 | &chip->pci->dev); | ||
2006 | if (err >= 0) { | ||
2007 | if (chip->dsp_microcode->size == YDSXG_DSPLENGTH) | ||
2008 | snd_ymfpci_convert_from_le(chip->dsp_microcode); | ||
2009 | else { | ||
2010 | snd_printk(KERN_ERR "DSP microcode has wrong size\n"); | ||
2011 | err = -EINVAL; | ||
2012 | } | ||
2013 | } | ||
2014 | if (err < 0) { | ||
2015 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2016 | chip->dsp_microcode = &snd_ymfpci_dsp_microcode; | ||
2017 | #else | ||
2018 | return err; | ||
2019 | #endif | ||
2020 | } | ||
2021 | is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F || | ||
2022 | chip->device_id == PCI_DEVICE_ID_YAMAHA_740C || | ||
2023 | chip->device_id == PCI_DEVICE_ID_YAMAHA_744 || | ||
2024 | chip->device_id == PCI_DEVICE_ID_YAMAHA_754; | ||
2025 | name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw"; | ||
2026 | err = request_firmware(&chip->controller_microcode, name, | ||
2027 | &chip->pci->dev); | ||
2028 | if (err >= 0) { | ||
2029 | if (chip->controller_microcode->size == YDSXG_CTRLLENGTH) | ||
2030 | snd_ymfpci_convert_from_le(chip->controller_microcode); | ||
2031 | else { | ||
2032 | snd_printk(KERN_ERR "controller microcode" | ||
2033 | " has wrong size\n"); | ||
2034 | err = -EINVAL; | ||
2035 | } | ||
2036 | } | ||
2037 | if (err < 0) { | ||
2038 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2039 | chip->controller_microcode = | ||
2040 | is_1e ? &snd_ymfpci_controller_1e_microcode | ||
2041 | : &snd_ymfpci_controller_microcode; | ||
2042 | #else | ||
2043 | return err; | ||
2044 | #endif | ||
2045 | } | ||
2046 | return 0; | ||
2047 | } | ||
2048 | |||
1976 | static void snd_ymfpci_download_image(struct snd_ymfpci *chip) | 2049 | static void snd_ymfpci_download_image(struct snd_ymfpci *chip) |
1977 | { | 2050 | { |
1978 | int i; | 2051 | int i; |
1979 | u16 ctrl; | 2052 | u16 ctrl; |
1980 | unsigned long *inst; | 2053 | u32 *inst; |
1981 | 2054 | ||
1982 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000); | 2055 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000); |
1983 | snd_ymfpci_disable_dsp(chip); | 2056 | snd_ymfpci_disable_dsp(chip); |
@@ -1992,21 +2065,12 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip) | |||
1992 | snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); | 2065 | snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); |
1993 | 2066 | ||
1994 | /* setup DSP instruction code */ | 2067 | /* setup DSP instruction code */ |
2068 | inst = (u32 *)chip->dsp_microcode->data; | ||
1995 | for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) | 2069 | for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) |
1996 | snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]); | 2070 | snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]); |
1997 | 2071 | ||
1998 | /* setup control instruction code */ | 2072 | /* setup control instruction code */ |
1999 | switch (chip->device_id) { | 2073 | inst = (u32 *)chip->controller_microcode->data; |
2000 | case PCI_DEVICE_ID_YAMAHA_724F: | ||
2001 | case PCI_DEVICE_ID_YAMAHA_740C: | ||
2002 | case PCI_DEVICE_ID_YAMAHA_744: | ||
2003 | case PCI_DEVICE_ID_YAMAHA_754: | ||
2004 | inst = CntrlInst1E; | ||
2005 | break; | ||
2006 | default: | ||
2007 | inst = CntrlInst; | ||
2008 | break; | ||
2009 | } | ||
2010 | for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) | 2074 | for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) |
2011 | snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]); | 2075 | snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]); |
2012 | 2076 | ||
@@ -2160,6 +2224,15 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) | |||
2160 | pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); | 2224 | pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); |
2161 | 2225 | ||
2162 | pci_disable_device(chip->pci); | 2226 | pci_disable_device(chip->pci); |
2227 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2228 | if (chip->dsp_microcode != &snd_ymfpci_dsp_microcode) | ||
2229 | #endif | ||
2230 | release_firmware(chip->dsp_microcode); | ||
2231 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2232 | if (chip->controller_microcode != &snd_ymfpci_controller_microcode && | ||
2233 | chip->controller_microcode != &snd_ymfpci_controller_1e_microcode) | ||
2234 | #endif | ||
2235 | release_firmware(chip->controller_microcode); | ||
2163 | kfree(chip); | 2236 | kfree(chip); |
2164 | return 0; | 2237 | return 0; |
2165 | } | 2238 | } |
@@ -2315,6 +2388,12 @@ int __devinit snd_ymfpci_create(struct snd_card *card, | |||
2315 | return -EIO; | 2388 | return -EIO; |
2316 | } | 2389 | } |
2317 | 2390 | ||
2391 | err = snd_ymfpci_request_firmware(chip); | ||
2392 | if (err < 0) { | ||
2393 | snd_printk(KERN_ERR "firmware request failed: %d\n", err); | ||
2394 | snd_ymfpci_free(chip); | ||
2395 | return err; | ||
2396 | } | ||
2318 | snd_ymfpci_download_image(chip); | 2397 | snd_ymfpci_download_image(chip); |
2319 | 2398 | ||
2320 | udelay(100); /* seems we need a delay after downloading image.. */ | 2399 | udelay(100); /* seems we need a delay after downloading image.. */ |