Merge branch 'topic/oxygen' into for-linus
This commit is contained in:
Коммит
b54fc8dd2c
|
@ -1859,7 +1859,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
-------------------
|
||||
|
||||
Module for sound cards based on the Asus AV100/AV200 chips,
|
||||
i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe).
|
||||
i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX.
|
||||
|
||||
This module supports autoprobe and multiple cards.
|
||||
|
||||
|
|
|
@ -764,7 +764,8 @@ config SND_VIRTUOSO
|
|||
select SND_OXYGEN_LIB
|
||||
help
|
||||
Say Y here to include support for sound cards based on the
|
||||
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X.
|
||||
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and
|
||||
Essence STX.
|
||||
Support for the HDAV1.3 (Deluxe) is very experimental.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
|
|
|
@ -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);
|
||||
|
@ -151,7 +152,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,
|
||||
|
@ -173,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)
|
||||
{
|
||||
|
@ -185,7 +192,8 @@ 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,
|
||||
hifier_ids, get_hifier_model);
|
||||
if (err >= 0)
|
||||
++dev;
|
||||
return err;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian
|
||||
* C-Media CMI8788 driver for C-Media's reference design and similar models
|
||||
*
|
||||
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
|
||||
*
|
||||
|
@ -26,6 +26,7 @@
|
|||
*
|
||||
* GPIO 0 -> DFS0 of AK5385
|
||||
* GPIO 1 -> DFS1 of AK5385
|
||||
* GPIO 8 -> enable headphone amplifier on HT-Omega models
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@ -61,7 +62,8 @@ MODULE_PARM_DESC(enable, "enable card");
|
|||
enum {
|
||||
MODEL_CMEDIA_REF, /* C-Media's reference design */
|
||||
MODEL_MERIDIAN, /* AuzenTech X-Meridian */
|
||||
MODEL_HALO, /* HT-Omega Claro halo */
|
||||
MODEL_CLARO, /* HT-Omega Claro */
|
||||
MODEL_CLARO_HALO, /* HT-Omega Claro halo */
|
||||
};
|
||||
|
||||
static struct pci_device_id oxygen_ids[] __devinitdata = {
|
||||
|
@ -74,8 +76,8 @@ static struct pci_device_id oxygen_ids[] __devinitdata = {
|
|||
{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
|
||||
{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO },
|
||||
{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
|
||||
{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, oxygen_ids);
|
||||
|
@ -86,6 +88,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
|
|||
#define GPIO_AK5385_DFS_DOUBLE 0x0001
|
||||
#define GPIO_AK5385_DFS_QUAD 0x0002
|
||||
|
||||
#define GPIO_CLARO_HP 0x0100
|
||||
|
||||
struct generic_data {
|
||||
u8 ak4396_ctl2;
|
||||
u16 saved_wm8785_registers[2];
|
||||
|
@ -196,10 +200,46 @@ static void meridian_init(struct oxygen *chip)
|
|||
ak5385_init(chip);
|
||||
}
|
||||
|
||||
static void claro_enable_hp(struct oxygen *chip)
|
||||
{
|
||||
msleep(300);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_HP);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
|
||||
}
|
||||
|
||||
static void claro_init(struct oxygen *chip)
|
||||
{
|
||||
ak4396_init(chip);
|
||||
wm8785_init(chip);
|
||||
claro_enable_hp(chip);
|
||||
}
|
||||
|
||||
static void claro_halo_init(struct oxygen *chip)
|
||||
{
|
||||
ak4396_init(chip);
|
||||
ak5385_init(chip);
|
||||
claro_enable_hp(chip);
|
||||
}
|
||||
|
||||
static void generic_cleanup(struct oxygen *chip)
|
||||
{
|
||||
}
|
||||
|
||||
static void claro_disable_hp(struct oxygen *chip)
|
||||
{
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
|
||||
}
|
||||
|
||||
static void claro_cleanup(struct oxygen *chip)
|
||||
{
|
||||
claro_disable_hp(chip);
|
||||
}
|
||||
|
||||
static void claro_suspend(struct oxygen *chip)
|
||||
{
|
||||
claro_disable_hp(chip);
|
||||
}
|
||||
|
||||
static void generic_resume(struct oxygen *chip)
|
||||
{
|
||||
ak4396_registers_init(chip);
|
||||
|
@ -211,6 +251,12 @@ static void meridian_resume(struct oxygen *chip)
|
|||
ak4396_registers_init(chip);
|
||||
}
|
||||
|
||||
static void claro_resume(struct oxygen *chip)
|
||||
{
|
||||
ak4396_registers_init(chip);
|
||||
claro_enable_hp(chip);
|
||||
}
|
||||
|
||||
static void set_ak4396_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
|
@ -293,30 +339,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",
|
||||
.owner = THIS_MODULE,
|
||||
.probe = generic_probe,
|
||||
.init = generic_init,
|
||||
.cleanup = generic_cleanup,
|
||||
.resume = generic_resume,
|
||||
|
@ -341,6 +367,42 @@ 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;
|
||||
case MODEL_CLARO:
|
||||
chip->model.init = claro_init;
|
||||
chip->model.cleanup = claro_cleanup;
|
||||
chip->model.suspend = claro_suspend;
|
||||
chip->model.resume = claro_resume;
|
||||
break;
|
||||
case MODEL_CLARO_HALO:
|
||||
chip->model.init = claro_halo_init;
|
||||
chip->model.cleanup = claro_cleanup;
|
||||
chip->model.suspend = claro_suspend;
|
||||
chip->model.resume = claro_resume;
|
||||
chip->model.set_adc_params = set_ak5385_params;
|
||||
break;
|
||||
}
|
||||
if (id->driver_data == MODEL_MERIDIAN ||
|
||||
id->driver_data == MODEL_CLARO_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,8 +415,8 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
|
|||
++dev;
|
||||
return -ENOENT;
|
||||
}
|
||||
err = oxygen_pci_probe(pci, index[dev], id[dev],
|
||||
&model_generic, pci_id->driver_data);
|
||||
err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
|
||||
oxygen_ids, get_oxygen_model);
|
||||
if (err >= 0)
|
||||
++dev;
|
||||
return err;
|
||||
|
|
|
@ -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 */
|
||||
|
@ -49,7 +51,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,8 +70,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);
|
||||
int (*mixer_init)(struct oxygen *chip);
|
||||
|
@ -83,6 +89,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 +141,12 @@ struct oxygen {
|
|||
/* oxygen_lib.c */
|
||||
|
||||
int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
|
||||
const struct oxygen_model *model,
|
||||
unsigned long driver_data);
|
||||
struct module *owner,
|
||||
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 +191,9 @@ 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);
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -254,3 +254,34 @@ 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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
|
|||
MODULE_DESCRIPTION("C-Media CMI8788 helper library");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
#define DRIVER "oxygen"
|
||||
|
||||
static inline int oxygen_uart_input_ready(struct oxygen *chip)
|
||||
{
|
||||
|
@ -243,6 +244,62 @@ 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_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;
|
||||
|
@ -446,21 +503,26 @@ 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);
|
||||
}
|
||||
|
||||
int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
|
||||
const struct oxygen_model *model,
|
||||
unsigned long driver_data)
|
||||
struct module *owner,
|
||||
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, model->owner,
|
||||
sizeof(*chip) + model->model_data_size, &card);
|
||||
err = snd_card_create(index, id, owner, sizeof(*chip), &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -468,8 +530,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;
|
||||
chip->model_data = chip + 1;
|
||||
spin_lock_init(&chip->reg_lock);
|
||||
mutex_init(&chip->mutex);
|
||||
INIT_WORK(&chip->spdif_input_bits_work,
|
||||
|
@ -481,7 +541,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;
|
||||
|
@ -495,20 +555,34 @@ 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;
|
||||
}
|
||||
oxygen_restore_eeprom(chip, pci_id);
|
||||
err = get_model(chip, pci_id);
|
||||
if (err < 0)
|
||||
goto err_pci_regions;
|
||||
|
||||
if (chip->model.model_data_size) {
|
||||
chip->model_data = kzalloc(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;
|
||||
|
||||
if (chip->model.probe) {
|
||||
err = chip->model.probe(chip, driver_data);
|
||||
if (err < 0)
|
||||
goto err_card;
|
||||
}
|
||||
oxygen_init(chip);
|
||||
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;
|
||||
|
|
|
@ -112,6 +112,34 @@
|
|||
* CS4362A: AD0 <- 0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xonar Essence STX
|
||||
* -----------------
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* I²C <-> PCM1792A
|
||||
*
|
||||
* GPI 0 <- external power present
|
||||
*
|
||||
* GPIO 0 -> enable output to speakers
|
||||
* GPIO 1 -> route HP to front panel (0) or rear jack (1)
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 7 -> route output to speaker jacks (0) or HP (1)
|
||||
* GPIO 8 -> route input jack to line-in (0) or mic-in (1)
|
||||
*
|
||||
* PCM1792A:
|
||||
*
|
||||
* AD0 <- 0
|
||||
*
|
||||
* H6 daughterboard
|
||||
* ----------------
|
||||
*
|
||||
* GPIO 4 <- 0
|
||||
* GPIO 5 <- 0
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -152,6 +180,7 @@ enum {
|
|||
MODEL_DX,
|
||||
MODEL_HDAV, /* without daughterboard */
|
||||
MODEL_HDAV_H6, /* with H6 daughterboard */
|
||||
MODEL_STX,
|
||||
};
|
||||
|
||||
static struct pci_device_id xonar_ids[] __devinitdata = {
|
||||
|
@ -160,6 +189,8 @@ 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(0x1043, 0x835c), .driver_data = MODEL_STX },
|
||||
{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, xonar_ids);
|
||||
|
@ -183,12 +214,14 @@ MODULE_DEVICE_TABLE(pci, xonar_ids);
|
|||
#define GPIO_HDAV_DB_H6 0x0000
|
||||
#define GPIO_HDAV_DB_XX 0x0020
|
||||
|
||||
#define GPIO_ST_HP_REAR 0x0002
|
||||
#define GPIO_ST_HP 0x0080
|
||||
|
||||
#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */
|
||||
#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */
|
||||
#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 +367,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 +382,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 +461,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 +481,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 +503,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;
|
||||
|
@ -484,6 +530,36 @@ static void xonar_hdav_init(struct oxygen *chip)
|
|||
snd_component_add(chip->card, "CS5381");
|
||||
}
|
||||
|
||||
static void xonar_stx_init(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_data *data = chip->model_data;
|
||||
|
||||
oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
|
||||
OXYGEN_2WIRE_LENGTH_8 |
|
||||
OXYGEN_2WIRE_INTERRUPT_MASK |
|
||||
OXYGEN_2WIRE_SPEED_FAST);
|
||||
|
||||
data->anti_pop_delay = 100;
|
||||
data->dacs = 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;
|
||||
data->ext_power_bit = GPI_DX_EXT_POWER;
|
||||
data->pcm1796_oversampling = PCM1796_OS_64;
|
||||
|
||||
pcm1796_init(chip);
|
||||
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
|
||||
GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
|
||||
|
||||
xonar_common_init(chip);
|
||||
|
||||
snd_component_add(chip->card, "PCM1792A");
|
||||
snd_component_add(chip->card, "CS5381");
|
||||
}
|
||||
|
||||
static void xonar_disable_output(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_data *data = chip->model_data;
|
||||
|
@ -511,6 +587,11 @@ static void xonar_hdav_cleanup(struct oxygen *chip)
|
|||
xonar_disable_output(chip);
|
||||
}
|
||||
|
||||
static void xonar_st_cleanup(struct oxygen *chip)
|
||||
{
|
||||
xonar_disable_output(chip);
|
||||
}
|
||||
|
||||
static void xonar_d2_suspend(struct oxygen *chip)
|
||||
{
|
||||
xonar_d2_cleanup(chip);
|
||||
|
@ -527,6 +608,11 @@ static void xonar_hdav_suspend(struct oxygen *chip)
|
|||
msleep(2);
|
||||
}
|
||||
|
||||
static void xonar_st_suspend(struct oxygen *chip)
|
||||
{
|
||||
xonar_st_cleanup(chip);
|
||||
}
|
||||
|
||||
static void xonar_d2_resume(struct oxygen *chip)
|
||||
{
|
||||
pcm1796_init(chip);
|
||||
|
@ -554,6 +640,12 @@ static void xonar_hdav_resume(struct oxygen *chip)
|
|||
xonar_enable_output(chip);
|
||||
}
|
||||
|
||||
static void xonar_st_resume(struct oxygen *chip)
|
||||
{
|
||||
pcm1796_init(chip);
|
||||
xonar_enable_output(chip);
|
||||
}
|
||||
|
||||
static void xonar_hdav_pcm_hardware_filter(unsigned int channel,
|
||||
struct snd_pcm_hardware *hardware)
|
||||
{
|
||||
|
@ -733,6 +825,72 @@ static const struct snd_kcontrol_new front_panel_switch = {
|
|||
.private_value = GPIO_DX_FRONT_PANEL,
|
||||
};
|
||||
|
||||
static int st_output_switch_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[3] = {
|
||||
"Speakers", "Headphones", "FP Headphones"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 3;
|
||||
if (info->value.enumerated.item >= 3)
|
||||
info->value.enumerated.item = 2;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_output_switch_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u16 gpio;
|
||||
|
||||
gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
|
||||
if (!(gpio & GPIO_ST_HP))
|
||||
value->value.enumerated.item[0] = 0;
|
||||
else if (gpio & GPIO_ST_HP_REAR)
|
||||
value->value.enumerated.item[0] = 1;
|
||||
else
|
||||
value->value.enumerated.item[0] = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int st_output_switch_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u16 gpio_old, gpio;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
|
||||
gpio = gpio_old;
|
||||
switch (value->value.enumerated.item[0]) {
|
||||
case 0:
|
||||
gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
|
||||
break;
|
||||
case 1:
|
||||
gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
|
||||
break;
|
||||
case 2:
|
||||
gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
|
||||
break;
|
||||
}
|
||||
oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
|
||||
mutex_unlock(&chip->mutex);
|
||||
return gpio != gpio_old;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new st_output_switch = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Output",
|
||||
.info = st_output_switch_info,
|
||||
.get = st_output_switch_get,
|
||||
.put = st_output_switch_put,
|
||||
};
|
||||
|
||||
static void xonar_line_mic_ac97_switch(struct oxygen *chip,
|
||||
unsigned int reg, unsigned int mute)
|
||||
{
|
||||
|
@ -745,8 +903,8 @@ static void xonar_line_mic_ac97_switch(struct oxygen *chip,
|
|||
}
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
|
||||
|
||||
static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
|
||||
{
|
||||
|
@ -763,6 +921,15 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_st_control_filter(struct snd_kcontrol_new *template)
|
||||
{
|
||||
if (!strncmp(template->name, "CD Capture ", 11))
|
||||
return 1; /* no CD input */
|
||||
if (!strcmp(template->name, "Stereo Upmixing"))
|
||||
return 1; /* stereo only - we don't need upmixing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_d2_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
|
||||
|
@ -773,51 +940,14 @@ 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 int xonar_st_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
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;
|
||||
return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip));
|
||||
}
|
||||
|
||||
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,
|
||||
.mixer_init = xonar_d2_mixer_init,
|
||||
|
@ -837,8 +967,8 @@ static const struct oxygen_model model_xonar_d2 = {
|
|||
MIDI_OUTPUT |
|
||||
MIDI_INPUT,
|
||||
.dac_channels = 8,
|
||||
.dac_volume_min = 0x0f,
|
||||
.dac_volume_max = 0xff,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.misc_flags = OXYGEN_MISC_MIDI,
|
||||
.function_flags = OXYGEN_FUNCTION_SPI |
|
||||
OXYGEN_FUNCTION_ENABLE_SPI_4_5,
|
||||
|
@ -849,8 +979,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,
|
||||
.mixer_init = xonar_d1_mixer_init,
|
||||
|
@ -868,7 +996,7 @@ static const struct oxygen_model model_xonar_d1 = {
|
|||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2,
|
||||
.dac_channels = 8,
|
||||
.dac_volume_min = 0,
|
||||
.dac_volume_min = 127 - 60,
|
||||
.dac_volume_max = 127,
|
||||
.function_flags = OXYGEN_FUNCTION_2WIRE,
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
|
@ -878,8 +1006,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,
|
||||
.suspend = xonar_hdav_suspend,
|
||||
|
@ -897,16 +1023,43 @@ static const struct oxygen_model model_xonar_hdav = {
|
|||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2,
|
||||
.dac_channels = 8,
|
||||
.dac_volume_min = 0x0f,
|
||||
.dac_volume_max = 0xff,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.misc_flags = OXYGEN_MISC_MIDI,
|
||||
.function_flags = OXYGEN_FUNCTION_2WIRE,
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
||||
static int __devinit xonar_probe(struct pci_dev *pci,
|
||||
const struct pci_device_id *pci_id)
|
||||
static const struct oxygen_model model_xonar_st = {
|
||||
.longname = "Asus Virtuoso 100",
|
||||
.chip = "AV200",
|
||||
.init = xonar_stx_init,
|
||||
.control_filter = xonar_st_control_filter,
|
||||
.mixer_init = xonar_st_mixer_init,
|
||||
.cleanup = xonar_st_cleanup,
|
||||
.suspend = xonar_st_suspend,
|
||||
.resume = xonar_st_resume,
|
||||
.set_dac_params = set_pcm1796_params,
|
||||
.set_adc_params = set_cs53x1_params,
|
||||
.update_dac_volume = update_pcm1796_volume,
|
||||
.update_dac_mute = update_pcm1796_mute,
|
||||
.ac97_switch = xonar_line_mic_ac97_switch,
|
||||
.dac_tlv = pcm1796_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_data),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2,
|
||||
.dac_channels = 2,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.function_flags = OXYGEN_FUNCTION_2WIRE,
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
||||
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,
|
||||
|
@ -914,7 +1067,57 @@ static int __devinit xonar_probe(struct pci_dev *pci,
|
|||
[MODEL_D2] = &model_xonar_d2,
|
||||
[MODEL_D2X] = &model_xonar_d2,
|
||||
[MODEL_HDAV] = &model_xonar_hdav,
|
||||
[MODEL_STX] = &model_xonar_st,
|
||||
};
|
||||
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",
|
||||
[MODEL_STX] = "Xonar Essence STX",
|
||||
};
|
||||
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;
|
||||
case MODEL_STX:
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_HDAV_DB_MASK);
|
||||
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;
|
||||
|
||||
|
@ -924,10 +1127,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],
|
||||
models[pci_id->driver_data],
|
||||
pci_id->driver_data);
|
||||
err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
|
||||
xonar_ids, get_xonar_model);
|
||||
if (err >= 0)
|
||||
++dev;
|
||||
return err;
|
||||
|
|
Загрузка…
Ссылка в новой задаче