diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2009-02-19 02:42:44 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-02-19 04:22:25 -0500 |
commit | 30459d7b1843cbdea56ca120c8cac10dc5613e90 (patch) | |
tree | 47341d43931193917c28dab16eaf7e1a12b2b6d6 /sound/pci/oxygen/virtuoso.c | |
parent | a69bb3c3fe0881d986ec78e253cb8a6bb9c28230 (diff) |
sound: oxygen: handle cards with broken EEPROM
Under as yet unknown circumstances, the first word of the sound card's
EEPROM gets overwritten. When this has happened, we cannot rely on the
subsystem IDs that the kernel reads from the PCI configuration
registers. Instead, we read the IDs directly from the EEPROM and do the
ID matching manually.
Because the model-specific driver cannot determine the model before
calling oxygen_pci_probe(), that function now gets a get_model()
callback as parameter. The customizing of the model structure, which
was formerly done by the probe() callback, also has moved into
get_model().
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/oxygen/virtuoso.c')
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 134 |
1 files changed, 73 insertions, 61 deletions
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index c05f7e7bdb34..4ac49772da8c 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -160,6 +160,7 @@ static struct pci_device_id xonar_ids[] __devinitdata = { | |||
160 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, | 160 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, |
161 | { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, | 161 | { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, |
162 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, | 162 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, |
163 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | ||
163 | { } | 164 | { } |
164 | }; | 165 | }; |
165 | MODULE_DEVICE_TABLE(pci, xonar_ids); | 166 | MODULE_DEVICE_TABLE(pci, xonar_ids); |
@@ -188,7 +189,6 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); | |||
188 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ | 189 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ |
189 | 190 | ||
190 | struct xonar_data { | 191 | struct xonar_data { |
191 | unsigned int model; | ||
192 | unsigned int anti_pop_delay; | 192 | unsigned int anti_pop_delay; |
193 | unsigned int dacs; | 193 | unsigned int dacs; |
194 | u16 output_enable_bit; | 194 | u16 output_enable_bit; |
@@ -334,15 +334,9 @@ static void xonar_d2_init(struct oxygen *chip) | |||
334 | struct xonar_data *data = chip->model_data; | 334 | struct xonar_data *data = chip->model_data; |
335 | 335 | ||
336 | data->anti_pop_delay = 300; | 336 | data->anti_pop_delay = 300; |
337 | data->dacs = 4; | ||
337 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | 338 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; |
338 | data->pcm1796_oversampling = PCM1796_OS_64; | 339 | data->pcm1796_oversampling = PCM1796_OS_64; |
339 | if (data->model == MODEL_D2X) { | ||
340 | data->ext_power_reg = OXYGEN_GPIO_DATA; | ||
341 | data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; | ||
342 | data->ext_power_bit = GPIO_D2X_EXT_POWER; | ||
343 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
344 | GPIO_D2X_EXT_POWER); | ||
345 | } | ||
346 | 340 | ||
347 | pcm1796_init(chip); | 341 | pcm1796_init(chip); |
348 | 342 | ||
@@ -355,6 +349,18 @@ static void xonar_d2_init(struct oxygen *chip) | |||
355 | snd_component_add(chip->card, "CS5381"); | 349 | snd_component_add(chip->card, "CS5381"); |
356 | } | 350 | } |
357 | 351 | ||
352 | static void xonar_d2x_init(struct oxygen *chip) | ||
353 | { | ||
354 | struct xonar_data *data = chip->model_data; | ||
355 | |||
356 | data->ext_power_reg = OXYGEN_GPIO_DATA; | ||
357 | data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; | ||
358 | data->ext_power_bit = GPIO_D2X_EXT_POWER; | ||
359 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER); | ||
360 | |||
361 | xonar_d2_init(chip); | ||
362 | } | ||
363 | |||
358 | static void update_cs4362a_volumes(struct oxygen *chip) | 364 | static void update_cs4362a_volumes(struct oxygen *chip) |
359 | { | 365 | { |
360 | u8 mute; | 366 | u8 mute; |
@@ -422,11 +428,6 @@ static void xonar_d1_init(struct oxygen *chip) | |||
422 | data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; | 428 | data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; |
423 | data->cs4362a_fm = CS4362A_FM_SINGLE | | 429 | data->cs4362a_fm = CS4362A_FM_SINGLE | |
424 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | 430 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
425 | if (data->model == MODEL_DX) { | ||
426 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
427 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
428 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
429 | } | ||
430 | 431 | ||
431 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 432 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
432 | OXYGEN_2WIRE_LENGTH_8 | | 433 | OXYGEN_2WIRE_LENGTH_8 | |
@@ -447,6 +448,17 @@ static void xonar_d1_init(struct oxygen *chip) | |||
447 | snd_component_add(chip->card, "CS5361"); | 448 | snd_component_add(chip->card, "CS5361"); |
448 | } | 449 | } |
449 | 450 | ||
451 | static void xonar_dx_init(struct oxygen *chip) | ||
452 | { | ||
453 | struct xonar_data *data = chip->model_data; | ||
454 | |||
455 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
456 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
457 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
458 | |||
459 | xonar_d1_init(chip); | ||
460 | } | ||
461 | |||
450 | static void xonar_hdav_init(struct oxygen *chip) | 462 | static void xonar_hdav_init(struct oxygen *chip) |
451 | { | 463 | { |
452 | struct xonar_data *data = chip->model_data; | 464 | struct xonar_data *data = chip->model_data; |
@@ -458,6 +470,7 @@ static void xonar_hdav_init(struct oxygen *chip) | |||
458 | OXYGEN_2WIRE_SPEED_FAST); | 470 | OXYGEN_2WIRE_SPEED_FAST); |
459 | 471 | ||
460 | data->anti_pop_delay = 100; | 472 | data->anti_pop_delay = 100; |
473 | data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 1; | ||
461 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | 474 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; |
462 | data->ext_power_reg = OXYGEN_GPI_DATA; | 475 | data->ext_power_reg = OXYGEN_GPI_DATA; |
463 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 476 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
@@ -773,50 +786,9 @@ static int xonar_d1_mixer_init(struct oxygen *chip) | |||
773 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); | 786 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); |
774 | } | 787 | } |
775 | 788 | ||
776 | static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data) | ||
777 | { | ||
778 | static const char *const names[] = { | ||
779 | [MODEL_D1] = "Xonar D1", | ||
780 | [MODEL_DX] = "Xonar DX", | ||
781 | [MODEL_D2] = "Xonar D2", | ||
782 | [MODEL_D2X] = "Xonar D2X", | ||
783 | [MODEL_HDAV] = "Xonar HDAV1.3", | ||
784 | [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", | ||
785 | }; | ||
786 | static const u8 dacs[] = { | ||
787 | [MODEL_D1] = 2, | ||
788 | [MODEL_DX] = 2, | ||
789 | [MODEL_D2] = 4, | ||
790 | [MODEL_D2X] = 4, | ||
791 | [MODEL_HDAV] = 1, | ||
792 | [MODEL_HDAV_H6] = 4, | ||
793 | }; | ||
794 | struct xonar_data *data = chip->model_data; | ||
795 | |||
796 | data->model = driver_data; | ||
797 | if (data->model == MODEL_HDAV) { | ||
798 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
799 | GPIO_HDAV_DB_MASK); | ||
800 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
801 | GPIO_HDAV_DB_MASK) { | ||
802 | case GPIO_HDAV_DB_H6: | ||
803 | data->model = MODEL_HDAV_H6; | ||
804 | break; | ||
805 | case GPIO_HDAV_DB_XX: | ||
806 | snd_printk(KERN_ERR "unknown daughterboard\n"); | ||
807 | return -ENODEV; | ||
808 | } | ||
809 | } | ||
810 | |||
811 | data->dacs = dacs[data->model]; | ||
812 | chip->model.shortname = names[data->model]; | ||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | static const struct oxygen_model model_xonar_d2 = { | 789 | static const struct oxygen_model model_xonar_d2 = { |
817 | .longname = "Asus Virtuoso 200", | 790 | .longname = "Asus Virtuoso 200", |
818 | .chip = "AV200", | 791 | .chip = "AV200", |
819 | .probe = xonar_model_probe, | ||
820 | .init = xonar_d2_init, | 792 | .init = xonar_d2_init, |
821 | .control_filter = xonar_d2_control_filter, | 793 | .control_filter = xonar_d2_control_filter, |
822 | .mixer_init = xonar_d2_mixer_init, | 794 | .mixer_init = xonar_d2_mixer_init, |
@@ -848,7 +820,6 @@ static const struct oxygen_model model_xonar_d2 = { | |||
848 | static const struct oxygen_model model_xonar_d1 = { | 820 | static const struct oxygen_model model_xonar_d1 = { |
849 | .longname = "Asus Virtuoso 100", | 821 | .longname = "Asus Virtuoso 100", |
850 | .chip = "AV200", | 822 | .chip = "AV200", |
851 | .probe = xonar_model_probe, | ||
852 | .init = xonar_d1_init, | 823 | .init = xonar_d1_init, |
853 | .control_filter = xonar_d1_control_filter, | 824 | .control_filter = xonar_d1_control_filter, |
854 | .mixer_init = xonar_d1_mixer_init, | 825 | .mixer_init = xonar_d1_mixer_init, |
@@ -876,7 +847,6 @@ static const struct oxygen_model model_xonar_d1 = { | |||
876 | static const struct oxygen_model model_xonar_hdav = { | 847 | static const struct oxygen_model model_xonar_hdav = { |
877 | .longname = "Asus Virtuoso 200", | 848 | .longname = "Asus Virtuoso 200", |
878 | .chip = "AV200", | 849 | .chip = "AV200", |
879 | .probe = xonar_model_probe, | ||
880 | .init = xonar_hdav_init, | 850 | .init = xonar_hdav_init, |
881 | .cleanup = xonar_hdav_cleanup, | 851 | .cleanup = xonar_hdav_cleanup, |
882 | .suspend = xonar_hdav_suspend, | 852 | .suspend = xonar_hdav_suspend, |
@@ -902,8 +872,8 @@ static const struct oxygen_model model_xonar_hdav = { | |||
902 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 872 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
903 | }; | 873 | }; |
904 | 874 | ||
905 | static int __devinit xonar_probe(struct pci_dev *pci, | 875 | static int __devinit get_xonar_model(struct oxygen *chip, |
906 | const struct pci_device_id *pci_id) | 876 | const struct pci_device_id *id) |
907 | { | 877 | { |
908 | static const struct oxygen_model *const models[] = { | 878 | static const struct oxygen_model *const models[] = { |
909 | [MODEL_D1] = &model_xonar_d1, | 879 | [MODEL_D1] = &model_xonar_d1, |
@@ -912,6 +882,50 @@ static int __devinit xonar_probe(struct pci_dev *pci, | |||
912 | [MODEL_D2X] = &model_xonar_d2, | 882 | [MODEL_D2X] = &model_xonar_d2, |
913 | [MODEL_HDAV] = &model_xonar_hdav, | 883 | [MODEL_HDAV] = &model_xonar_hdav, |
914 | }; | 884 | }; |
885 | static const char *const names[] = { | ||
886 | [MODEL_D1] = "Xonar D1", | ||
887 | [MODEL_DX] = "Xonar DX", | ||
888 | [MODEL_D2] = "Xonar D2", | ||
889 | [MODEL_D2X] = "Xonar D2X", | ||
890 | [MODEL_HDAV] = "Xonar HDAV1.3", | ||
891 | [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", | ||
892 | }; | ||
893 | unsigned int model = id->driver_data; | ||
894 | |||
895 | if (model >= ARRAY_SIZE(models) || !models[model]) | ||
896 | return -EINVAL; | ||
897 | chip->model = *models[model]; | ||
898 | |||
899 | switch (model) { | ||
900 | case MODEL_D2X: | ||
901 | chip->model.init = xonar_d2x_init; | ||
902 | break; | ||
903 | case MODEL_DX: | ||
904 | chip->model.init = xonar_dx_init; | ||
905 | break; | ||
906 | case MODEL_HDAV: | ||
907 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
908 | GPIO_HDAV_DB_MASK); | ||
909 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
910 | GPIO_HDAV_DB_MASK) { | ||
911 | case GPIO_HDAV_DB_H6: | ||
912 | model = MODEL_HDAV_H6; | ||
913 | break; | ||
914 | case GPIO_HDAV_DB_XX: | ||
915 | snd_printk(KERN_ERR "unknown daughterboard\n"); | ||
916 | return -ENODEV; | ||
917 | } | ||
918 | break; | ||
919 | } | ||
920 | |||
921 | chip->model.shortname = names[model]; | ||
922 | chip->model.private_data = model; | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | static int __devinit xonar_probe(struct pci_dev *pci, | ||
927 | const struct pci_device_id *pci_id) | ||
928 | { | ||
915 | static int dev; | 929 | static int dev; |
916 | int err; | 930 | int err; |
917 | 931 | ||
@@ -921,10 +935,8 @@ static int __devinit xonar_probe(struct pci_dev *pci, | |||
921 | ++dev; | 935 | ++dev; |
922 | return -ENOENT; | 936 | return -ENOENT; |
923 | } | 937 | } |
924 | BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models)); | ||
925 | err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, | 938 | err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, |
926 | models[pci_id->driver_data], | 939 | xonar_ids, get_xonar_model); |
927 | pci_id->driver_data); | ||
928 | if (err >= 0) | 940 | if (err >= 0) |
929 | ++dev; | 941 | ++dev; |
930 | return err; | 942 | return err; |