aboutsummaryrefslogtreecommitdiff
path: root/sound/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/oxygen/oxygen.h3
-rw-r--r--sound/pci/oxygen/oxygen_io.c16
-rw-r--r--sound/pci/oxygen/oxygen_lib.c29
3 files changed, 48 insertions, 0 deletions
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index c500d48ea34..bd615dbffad 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -18,6 +18,8 @@
#define OXYGEN_IO_SIZE 0x100
+#define OXYGEN_EEPROM_ID 0x434d /* "CM" */
+
/* model-specific configuration of outputs/inputs */
#define PLAYBACK_0_TO_I2S 0x0001
/* PLAYBACK_0_TO_AC97_0 not implemented */
@@ -190,6 +192,7 @@ 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);
+void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value);
static inline void oxygen_set_bits8(struct oxygen *chip,
unsigned int reg, u8 value)
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 05f48ef1a44..c1eb923f2ac 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -269,3 +269,19 @@ u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index)
}
return oxygen_read16(chip, OXYGEN_EEPROM_DATA);
}
+
+void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value)
+{
+ unsigned int timeout;
+
+ oxygen_write16(chip, OXYGEN_EEPROM_DATA, value);
+ oxygen_write8(chip, OXYGEN_EEPROM_CONTROL,
+ index | OXYGEN_EEPROM_DIR_WRITE);
+ for (timeout = 0; timeout < 10; ++timeout) {
+ msleep(1);
+ if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS)
+ & OXYGEN_EEPROM_BUSY))
+ return;
+ }
+ snd_printk(KERN_ERR "EEPROM write timeout\n");
+}
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index d83c3a95732..6e1cdd2fd76 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -272,6 +272,34 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
return NULL;
}
+static void oxygen_restore_eeprom(struct oxygen *chip,
+ const struct pci_device_id *id)
+{
+ if (oxygen_read_eeprom(chip, 0) != OXYGEN_EEPROM_ID) {
+ /*
+ * This function gets called only when a known card model has
+ * been detected, i.e., we know there is a valid subsystem
+ * product ID at index 2 in the EEPROM. Therefore, we have
+ * been able to deduce the correct subsystem vendor ID, and
+ * this is enough information to restore the original EEPROM
+ * contents.
+ */
+ oxygen_write_eeprom(chip, 1, id->subvendor);
+ oxygen_write_eeprom(chip, 0, OXYGEN_EEPROM_ID);
+
+ oxygen_set_bits8(chip, OXYGEN_MISC,
+ OXYGEN_MISC_WRITE_PCI_SUBID);
+ pci_write_config_word(chip->pci, PCI_SUBSYSTEM_VENDOR_ID,
+ id->subvendor);
+ pci_write_config_word(chip->pci, PCI_SUBSYSTEM_ID,
+ id->subdevice);
+ oxygen_clear_bits8(chip, OXYGEN_MISC,
+ OXYGEN_MISC_WRITE_PCI_SUBID);
+
+ snd_printk(KERN_INFO "EEPROM ID restored\n");
+ }
+}
+
static void oxygen_init(struct oxygen *chip)
{
unsigned int i;
@@ -532,6 +560,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
err = -ENODEV;
goto err_pci_regions;
}
+ oxygen_restore_eeprom(chip, pci_id);
err = get_model(chip, pci_id);
if (err < 0)
goto err_pci_regions;