aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/maestro3.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/maestro3.c')
-rw-r--r--sound/pci/maestro3.c373
1 files changed, 200 insertions, 173 deletions
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 6efe6d5ade1e..4526904e3f86 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -41,6 +41,7 @@
41#include <linux/slab.h> 41#include <linux/slab.h>
42#include <linux/vmalloc.h> 42#include <linux/vmalloc.h>
43#include <linux/moduleparam.h> 43#include <linux/moduleparam.h>
44#include <linux/firmware.h>
44#include <sound/core.h> 45#include <sound/core.h>
45#include <sound/info.h> 46#include <sound/info.h>
46#include <sound/control.h> 47#include <sound/control.h>
@@ -48,6 +49,7 @@
48#include <sound/mpu401.h> 49#include <sound/mpu401.h>
49#include <sound/ac97_codec.h> 50#include <sound/ac97_codec.h>
50#include <sound/initval.h> 51#include <sound/initval.h>
52#include <asm/byteorder.h>
51 53
52MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>"); 54MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
53MODULE_DESCRIPTION("ESS Maestro3 PCI"); 55MODULE_DESCRIPTION("ESS Maestro3 PCI");
@@ -768,21 +770,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
768/* 770/*
769 */ 771 */
770 772
771/* quirk lists */
772struct m3_quirk {
773 const char *name; /* device name */
774 u16 vendor, device; /* subsystem ids */
775 int amp_gpio; /* gpio pin # for external amp, -1 = default */
776 int irda_workaround; /* non-zero if avoid to touch 0x10 on GPIO_DIRECTION
777 (e.g. for IrDA on Dell Inspirons) */
778};
779
780struct m3_hv_quirk {
781 u16 vendor, device, subsystem_vendor, subsystem_device;
782 u32 config; /* ALLEGRO_CONFIG hardware volume bits */
783 int is_omnibook; /* Do HP OmniBook GPIO magic? */
784};
785
786struct m3_list { 773struct m3_list {
787 int curlen; 774 int curlen;
788 int mem_addr; 775 int mem_addr;
@@ -830,8 +817,6 @@ struct snd_m3 {
830 struct snd_pcm *pcm; 817 struct snd_pcm *pcm;
831 818
832 struct pci_dev *pci; 819 struct pci_dev *pci;
833 const struct m3_quirk *quirk;
834 const struct m3_hv_quirk *hv_quirk;
835 820
836 int dacs_active; 821 int dacs_active;
837 int timer_users; 822 int timer_users;
@@ -845,7 +830,11 @@ struct snd_m3 {
845 u8 reset_state; 830 u8 reset_state;
846 831
847 int external_amp; 832 int external_amp;
848 int amp_gpio; 833 int amp_gpio; /* gpio pin # for external amp, -1 = default */
834 unsigned int hv_config; /* hardware-volume config bits */
835 unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION
836 (e.g. for IrDA on Dell Inspirons) */
837 unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */
849 838
850 /* midi */ 839 /* midi */
851 struct snd_rawmidi *rmidi; 840 struct snd_rawmidi *rmidi;
@@ -864,6 +853,9 @@ struct snd_m3 {
864#ifdef CONFIG_PM 853#ifdef CONFIG_PM
865 u16 *suspend_mem; 854 u16 *suspend_mem;
866#endif 855#endif
856
857 const struct firmware *assp_kernel_image;
858 const struct firmware *assp_minisrc_image;
867}; 859};
868 860
869/* 861/*
@@ -891,127 +883,104 @@ static struct pci_device_id snd_m3_ids[] = {
891 883
892MODULE_DEVICE_TABLE(pci, snd_m3_ids); 884MODULE_DEVICE_TABLE(pci, snd_m3_ids);
893 885
894static const struct m3_quirk m3_quirk_list[] = { 886static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = {
895 /* panasonic CF-28 "toughbook" */ 887 SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d),
896 { 888 SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d),
897 .name = "Panasonic CF-28", 889 SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03),
898 .vendor = 0x10f7, 890 SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03),
899 .device = 0x833e, 891 { } /* END */
900 .amp_gpio = 0x0d,
901 },
902 /* panasonic CF-72 "toughbook" */
903 {
904 .name = "Panasonic CF-72",
905 .vendor = 0x10f7,
906 .device = 0x833d,
907 .amp_gpio = 0x0d,
908 },
909 /* Dell Inspiron 4000 */
910 {
911 .name = "Dell Inspiron 4000",
912 .vendor = 0x1028,
913 .device = 0x00b0,
914 .amp_gpio = -1,
915 .irda_workaround = 1,
916 },
917 /* Dell Inspiron 8000 */
918 {
919 .name = "Dell Inspiron 8000",
920 .vendor = 0x1028,
921 .device = 0x00a4,
922 .amp_gpio = -1,
923 .irda_workaround = 1,
924 },
925 /* Dell Inspiron 8100 */
926 {
927 .name = "Dell Inspiron 8100",
928 .vendor = 0x1028,
929 .device = 0x00e6,
930 .amp_gpio = -1,
931 .irda_workaround = 1,
932 },
933 /* NEC LM800J/7 */
934 {
935 .name = "NEC LM800J/7",
936 .vendor = 0x1033,
937 .device = 0x80f1,
938 .amp_gpio = 0x03,
939 },
940 /* LEGEND ZhaoYang 3100CF */
941 {
942 .name = "LEGEND ZhaoYang 3100CF",
943 .vendor = 0x1509,
944 .device = 0x1740,
945 .amp_gpio = 0x03,
946 },
947 /* END */
948 { NULL }
949}; 892};
950 893
951/* These values came from the Windows driver. */ 894static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = {
952static const struct m3_hv_quirk m3_hv_quirk_list[] = { 895 SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1),
896 SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1),
897 SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1),
898 { } /* END */
899};
900
901/* hardware volume quirks */
902static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = {
953 /* Allegro chips */ 903 /* Allegro chips */
954 { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 904 SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
955 { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 905 SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
956 { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 906 SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
957 { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 907 SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
958 { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 908 SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
959 { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 909 SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
960 { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 910 SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
961 { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 911 SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
962 { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 912 SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
963 { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 913 SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
964 { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 914 SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
965 { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 915 SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
966 { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 916 SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
967 { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 917 SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
968 { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 918 SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
969 { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 919 SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
970 { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 920 SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
971 { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 921 SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
972 { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 922 SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
973 { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 923 SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
974 { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 924 SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
975 { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 925 SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
976 { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 926 SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
977 { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 927 SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
978 { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, 928 SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
979 { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 929 SND_PCI_QUIRK(0x1033, 0x80F1, NULL,
980 { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */ 930 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
981 { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 931 SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */
982 { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 932 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
983 { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 933 SND_PCI_QUIRK(0x107B, 0x340A, NULL,
984 { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 934 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
985 { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 935 SND_PCI_QUIRK(0x107B, 0x3450, NULL,
986 { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 936 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
987 { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 937 SND_PCI_QUIRK(0x109F, 0x3134, NULL,
988 { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 938 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
989 { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 939 SND_PCI_QUIRK(0x109F, 0x3161, NULL,
990 { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, 940 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
991 { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 }, 941 SND_PCI_QUIRK(0x144D, 0x3280, NULL,
992 { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 }, 942 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
993 { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 }, 943 SND_PCI_QUIRK(0x144D, 0x3281, NULL,
994 { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 }, 944 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
995 { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 }, 945 SND_PCI_QUIRK(0x144D, 0xC002, NULL,
946 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
947 SND_PCI_QUIRK(0x144D, 0xC003, NULL,
948 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
949 SND_PCI_QUIRK(0x1509, 0x1740, NULL,
950 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
951 SND_PCI_QUIRK(0x1610, 0x0010, NULL,
952 HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
953 SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE),
954 SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE),
955 SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE),
956 SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE),
957 SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE),
996 /* Maestro3 chips */ 958 /* Maestro3 chips */
997 { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 }, 959 SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE),
998 { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */ 960 SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE),
999 { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */ 961 SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE),
1000 { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 }, 962 SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE),
1001 { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 }, 963 SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE),
1002 { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 }, 964 SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE),
1003 { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 }, 965 SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE),
1004 { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 }, 966 SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE),
1005 { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 }, 967 SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE),
1006 { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 }, 968 SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE),
1007 { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 }, 969 SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE),
1008 { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 }, 970 SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE),
1009 { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 }, 971 SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE),
1010 { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, 972 SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
1011 { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, 973 SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
1012 { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, 974 SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
1013 { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, 975 SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
1014 { 0 } 976 { } /* END */
977};
978
979/* HP Omnibook quirks */
980static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = {
981 SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */
982 SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */
983 { } /* END */
1015}; 984};
1016 985
1017/* 986/*
@@ -2050,7 +2019,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
2050 2019
2051 for (i = 0; i < 5; i++) { 2020 for (i = 0; i < 5; i++) {
2052 dir = inw(io + GPIO_DIRECTION); 2021 dir = inw(io + GPIO_DIRECTION);
2053 if (! chip->quirk || ! chip->quirk->irda_workaround) 2022 if (!chip->irda_workaround)
2054 dir |= 0x10; /* assuming pci bus master? */ 2023 dir |= 0x10; /* assuming pci bus master? */
2055 2024
2056 snd_m3_remote_codec_config(io, 0); 2025 snd_m3_remote_codec_config(io, 0);
@@ -2132,6 +2101,10 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
2132} 2101}
2133 2102
2134 2103
2104#define FIRMWARE_IN_THE_KERNEL
2105
2106#ifdef FIRMWARE_IN_THE_KERNEL
2107
2135/* 2108/*
2136 * DSP Code images 2109 * DSP Code images
2137 */ 2110 */
@@ -2260,6 +2233,30 @@ static const u16 assp_minisrc_image[] = {
2260 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 2233 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2261}; 2234};
2262 2235
2236static const struct firmware assp_kernel = {
2237 .data = (u8 *)assp_kernel_image,
2238 .size = sizeof assp_kernel_image
2239};
2240static const struct firmware assp_minisrc = {
2241 .data = (u8 *)assp_minisrc_image,
2242 .size = sizeof assp_minisrc_image
2243};
2244
2245#endif /* FIRMWARE_IN_THE_KERNEL */
2246
2247#ifdef __LITTLE_ENDIAN
2248static inline void snd_m3_convert_from_le(const struct firmware *fw) { }
2249#else
2250static void snd_m3_convert_from_le(const struct firmware *fw)
2251{
2252 int i;
2253 u16 *data = (u16 *)fw->data;
2254
2255 for (i = 0; i < fw->size / 2; ++i)
2256 le16_to_cpus(&data[i]);
2257}
2258#endif
2259
2263 2260
2264/* 2261/*
2265 * initialize ASSP 2262 * initialize ASSP
@@ -2274,6 +2271,7 @@ static const u16 minisrc_lpf[MINISRC_LPF_LEN] = {
2274static void snd_m3_assp_init(struct snd_m3 *chip) 2271static void snd_m3_assp_init(struct snd_m3 *chip)
2275{ 2272{
2276 unsigned int i; 2273 unsigned int i;
2274 u16 *data;
2277 2275
2278 /* zero kernel data */ 2276 /* zero kernel data */
2279 for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) 2277 for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
@@ -2291,10 +2289,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
2291 KDATA_DMA_XFER0); 2289 KDATA_DMA_XFER0);
2292 2290
2293 /* write kernel into code memory.. */ 2291 /* write kernel into code memory.. */
2294 for (i = 0 ; i < ARRAY_SIZE(assp_kernel_image); i++) { 2292 data = (u16 *)chip->assp_kernel_image->data;
2293 for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) {
2295 snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 2294 snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
2296 REV_B_CODE_MEMORY_BEGIN + i, 2295 REV_B_CODE_MEMORY_BEGIN + i, data[i]);
2297 assp_kernel_image[i]);
2298 } 2296 }
2299 2297
2300 /* 2298 /*
@@ -2303,10 +2301,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
2303 * drop it there. It seems that the minisrc doesn't 2301 * drop it there. It seems that the minisrc doesn't
2304 * need vectors, so we won't bother with them.. 2302 * need vectors, so we won't bother with them..
2305 */ 2303 */
2306 for (i = 0; i < ARRAY_SIZE(assp_minisrc_image); i++) { 2304 data = (u16 *)chip->assp_minisrc_image->data;
2305 for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) {
2307 snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 2306 snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
2308 0x400 + i, 2307 0x400 + i, data[i]);
2309 assp_minisrc_image[i]);
2310 } 2308 }
2311 2309
2312 /* 2310 /*
@@ -2444,7 +2442,7 @@ snd_m3_chip_init(struct snd_m3 *chip)
2444 DISABLE_LEGACY); 2442 DISABLE_LEGACY);
2445 pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); 2443 pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
2446 2444
2447 if (chip->hv_quirk && chip->hv_quirk->is_omnibook) { 2445 if (chip->is_omnibook) {
2448 /* 2446 /*
2449 * Volume buttons on some HP OmniBook laptops don't work 2447 * Volume buttons on some HP OmniBook laptops don't work
2450 * correctly. This makes them work for the most part. 2448 * correctly. This makes them work for the most part.
@@ -2461,8 +2459,7 @@ snd_m3_chip_init(struct snd_m3 *chip)
2461 } 2459 }
2462 pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); 2460 pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
2463 n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); 2461 n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
2464 if (chip->hv_quirk) 2462 n |= chip->hv_config;
2465 n |= chip->hv_quirk->config;
2466 /* For some reason we must always use reduced debounce. */ 2463 /* For some reason we must always use reduced debounce. */
2467 n |= REDUCED_DEBOUNCE; 2464 n |= REDUCED_DEBOUNCE;
2468 n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; 2465 n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
@@ -2510,7 +2507,7 @@ snd_m3_enable_ints(struct snd_m3 *chip)
2510 2507
2511 /* TODO: MPU401 not supported yet */ 2508 /* TODO: MPU401 not supported yet */
2512 val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/; 2509 val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
2513 if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE)) 2510 if (chip->hv_config & HV_CTRL_ENABLE)
2514 val |= HV_INT_ENABLE; 2511 val |= HV_INT_ENABLE;
2515 outw(val, io + HOST_INT_CTRL); 2512 outw(val, io + HOST_INT_CTRL);
2516 outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, 2513 outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
@@ -2553,6 +2550,15 @@ static int snd_m3_free(struct snd_m3 *chip)
2553 if (chip->iobase) 2550 if (chip->iobase)
2554 pci_release_regions(chip->pci); 2551 pci_release_regions(chip->pci);
2555 2552
2553#ifdef FIRMWARE_IN_THE_KERNEL
2554 if (chip->assp_kernel_image != &assp_kernel)
2555#endif
2556 release_firmware(chip->assp_kernel_image);
2557#ifdef FIRMWARE_IN_THE_KERNEL
2558 if (chip->assp_minisrc_image != &assp_minisrc)
2559#endif
2560 release_firmware(chip->assp_minisrc_image);
2561
2556 pci_disable_device(chip->pci); 2562 pci_disable_device(chip->pci);
2557 kfree(chip); 2563 kfree(chip);
2558 return 0; 2564 return 0;
@@ -2665,8 +2671,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
2665{ 2671{
2666 struct snd_m3 *chip; 2672 struct snd_m3 *chip;
2667 int i, err; 2673 int i, err;
2668 const struct m3_quirk *quirk; 2674 const struct snd_pci_quirk *quirk;
2669 const struct m3_hv_quirk *hv_quirk;
2670 static struct snd_device_ops ops = { 2675 static struct snd_device_ops ops = {
2671 .dev_free = snd_m3_dev_free, 2676 .dev_free = snd_m3_dev_free,
2672 }; 2677 };
@@ -2706,34 +2711,32 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
2706 chip->pci = pci; 2711 chip->pci = pci;
2707 chip->irq = -1; 2712 chip->irq = -1;
2708 2713
2709 for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
2710 if (pci->subsystem_vendor == quirk->vendor &&
2711 pci->subsystem_device == quirk->device) {
2712 printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name);
2713 chip->quirk = quirk;
2714 break;
2715 }
2716 }
2717
2718 for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) {
2719 if (pci->vendor == hv_quirk->vendor &&
2720 pci->device == hv_quirk->device &&
2721 pci->subsystem_vendor == hv_quirk->subsystem_vendor &&
2722 pci->subsystem_device == hv_quirk->subsystem_device) {
2723 chip->hv_quirk = hv_quirk;
2724 break;
2725 }
2726 }
2727
2728 chip->external_amp = enable_amp; 2714 chip->external_amp = enable_amp;
2729 if (amp_gpio >= 0 && amp_gpio <= 0x0f) 2715 if (amp_gpio >= 0 && amp_gpio <= 0x0f)
2730 chip->amp_gpio = amp_gpio; 2716 chip->amp_gpio = amp_gpio;
2731 else if (chip->quirk && chip->quirk->amp_gpio >= 0) 2717 else {
2732 chip->amp_gpio = chip->quirk->amp_gpio; 2718 quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
2733 else if (chip->allegro_flag) 2719 if (quirk) {
2734 chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; 2720 snd_printdd(KERN_INFO "maestro3: set amp-gpio "
2735 else /* presumably this is for all 'maestro3's.. */ 2721 "for '%s'\n", quirk->name);
2736 chip->amp_gpio = GPO_EXT_AMP_M3; 2722 chip->amp_gpio = quirk->value;
2723 } else if (chip->allegro_flag)
2724 chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
2725 else /* presumably this is for all 'maestro3's.. */
2726 chip->amp_gpio = GPO_EXT_AMP_M3;
2727 }
2728
2729 quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
2730 if (quirk) {
2731 snd_printdd(KERN_INFO "maestro3: enabled irda workaround "
2732 "for '%s'\n", quirk->name);
2733 chip->irda_workaround = 1;
2734 }
2735 quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);
2736 if (quirk)
2737 chip->hv_config = quirk->value;
2738 if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list))
2739 chip->is_omnibook = 1;
2737 2740
2738 chip->num_substreams = NR_DSPS; 2741 chip->num_substreams = NR_DSPS;
2739 chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma), 2742 chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma),
@@ -2744,6 +2747,30 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
2744 return -ENOMEM; 2747 return -ENOMEM;
2745 } 2748 }
2746 2749
2750 err = request_firmware(&chip->assp_kernel_image,
2751 "ess/maestro3_assp_kernel.fw", &pci->dev);
2752 if (err < 0) {
2753#ifdef FIRMWARE_IN_THE_KERNEL
2754 chip->assp_kernel_image = &assp_kernel;
2755#else
2756 snd_m3_free(chip);
2757 return err;
2758#endif
2759 } else
2760 snd_m3_convert_from_le(chip->assp_kernel_image);
2761
2762 err = request_firmware(&chip->assp_minisrc_image,
2763 "ess/maestro3_assp_minisrc.fw", &pci->dev);
2764 if (err < 0) {
2765#ifdef FIRMWARE_IN_THE_KERNEL
2766 chip->assp_minisrc_image = &assp_minisrc;
2767#else
2768 snd_m3_free(chip);
2769 return err;
2770#endif
2771 } else
2772 snd_m3_convert_from_le(chip->assp_minisrc_image);
2773
2747 if ((err = pci_request_regions(pci, card->driver)) < 0) { 2774 if ((err = pci_request_regions(pci, card->driver)) < 0) {
2748 snd_m3_free(chip); 2775 snd_m3_free(chip);
2749 return err; 2776 return err;