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>
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 268bff4..c500d48 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -49,7 +49,13 @@
 	.subvendor = sv, \
 	.subdevice = sd
 
+#define BROKEN_EEPROM_DRIVER_DATA ((unsigned long)-1)
+#define OXYGEN_PCI_SUBID_BROKEN_EEPROM \
+	OXYGEN_PCI_SUBID(PCI_VENDOR_ID_CMEDIA, 0x8788), \
+	.driver_data = BROKEN_EEPROM_DRIVER_DATA
+
 struct pci_dev;
+struct pci_device_id;
 struct snd_card;
 struct snd_pcm_substream;
 struct snd_pcm_hardware;
@@ -62,7 +68,6 @@
 	const char *shortname;
 	const char *longname;
 	const char *chip;
-	int (*probe)(struct oxygen *chip, unsigned long driver_data);
 	void (*init)(struct oxygen *chip);
 	int (*control_filter)(struct snd_kcontrol_new *template);
 	int (*mixer_init)(struct oxygen *chip);
@@ -82,6 +87,7 @@
 	void (*ac97_switch)(struct oxygen *chip,
 			    unsigned int reg, unsigned int mute);
 	const unsigned int *dac_tlv;
+	unsigned long private_data;
 	size_t model_data_size;
 	unsigned int device_config;
 	u8 dac_channels;
@@ -134,8 +140,11 @@
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
 		     struct module *owner,
-		     const struct oxygen_model *model,
-		     unsigned long driver_data);
+		     const struct pci_device_id *ids,
+		     int (*get_model)(struct oxygen *chip,
+				      const struct pci_device_id *id
+				     )
+		    );
 void oxygen_pci_remove(struct pci_dev *pci);
 #ifdef CONFIG_PM
 int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
@@ -180,6 +189,8 @@
 void oxygen_reset_uart(struct oxygen *chip);
 void oxygen_write_uart(struct oxygen *chip, u8 data);
 
+u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index);
+
 static inline void oxygen_set_bits8(struct oxygen *chip,
 				    unsigned int reg, u8 value)
 {