From e58de7baf7de11f01a675cbbf6ecc8a2758b9ca5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 28 Dec 2008 16:44:30 +0100 Subject: ALSA: Convert to snd_card_create() in sound/pci/* Convert from snd_card_new() to the new snd_card_create() function in sound/pci/*. Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/pci/oxygen/oxygen_lib.c') diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 84f481d41efa..9c81e0b05113 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -459,10 +459,10 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, struct oxygen *chip; int err; - card = snd_card_new(index, id, model->owner, - sizeof *chip + model->model_data_size); - if (!card) - return -ENOMEM; + err = snd_card_create(index, id, model->owner, + sizeof(*chip) + model->model_data_size, &card); + if (err < 0) + return err; chip = card->private_data; chip->card = card; -- cgit v1.2.3 From bb71858853a5c9616eea98512f4075d4f081154d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Feb 2009 08:37:13 +0100 Subject: sound: oxygen: make the owner module a parameter of the probe function Move the owner field out of the oxygen_model structure and make it a parameter of oxygen_pci_probe(), because the actual owner module does not depend on the card model. Furthermore, moving it out of the model structure allows us to create the card structure before the actual model is known. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/hifier.c | 3 +-- sound/pci/oxygen/oxygen.c | 3 +-- sound/pci/oxygen/oxygen.h | 2 +- sound/pci/oxygen/oxygen_lib.c | 3 ++- sound/pci/oxygen/virtuoso.c | 5 +---- 5 files changed, 6 insertions(+), 10 deletions(-) (limited to 'sound/pci/oxygen/oxygen_lib.c') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 1ab833f843eb..cc98bad9916a 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -151,7 +151,6 @@ static const struct oxygen_model model_hifier = { .shortname = "C-Media CMI8787", .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", - .owner = THIS_MODULE, .init = hifier_init, .control_filter = hifier_control_filter, .cleanup = hifier_cleanup, @@ -185,7 +184,7 @@ static int __devinit hifier_probe(struct pci_dev *pci, ++dev; return -ENOENT; } - err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier, 0); + err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, &model_hifier, 0); if (err >= 0) ++dev; return err; diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index de999c6d6dd3..12b6c2137d50 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -315,7 +315,6 @@ static const struct oxygen_model model_generic = { .shortname = "C-Media CMI8788", .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", - .owner = THIS_MODULE, .probe = generic_probe, .init = generic_init, .cleanup = generic_cleanup, @@ -353,7 +352,7 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci, ++dev; return -ENOENT; } - err = oxygen_pci_probe(pci, index[dev], id[dev], + err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, &model_generic, pci_id->driver_data); if (err >= 0) ++dev; diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 19107c6307e5..268bff4f29d2 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -62,7 +62,6 @@ struct oxygen_model { const char *shortname; const char *longname; const char *chip; - struct module *owner; int (*probe)(struct oxygen *chip, unsigned long driver_data); void (*init)(struct oxygen *chip); int (*control_filter)(struct snd_kcontrol_new *template); @@ -134,6 +133,7 @@ struct oxygen { /* oxygen_lib.c */ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, + struct module *owner, const struct oxygen_model *model, unsigned long driver_data); void oxygen_pci_remove(struct pci_dev *pci); diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 9c81e0b05113..b5560fa5a5e3 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -452,6 +452,7 @@ static void oxygen_card_free(struct snd_card *card) } int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, + struct module *owner, const struct oxygen_model *model, unsigned long driver_data) { @@ -459,7 +460,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, struct oxygen *chip; int err; - err = snd_card_create(index, id, model->owner, + err = snd_card_create(index, id, owner, sizeof(*chip) + model->model_data_size, &card); if (err < 0) return err; diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 6c870c12a177..c05f7e7bdb34 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -816,7 +816,6 @@ static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data) static const struct oxygen_model model_xonar_d2 = { .longname = "Asus Virtuoso 200", .chip = "AV200", - .owner = THIS_MODULE, .probe = xonar_model_probe, .init = xonar_d2_init, .control_filter = xonar_d2_control_filter, @@ -849,7 +848,6 @@ static const struct oxygen_model model_xonar_d2 = { static const struct oxygen_model model_xonar_d1 = { .longname = "Asus Virtuoso 100", .chip = "AV200", - .owner = THIS_MODULE, .probe = xonar_model_probe, .init = xonar_d1_init, .control_filter = xonar_d1_control_filter, @@ -878,7 +876,6 @@ static const struct oxygen_model model_xonar_d1 = { static const struct oxygen_model model_xonar_hdav = { .longname = "Asus Virtuoso 200", .chip = "AV200", - .owner = THIS_MODULE, .probe = xonar_model_probe, .init = xonar_hdav_init, .cleanup = xonar_hdav_cleanup, @@ -925,7 +922,7 @@ static int __devinit xonar_probe(struct pci_dev *pci, return -ENOENT; } BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models)); - err = oxygen_pci_probe(pci, index[dev], id[dev], + err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, models[pci_id->driver_data], pci_id->driver_data); if (err >= 0) -- cgit v1.2.3 From 6ed91157093c60e26bf0215b752f07af52935afc Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Feb 2009 08:38:25 +0100 Subject: sound: oxygen: allocate model_data dynamically Allocate the model-specific data dynamically instead of including it in the memory block of the card structure. This will allow us to determine the actual model after the card creation. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_lib.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'sound/pci/oxygen/oxygen_lib.c') diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index b5560fa5a5e3..228f30800fd9 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -446,6 +446,7 @@ static void oxygen_card_free(struct snd_card *card) free_irq(chip->irq, chip); flush_scheduled_work(); chip->model.cleanup(chip); + kfree(chip->model_data); mutex_destroy(&chip->mutex); pci_release_regions(chip->pci); pci_disable_device(chip->pci); @@ -460,8 +461,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, struct oxygen *chip; int err; - err = snd_card_create(index, id, owner, - sizeof(*chip) + model->model_data_size, &card); + err = snd_card_create(index, id, owner, sizeof(*chip), &card); if (err < 0) return err; @@ -470,7 +470,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, chip->pci = pci; chip->irq = -1; chip->model = *model; - chip->model_data = chip + 1; spin_lock_init(&chip->reg_lock); mutex_init(&chip->mutex); INIT_WORK(&chip->spdif_input_bits_work, @@ -496,6 +495,15 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, } chip->addr = pci_resource_start(pci, 0); + if (chip->model.model_data_size) { + chip->model_data = kmalloc(chip->model.model_data_size, + GFP_KERNEL); + if (!chip->model_data) { + err = -ENOMEM; + goto err_pci_regions; + } + } + pci_set_master(pci); snd_card_set_dev(card, &pci->dev); card->private_free = oxygen_card_free; -- cgit v1.2.3 From a69bb3c3fe0881d986ec78e253cb8a6bb9c28230 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Feb 2009 08:38:55 +0100 Subject: sound: oxygen: use static driver name When allocating resources, use a fixed name instead of reading it from the model structure. This allows us to allocate the resources before the actual model is known. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_lib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/pci/oxygen/oxygen_lib.c') diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 228f30800fd9..516d94ad2bbb 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -34,6 +34,7 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("C-Media CMI8788 helper library"); MODULE_LICENSE("GPL v2"); +#define DRIVER "oxygen" static inline int oxygen_uart_input_ready(struct oxygen *chip) { @@ -481,7 +482,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, if (err < 0) goto err_card; - err = pci_request_regions(pci, model->chip); + err = pci_request_regions(pci, DRIVER); if (err < 0) { snd_printk(KERN_ERR "cannot reserve PCI resources\n"); goto err_pci_enable; @@ -517,7 +518,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, chip->model.init(chip); err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED, - chip->model.chip, chip); + DRIVER, chip); if (err < 0) { snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq); goto err_card; -- cgit v1.2.3 From 30459d7b1843cbdea56ca120c8cac10dc5613e90 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Feb 2009 08:42:44 +0100 Subject: 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 Signed-off-by: Takashi Iwai --- sound/pci/oxygen/hifier.c | 11 +++- sound/pci/oxygen/oxygen.c | 44 +++++++------- sound/pci/oxygen/oxygen.h | 17 +++++- sound/pci/oxygen/oxygen_io.c | 15 +++++ sound/pci/oxygen/oxygen_lib.c | 51 +++++++++++++--- sound/pci/oxygen/virtuoso.c | 134 +++++++++++++++++++++++------------------- 6 files changed, 179 insertions(+), 93 deletions(-) (limited to 'sound/pci/oxygen/oxygen_lib.c') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index cc98bad9916a..84ef13183419 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -45,6 +45,7 @@ MODULE_PARM_DESC(enable, "enable card"); static struct pci_device_id hifier_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, + { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; MODULE_DEVICE_TABLE(pci, hifier_ids); @@ -172,6 +173,13 @@ static const struct oxygen_model model_hifier = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; +static int __devinit get_hifier_model(struct oxygen *chip, + const struct pci_device_id *id) +{ + chip->model = model_hifier; + return 0; +} + static int __devinit hifier_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -184,7 +192,8 @@ static int __devinit hifier_probe(struct pci_dev *pci, ++dev; return -ENOENT; } - err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, &model_hifier, 0); + err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, + hifier_ids, get_hifier_model); if (err >= 0) ++dev; return err; diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 12b6c2137d50..f2c37f379d39 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -293,29 +293,10 @@ static void set_ak5385_params(struct oxygen *chip, static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); -static int generic_probe(struct oxygen *chip, unsigned long driver_data) -{ - if (driver_data == MODEL_MERIDIAN) { - chip->model.init = meridian_init; - chip->model.resume = meridian_resume; - chip->model.set_adc_params = set_ak5385_params; - chip->model.device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2 | - CAPTURE_1_FROM_SPDIF; - } - if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) { - chip->model.misc_flags = OXYGEN_MISC_MIDI; - chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; - } - return 0; -} - static const struct oxygen_model model_generic = { .shortname = "C-Media CMI8788", .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", - .probe = generic_probe, .init = generic_init, .cleanup = generic_cleanup, .resume = generic_resume, @@ -340,6 +321,29 @@ static const struct oxygen_model model_generic = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; +static int __devinit get_oxygen_model(struct oxygen *chip, + const struct pci_device_id *id) +{ + chip->model = model_generic; + switch (id->driver_data) { + case MODEL_MERIDIAN: + chip->model.init = meridian_init; + chip->model.resume = meridian_resume; + chip->model.set_adc_params = set_ak5385_params; + chip->model.device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2 | + CAPTURE_1_FROM_SPDIF; + break; + } + if (id->driver_data == MODEL_MERIDIAN || + id->driver_data == MODEL_HALO) { + chip->model.misc_flags = OXYGEN_MISC_MIDI; + chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; + } + return 0; +} + static int __devinit generic_oxygen_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -353,7 +357,7 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci, return -ENOENT; } err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, - &model_generic, pci_id->driver_data); + oxygen_ids, get_oxygen_model); if (err >= 0) ++dev; return err; diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 268bff4f29d2..c500d48ea349 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -49,7 +49,13 @@ enum { .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 @@ struct oxygen_model { 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 @@ struct oxygen_model { 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 @@ struct oxygen { 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_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data); 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) { diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 3126c4b403dd..05f48ef1a442 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c @@ -254,3 +254,18 @@ void oxygen_write_uart(struct oxygen *chip, u8 data) _write_uart(chip, 0, data); } EXPORT_SYMBOL(oxygen_write_uart); + +u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index) +{ + unsigned int timeout; + + oxygen_write8(chip, OXYGEN_EEPROM_CONTROL, + index | OXYGEN_EEPROM_DIR_READ); + for (timeout = 0; timeout < 100; ++timeout) { + udelay(1); + if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS) + & OXYGEN_EEPROM_BUSY)) + break; + } + return oxygen_read16(chip, OXYGEN_EEPROM_DATA); +} diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 516d94ad2bbb..d83c3a957323 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -244,6 +244,34 @@ static void oxygen_proc_init(struct oxygen *chip) #define oxygen_proc_init(chip) #endif +static const struct pci_device_id * +oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[]) +{ + u16 subdevice; + + /* + * Make sure the EEPROM pins are available, i.e., not used for SPI. + * (This function is called before we initialize or use SPI.) + */ + oxygen_clear_bits8(chip, OXYGEN_FUNCTION, + OXYGEN_FUNCTION_ENABLE_SPI_4_5); + /* + * Read the subsystem device ID directly from the EEPROM, because the + * chip didn't if the first EEPROM word was overwritten. + */ + subdevice = oxygen_read_eeprom(chip, 2); + /* + * We use only the subsystem device ID for searching because it is + * unique even without the subsystem vendor ID, which may have been + * overwritten in the EEPROM. + */ + for (; ids->vendor; ++ids) + if (ids->subdevice == subdevice && + ids->driver_data != BROKEN_EEPROM_DRIVER_DATA) + return ids; + return NULL; +} + static void oxygen_init(struct oxygen *chip) { unsigned int i; @@ -455,11 +483,15 @@ static void oxygen_card_free(struct snd_card *card) 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 + ) + ) { struct snd_card *card; struct oxygen *chip; + const struct pci_device_id *pci_id; int err; err = snd_card_create(index, id, owner, sizeof(*chip), &card); @@ -470,7 +502,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, chip->card = card; chip->pci = pci; chip->irq = -1; - chip->model = *model; spin_lock_init(&chip->reg_lock); mutex_init(&chip->mutex); INIT_WORK(&chip->spdif_input_bits_work, @@ -496,6 +527,15 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, } chip->addr = pci_resource_start(pci, 0); + pci_id = oxygen_search_pci_id(chip, ids); + if (!pci_id) { + err = -ENODEV; + goto err_pci_regions; + } + err = get_model(chip, pci_id); + if (err < 0) + goto err_pci_regions; + if (chip->model.model_data_size) { chip->model_data = kmalloc(chip->model.model_data_size, GFP_KERNEL); @@ -509,11 +549,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, snd_card_set_dev(card, &pci->dev); card->private_free = oxygen_card_free; - if (chip->model.probe) { - err = chip->model.probe(chip, driver_data); - if (err < 0) - goto err_card; - } oxygen_init(chip); chip->model.init(chip); 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 = { { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, + { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; MODULE_DEVICE_TABLE(pci, xonar_ids); @@ -188,7 +189,6 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ struct xonar_data { - unsigned int model; unsigned int anti_pop_delay; unsigned int dacs; u16 output_enable_bit; @@ -334,15 +334,9 @@ static void xonar_d2_init(struct oxygen *chip) struct xonar_data *data = chip->model_data; data->anti_pop_delay = 300; + data->dacs = 4; data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; data->pcm1796_oversampling = PCM1796_OS_64; - if (data->model == MODEL_D2X) { - data->ext_power_reg = OXYGEN_GPIO_DATA; - data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; - data->ext_power_bit = GPIO_D2X_EXT_POWER; - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_D2X_EXT_POWER); - } pcm1796_init(chip); @@ -355,6 +349,18 @@ static void xonar_d2_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } +static void xonar_d2x_init(struct oxygen *chip) +{ + struct xonar_data *data = chip->model_data; + + data->ext_power_reg = OXYGEN_GPIO_DATA; + data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; + data->ext_power_bit = GPIO_D2X_EXT_POWER; + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER); + + xonar_d2_init(chip); +} + static void update_cs4362a_volumes(struct oxygen *chip) { u8 mute; @@ -422,11 +428,6 @@ static void xonar_d1_init(struct oxygen *chip) data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; data->cs4362a_fm = CS4362A_FM_SINGLE | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; - if (data->model == MODEL_DX) { - data->ext_power_reg = OXYGEN_GPI_DATA; - data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; - data->ext_power_bit = GPI_DX_EXT_POWER; - } oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, OXYGEN_2WIRE_LENGTH_8 | @@ -447,6 +448,17 @@ static void xonar_d1_init(struct oxygen *chip) snd_component_add(chip->card, "CS5361"); } +static void xonar_dx_init(struct oxygen *chip) +{ + struct xonar_data *data = chip->model_data; + + data->ext_power_reg = OXYGEN_GPI_DATA; + data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->ext_power_bit = GPI_DX_EXT_POWER; + + xonar_d1_init(chip); +} + static void xonar_hdav_init(struct oxygen *chip) { struct xonar_data *data = chip->model_data; @@ -458,6 +470,7 @@ static void xonar_hdav_init(struct oxygen *chip) OXYGEN_2WIRE_SPEED_FAST); data->anti_pop_delay = 100; + data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 1; data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; data->ext_power_reg = OXYGEN_GPI_DATA; data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; @@ -773,50 +786,9 @@ static int xonar_d1_mixer_init(struct oxygen *chip) return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); } -static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data) -{ - static const char *const names[] = { - [MODEL_D1] = "Xonar D1", - [MODEL_DX] = "Xonar DX", - [MODEL_D2] = "Xonar D2", - [MODEL_D2X] = "Xonar D2X", - [MODEL_HDAV] = "Xonar HDAV1.3", - [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", - }; - static const u8 dacs[] = { - [MODEL_D1] = 2, - [MODEL_DX] = 2, - [MODEL_D2] = 4, - [MODEL_D2X] = 4, - [MODEL_HDAV] = 1, - [MODEL_HDAV_H6] = 4, - }; - struct xonar_data *data = chip->model_data; - - data->model = driver_data; - if (data->model == MODEL_HDAV) { - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_HDAV_DB_MASK); - switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & - GPIO_HDAV_DB_MASK) { - case GPIO_HDAV_DB_H6: - data->model = MODEL_HDAV_H6; - break; - case GPIO_HDAV_DB_XX: - snd_printk(KERN_ERR "unknown daughterboard\n"); - return -ENODEV; - } - } - - data->dacs = dacs[data->model]; - chip->model.shortname = names[data->model]; - return 0; -} - static const struct oxygen_model model_xonar_d2 = { .longname = "Asus Virtuoso 200", .chip = "AV200", - .probe = xonar_model_probe, .init = xonar_d2_init, .control_filter = xonar_d2_control_filter, .mixer_init = xonar_d2_mixer_init, @@ -848,7 +820,6 @@ static const struct oxygen_model model_xonar_d2 = { static const struct oxygen_model model_xonar_d1 = { .longname = "Asus Virtuoso 100", .chip = "AV200", - .probe = xonar_model_probe, .init = xonar_d1_init, .control_filter = xonar_d1_control_filter, .mixer_init = xonar_d1_mixer_init, @@ -876,7 +847,6 @@ static const struct oxygen_model model_xonar_d1 = { static const struct oxygen_model model_xonar_hdav = { .longname = "Asus Virtuoso 200", .chip = "AV200", - .probe = xonar_model_probe, .init = xonar_hdav_init, .cleanup = xonar_hdav_cleanup, .suspend = xonar_hdav_suspend, @@ -902,8 +872,8 @@ static const struct oxygen_model model_xonar_hdav = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -static int __devinit xonar_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int __devinit get_xonar_model(struct oxygen *chip, + const struct pci_device_id *id) { static const struct oxygen_model *const models[] = { [MODEL_D1] = &model_xonar_d1, @@ -912,6 +882,50 @@ static int __devinit xonar_probe(struct pci_dev *pci, [MODEL_D2X] = &model_xonar_d2, [MODEL_HDAV] = &model_xonar_hdav, }; + static const char *const names[] = { + [MODEL_D1] = "Xonar D1", + [MODEL_DX] = "Xonar DX", + [MODEL_D2] = "Xonar D2", + [MODEL_D2X] = "Xonar D2X", + [MODEL_HDAV] = "Xonar HDAV1.3", + [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", + }; + unsigned int model = id->driver_data; + + if (model >= ARRAY_SIZE(models) || !models[model]) + return -EINVAL; + chip->model = *models[model]; + + switch (model) { + case MODEL_D2X: + chip->model.init = xonar_d2x_init; + break; + case MODEL_DX: + chip->model.init = xonar_dx_init; + break; + case MODEL_HDAV: + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_HDAV_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & + GPIO_HDAV_DB_MASK) { + case GPIO_HDAV_DB_H6: + model = MODEL_HDAV_H6; + break; + case GPIO_HDAV_DB_XX: + snd_printk(KERN_ERR "unknown daughterboard\n"); + return -ENODEV; + } + break; + } + + chip->model.shortname = names[model]; + chip->model.private_data = model; + return 0; +} + +static int __devinit xonar_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ static int dev; int err; @@ -921,10 +935,8 @@ static int __devinit xonar_probe(struct pci_dev *pci, ++dev; return -ENOENT; } - BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models)); err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, - models[pci_id->driver_data], - pci_id->driver_data); + xonar_ids, get_xonar_model); if (err >= 0) ++dev; return err; -- cgit v1.2.3 From 1275d6f608abda23d101ada17dc39940192d4bc4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Feb 2009 08:44:12 +0100 Subject: 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 Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.h | 3 +++ sound/pci/oxygen/oxygen_io.c | 16 ++++++++++++++++ sound/pci/oxygen/oxygen_lib.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) (limited to 'sound/pci/oxygen/oxygen_lib.c') 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 @@ #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 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) } 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 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[]) 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; -- cgit v1.2.3 From 82af308f658cf2193e5058bbbfd37c3437cfb4e7 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 27 Feb 2009 09:27:44 +0100 Subject: sound: oxygen: zero-initialize model data Model drivers assume that model_data is zeroed, so we better use kzalloc() (like we did before when it was allocated together with the card structure). Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/oxygen/oxygen_lib.c') diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 6e1cdd2fd768..312251d39696 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -566,7 +566,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, goto err_pci_regions; if (chip->model.model_data_size) { - chip->model_data = kmalloc(chip->model.model_data_size, + chip->model_data = kzalloc(chip->model.model_data_size, GFP_KERNEL); if (!chip->model_data) { err = -ENOMEM; -- cgit v1.2.3