diff options
| -rw-r--r-- | sound/pci/oxygen/oxygen.h | 3 | ||||
| -rw-r--r-- | sound/pci/oxygen/oxygen_io.c | 16 | ||||
| -rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 29 | 
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;  |