aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2009-02-19 02:44:12 -0500
committerTakashi Iwai <tiwai@suse.de>2009-02-19 04:22:26 -0500
commit1275d6f608abda23d101ada17dc39940192d4bc4 (patch)
tree17a9954dc31d2fa79494fe9b9b867a48a1dafc3e
parent30459d7b1843cbdea56ca120c8cac10dc5613e90 (diff)
sound: oxygen: automatically restore overwritten EEPROM
If the EEPROM was partially overwritten (which seems to happen before the OS is booted), restore its entire contents by deducing it from the remaining information. This does not have any effect on the Linux driver, which works even with incomplete information in the EEPROM, but it makes other drivers work again. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-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 c500d48ea349..bd615dbffadb 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -18,6 +18,8 @@
18 18
19#define OXYGEN_IO_SIZE 0x100 19#define OXYGEN_IO_SIZE 0x100
20 20
21#define OXYGEN_EEPROM_ID 0x434d /* "CM" */
22
21/* model-specific configuration of outputs/inputs */ 23/* model-specific configuration of outputs/inputs */
22#define PLAYBACK_0_TO_I2S 0x0001 24#define PLAYBACK_0_TO_I2S 0x0001
23 /* PLAYBACK_0_TO_AC97_0 not implemented */ 25 /* PLAYBACK_0_TO_AC97_0 not implemented */
@@ -190,6 +192,7 @@ void oxygen_reset_uart(struct oxygen *chip);
190void oxygen_write_uart(struct oxygen *chip, u8 data); 192void oxygen_write_uart(struct oxygen *chip, u8 data);
191 193
192u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index); 194u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index);
195void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value);
193 196
194static inline void oxygen_set_bits8(struct oxygen *chip, 197static inline void oxygen_set_bits8(struct oxygen *chip,
195 unsigned int reg, u8 value) 198 unsigned int reg, u8 value)
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 05f48ef1a442..c1eb923f2ac9 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)
269 } 269 }
270 return oxygen_read16(chip, OXYGEN_EEPROM_DATA); 270 return oxygen_read16(chip, OXYGEN_EEPROM_DATA);
271} 271}
272
273void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value)
274{
275 unsigned int timeout;
276
277 oxygen_write16(chip, OXYGEN_EEPROM_DATA, value);
278 oxygen_write8(chip, OXYGEN_EEPROM_CONTROL,
279 index | OXYGEN_EEPROM_DIR_WRITE);
280 for (timeout = 0; timeout < 10; ++timeout) {
281 msleep(1);
282 if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS)
283 & OXYGEN_EEPROM_BUSY))
284 return;
285 }
286 snd_printk(KERN_ERR "EEPROM write timeout\n");
287}
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index d83c3a957323..6e1cdd2fd768 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[])
272 return NULL; 272 return NULL;
273} 273}
274 274
275static void oxygen_restore_eeprom(struct oxygen *chip,
276 const struct pci_device_id *id)
277{
278 if (oxygen_read_eeprom(chip, 0) != OXYGEN_EEPROM_ID) {
279 /*
280 * This function gets called only when a known card model has
281 * been detected, i.e., we know there is a valid subsystem
282 * product ID at index 2 in the EEPROM. Therefore, we have
283 * been able to deduce the correct subsystem vendor ID, and
284 * this is enough information to restore the original EEPROM
285 * contents.
286 */
287 oxygen_write_eeprom(chip, 1, id->subvendor);
288 oxygen_write_eeprom(chip, 0, OXYGEN_EEPROM_ID);
289
290 oxygen_set_bits8(chip, OXYGEN_MISC,
291 OXYGEN_MISC_WRITE_PCI_SUBID);
292 pci_write_config_word(chip->pci, PCI_SUBSYSTEM_VENDOR_ID,
293 id->subvendor);
294 pci_write_config_word(chip->pci, PCI_SUBSYSTEM_ID,
295 id->subdevice);
296 oxygen_clear_bits8(chip, OXYGEN_MISC,
297 OXYGEN_MISC_WRITE_PCI_SUBID);
298
299 snd_printk(KERN_INFO "EEPROM ID restored\n");
300 }
301}
302
275static void oxygen_init(struct oxygen *chip) 303static void oxygen_init(struct oxygen *chip)
276{ 304{
277 unsigned int i; 305 unsigned int i;
@@ -532,6 +560,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
532 err = -ENODEV; 560 err = -ENODEV;
533 goto err_pci_regions; 561 goto err_pci_regions;
534 } 562 }
563 oxygen_restore_eeprom(chip, pci_id);
535 err = get_model(chip, pci_id); 564 err = get_model(chip, pci_id);
536 if (err < 0) 565 if (err < 0)
537 goto err_pci_regions; 566 goto err_pci_regions;