diff options
Diffstat (limited to 'sound/pci/maestro3.c')
-rw-r--r-- | sound/pci/maestro3.c | 373 |
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 | ||
52 | MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>"); | 54 | MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>"); |
53 | MODULE_DESCRIPTION("ESS Maestro3 PCI"); | 55 | MODULE_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 */ | ||
772 | struct 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 | |||
780 | struct 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 | |||
786 | struct m3_list { | 773 | struct 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 | ||
892 | MODULE_DEVICE_TABLE(pci, snd_m3_ids); | 884 | MODULE_DEVICE_TABLE(pci, snd_m3_ids); |
893 | 885 | ||
894 | static const struct m3_quirk m3_quirk_list[] = { | 886 | static 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. */ | 894 | static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { |
952 | static 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 */ | ||
902 | static 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 */ | ||
980 | static 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 | ||
2236 | static const struct firmware assp_kernel = { | ||
2237 | .data = (u8 *)assp_kernel_image, | ||
2238 | .size = sizeof assp_kernel_image | ||
2239 | }; | ||
2240 | static 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 | ||
2248 | static inline void snd_m3_convert_from_le(const struct firmware *fw) { } | ||
2249 | #else | ||
2250 | static 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] = { | |||
2274 | static void snd_m3_assp_init(struct snd_m3 *chip) | 2271 | static 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; |