diff options
Diffstat (limited to 'sound/pci')
68 files changed, 3067 insertions, 1037 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 3020ca2b602b..278319bbdea1 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/ac97_codec.h> @@ -149,7 +150,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x49544561, 0xffffffff, "IT2646E", patch_it2646, NULL }, { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, -{ 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, +{ 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, @@ -191,9 +192,6 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { static int snd_ac97_valid_reg(struct snd_ac97 *ac97, unsigned short reg) { - if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed)) - return 0; - /* filter some registers for buggy codecs */ switch (ac97->id) { case AC97_ID_AK4540: @@ -296,11 +294,11 @@ void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned sh { if (!snd_ac97_valid_reg(ac97, reg)) return; - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); ac97->regs[reg] = value; ac97->bus->ops->write(ac97, reg, value); set_bit(reg, ac97->reg_accessed); - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); } /** @@ -321,14 +319,14 @@ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short va if (!snd_ac97_valid_reg(ac97, reg)) return -EINVAL; - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); change = ac97->regs[reg] != value; if (change) { ac97->regs[reg] = value; ac97->bus->ops->write(ac97, reg, value); } set_bit(reg, ac97->reg_accessed); - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); return change; } @@ -351,9 +349,9 @@ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned sho if (!snd_ac97_valid_reg(ac97, reg)) return -EINVAL; - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); change = snd_ac97_update_bits_nolock(ac97, reg, mask, value); - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); return change; } @@ -380,12 +378,12 @@ static int snd_ac97_ad18xx_update_pcm_bits(struct snd_ac97 *ac97, int codec, uns int change; unsigned short old, new, cfg; - down(&ac97->page_mutex); + mutex_lock(&ac97->page_mutex); old = ac97->spec.ad18xx.pcmreg[codec]; new = (old & ~mask) | value; change = old != new; if (change) { - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG); ac97->spec.ad18xx.pcmreg[codec] = new; /* select single codec */ @@ -397,9 +395,9 @@ static int snd_ac97_ad18xx_update_pcm_bits(struct snd_ac97 *ac97, int codec, uns /* select all codecs */ ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG, cfg | 0x7000); - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); } - up(&ac97->page_mutex); + mutex_unlock(&ac97->page_mutex); return change; } @@ -467,7 +465,7 @@ static int snd_ac97_page_save(struct snd_ac97 *ac97, int reg, struct snd_kcontro (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 && (reg >= 0x60 && reg < 0x70)) { unsigned short page = (kcontrol->private_value >> 26) & 0x0f; - down(&ac97->page_mutex); /* lock paging */ + mutex_lock(&ac97->page_mutex); /* lock paging */ page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK; snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page); } @@ -478,7 +476,7 @@ static void snd_ac97_page_restore(struct snd_ac97 *ac97, int page_save) { if (page_save >= 0) { snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save); - up(&ac97->page_mutex); /* unlock paging */ + mutex_unlock(&ac97->page_mutex); /* unlock paging */ } } @@ -674,12 +672,12 @@ static int snd_ac97_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); ucontrol->value.iec958.status[0] = ac97->spdif_status & 0xff; ucontrol->value.iec958.status[1] = (ac97->spdif_status >> 8) & 0xff; ucontrol->value.iec958.status[2] = (ac97->spdif_status >> 16) & 0xff; ucontrol->value.iec958.status[3] = (ac97->spdif_status >> 24) & 0xff; - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); return 0; } @@ -718,7 +716,7 @@ static int snd_ac97_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ } } - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); change = ac97->spdif_status != new; ac97->spdif_status = new; @@ -746,7 +744,7 @@ static int snd_ac97_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ } } - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); return change; } @@ -763,7 +761,7 @@ static int snd_ac97_put_spsa(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ value = (ucontrol->value.integer.value[0] & mask); - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); mask <<= shift; value <<= shift; old = snd_ac97_read_cache(ac97, reg); @@ -777,7 +775,7 @@ static int snd_ac97_put_spsa(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ if (extst & AC97_EA_SPDIF) snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ } - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); return change; } @@ -888,10 +886,10 @@ static int snd_ac97_ad18xx_pcm_get_volume(struct snd_kcontrol *kcontrol, struct struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; - down(&ac97->page_mutex); + mutex_lock(&ac97->page_mutex); ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); - up(&ac97->page_mutex); + mutex_unlock(&ac97->page_mutex); return 0; } @@ -1007,9 +1005,6 @@ static int snd_ac97_try_volume_mix(struct snd_ac97 * ac97, int reg) break; } - if (ac97->limited_regs && test_bit(reg, ac97->reg_accessed)) - return 1; /* allow without check */ - val = snd_ac97_read(ac97, reg); if (!(val & mask)) { /* nothing seems to be here - mute flag is not set */ @@ -1029,6 +1024,18 @@ static void check_volume_resolution(struct snd_ac97 *ac97, int reg, unsigned cha unsigned char max[3] = { 63, 31, 15 }; int i; + /* first look up the static resolution table */ + if (ac97->res_table) { + const struct snd_ac97_res_table *tbl; + for (tbl = ac97->res_table; tbl->reg; tbl++) { + if (tbl->reg == reg) { + *lo_max = tbl->bits & 0xff; + *hi_max = (tbl->bits >> 8) & 0xff; + return; + } + } + } + *lo_max = *hi_max = 0; for (i = 0 ; i < ARRAY_SIZE(cbit); i++) { unsigned short val; @@ -1853,11 +1860,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, ac97->num = template->num; ac97->addr = template->addr; ac97->scaps = template->scaps; - ac97->limited_regs = template->limited_regs; - memcpy(ac97->reg_accessed, template->reg_accessed, sizeof(ac97->reg_accessed)); + ac97->res_table = template->res_table; bus->codec[ac97->num] = ac97; - init_MUTEX(&ac97->reg_mutex); - init_MUTEX(&ac97->page_mutex); + mutex_init(&ac97->reg_mutex); + mutex_init(&ac97->page_mutex); #ifdef CONFIG_PCI if (ac97->pci) { diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index a444a78c7c94..4d9cf37300f7 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -27,6 +27,8 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/pcm.h> #include <sound/control.h> @@ -55,12 +57,12 @@ static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsi unsigned short page_save; int ret; - down(&ac97->page_mutex); + mutex_lock(&ac97->page_mutex); page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK; snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page); ret = snd_ac97_update_bits(ac97, reg, mask, value); snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save); - up(&ac97->page_mutex); /* unlock paging */ + mutex_unlock(&ac97->page_mutex); /* unlock paging */ return ret; } @@ -897,12 +899,12 @@ static int snd_ac97_stac9708_put_bias(struct snd_kcontrol *kcontrol, struct snd_ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); int err; - down(&ac97->page_mutex); + mutex_lock(&ac97->page_mutex); snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0xabba); err = snd_ac97_update_bits(ac97, AC97_SIGMATEL_BIAS2, 0x0010, (ucontrol->value.integer.value[0] & 1) << 4); snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0); - up(&ac97->page_mutex); + mutex_unlock(&ac97->page_mutex); return err; } @@ -2823,3 +2825,33 @@ int mpatch_si3036(struct snd_ac97 * ac97) snd_ac97_write_cache(ac97, 0x68, 0); return 0; } + +/* + * LM 4550 Codec + * + * We use a static resolution table since LM4550 codec cannot be + * properly autoprobed to determine the resolution via + * check_volume_resolution(). + */ + +static struct snd_ac97_res_table lm4550_restbl[] = { + { AC97_MASTER, 0x1f1f }, + { AC97_HEADPHONE, 0x1f1f }, + { AC97_MASTER_MONO, 0x001f }, + { AC97_PC_BEEP, 0x001f }, /* LSB is ignored */ + { AC97_PHONE, 0x001f }, + { AC97_MIC, 0x001f }, + { AC97_LINE, 0x1f1f }, + { AC97_CD, 0x1f1f }, + { AC97_VIDEO, 0x1f1f }, + { AC97_AUX, 0x1f1f }, + { AC97_PCM, 0x1f1f }, + { AC97_REC_GAIN, 0x0f0f }, + { } /* terminator */ +}; + +int patch_lm4550(struct snd_ac97 *ac97) +{ + ac97->res_table = lm4550_restbl; + return 0; +} diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 5060cb6f2ec3..adcaa04586cb 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -59,3 +59,4 @@ int patch_vt1616(struct snd_ac97 * ac97); int patch_vt1617a(struct snd_ac97 * ac97); int patch_it2646(struct snd_ac97 * ac97); int mpatch_si3036(struct snd_ac97 * ac97); +int patch_lm4550(struct snd_ac97 * ac97); diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index c3e590bf7a02..512a3583b0ce 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -27,6 +27,8 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/pcm.h> #include <sound/control.h> @@ -206,7 +208,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate) mask = AC97_SC_SPSR_MASK; } - down(&ac97->reg_mutex); + mutex_lock(&ac97->reg_mutex); old = snd_ac97_read(ac97, reg) & mask; if (old != bits) { snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); @@ -231,7 +233,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate) ac97->spdif_status = sbits; } snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); - up(&ac97->reg_mutex); + mutex_unlock(&ac97->reg_mutex); return 0; } diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 7134b3f55fb5..4d523df79cc7 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -24,6 +24,8 @@ #include <sound/driver.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/ac97_codec.h> #include <sound/asoundef.h> @@ -338,7 +340,7 @@ static void snd_ac97_proc_read(struct snd_info_entry *entry, struct snd_info_buf { struct snd_ac97 *ac97 = entry->private_data; - down(&ac97->page_mutex); + mutex_lock(&ac97->page_mutex); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; for (idx = 0; idx < 3; idx++) @@ -364,7 +366,7 @@ static void snd_ac97_proc_read(struct snd_info_entry *entry, struct snd_info_buf } else { snd_ac97_proc_read_main(ac97, buffer, 0); } - up(&ac97->page_mutex); + mutex_unlock(&ac97->page_mutex); } #ifdef CONFIG_SND_DEBUG @@ -374,7 +376,7 @@ static void snd_ac97_proc_regs_write(struct snd_info_entry *entry, struct snd_in struct snd_ac97 *ac97 = entry->private_data; char line[64]; unsigned int reg, val; - down(&ac97->page_mutex); + mutex_lock(&ac97->page_mutex); while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; @@ -382,7 +384,7 @@ static void snd_ac97_proc_regs_write(struct snd_info_entry *entry, struct snd_in if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff) snd_ac97_write_cache(ac97, reg, val); } - up(&ac97->page_mutex); + mutex_unlock(&ac97->page_mutex); } #endif @@ -401,7 +403,7 @@ static void snd_ac97_proc_regs_read(struct snd_info_entry *entry, { struct snd_ac97 *ac97 = entry->private_data; - down(&ac97->page_mutex); + mutex_lock(&ac97->page_mutex); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; @@ -417,7 +419,7 @@ static void snd_ac97_proc_regs_read(struct snd_info_entry *entry, } else { snd_ac97_proc_regs_read_main(ac97, buffer, 0); } - up(&ac97->page_mutex); + mutex_unlock(&ac97->page_mutex); } void snd_ac97_proc_init(struct snd_ac97 * ac97) diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index dcfb5036ff8b..0fb7b3407312 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c @@ -23,6 +23,8 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/ak4531_codec.h> @@ -82,9 +84,9 @@ static int snd_ak4531_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e int invert = (kcontrol->private_value >> 22) & 1; int val; - down(&ak4531->reg_mutex); + mutex_lock(&ak4531->reg_mutex); val = (ak4531->regs[reg] >> shift) & mask; - up(&ak4531->reg_mutex); + mutex_unlock(&ak4531->reg_mutex); if (invert) { val = mask - val; } @@ -107,11 +109,11 @@ static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e val = mask - val; } val <<= shift; - down(&ak4531->reg_mutex); + mutex_lock(&ak4531->reg_mutex); val = (ak4531->regs[reg] & ~(mask << shift)) | val; change = val != ak4531->regs[reg]; ak4531->write(ak4531, reg, ak4531->regs[reg] = val); - up(&ak4531->reg_mutex); + mutex_unlock(&ak4531->reg_mutex); return change; } @@ -143,10 +145,10 @@ static int snd_ak4531_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e int invert = (kcontrol->private_value >> 22) & 1; int left, right; - down(&ak4531->reg_mutex); + mutex_lock(&ak4531->reg_mutex); left = (ak4531->regs[left_reg] >> left_shift) & mask; right = (ak4531->regs[right_reg] >> right_shift) & mask; - up(&ak4531->reg_mutex); + mutex_unlock(&ak4531->reg_mutex); if (invert) { left = mask - left; right = mask - right; @@ -176,7 +178,7 @@ static int snd_ak4531_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e } left <<= left_shift; right <<= right_shift; - down(&ak4531->reg_mutex); + mutex_lock(&ak4531->reg_mutex); if (left_reg == right_reg) { left = (ak4531->regs[left_reg] & ~((mask << left_shift) | (mask << right_shift))) | left | right; change = left != ak4531->regs[left_reg]; @@ -188,7 +190,7 @@ static int snd_ak4531_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e ak4531->write(ak4531, left_reg, ak4531->regs[left_reg] = left); ak4531->write(ak4531, right_reg, ak4531->regs[right_reg] = right); } - up(&ak4531->reg_mutex); + mutex_unlock(&ak4531->reg_mutex); return change; } @@ -215,12 +217,12 @@ static int snd_ak4531_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl int left_shift = (kcontrol->private_value >> 16) & 0x0f; int right_shift = (kcontrol->private_value >> 24) & 0x0f; - down(&ak4531->reg_mutex); + mutex_lock(&ak4531->reg_mutex); ucontrol->value.integer.value[0] = (ak4531->regs[reg1] >> left_shift) & 1; ucontrol->value.integer.value[1] = (ak4531->regs[reg2] >> left_shift) & 1; ucontrol->value.integer.value[2] = (ak4531->regs[reg1] >> right_shift) & 1; ucontrol->value.integer.value[3] = (ak4531->regs[reg2] >> right_shift) & 1; - up(&ak4531->reg_mutex); + mutex_unlock(&ak4531->reg_mutex); return 0; } @@ -234,7 +236,7 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl int change; int val1, val2; - down(&ak4531->reg_mutex); + mutex_lock(&ak4531->reg_mutex); val1 = ak4531->regs[reg1] & ~((1 << left_shift) | (1 << right_shift)); val2 = ak4531->regs[reg2] & ~((1 << left_shift) | (1 << right_shift)); val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; @@ -244,7 +246,7 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl change = val1 != ak4531->regs[reg1] || val2 != ak4531->regs[reg2]; ak4531->write(ak4531, reg1, ak4531->regs[reg1] = val1); ak4531->write(ak4531, reg2, ak4531->regs[reg2] = val2); - up(&ak4531->reg_mutex); + mutex_unlock(&ak4531->reg_mutex); return change; } @@ -366,7 +368,7 @@ int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531, if (ak4531 == NULL) return -ENOMEM; *ak4531 = *_ak4531; - init_MUTEX(&ak4531->reg_mutex); + mutex_init(&ak4531->reg_mutex); if ((err = snd_component_add(card, "AK4531")) < 0) { snd_ak4531_free(ak4531); return err; diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index a208075cdc1e..2aa5a7fdb6e0 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -34,6 +34,7 @@ #include <linux/init.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/compiler.h> @@ -909,10 +910,10 @@ snd_ad1889_create(struct snd_card *card, if ((err = pci_enable_device(pci)) < 0) return err; - + /* check PCI availability (32bit DMA) */ - if (pci_set_dma_mask(pci, 0xffffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0xffffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n"); pci_disable_device(pci); return -ENXIO; diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index b7217adaf1d7..12e618851262 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -27,6 +27,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -277,7 +278,7 @@ struct atiixp { unsigned int codec_not_ready_bits; /* for codec detection */ int spdif_over_aclink; /* passed from the module option */ - struct semaphore open_mutex; /* playback open mutex */ + struct mutex open_mutex; /* playback open mutex */ }; @@ -1051,9 +1052,9 @@ static int snd_atiixp_playback_open(struct snd_pcm_substream *substream) struct atiixp *chip = snd_pcm_substream_chip(substream); int err; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); if (err < 0) return err; substream->runtime->hw.channels_max = chip->max_channels; @@ -1068,9 +1069,9 @@ static int snd_atiixp_playback_close(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); int err; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return err; } @@ -1090,12 +1091,12 @@ static int snd_atiixp_spdif_open(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); int err; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */ err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2); else err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return err; } @@ -1103,12 +1104,12 @@ static int snd_atiixp_spdif_close(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); int err; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); if (chip->spdif_over_aclink) err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); else err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return err; } @@ -1560,7 +1561,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } spin_lock_init(&chip->reg_lock); - init_MUTEX(&chip->open_mutex); + mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 8d8fd5a4ed35..1d3766044643 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -27,6 +27,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -255,7 +256,7 @@ struct atiixp_modem { unsigned int codec_not_ready_bits; /* for codec detection */ int spdif_over_aclink; /* passed from the module option */ - struct semaphore open_mutex; /* playback open mutex */ + struct mutex open_mutex; /* playback open mutex */ }; @@ -911,9 +912,9 @@ static int snd_atiixp_playback_open(struct snd_pcm_substream *substream) struct atiixp_modem *chip = snd_pcm_substream_chip(substream); int err; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); if (err < 0) return err; return 0; @@ -923,9 +924,9 @@ static int snd_atiixp_playback_close(struct snd_pcm_substream *substream) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); int err; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return err; } @@ -1233,7 +1234,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } spin_lock_init(&chip->reg_lock); - init_MUTEX(&chip->open_mutex); + mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 7d9184f7367a..126870ec063a 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -151,14 +151,18 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) // check PCI availability (DMA). if ((err = pci_enable_device(pci)) < 0) return err; - if (pci_set_dma_mask(pci, DMA_32BIT_MASK)) { + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set DMA mask\n"); + pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } chip->card = card; @@ -208,6 +212,8 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) goto alloc_out; } + snd_card_set_dev(card, &pci->dev); + *rchip = chip; return 0; diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index c2ad2674bea7..d65ccb1866a0 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -39,8 +39,8 @@ #include "au88x0_wt.h" #endif -#define hwread(x,y) readl((x)+((y)>>2)) -#define hwwrite(x,y,z) writel((z),(x)+((y)>>2)) +#define hwread(x,y) readl((x)+(y)) +#define hwwrite(x,y,z) writel((z),(x)+(y)) /* Vortex MPU401 defines. */ #define MIDI_CLOCK_DIV 0x61 @@ -113,7 +113,7 @@ typedef struct { //int this_08; /* Still unknown */ int fifo_enabled; /* this_24 */ int fifo_status; /* this_1c */ - int dma_ctrl; /* this_78 (ADB), this_7c (WT) */ + u32 dma_ctrl; /* this_78 (ADB), this_7c (WT) */ int dma_unknown; /* this_74 (ADB), this_78 (WT). WDM: +8 */ int cfg0; int cfg1; @@ -178,7 +178,7 @@ struct snd_vortex { /* PCI hardware resources */ unsigned long io; - unsigned long __iomem *mmio; + void __iomem *mmio; unsigned int irq; spinlock_t lock; @@ -201,14 +201,14 @@ static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, int count); static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir, int fmt, int d, - unsigned long offset); + u32 offset); static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb); #ifndef CHIP_AU8810 static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma, struct snd_sg_buf * sgbuf, int size, int count); static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, /*int e, */ - unsigned long offset); + u32 offset); static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb); #endif diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index e3394fe63253..9cac02e93b25 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -376,7 +376,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) static void vortex_mixer_init(vortex_t * vortex) { - unsigned long addr; + u32 addr; int x; // FIXME: get rid of this crap. @@ -639,7 +639,7 @@ static void vortex_src_setupchannel(vortex_t * card, unsigned char src, static void vortex_srcblock_init(vortex_t * vortex) { - unsigned long addr; + u32 addr; int x; hwwrite(vortex->mmio, VORTEX_SRC_SOURCESIZE, 0x1ff); /* @@ -1035,7 +1035,7 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority, static void vortex_fifo_init(vortex_t * vortex) { int x; - unsigned long addr; + u32 addr; /* ADB DMA channels fifos. */ addr = VORTEX_FIFO_ADBCTRL + ((NR_ADB - 1) * 4); @@ -1054,7 +1054,7 @@ static void vortex_fifo_init(vortex_t * vortex) hwwrite(vortex->mmio, addr, FIFO_U0); if (hwread(vortex->mmio, addr) != FIFO_U0) printk(KERN_ERR - "bad wt fifo reset (0x%08lx, 0x%08x)!\n", + "bad wt fifo reset (0x%08x, 0x%08x)!\n", addr, hwread(vortex->mmio, addr)); vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE); addr -= 4; @@ -1152,7 +1152,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir, - int fmt, int d, unsigned long offset) + int fmt, int d, u32 offset) { stream_t *dma = &vortex->dma_adb[adbdma]; @@ -1411,7 +1411,7 @@ vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma, static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, - /*int e, */ unsigned long offset) + /*int e, */ u32 offset) { stream_t *dma = &vortex->dma_wt[wtdma]; diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index c8280f82eb5a..64fbfbbaf816 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -377,23 +377,23 @@ static void vortex_EqHw_GetLevels(vortex_t * vortex, u16 a[]) #endif /* Global Control */ -static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg) +static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg) { hwwrite(vortex->mmio, 0x2b440, reg); } -static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr) +static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr) { hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800); } #if 0 -static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg) +static void vortex_EqHw_GetControlReg(vortex_t * vortex, u32 *reg) { *reg = hwread(vortex->mmio, 0x2b440); } -static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr) +static void vortex_EqHw_GetSampleRate(vortex_t * vortex, u32 *sr) { *sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f; } @@ -554,7 +554,7 @@ static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain) #if 0 static int -vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, unsigned long *cnt) +vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, s32 *cnt) { eqlzr_t *eq = &(vortex->eq); int si = 0; @@ -586,7 +586,7 @@ static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex) } static int -vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long count) +vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count) { eqlzr_t *eq = &(vortex->eq); int i; @@ -604,11 +604,10 @@ vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long count) } static void -vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a, - unsigned long b) +vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b) { eqlzr_t *eq = &(vortex->eq); - int eax, ebx; + u32 eax, ebx; eq->this58 = a; eq->this5c = b; @@ -624,7 +623,7 @@ vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a, static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex) { eqlzr_t *eq = &(vortex->eq); - int eax, ebx; + u32 eax, ebx; if (eq->this54) eax = eq->this0e; @@ -641,7 +640,7 @@ static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex) vortex_EqHw_ZeroA3DIO(vortex); } -static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp) +static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp) { eqlzr_t *eq = &(vortex->eq); @@ -651,8 +650,8 @@ static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp) vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08); } else { /* EQ disabled. */ - vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14)); - vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14)); + vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array); + vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array); vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c); } vortex_Eqlzr_ProgramA3dBypassGain(vortex); @@ -706,7 +705,7 @@ static void vortex_Eqlzr_init(vortex_t * vortex) eq->this5c = 0xffff; /* Set gains. */ - memset(eq->this14, 0, 2 * 10); + memset(eq->this14_array, 0, sizeof(eq->this14_array)); /* Actual init. */ vortex_EqHw_ZeroState(vortex); @@ -792,7 +791,7 @@ snd_vortex_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucon { vortex_t *vortex = snd_kcontrol_chip(kcontrol); int i = kcontrol->private_value; - u16 gainL, gainR; + u16 gainL = 0, gainR = 0; vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); vortex_Eqlzr_GetRightGain(vortex, i, &gainR); @@ -806,7 +805,7 @@ snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucon { vortex_t *vortex = snd_kcontrol_chip(kcontrol); int changed = 0, i = kcontrol->private_value; - u16 gainL, gainR; + u16 gainL = 0, gainR = 0; vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); vortex_Eqlzr_GetRightGain(vortex, i, &gainR); diff --git a/sound/pci/au88x0/au88x0_eq.h b/sound/pci/au88x0/au88x0_eq.h index e49bc625c873..474cd0046294 100644 --- a/sound/pci/au88x0/au88x0_eq.h +++ b/sound/pci/au88x0/au88x0_eq.h @@ -13,31 +13,28 @@ typedef struct { u16 LeftCoefs[50]; //0x4 u16 RightCoefs[50]; // 0x68 - u16 LeftGains[20]; //0xd0 - u16 RightGains[20]; //0xe4 + u16 LeftGains[10]; //0xd0 + u16 RightGains[10]; //0xe4 } auxxEqCoeffSet_t; typedef struct { - unsigned int *this00; /*CAsp4HwIO */ - long this04; /* How many filters for each side (default = 10) */ - long this08; /* inited to cero. Stereo flag? */ + s32 this04; /* How many filters for each side (default = 10) */ + s32 this08; /* inited to cero. Stereo flag? */ } eqhw_t; typedef struct { - unsigned int *this00; /*CAsp4Core */ eqhw_t this04; /* CHwEq */ - short this08; /* Bad codec flag ? SetBypassGain: bypass gain */ - short this0a; - short this0c; /* SetBypassGain: bypass gain when this28 is not set. */ - short this0e; + u16 this08; /* Bad codec flag ? SetBypassGain: bypass gain */ + u16 this0a; + u16 this0c; /* SetBypassGain: bypass gain when this28 is not set. */ + u16 this0e; - long this10; /* How many gains are used for each side (right or left). */ - u16 this14[32]; /* SetLeftGainsTarget: Left (and right?) EQ gains */ - long this24; - long this28; /* flag related to EQ enabled or not. Gang flag ? */ - long this54; /* SetBypass */ - long this58; - long this5c; + s32 this10; /* How many gains are used for each side (right or left). */ + u16 this14_array[10]; /* SetLeftGainsTarget: Left (and right?) EQ gains */ + s32 this28; /* flag related to EQ enabled or not. Gang flag ? */ + s32 this54; /* SetBypass */ + s32 this58; + s32 this5c; /*0x60 */ auxxEqCoeffSet_t coefset; /* 50 u16 word each channel. */ u16 this130[20]; /* Left and Right gains */ diff --git a/sound/pci/au88x0/au88x0_eqdata.c b/sound/pci/au88x0/au88x0_eqdata.c index abf8d6ac4c15..ce8dca8ce1e2 100644 --- a/sound/pci/au88x0/au88x0_eqdata.c +++ b/sound/pci/au88x0/au88x0_eqdata.c @@ -104,7 +104,11 @@ static u16 asEqOutStateZeros[48] = { }; /*_rodataba0:*/ -static long eq_levels[32] = { +static u16 eq_levels[64] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 8ba6dd36222b..873f486b07b8 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c @@ -95,7 +95,7 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) return temp; } #else - port = (unsigned long)(vortex->mmio + (VORTEX_MIDI_DATA >> 2)); + port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); if ((temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, 1, 0, 0, &rmidi)) != 0) { @@ -105,7 +105,7 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) return temp; } mpu = rmidi->private_data; - mpu->cport = (unsigned long)(vortex->mmio + (VORTEX_MIDI_CMD >> 2)); + mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD); #endif vortex->rmidi = rmidi; return 0; diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index 65f375bad43a..d3e662a1285d 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -32,7 +32,7 @@ static void vortex_connection_mixin_mix(vortex_t * vortex, int en, unsigned char mix, int a); static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j); static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, - unsigned long val); + u32 val); /* WT */ @@ -166,7 +166,7 @@ static int vortex_wt_GetReg(vortex_t * vortex, char reg, int wt) /* WT hardware abstraction layer generic register interface. */ static int vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt, - unsigned short val) + u16 val) { /* int eax, edx; @@ -190,7 +190,7 @@ vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt, #endif static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, - unsigned long val) + u32 val) { int ecx; @@ -279,7 +279,7 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, static void vortex_wt_init(vortex_t * vortex) { - int var4, var8, varc, var10 = 0, edi; + u32 var4, var8, varc, var10 = 0, edi; var10 &= 0xFFFFFFE3; var10 |= 0x22; @@ -353,7 +353,7 @@ static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[]) static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr) { wt_voice_t *voice = &(vortex->wt_voice[wt]); - long int eax, edx; + u32 eax, edx; //FIXME: 64 bit operation. eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff; diff --git a/sound/pci/au88x0/au88x0_wt.h b/sound/pci/au88x0/au88x0_wt.h index d536c88b43bf..38d98f88a95c 100644 --- a/sound/pci/au88x0/au88x0_wt.h +++ b/sound/pci/au88x0/au88x0_wt.h @@ -53,11 +53,11 @@ enum { #endif typedef struct { - unsigned int parm0; /* this_1E4 */ - unsigned int parm1; /* this_1E8 */ - unsigned int parm2; /* this_1EC */ - unsigned int parm3; /* this_1F0 */ - unsigned int this_1D0; + u32 parm0; /* this_1E4 */ + u32 parm1; /* this_1E8 */ + u32 parm2; /* this_1EC */ + u32 parm3; /* this_1F0 */ + u32 this_1D0; } wt_voice_t; #endif /* _AU88X0_WT_H */ diff --git a/sound/pci/au88x0/au88x0_xtalk.c b/sound/pci/au88x0/au88x0_xtalk.c index df915fa3f88d..4534e1882ada 100644 --- a/sound/pci/au88x0/au88x0_xtalk.c +++ b/sound/pci/au88x0/au88x0_xtalk.c @@ -562,7 +562,7 @@ static void vortex_XtalkHw_SetDelay(vortex_t * vortex, unsigned short right, unsigned short left) { - int esp0 = 0; + u32 esp0 = 0; esp0 &= 0x1FFFFFFF; esp0 |= 0xA0000000; @@ -632,18 +632,18 @@ static void vortex_XtalkHw_GetRightDline(vortex_t * vortex, xtalk_dline_t dline) /* Control/Global stuff */ #if 0 -static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, unsigned long ctrl) +static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, u32 ctrl) { hwwrite(vortex->mmio, 0x24660, ctrl); } -static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, unsigned long *ctrl) +static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, u32 *ctrl) { *ctrl = hwread(vortex->mmio, 0x24660); } #endif -static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr) +static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr) { - int temp; + u32 temp; temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000; temp = (temp & 0xffffff07) | ((sr & 0x1f) << 3); @@ -651,7 +651,7 @@ static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr) } #if 0 -static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr) +static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, u32 *sr) { *sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f; } @@ -659,7 +659,7 @@ static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr) #endif static void vortex_XtalkHw_Enable(vortex_t * vortex) { - int temp; + u32 temp; temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000; temp |= 1; @@ -669,7 +669,7 @@ static void vortex_XtalkHw_Enable(vortex_t * vortex) static void vortex_XtalkHw_Disable(vortex_t * vortex) { - int temp; + u32 temp; temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000; temp &= 0xfffffffe; diff --git a/sound/pci/au88x0/au88x0_xtalk.h b/sound/pci/au88x0/au88x0_xtalk.h index 0b8d7b64012d..7f4534b94d00 100644 --- a/sound/pci/au88x0/au88x0_xtalk.h +++ b/sound/pci/au88x0/au88x0_xtalk.h @@ -39,16 +39,16 @@ #define XT_SPEAKER1 3 #define XT_DIAMOND 4 -typedef long xtalk_dline_t[XTDLINE_SZ]; -typedef short xtalk_gains_t[XTGAINS_SZ]; -typedef short xtalk_instate_t[XTINST_SZ]; -typedef short xtalk_coefs_t[5][5]; -typedef short xtalk_state_t[5][4]; +typedef u32 xtalk_dline_t[XTDLINE_SZ]; +typedef u16 xtalk_gains_t[XTGAINS_SZ]; +typedef u16 xtalk_instate_t[XTINST_SZ]; +typedef u16 xtalk_coefs_t[5][5]; +typedef u16 xtalk_state_t[5][4]; static void vortex_XtalkHw_SetGains(vortex_t * vortex, xtalk_gains_t const gains); static void vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex); -static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr); +static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr); static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex); static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex); static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex); diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index c840a4c08e98..7b44a8db033d 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -783,6 +783,8 @@ static struct pci_device_id snd_bt87x_ids[] = { BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100), /* AVerMedia Studio No. 103, 203, ...? */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000), + /* Leadtek Winfast tv 2000xp delux */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000), { } }; MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); @@ -793,12 +795,15 @@ static struct { unsigned short subvendor, subdevice; } blacklist[] __devinitdata = { {0x0071, 0x0101}, /* Nebula Electronics DigiTV */ + {0x11bd, 0x001c}, /* Pinnacle PCTV Sat */ {0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */ {0x1461, 0x0761}, /* AVermedia AverTV DVB-T */ {0x1461, 0x0771}, /* AVermedia DVB-T 771 */ {0x1822, 0x0001}, /* Twinhan VisionPlus DVB-T */ + {0x18ac, 0xd500}, /* DVICO FusionHDTV 5 Lite */ {0x18ac, 0xdb10}, /* DVICO FusionHDTV DVB-T Lite */ {0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */ + {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */ }; static struct pci_driver driver; @@ -816,13 +821,13 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) for (i = 0; i < ARRAY_SIZE(blacklist); ++i) if (blacklist[i].subvendor == pci->subsystem_vendor && blacklist[i].subdevice == pci->subsystem_device) { - snd_printdd(KERN_INFO "card %#04x:%#04x has no audio\n", - pci->subsystem_vendor, pci->subsystem_device); + snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n", + pci->device, pci->subsystem_vendor, pci->subsystem_device); return -EBUSY; } - snd_printk(KERN_INFO "unknown card %#04x:%#04x, using default rate 32000\n", - pci->subsystem_vendor, pci->subsystem_device); + snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x, using default rate 32000\n", + pci->device, pci->subsystem_vendor, pci->subsystem_device); snd_printk(KERN_DEBUG "please mail id, board name, and, " "if it works, the correct digital_rate option to " "<alsa-devel@lists.sf.net>\n"); diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index c03b0a0a3b27..2ecbddbbdcf0 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/gameport.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -439,7 +440,7 @@ struct cmipci { struct snd_pcm_hardware *hw_info[3]; /* for playbacks */ int opened[2]; /* open mode */ - struct semaphore open_mutex; + struct mutex open_mutex; unsigned int mixer_insensitive: 1; struct snd_kcontrol *mixer_res_ctl[CM_SAVED_MIXERS]; @@ -641,14 +642,14 @@ static int snd_cmipci_playback2_hw_params(struct snd_pcm_substream *substream, { struct cmipci *cm = snd_pcm_substream_chip(substream); if (params_channels(hw_params) > 2) { - down(&cm->open_mutex); + mutex_lock(&cm->open_mutex); if (cm->opened[CM_CH_PLAY]) { - up(&cm->open_mutex); + mutex_unlock(&cm->open_mutex); return -EBUSY; } /* reserve the channel A */ cm->opened[CM_CH_PLAY] = CM_OPEN_PLAYBACK_MULTI; - up(&cm->open_mutex); + mutex_unlock(&cm->open_mutex); } return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } @@ -1461,9 +1462,9 @@ static int open_device_check(struct cmipci *cm, int mode, struct snd_pcm_substre * pcm framework doesn't pass file pointer before actually opened, * we can't know whether blocking mode or not in open callback.. */ - down(&cm->open_mutex); + mutex_lock(&cm->open_mutex); if (cm->opened[ch]) { - up(&cm->open_mutex); + mutex_unlock(&cm->open_mutex); return -EBUSY; } cm->opened[ch] = mode; @@ -1475,7 +1476,7 @@ static int open_device_check(struct cmipci *cm, int mode, struct snd_pcm_substre snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC); spin_unlock_irq(&cm->reg_lock); } - up(&cm->open_mutex); + mutex_unlock(&cm->open_mutex); return 0; } @@ -1483,7 +1484,7 @@ static void close_device_check(struct cmipci *cm, int mode) { int ch = mode & CM_OPEN_CH_MASK; - down(&cm->open_mutex); + mutex_lock(&cm->open_mutex); if (cm->opened[ch] == mode) { if (cm->channel[ch].substream) { snd_cmipci_ch_reset(cm, ch); @@ -1499,7 +1500,7 @@ static void close_device_check(struct cmipci *cm, int mode) spin_unlock_irq(&cm->reg_lock); } } - up(&cm->open_mutex); + mutex_unlock(&cm->open_mutex); } /* @@ -1546,7 +1547,7 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) if ((err = open_device_check(cm, CM_OPEN_PLAYBACK2, substream)) < 0) /* use channel B */ return err; runtime->hw = snd_cmipci_playback2; - down(&cm->open_mutex); + mutex_lock(&cm->open_mutex); if (! cm->opened[CM_CH_PLAY]) { if (cm->can_multi_ch) { runtime->hw.channels_max = cm->max_channels; @@ -1559,7 +1560,7 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); } - up(&cm->open_mutex); + mutex_unlock(&cm->open_mutex); return 0; } @@ -2844,7 +2845,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc } spin_lock_init(&cm->reg_lock); - init_MUTEX(&cm->open_mutex); + mutex_init(&cm->open_mutex); cm->device = pci->device; cm->card = card; cm->pci = pci; diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 8fb275d6eb77..69dbf542a6de 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -53,6 +53,8 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/gameport.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/control.h> @@ -909,22 +911,22 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, #ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (sample_rate != 0, return -ENXIO); - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) { - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return -ENXIO; } snd_assert (cpcm->pcm_channel != NULL); if (!cpcm->pcm_channel) { - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return -ENXIO; } if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) { - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return -EINVAL; } @@ -965,7 +967,7 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, } if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) { #ifdef CONFIG_SND_CS46XX_NEW_DSP - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); #endif return err; } @@ -989,7 +991,7 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, } #ifdef CONFIG_SND_CS46XX_NEW_DSP - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); #endif return 0; @@ -1319,7 +1321,7 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in cpcm->substream = substream; #ifdef CONFIG_SND_CS46XX_NEW_DSP - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); cpcm->pcm_channel = NULL; cpcm->pcm_channel_id = pcm_channel_id; @@ -1328,7 +1330,7 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_sizes); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); #else chip->playback_pcm = cpcm; /* HACK */ #endif @@ -1367,9 +1369,9 @@ static int snd_cs46xx_playback_open_iec958(struct snd_pcm_substream *substream) snd_printdd("open raw iec958 channel\n"); - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); cs46xx_iec958_pre_open (chip); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL); } @@ -1385,9 +1387,9 @@ static int snd_cs46xx_playback_close_iec958(struct snd_pcm_substream *substream) err = snd_cs46xx_playback_close(substream); - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); cs46xx_iec958_post_close (chip); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return err; } @@ -1428,12 +1430,12 @@ static int snd_cs46xx_playback_close(struct snd_pcm_substream *substream) if (!cpcm) return -ENXIO; #ifdef CONFIG_SND_CS46XX_NEW_DSP - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); if (cpcm->pcm_channel) { cs46xx_dsp_destroy_pcm_channel(chip,cpcm->pcm_channel); cpcm->pcm_channel = NULL; } - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); #else chip->playback_pcm = NULL; #endif @@ -1848,7 +1850,7 @@ static int snd_cs46xx_iec958_put(struct snd_kcontrol *kcontrol, switch (kcontrol->private_value) { case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT: - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED); if (ucontrol->value.integer.value[0] && !change) cs46xx_dsp_enable_spdif_out(chip); @@ -1856,7 +1858,7 @@ static int snd_cs46xx_iec958_put(struct snd_kcontrol *kcontrol, cs46xx_dsp_disable_spdif_out(chip); res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED)); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); break; case CS46XX_MIXER_SPDIF_INPUT_ELEMENT: change = chip->dsp_spos_instance->spdif_status_in; @@ -1997,12 +1999,12 @@ static int snd_cs46xx_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); struct dsp_spos_instance * ins = chip->dsp_spos_instance; - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_default >> 24) & 0xff); ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_default >> 16) & 0xff); ucontrol->value.iec958.status[2] = 0; ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_default) & 0xff); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -2015,7 +2017,7 @@ static int snd_cs46xx_spdif_default_put(struct snd_kcontrol *kcontrol, unsigned int val; int change; - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[2]) << 16) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) | @@ -2029,7 +2031,7 @@ static int snd_cs46xx_spdif_default_put(struct snd_kcontrol *kcontrol, if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) ) cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return change; } @@ -2050,12 +2052,12 @@ static int snd_cs46xx_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); struct dsp_spos_instance * ins = chip->dsp_spos_instance; - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_stream >> 24) & 0xff); ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_stream >> 16) & 0xff); ucontrol->value.iec958.status[2] = 0; ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_stream) & 0xff); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -2068,7 +2070,7 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, unsigned int val; int change; - down (&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[1]) << 16) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) | @@ -2082,7 +2084,7 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN ) cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val); - up (&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return change; } @@ -3755,7 +3757,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card, } spin_lock_init(&chip->reg_lock); #ifdef CONFIG_SND_CS46XX_NEW_DSP - init_MUTEX(&chip->spos_mutex); + mutex_init(&chip->spos_mutex); #endif chip->card = card; chip->pci = pci; diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 445a448949e7..f407d2a5ce3b 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -28,6 +28,8 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> @@ -235,7 +237,7 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip) if (ins->symbol_table.symbols == NULL) { cs46xx_dsp_spos_destroy(chip); - return NULL; + goto error; } ins->code.offset = 0; @@ -244,7 +246,7 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip) if (ins->code.data == NULL) { cs46xx_dsp_spos_destroy(chip); - return NULL; + goto error; } ins->nscb = 0; @@ -255,7 +257,7 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip) if (ins->modules == NULL) { cs46xx_dsp_spos_destroy(chip); - return NULL; + goto error; } /* default SPDIF input sample rate @@ -278,6 +280,10 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip) /* left and right validity bits */ (1 << 13) | (1 << 12); return ins; + +error: + kfree(ins); + return NULL; } void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) @@ -287,7 +293,7 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) snd_assert(ins != NULL, return); - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; @@ -298,7 +304,7 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) vfree(ins->symbol_table.symbols); kfree(ins->modules); kfree(ins); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module) @@ -497,7 +503,7 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry, struct dsp_spos_instance * ins = chip->dsp_spos_instance; int i,j; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); snd_iprintf(buffer, "MODULES:\n"); for ( i = 0; i < ins->nmodules; ++i ) { snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name); @@ -510,7 +516,7 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry, desc->segment_type,desc->offset, desc->size); } } - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, @@ -521,7 +527,7 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, int i, j, col; void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); snd_iprintf(buffer, "TASK TREES:\n"); for ( i = 0; i < ins->ntask; ++i) { snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name); @@ -538,7 +544,7 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, } snd_iprintf(buffer,"\n"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, @@ -548,7 +554,7 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, struct dsp_spos_instance * ins = chip->dsp_spos_instance; int i; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); snd_iprintf(buffer, "SCB's:\n"); for ( i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) @@ -571,7 +577,7 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, } snd_iprintf(buffer,"\n"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry, @@ -852,14 +858,14 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) } ins->proc_scb_info_entry = entry; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); /* register/update SCB's entries on proc */ for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i)); } - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -899,12 +905,12 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) ins->proc_task_info_entry = NULL; } - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); } - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); if (ins->proc_dsp_dir) { snd_info_unregister (ins->proc_dsp_dir); @@ -1694,7 +1700,7 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL); snd_assert (ins->spdif_in_src != NULL,return -EINVAL); - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) { /* time countdown enable */ @@ -1738,7 +1744,7 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) /* monitor state */ ins->spdif_status_in = 1; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1750,7 +1756,7 @@ int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip) snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL); snd_assert (ins->spdif_in_src != NULL,return -EINVAL); - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); /* Remove the asynchronous receiver SCB */ cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb); @@ -1760,7 +1766,7 @@ int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip) /* monitor state */ ins->spdif_status_in = 0; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); /* restore amplifier */ chip->active_ctrl(chip, -1); @@ -1776,10 +1782,10 @@ int cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip) snd_assert (ins->pcm_input == NULL,return -EINVAL); snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL); - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR, "PCMSerialInput_Wave"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1790,10 +1796,10 @@ int cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip) snd_assert (ins->pcm_input != NULL,return -EINVAL); - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->pcm_input); ins->pcm_input = NULL; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1805,10 +1811,10 @@ int cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip) snd_assert (ins->adc_input == NULL,return -EINVAL); snd_assert (ins->codec_in_scb != NULL,return -EINVAL); - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR, "PCMSerialInput_ADC"); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1819,10 +1825,10 @@ int cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip) snd_assert (ins->adc_input != NULL,return -EINVAL); - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->adc_input); ins->adc_input = NULL; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1869,7 +1875,7 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right) struct dsp_spos_instance * ins = chip->dsp_spos_instance; struct dsp_scb_descriptor * scb; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); /* main output */ scb = ins->master_mix_scb->sub_list_ptr; @@ -1888,7 +1894,7 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right) ins->dac_volume_left = left; ins->dac_volume_right = right; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } @@ -1897,7 +1903,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); if (ins->asynch_rx_scb != NULL) cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb, @@ -1906,7 +1912,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right) ins->spdif_input_volume_left = left; ins->spdif_input_volume_right = right; - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); return 0; } diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index d4e0fb39bd06..2c4ee45fe10c 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -28,6 +28,8 @@ #include <linux/pm.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> @@ -77,7 +79,7 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, ins = chip->dsp_spos_instance; - down(&chip->spos_mutex); + mutex_lock(&chip->spos_mutex); snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name); for (col = 0,j = 0;j < 0x10; j++,col++) { @@ -105,7 +107,7 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, scb->task_entry->address); snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count); - up(&chip->spos_mutex); + mutex_unlock(&chip->spos_mutex); } #endif diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 02e3721030b7..9fc7f3827461 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -62,7 +62,7 @@ static void wait_till_cmd_acked(struct cs5535audio *cs5535au, unsigned long time tmp = cs_readl(cs5535au, ACC_CODEC_CNTL); if (!(tmp & CMD_NEW)) break; - msleep(10); + udelay(1); } while (--timeout); if (!timeout) snd_printk(KERN_ERR "Failure writing to cs5535 codec\n"); @@ -80,14 +80,14 @@ static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au, regdata |= CMD_NEW; cs_writel(cs5535au, ACC_CODEC_CNTL, regdata); - wait_till_cmd_acked(cs5535au, 500); + wait_till_cmd_acked(cs5535au, 50); timeout = 50; do { val = cs_readl(cs5535au, ACC_CODEC_STATUS); if ((val & STS_NEW) && reg == (val >> 24)) break; - msleep(10); + udelay(1); } while (--timeout); if (!timeout) snd_printk(KERN_ERR "Failure reading cs5535 codec\n"); diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 3c7043b7d4c9..31cb9b48bb59 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -36,6 +36,8 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/emu10k1.h> @@ -775,6 +777,14 @@ static int snd_emu10k1_dev_free(struct snd_device *device) static struct snd_emu_chip_details emu_chip_details[] = { /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ + /* Audigy4 SB0400 */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, + .driver = "Audigy2", .name = "Audigy 4 [SB0400]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0108_chip = 1, + .spk71 = 1, + .ac97_chip = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ /* DSP: CA0108-IAT * DAC: CS4382-KQ @@ -1097,8 +1107,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, spin_lock_init(&emu->voice_lock); spin_lock_init(&emu->synth_lock); spin_lock_init(&emu->memblk_lock); - init_MUTEX(&emu->ptb_lock); - init_MUTEX(&emu->fx8010.lock); + mutex_init(&emu->fx8010.lock); INIT_LIST_HEAD(&emu->mapped_link_head); INIT_LIST_HEAD(&emu->mapped_order_link_head); emu->pci = pci; diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 1fa393f22a99..204995a1dfbd 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c @@ -62,7 +62,6 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) { snd_emux_free(emu); - emu->hw = NULL; return -ENOMEM; } diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1107c8ec7f78..2208dbd48be9 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -33,6 +33,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> @@ -893,24 +894,24 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card, static struct snd_device_ops ops = { .dev_free = snd_emu10k1x_dev_free, }; - + *rchip = NULL; - + if ((err = pci_enable_device(pci)) < 0) return err; - if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { snd_printk(KERN_ERR "error to set 28bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } - + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } - + chip->card = card; chip->pci = pci; chip->irq = -1; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 509837252735..dfba00230d4d 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -32,6 +32,8 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/init.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/emu10k1.h> @@ -874,7 +876,7 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu, { int err = 0; - down(&emu->fx8010.lock); + mutex_lock(&emu->fx8010.lock); if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0) goto __error; strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); @@ -897,7 +899,7 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu, else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg); __error: - up(&emu->fx8010.lock); + mutex_unlock(&emu->fx8010.lock); return err; } @@ -906,7 +908,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu, { int err; - down(&emu->fx8010.lock); + mutex_lock(&emu->fx8010.lock); strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name)); /* ok, do the main job */ err = snd_emu10k1_gpr_peek(emu, icode); @@ -916,7 +918,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu, err = snd_emu10k1_code_peek(emu, icode); if (err >= 0) err = snd_emu10k1_list_controls(emu, icode); - up(&emu->fx8010.lock); + mutex_unlock(&emu->fx8010.lock); return err; } @@ -932,7 +934,7 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu, if (ipcm->channels > 32) return -EINVAL; pcm = &emu->fx8010.pcm[ipcm->substream]; - down(&emu->fx8010.lock); + mutex_lock(&emu->fx8010.lock); spin_lock_irq(&emu->reg_lock); if (pcm->opened) { err = -EBUSY; @@ -962,7 +964,7 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu, } __error: spin_unlock_irq(&emu->reg_lock); - up(&emu->fx8010.lock); + mutex_unlock(&emu->fx8010.lock); return err; } @@ -976,7 +978,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT) return -EINVAL; pcm = &emu->fx8010.pcm[ipcm->substream]; - down(&emu->fx8010.lock); + mutex_lock(&emu->fx8010.lock); spin_lock_irq(&emu->reg_lock); ipcm->channels = pcm->channels; ipcm->tram_start = pcm->tram_start; @@ -992,7 +994,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, ipcm->res1 = ipcm->res2 = 0; ipcm->pad = 0; spin_unlock_irq(&emu->reg_lock); - up(&emu->fx8010.lock); + mutex_unlock(&emu->fx8010.lock); return err; } @@ -2308,9 +2310,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un return -EPERM; if (get_user(addr, (unsigned int __user *)argp)) return -EFAULT; - down(&emu->fx8010.lock); + mutex_lock(&emu->fx8010.lock); res = snd_emu10k1_fx8010_tram_setup(emu, addr); - up(&emu->fx8010.lock); + mutex_unlock(&emu->fx8010.lock); return res; case SNDRV_EMU10K1_IOCTL_STOP: if (!capable(CAP_SYS_ADMIN)) diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 68c795c03109..e7ec98649f04 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -24,6 +24,8 @@ #include <sound/driver.h> #include <linux/pci.h> #include <linux/time.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/emu10k1.h> @@ -302,10 +304,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst hdr = emu->memhdr; snd_assert(hdr, return NULL); - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); blk = search_empty(emu, runtime->dma_bytes); if (blk == NULL) { - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } /* fill buffer addresses but pointers are not stored so that @@ -318,14 +320,14 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (idx >= sgbuf->pages) { printk(KERN_ERR "emu: pages overflow! (%d-%d) for %d\n", blk->first_page, blk->last_page, sgbuf->pages); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } #endif addr = sgbuf->table[idx].addr; if (! is_valid_page(emu, addr)) { printk(KERN_ERR "emu: failure page = %d\n", idx); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } emu->page_addr_table[page] = addr; @@ -337,10 +339,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst err = snd_emu10k1_memblk_map(emu, blk); if (err < 0) { __snd_util_mem_free(hdr, (struct snd_util_memblk *)blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return (struct snd_util_memblk *)blk; } @@ -369,19 +371,19 @@ snd_emu10k1_synth_alloc(struct snd_emu10k1 *hw, unsigned int size) struct snd_emu10k1_memblk *blk; struct snd_util_memhdr *hdr = hw->memhdr; - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); blk = (struct snd_emu10k1_memblk *)__snd_util_mem_alloc(hdr, size); if (blk == NULL) { - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } if (synth_alloc_pages(hw, blk)) { __snd_util_mem_free(hdr, (struct snd_util_memblk *)blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } snd_emu10k1_memblk_map(hw, blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return (struct snd_util_memblk *)blk; } @@ -396,14 +398,14 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk) struct snd_emu10k1_memblk *blk = (struct snd_emu10k1_memblk *)memblk; unsigned long flags; - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); spin_lock_irqsave(&emu->memblk_lock, flags); if (blk->mapped_page >= 0) unmap_memblk(emu, blk); spin_unlock_irqrestore(&emu->memblk_lock, flags); synth_free_pages(emu, blk); __snd_util_mem_free(hdr, memblk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return 0; } diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 55aaf110331a..a5533c86b0b6 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -35,6 +35,8 @@ #include <linux/slab.h> #include <linux/gameport.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> @@ -379,7 +381,7 @@ MODULE_PARM_DESC(lineio, "Line In to Rear Out (0 = auto, 1 = force)."); struct ensoniq { spinlock_t reg_lock; - struct semaphore src_mutex; + struct mutex src_mutex; int irq; @@ -609,7 +611,7 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97, struct ensoniq *ensoniq = ac97->private_data; unsigned int t, x; - down(&ensoniq->src_mutex); + mutex_lock(&ensoniq->src_mutex); for (t = 0; t < POLL_COUNT; t++) { if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) { /* save the current state for latter */ @@ -634,11 +636,11 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97, /* restore SRC reg */ snd_es1371_wait_src_ready(ensoniq); outl(x, ES_REG(ensoniq, 1371_SMPRATE)); - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); return; } } - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); snd_printk(KERN_ERR "codec write timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); } @@ -650,7 +652,7 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, unsigned int t, x, fail = 0; __again: - down(&ensoniq->src_mutex); + mutex_lock(&ensoniq->src_mutex); for (t = 0; t < POLL_COUNT; t++) { if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) { /* save the current state for latter */ @@ -683,11 +685,11 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, /* now wait for the stinkin' data (RDY) */ for (t = 0; t < POLL_COUNT; t++) { if ((x = inl(ES_REG(ensoniq, 1371_CODEC))) & ES_1371_CODEC_RDY) { - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); return ES_1371_CODEC_READ(x); } } - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); if (++fail > 10) { snd_printk(KERN_ERR "codec read timeout (final) " "at 0x%lx, reg = 0x%x [0x%x]\n", @@ -698,7 +700,7 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, goto __again; } } - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); snd_printk(KERN_ERR "es1371: codec read timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); return 0; @@ -717,7 +719,7 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) { unsigned int n, truncm, freq, result; - down(&ensoniq->src_mutex); + mutex_lock(&ensoniq->src_mutex); n = rate / 3000; if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9))) n--; @@ -742,14 +744,14 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) snd_es1371_src_write(ensoniq, ES_SMPREG_ADC + ES_SMPREG_VFREQ_FRAC, freq & 0x7fff); snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC, n << 8); snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC + 1, n << 8); - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); } static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate) { unsigned int freq, r; - down(&ensoniq->src_mutex); + mutex_lock(&ensoniq->src_mutex); freq = ((rate << 15) + 1500) / 3000; r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P2 | ES_1371_DIS_R1)) | @@ -763,14 +765,14 @@ static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate) r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P2 | ES_1371_DIS_R1)); outl(r, ES_REG(ensoniq, 1371_SMPRATE)); - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); } static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate) { unsigned int freq, r; - down(&ensoniq->src_mutex); + mutex_lock(&ensoniq->src_mutex); freq = ((rate << 15) + 1500) / 3000; r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P1 | ES_1371_DIS_R1)) | @@ -785,7 +787,7 @@ static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate) r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P1 | ES_1371_DIS_R1)); outl(r, ES_REG(ensoniq, 1371_SMPRATE)); - up(&ensoniq->src_mutex); + mutex_unlock(&ensoniq->src_mutex); } #endif /* CHIP1371 */ @@ -2061,6 +2063,13 @@ static int snd_ensoniq_suspend(struct pci_dev *pci, pm_message_t state) #ifdef CHIP1371 snd_ac97_suspend(ensoniq->u.es1371.ac97); #else + /* try to reset AK4531 */ + outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x02), ES_REG(ensoniq, 1370_CODEC)); + inw(ES_REG(ensoniq, 1370_CODEC)); + udelay(100); + outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x03), ES_REG(ensoniq, 1370_CODEC)); + inw(ES_REG(ensoniq, 1370_CODEC)); + udelay(100); snd_ak4531_suspend(ensoniq->u.es1370.ak4531); #endif pci_set_power_state(pci, PCI_D3hot); @@ -2116,7 +2125,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, return -ENOMEM; } spin_lock_init(&ensoniq->reg_lock); - init_MUTEX(&ensoniq->src_mutex); + mutex_init(&ensoniq->src_mutex); ensoniq->card = card; ensoniq->pci = pci; ensoniq->irq = -1; diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 3747a436f0cd..dd465a186e11 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -100,9 +100,12 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/gameport.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/pcm.h> #include <sound/mpu401.h> @@ -569,7 +572,7 @@ struct es1968 { u16 maestro_map[32]; int bobclient; /* active timer instancs */ int bob_freq; /* timer frequency */ - struct semaphore memory_mutex; /* memory lock */ + struct mutex memory_mutex; /* memory lock */ /* APU states */ unsigned char apu[NR_APUS]; @@ -1356,13 +1359,13 @@ static int calc_available_memory_size(struct es1968 *chip) struct list_head *p; int max_size = 0; - down(&chip->memory_mutex); + mutex_lock(&chip->memory_mutex); list_for_each(p, &chip->buf_list) { struct esm_memory *buf = list_entry(p, struct esm_memory, list); if (buf->empty && buf->buf.bytes > max_size) max_size = buf->buf.bytes; } - up(&chip->memory_mutex); + mutex_unlock(&chip->memory_mutex); if (max_size >= 128*1024) max_size = 127*1024; return max_size; @@ -1375,20 +1378,20 @@ static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size) struct list_head *p; size = ((size + ESM_MEM_ALIGN - 1) / ESM_MEM_ALIGN) * ESM_MEM_ALIGN; - down(&chip->memory_mutex); + mutex_lock(&chip->memory_mutex); list_for_each(p, &chip->buf_list) { buf = list_entry(p, struct esm_memory, list); if (buf->empty && buf->buf.bytes >= size) goto __found; } - up(&chip->memory_mutex); + mutex_unlock(&chip->memory_mutex); return NULL; __found: if (buf->buf.bytes > size) { struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL); if (chunk == NULL) { - up(&chip->memory_mutex); + mutex_unlock(&chip->memory_mutex); return NULL; } chunk->buf = buf->buf; @@ -1400,7 +1403,7 @@ __found: list_add(&chunk->list, &buf->list); } buf->empty = 0; - up(&chip->memory_mutex); + mutex_unlock(&chip->memory_mutex); return buf; } @@ -1409,7 +1412,7 @@ static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf) { struct esm_memory *chunk; - down(&chip->memory_mutex); + mutex_lock(&chip->memory_mutex); buf->empty = 1; if (buf->list.prev != &chip->buf_list) { chunk = list_entry(buf->list.prev, struct esm_memory, list); @@ -1428,7 +1431,7 @@ static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf) kfree(chunk); } } - up(&chip->memory_mutex); + mutex_unlock(&chip->memory_mutex); } static void snd_es1968_free_dmabuf(struct es1968 *chip) @@ -2559,8 +2562,8 @@ static int __devinit snd_es1968_create(struct snd_card *card, if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 28 bits */ - if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; @@ -2579,7 +2582,7 @@ static int __devinit snd_es1968_create(struct snd_card *card, INIT_LIST_HEAD(&chip->buf_list); INIT_LIST_HEAD(&chip->substream_list); spin_lock_init(&chip->ac97_lock); - init_MUTEX(&chip->memory_mutex); + mutex_init(&chip->memory_mutex); tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); chip->card = card; chip->pci = pci; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4a6dd97deba6..b42dff7ceed0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -25,6 +25,7 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include "hda_codec.h" #include <sound/asoundef.h> @@ -76,12 +77,12 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int dire unsigned int verb, unsigned int parm) { unsigned int res; - down(&codec->bus->cmd_mutex); + mutex_lock(&codec->bus->cmd_mutex); if (! codec->bus->ops.command(codec, nid, direct, verb, parm)) res = codec->bus->ops.get_response(codec); else res = (unsigned int)-1; - up(&codec->bus->cmd_mutex); + mutex_unlock(&codec->bus->cmd_mutex); return res; } @@ -101,9 +102,9 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { int err; - down(&codec->bus->cmd_mutex); + mutex_lock(&codec->bus->cmd_mutex); err = codec->bus->ops.command(codec, nid, direct, verb, parm); - up(&codec->bus->cmd_mutex); + mutex_unlock(&codec->bus->cmd_mutex); return err; } @@ -371,7 +372,7 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, bus->modelname = temp->modelname; bus->ops = temp->ops; - init_MUTEX(&bus->cmd_mutex); + mutex_init(&bus->cmd_mutex); INIT_LIST_HEAD(&bus->codec_list); if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) { @@ -523,13 +524,19 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, codec->bus = bus; codec->addr = codec_addr; - init_MUTEX(&codec->spdif_mutex); + mutex_init(&codec->spdif_mutex); init_amp_hash(codec); list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID); + if (codec->vendor_id == -1) + /* read again, hopefully the access method was corrected + * in the last read... + */ + codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, + AC_PAR_VENDOR_ID); codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID); codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID); @@ -722,7 +729,8 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, /* * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. */ -static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) +int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int index) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); if (! info) @@ -733,7 +741,8 @@ static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch /* * update the AMP value, mask = bit mask to set, val = the value */ -static int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val) +int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); @@ -881,12 +890,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ unsigned long pval; int err; - down(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); kcontrol->private_value = pval; - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return err; } @@ -896,7 +905,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ unsigned long pval; int i, indices, err = 0, change = 0; - down(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ pval = kcontrol->private_value; indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; for (i = 0; i < indices; i++) { @@ -907,7 +916,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ change |= err; } kcontrol->private_value = pval; - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } @@ -1011,7 +1020,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_c unsigned short val; int change; - down(&codec->spdif_mutex); + mutex_lock(&codec->spdif_mutex); codec->spdif_status = ucontrol->value.iec958.status[0] | ((unsigned int)ucontrol->value.iec958.status[1] << 8) | ((unsigned int)ucontrol->value.iec958.status[2] << 16) | @@ -1026,7 +1035,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_c snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8); } - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return change; } @@ -1054,7 +1063,7 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, struct sn unsigned short val; int change; - down(&codec->spdif_mutex); + mutex_lock(&codec->spdif_mutex); val = codec->spdif_ctls & ~1; if (ucontrol->value.integer.value[0]) val |= 1; @@ -1066,7 +1075,7 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, struct sn AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80)); } - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return change; } @@ -1150,13 +1159,13 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, struct snd unsigned int val = !!ucontrol->value.integer.value[0]; int change; - down(&codec->spdif_mutex); + mutex_lock(&codec->spdif_mutex); change = codec->spdif_in_enable != val; if (change || codec->in_resume) { codec->spdif_in_enable = val; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val); } - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return change; } @@ -1824,13 +1833,13 @@ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *i */ int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout) { - down(&codec->spdif_mutex); + mutex_lock(&codec->spdif_mutex); if (mout->dig_out_used) { - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return -EBUSY; /* already being used */ } mout->dig_out_used = HDA_DIG_EXCLUSIVE; - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return 0; } @@ -1839,9 +1848,9 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mo */ int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout) { - down(&codec->spdif_mutex); + mutex_lock(&codec->spdif_mutex); mout->dig_out_used = 0; - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return 0; } @@ -1869,7 +1878,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o int chs = substream->runtime->channels; int i; - down(&codec->spdif_mutex); + mutex_lock(&codec->spdif_mutex); if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { if (chs == 2 && snd_hda_is_supported_format(codec, mout->dig_out_nid, format) && @@ -1883,13 +1892,20 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); } } - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); /* front */ snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); if (mout->hp_nid) /* headphone out will just decode front left/right (stereo) */ snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); + /* extra outputs copied from front */ + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + stream_tag, 0, format); + /* surrounds */ for (i = 1; i < mout->num_dacs; i++) { if (chs >= (i + 1) * 2) /* independent out */ @@ -1914,12 +1930,17 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); if (mout->hp_nid) snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0); - down(&codec->spdif_mutex); + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + 0, 0, 0); + mutex_lock(&codec->spdif_mutex); if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); mout->dig_out_used = 0; } - up(&codec->spdif_mutex); + mutex_unlock(&codec->spdif_mutex); return 0; } @@ -1935,13 +1956,29 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) return 0; } -/* parse all pin widgets and store the useful pin nids to cfg */ +/* + * Parse all pin widgets and store the useful pin nids to cfg + * + * The number of line-outs or any primary output is stored in line_outs, + * and the corresponding output pins are assigned to line_out_pins[], + * in the order of front, rear, CLFE, side, ... + * + * If more extra outputs (speaker and headphone) are found, the pins are + * assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack + * is detected, one of speaker of HP pins is assigned as the primary + * output, i.e. to line_out_pins[0]. So, line_outs is always positive + * if any analog output exists. + * + * The analog input pins are assigned to input_pins array. + * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, + * respectively. + */ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, hda_nid_t *ignore_nids) { hda_nid_t nid, nid_start; int i, j, nodes; - short seq, sequences[4], assoc_line_out; + short seq, assoc_line_out, sequences[ARRAY_SIZE(cfg->line_out_pins)]; memset(cfg, 0, sizeof(*cfg)); @@ -1983,7 +2020,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c cfg->line_outs++; break; case AC_JACK_SPEAKER: - cfg->speaker_pin = nid; + if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) + continue; + cfg->speaker_pins[cfg->speaker_outs] = nid; + cfg->speaker_outs++; break; case AC_JACK_HP_OUT: cfg->hp_pin = nid; @@ -2048,6 +2088,46 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c break; } + /* + * debug prints of the parsed results + */ + snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], + cfg->line_out_pins[2], cfg->line_out_pins[3], + cfg->line_out_pins[4]); + snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + cfg->speaker_outs, cfg->speaker_pins[0], + cfg->speaker_pins[1], cfg->speaker_pins[2], + cfg->speaker_pins[3], cfg->speaker_pins[4]); + snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n", + cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin); + snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," + " cd=0x%x, aux=0x%x\n", + cfg->input_pins[AUTO_PIN_MIC], + cfg->input_pins[AUTO_PIN_FRONT_MIC], + cfg->input_pins[AUTO_PIN_LINE], + cfg->input_pins[AUTO_PIN_FRONT_LINE], + cfg->input_pins[AUTO_PIN_CD], + cfg->input_pins[AUTO_PIN_AUX]); + + /* + * FIX-UP: if no line-outs are detected, try to use speaker or HP pin + * as a primary output + */ + if (! cfg->line_outs) { + if (cfg->speaker_outs) { + cfg->line_outs = cfg->speaker_outs; + memcpy(cfg->line_out_pins, cfg->speaker_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = 0; + memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); + } else if (cfg->hp_pin) { + cfg->line_outs = 1; + cfg->line_out_pins[0] = cfg->hp_pin; + cfg->hp_pin = 0; + } + } + return 0; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 63e26c7a2b7a..40520e9d5a4b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -438,7 +438,7 @@ struct hda_bus { struct list_head codec_list; struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ - struct semaphore cmd_mutex; + struct mutex cmd_mutex; /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; @@ -559,7 +559,7 @@ struct hda_codec { int amp_info_size; struct hda_amp_info *amp_info; - struct semaphore spdif_mutex; + struct mutex spdif_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 39edfcfd3abd..85ad164ada59 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -47,10 +47,10 @@ struct hda_gnode { /* patch-specific record */ struct hda_gspec { - struct hda_gnode *dac_node; /* DAC node */ - struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */ - struct hda_gnode *pcm_vol_node; /* Node for PCM volume */ - unsigned int pcm_vol_index; /* connection of PCM volume */ + struct hda_gnode *dac_node[2]; /* DAC node */ + struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ + struct hda_gnode *pcm_vol_node[2]; /* Node for PCM volume */ + unsigned int pcm_vol_index[2]; /* connection of PCM volume */ struct hda_gnode *adc_node; /* ADC node */ struct hda_gnode *cap_vol_node; /* Node for capture volume */ @@ -69,8 +69,12 @@ struct hda_gspec { /* * retrieve the default device type from the default config value */ -#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) -#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> \ + AC_DEFCFG_DEVICE_SHIFT) +#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> \ + AC_DEFCFG_LOCATION_SHIFT) +#define defcfg_port_conn(node) (((node)->def_cfg & AC_DEFCFG_PORT_CONN) >> \ + AC_DEFCFG_PORT_CONN_SHIFT) /* * destructor @@ -261,7 +265,7 @@ static void clear_check_flags(struct hda_gspec *spec) * returns 0 if not found, 1 if found, or a negative error code. */ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node) + struct hda_gnode *node, int dac_idx) { int i, err; struct hda_gnode *child; @@ -276,14 +280,14 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, return 0; } snd_printdd("AUD_OUT found %x\n", node->nid); - if (spec->dac_node) { + if (spec->dac_node[dac_idx]) { /* already DAC node is assigned, just unmute & connect */ - return node == spec->dac_node; + return node == spec->dac_node[dac_idx]; } - spec->dac_node = node; + spec->dac_node[dac_idx] = node; if (node->wid_caps & AC_WCAP_OUT_AMP) { - spec->pcm_vol_node = node; - spec->pcm_vol_index = 0; + spec->pcm_vol_node[dac_idx] = node; + spec->pcm_vol_index[dac_idx] = 0; } return 1; /* found */ } @@ -292,7 +296,7 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, child = hda_get_node(spec, node->conn_list[i]); if (! child) continue; - err = parse_output_path(codec, spec, child); + err = parse_output_path(codec, spec, child, dac_idx); if (err < 0) return err; else if (err > 0) { @@ -303,13 +307,13 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, select_input_connection(codec, node, i); unmute_input(codec, node, i); unmute_output(codec, node); - if (! spec->pcm_vol_node) { + if (! spec->pcm_vol_node[dac_idx]) { if (node->wid_caps & AC_WCAP_IN_AMP) { - spec->pcm_vol_node = node; - spec->pcm_vol_index = i; + spec->pcm_vol_node[dac_idx] = node; + spec->pcm_vol_index[dac_idx] = i; } else if (node->wid_caps & AC_WCAP_OUT_AMP) { - spec->pcm_vol_node = node; - spec->pcm_vol_index = 0; + spec->pcm_vol_node[dac_idx] = node; + spec->pcm_vol_index[dac_idx] = 0; } } return 1; @@ -339,6 +343,8 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, /* output capable? */ if (! (node->pin_caps & AC_PINCAP_OUT)) continue; + if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) + continue; /* unconnected */ if (jack_type >= 0) { if (jack_type != defcfg_type(node)) continue; @@ -350,10 +356,15 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, continue; } clear_check_flags(spec); - err = parse_output_path(codec, spec, node); + err = parse_output_path(codec, spec, node, 0); if (err < 0) return NULL; - else if (err > 0) { + if (! err && spec->out_pin_node[0]) { + err = parse_output_path(codec, spec, node, 1); + if (err < 0) + return NULL; + } + if (err > 0) { /* unmute the PIN output */ unmute_output(codec, node); /* set PIN-Out enable */ @@ -381,20 +392,28 @@ static int parse_output(struct hda_codec *codec) /* first, look for the line-out pin */ node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT); if (node) /* found, remember the PIN node */ - spec->out_pin_node = node; + spec->out_pin_node[0] = node; + else { + /* if no line-out is found, try speaker out */ + node = parse_output_jack(codec, spec, AC_JACK_SPEAKER); + if (node) + spec->out_pin_node[0] = node; + } /* look for the HP-out pin */ node = parse_output_jack(codec, spec, AC_JACK_HP_OUT); if (node) { - if (! spec->out_pin_node) - spec->out_pin_node = node; + if (! spec->out_pin_node[0]) + spec->out_pin_node[0] = node; + else + spec->out_pin_node[1] = node; } - if (! spec->out_pin_node) { + if (! spec->out_pin_node[0]) { /* no line-out or HP pins found, * then choose for the first output pin */ - spec->out_pin_node = parse_output_jack(codec, spec, -1); - if (! spec->out_pin_node) + spec->out_pin_node[0] = parse_output_jack(codec, spec, -1); + if (! spec->out_pin_node[0]) snd_printd("hda_generic: no proper output path found\n"); } @@ -505,6 +524,9 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, if (! (node->pin_caps & AC_PINCAP_IN)) return 0; + if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) + return 0; /* unconnected */ + if (node->wid_caps & AC_WCAP_DIGITAL) return 0; /* skip SPDIF */ @@ -703,12 +725,16 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con static int build_output_controls(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - int err; + static const char *types[2] = { "Master", "Headphone" }; + int i, err; - err = create_mixer(codec, spec->pcm_vol_node, spec->pcm_vol_index, - "PCM", "Playback"); - if (err < 0) - return err; + for (i = 0; i < 2 && spec->pcm_vol_node[i]; i++) { + err = create_mixer(codec, spec->pcm_vol_node[i], + spec->pcm_vol_index[i], + types[i], "Playback"); + if (err < 0) + return err; + } return 0; } @@ -805,7 +831,7 @@ static int build_loopback_controls(struct hda_codec *codec) int err; const char *type; - if (! spec->out_pin_node) + if (! spec->out_pin_node[0]) return 0; list_for_each(p, &spec->nid_list) { @@ -820,7 +846,8 @@ static int build_loopback_controls(struct hda_codec *codec) if (check_existing_control(codec, type, "Playback")) continue; clear_check_flags(spec); - err = parse_loopback_path(codec, spec, spec->out_pin_node, + err = parse_loopback_path(codec, spec, + spec->out_pin_node[0], node, type); if (err < 0) return err; @@ -855,12 +882,37 @@ static struct hda_pcm_stream generic_pcm_playback = { .channels_max = 2, }; +static int generic_pcm2_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hda_gspec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, + stream_tag, 0, format); + return 0; +} + +static int generic_pcm2_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gspec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0); + snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, 0, 0, 0); + return 0; +} + static int build_generic_pcms(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; struct hda_pcm *info = &spec->pcm_rec; - if (! spec->dac_node && ! spec->adc_node) { + if (! spec->dac_node[0] && ! spec->adc_node) { snd_printd("hda_generic: no PCM found\n"); return 0; } @@ -869,9 +921,13 @@ static int build_generic_pcms(struct hda_codec *codec) codec->pcm_info = info; info->name = "HDA Generic"; - if (spec->dac_node) { + if (spec->dac_node[0]) { info->stream[0] = generic_pcm_playback; - info->stream[0].nid = spec->dac_node->nid; + info->stream[0].nid = spec->dac_node[0]->nid; + if (spec->dac_node[1]) { + info->stream[0].ops.prepare = generic_pcm2_prepare; + info->stream[0].ops.cleanup = generic_pcm2_cleanup; + } } if (spec->adc_node) { info->stream[1] = generic_pcm_playback; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index fd12b6991fe4..c096606970ff 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -43,6 +43,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/initval.h> #include "hda_codec.h" @@ -53,6 +54,7 @@ static char *id = SNDRV_DEFAULT_STR1; static char *model; static int position_fix; static int probe_mask = -1; +static int single_cmd; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -64,6 +66,8 @@ module_param(position_fix, int, 0444); MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); module_param(probe_mask, int, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); +module_param(single_cmd, bool, 0444); +MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); /* just for backward compatibility */ @@ -235,12 +239,6 @@ enum { #define NVIDIA_HDA_ENABLE_COHBITS 0x0f /* - * Use CORB/RIRB for communication from/to codecs. - * This is the way recommended by Intel (see below). - */ -#define USE_CORB_RIRB - -/* */ struct azx_dev { @@ -252,7 +250,6 @@ struct azx_dev { unsigned int fragsize; /* size of each period in bytes */ unsigned int frags; /* number for period in the play buffer */ unsigned int fifo_size; /* FIFO size */ - unsigned int last_pos; /* last updated period position */ void __iomem *sd_addr; /* stream descriptor pointer */ @@ -263,10 +260,11 @@ struct azx_dev { unsigned int format_val; /* format value to be set in the controller and the codec */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ + /* for sanity check of position buffer */ + unsigned int period_intr; unsigned int opened: 1; unsigned int running: 1; - unsigned int period_updating: 1; }; /* CORB/RIRB */ @@ -300,7 +298,7 @@ struct azx { /* locks */ spinlock_t reg_lock; - struct semaphore open_mutex; + struct mutex open_mutex; /* streams (x num_streams) */ struct azx_dev *azx_dev; @@ -325,6 +323,7 @@ struct azx { /* flags */ int position_fix; unsigned int initialized: 1; + unsigned int single_cmd: 1; }; /* driver types */ @@ -388,7 +387,6 @@ static char *driver_short_names[] __devinitdata = { * Interface for HD codec */ -#ifdef USE_CORB_RIRB /* * CORB / RIRB interface */ @@ -436,11 +434,7 @@ static void azx_init_cmd_io(struct azx *chip) /* set N=1, get RIRB response interrupt for new entry */ azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ -#ifdef USE_CORB_RIRB azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); -#else - azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN); -#endif chip->rirb.rp = chip->rirb.cmds = 0; } @@ -452,8 +446,8 @@ static void azx_free_cmd_io(struct azx *chip) } /* send a command */ -static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int para) +static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, + unsigned int verb, unsigned int para) { struct azx *chip = codec->bus->private_data; unsigned int wp; @@ -509,18 +503,21 @@ static void azx_update_rirb(struct azx *chip) } /* receive a response */ -static unsigned int azx_get_response(struct hda_codec *codec) +static unsigned int azx_rirb_get_response(struct hda_codec *codec) { struct azx *chip = codec->bus->private_data; int timeout = 50; while (chip->rirb.cmds) { if (! --timeout) { - if (printk_ratelimit()) - snd_printk(KERN_ERR - "azx_get_response timeout\n"); + snd_printk(KERN_ERR + "hda_intel: azx_get_response timeout, " + "switching to single_cmd mode...\n"); chip->rirb.rp = azx_readb(chip, RIRBWP); chip->rirb.cmds = 0; + /* switch to single_cmd mode */ + chip->single_cmd = 1; + azx_free_cmd_io(chip); return -1; } msleep(1); @@ -528,7 +525,6 @@ static unsigned int azx_get_response(struct hda_codec *codec) return chip->rirb.res; /* the last value */ } -#else /* * Use the single immediate command instead of CORB/RIRB for simplicity * @@ -539,13 +535,10 @@ static unsigned int azx_get_response(struct hda_codec *codec) * I left the codes, however, for debugging/testing purposes. */ -#define azx_alloc_cmd_io(chip) 0 -#define azx_init_cmd_io(chip) -#define azx_free_cmd_io(chip) - /* send a command */ -static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int para) +static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, + unsigned int para) { struct azx *chip = codec->bus->private_data; u32 val; @@ -573,7 +566,7 @@ static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, } /* receive a response */ -static unsigned int azx_get_response(struct hda_codec *codec) +static unsigned int azx_single_get_response(struct hda_codec *codec) { struct azx *chip = codec->bus->private_data; int timeout = 50; @@ -588,9 +581,35 @@ static unsigned int azx_get_response(struct hda_codec *codec) return (unsigned int)-1; } -#define azx_update_rirb(chip) +/* + * The below are the main callbacks from hda_codec. + * + * They are just the skeleton to call sub-callbacks according to the + * current setting of chip->single_cmd. + */ + +/* send a command */ +static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, + unsigned int para) +{ + struct azx *chip = codec->bus->private_data; + if (chip->single_cmd) + return azx_single_send_cmd(codec, nid, direct, verb, para); + else + return azx_corb_send_cmd(codec, nid, direct, verb, para); +} + +/* get a response */ +static unsigned int azx_get_response(struct hda_codec *codec) +{ + struct azx *chip = codec->bus->private_data; + if (chip->single_cmd) + return azx_single_get_response(codec); + else + return azx_rirb_get_response(codec); +} -#endif /* USE_CORB_RIRB */ /* reset codec link */ static int azx_reset(struct azx *chip) @@ -737,7 +756,8 @@ static void azx_init_chip(struct azx *chip) azx_int_enable(chip); /* initialize the codec command I/O */ - azx_init_cmd_io(chip); + if (! chip->single_cmd) + azx_init_cmd_io(chip); /* program the position buffer */ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); @@ -784,11 +804,10 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs) if (status & azx_dev->sd_int_sta_mask) { azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); if (azx_dev->substream && azx_dev->running) { - azx_dev->period_updating = 1; + azx_dev->period_intr++; spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(azx_dev->substream); spin_lock(&chip->reg_lock); - azx_dev->period_updating = 0; } } } @@ -796,7 +815,7 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs) /* clear rirb int */ status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) + if (! chip->single_cmd && (status & RIRB_INT_RESPONSE)) azx_update_rirb(chip); azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } @@ -1002,10 +1021,10 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) unsigned long flags; int err; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); azx_dev = azx_assign_device(chip, substream->stream); if (azx_dev == NULL) { - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return -EBUSY; } runtime->hw = azx_pcm_hw; @@ -1017,7 +1036,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) { azx_release_device(azx_dev); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return err; } spin_lock_irqsave(&chip->reg_lock, flags); @@ -1026,7 +1045,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) spin_unlock_irqrestore(&chip->reg_lock, flags); runtime->private_data = azx_dev; - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return 0; } @@ -1038,14 +1057,14 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) struct azx_dev *azx_dev = get_azx_dev(substream); unsigned long flags; - down(&chip->open_mutex); + mutex_lock(&chip->open_mutex); spin_lock_irqsave(&chip->reg_lock, flags); azx_dev->substream = NULL; azx_dev->running = 0; spin_unlock_irqrestore(&chip->reg_lock, flags); azx_release_device(azx_dev); hinfo->ops.close(hinfo, apcm->codec, substream); - up(&chip->open_mutex); + mutex_unlock(&chip->open_mutex); return 0; } @@ -1099,7 +1118,6 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; else azx_dev->fifo_size = 0; - azx_dev->last_pos = 0; return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, azx_dev->format_val, substream); @@ -1147,10 +1165,20 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) struct azx_dev *azx_dev = get_azx_dev(substream); unsigned int pos; - if (chip->position_fix == POS_FIX_POSBUF) { + if (chip->position_fix == POS_FIX_POSBUF || + chip->position_fix == POS_FIX_AUTO) { /* use the position buffer */ pos = *azx_dev->posbuf; + if (chip->position_fix == POS_FIX_AUTO && + azx_dev->period_intr == 1 && ! pos) { + printk(KERN_WARNING + "hda-intel: Invalid position buffer, " + "using LPIB read method instead.\n"); + chip->position_fix = POS_FIX_NONE; + goto read_lpib; + } } else { + read_lpib: /* read LPIB */ pos = azx_sd_readl(azx_dev, SD_LPIB); if (chip->position_fix == POS_FIX_FIFO) @@ -1415,13 +1443,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } spin_lock_init(&chip->reg_lock); - init_MUTEX(&chip->open_mutex); + mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; chip->driver_type = driver_type; - chip->position_fix = position_fix ? position_fix : POS_FIX_POSBUF; + chip->position_fix = position_fix; + chip->single_cmd = single_cmd; #if BITS_PER_LONG != 64 /* Fix up base address on ULI M5461 */ @@ -1492,8 +1521,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, goto errout; } /* allocate CORB/RIRB */ - if ((err = azx_alloc_cmd_io(chip)) < 0) - goto errout; + if (! chip->single_cmd) + if ((err = azx_alloc_cmd_io(chip)) < 0) + goto errout; /* initialize streams */ azx_init_stream(chip); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index c82d2a72d13e..14e8aa2806ed 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -66,6 +66,11 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +/* lowlevel accessor with caching; use carefully */ +int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int index); +int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val); /* mono switch binding multiple inputs */ #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ @@ -130,6 +135,7 @@ struct hda_multi_out { int num_dacs; /* # of DACs, must be more than 1 */ hda_nid_t *dac_nids; /* DAC list */ hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */ + hda_nid_t extra_out_nid[3]; /* optional DACs, 0 when not exists */ hda_nid_t dig_out_nid; /* digital out audio widget */ int max_channels; /* currently supported analog channels */ int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ @@ -216,7 +222,8 @@ extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; struct auto_pin_cfg { int line_outs; hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ - hda_nid_t speaker_pin; + int speaker_outs; + hda_nid_t speaker_pins[5]; hda_nid_t hp_pin; hda_nid_t input_pins[AUTO_PIN_LAST]; hda_nid_t dig_out_pin; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1ada1b075c9a..32401bd8c229 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -23,6 +23,8 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/mutex.h> + #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -60,7 +62,7 @@ struct ad198x_spec { /* PCM information */ struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ - struct semaphore amp_mutex; /* PCM volume/mute control mutex */ + struct mutex amp_mutex; /* PCM volume/mute control mutex */ unsigned int spdif_route; /* dynamic controls, init_verbs and input_mux */ @@ -308,7 +310,7 @@ static int ad198x_resume(struct hda_codec *codec) struct ad198x_spec *spec = codec->spec; int i; - ad198x_init(codec); + codec->patch_ops.init(codec); for (i = 0; i < spec->num_mixers; i++) snd_hda_resume_ctls(codec, spec->mixers[i]); if (spec->multiout.dig_out_nid) @@ -331,6 +333,61 @@ static struct hda_codec_ops ad198x_patch_ops = { /* + * EAPD control + * the private value = nid | (invert << 8) + */ +static int ad198x_eapd_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + int invert = (kcontrol->private_value >> 8) & 1; + if (invert) + ucontrol->value.integer.value[0] = ! spec->cur_eapd; + else + ucontrol->value.integer.value[0] = spec->cur_eapd; + return 0; +} + +static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + int invert = (kcontrol->private_value >> 8) & 1; + hda_nid_t nid = kcontrol->private_value & 0xff; + unsigned int eapd; + eapd = ucontrol->value.integer.value[0]; + if (invert) + eapd = !eapd; + if (eapd == spec->cur_eapd && ! codec->in_resume) + return 0; + spec->cur_eapd = eapd; + snd_hda_codec_write(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); + return 1; +} + +static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + + +/* * AD1986A specific */ @@ -344,6 +401,7 @@ static hda_nid_t ad1986a_dac_nids[3] = { AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC }; static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; +static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; static struct hda_input_mux ad1986a_capture_source = { .num_items = 7, @@ -371,9 +429,9 @@ static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *ad = codec->spec; - down(&ad->amp_mutex); + mutex_lock(&ad->amp_mutex); snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); - up(&ad->amp_mutex); + mutex_unlock(&ad->amp_mutex); return 0; } @@ -383,13 +441,13 @@ static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl struct ad198x_spec *ad = codec->spec; int i, change = 0; - down(&ad->amp_mutex); + mutex_lock(&ad->amp_mutex); for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); } kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - up(&ad->amp_mutex); + mutex_unlock(&ad->amp_mutex); return change; } @@ -400,9 +458,9 @@ static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *ad = codec->spec; - down(&ad->amp_mutex); + mutex_lock(&ad->amp_mutex); snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - up(&ad->amp_mutex); + mutex_unlock(&ad->amp_mutex); return 0; } @@ -412,13 +470,13 @@ static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct ad198x_spec *ad = codec->spec; int i, change = 0; - down(&ad->amp_mutex); + mutex_lock(&ad->amp_mutex); for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); } kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - up(&ad->amp_mutex); + mutex_unlock(&ad->amp_mutex); return change; } @@ -477,6 +535,143 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { { } /* end */ }; +/* additional mixers for 3stack mode */ +static struct snd_kcontrol_new ad1986a_3st_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = ad198x_ch_mode_info, + .get = ad198x_ch_mode_get, + .put = ad198x_ch_mode_put, + }, + { } /* end */ +}; + +/* laptop model - 2ch only */ +static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; + +static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + /* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { } /* end */ +}; + +/* laptop-eapd model - 2ch only */ + +/* master controls both pins 0x1a and 0x1b */ +static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + return change; +} + +static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, + 0x80, valp[0] ? 0 : 0x80); + change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, + 0x80, valp[1] ? 0 : 0x80); + snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, + 0x80, valp[0] ? 0 : 0x80); + snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, + 0x80, valp[1] ? 0 : 0x80); + return change; +} + +static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x4 }, + { "Mix", 0x5 }, + }, +}; + +static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = ad1986a_laptop_master_vol_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = ad1986a_laptop_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + /* * initialization verbs */ @@ -535,16 +730,89 @@ static struct hda_verb ad1986a_init_verbs[] = { { } /* end */ }; +/* additional verbs for 3-stack model */ +static struct hda_verb ad1986a_3st_init_verbs[] = { + /* Mic and line-in selectors */ + {0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, + {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, + { } /* end */ +}; + +static struct hda_verb ad1986a_ch2_init[] = { + /* Surround out -> Line In */ + { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* CLFE -> Mic in */ + { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + { } /* end */ +}; + +static struct hda_verb ad1986a_ch4_init[] = { + /* Surround out -> Surround */ + { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* CLFE -> Mic in */ + { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + { } /* end */ +}; + +static struct hda_verb ad1986a_ch6_init[] = { + /* Surround out -> Surround out */ + { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* CLFE -> CLFE */ + { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + { } /* end */ +}; + +static struct hda_channel_mode ad1986a_modes[3] = { + { 2, ad1986a_ch2_init }, + { 4, ad1986a_ch4_init }, + { 6, ad1986a_ch6_init }, +}; + +/* eapd initialization */ +static struct hda_verb ad1986a_eapd_init_verbs[] = { + {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, + {} +}; + +/* models */ +enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD }; + +static struct hda_board_config ad1986a_cfg_tbl[] = { + { .modelname = "6stack", .config = AD1986A_6STACK }, + { .modelname = "3stack", .config = AD1986A_3STACK }, + { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84, + .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ + { .modelname = "laptop", .config = AD1986A_LAPTOP }, + { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, + .config = AD1986A_LAPTOP }, /* FSC V2060 */ + { .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017, + .config = AD1986A_LAPTOP }, /* Samsung M50 */ + { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f, + .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */ + { .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD }, + { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, + .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, + .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */ + {} +}; static int patch_ad1986a(struct hda_codec *codec) { struct ad198x_spec *spec; + int board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; - init_MUTEX(&spec->amp_mutex); + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 6; @@ -553,7 +821,7 @@ static int patch_ad1986a(struct hda_codec *codec) spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; spec->num_adc_nids = 1; spec->adc_nids = ad1986a_adc_nids; - spec->capsrc_nids = ad1986a_adc_nids; + spec->capsrc_nids = ad1986a_capsrc_nids; spec->input_mux = &ad1986a_capture_source; spec->num_mixers = 1; spec->mixers[0] = ad1986a_mixers; @@ -562,6 +830,35 @@ static int patch_ad1986a(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; + /* override some parameters */ + board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl); + switch (board_config) { + case AD1986A_3STACK: + spec->num_mixers = 2; + spec->mixers[1] = ad1986a_3st_mixers; + spec->num_init_verbs = 2; + spec->init_verbs[1] = ad1986a_3st_init_verbs; + spec->channel_mode = ad1986a_modes; + spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); + break; + case AD1986A_LAPTOP: + spec->mixers[0] = ad1986a_laptop_mixers; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + break; + case AD1986A_LAPTOP_EAPD: + spec->mixers[0] = ad1986a_laptop_eapd_mixers; + spec->num_init_verbs = 2; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + break; + } + return 0; } @@ -575,6 +872,7 @@ static int patch_ad1986a(struct hda_codec *codec) static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; +static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; static struct hda_input_mux ad1983_capture_source = { .num_items = 4, @@ -708,7 +1006,7 @@ static int patch_ad1983(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - init_MUTEX(&spec->amp_mutex); + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -717,7 +1015,7 @@ static int patch_ad1983(struct hda_codec *codec) spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; spec->num_adc_nids = 1; spec->adc_nids = ad1983_adc_nids; - spec->capsrc_nids = ad1983_adc_nids; + spec->capsrc_nids = ad1983_capsrc_nids; spec->input_mux = &ad1983_capture_source; spec->num_mixers = 1; spec->mixers[0] = ad1983_mixers; @@ -741,6 +1039,7 @@ static int patch_ad1983(struct hda_codec *codec) static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; +static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ static struct hda_input_mux ad1981_capture_source = { @@ -846,15 +1145,200 @@ static struct hda_verb ad1981_init_verbs[] = { { } /* end */ }; +/* + * Patch for HP nx6320 + * + * nx6320 uses EAPD in the reserve way - EAPD-on means the internal + * speaker output enabled _and_ mute-LED off. + */ + +#define AD1981_HP_EVENT 0x37 +#define AD1981_MIC_EVENT 0x38 + +static struct hda_verb ad1981_hp_init_verbs[] = { + {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ + /* pin sensing on HP and Mic jacks */ + {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, + {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, + {} +}; + +/* turn on/off EAPD (+ mute HP) as a master switch */ +static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + if (! ad198x_eapd_put(kcontrol, ucontrol)) + return 0; + + /* toggle HP mute appropriately */ + snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, + 0x80, spec->cur_eapd ? 0 : 0x80); + snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, + 0x80, spec->cur_eapd ? 0 : 0x80); + return 1; +} + +/* bind volumes of both NID 0x05 and 0x06 */ +static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + return change; +} + +/* mute internal speaker if HP is plugged */ +static void ad1981_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x06, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); +} + +/* toggle input of built-in and mic jack appropriately */ +static void ad1981_hp_automic(struct hda_codec *codec) +{ + static struct hda_verb mic_jack_on[] = { + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {} + }; + static struct hda_verb mic_jack_off[] = { + {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {} + }; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x08, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + if (present) + snd_hda_sequence_write(codec, mic_jack_on); + else + snd_hda_sequence_write(codec, mic_jack_off); +} + +/* unsolicited event for HP jack sensing */ +static void ad1981_hp_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + res >>= 26; + switch (res) { + case AD1981_HP_EVENT: + ad1981_hp_automute(codec); + break; + case AD1981_MIC_EVENT: + ad1981_hp_automic(codec); + break; + } +} + +static struct hda_input_mux ad1981_hp_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Docking-Station", 0x1 }, + { "Mix", 0x2 }, + }, +}; + +static struct snd_kcontrol_new ad1981_hp_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = ad1981_hp_master_vol_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad1981_hp_master_sw_put, + .private_value = 0x05, + }, + HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), +#if 0 + /* FIXME: analog mic/line loopback doesn't work with my tests... + * (although recording is OK) + */ + HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), + /* FIXME: does this laptop have analog CD connection? */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), +#endif + HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { } /* end */ +}; + +/* initialize jack-sensing, too */ +static int ad1981_hp_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1981_hp_automute(codec); + ad1981_hp_automic(codec); + return 0; +} + +/* models */ +enum { AD1981_BASIC, AD1981_HP }; + +static struct hda_board_config ad1981_cfg_tbl[] = { + { .modelname = "hp", .config = AD1981_HP }, + { .pci_subvendor = 0x103c, .pci_subdevice = 0x30aa, + .config = AD1981_HP }, /* HP nx6320 */ + { .pci_subvendor = 0x103c, .pci_subdevice = 0x309f, + .config = AD1981_HP }, /* HP nx9420 AngelFire */ + { .modelname = "basic", .config = AD1981_BASIC }, + {} +}; + static int patch_ad1981(struct hda_codec *codec) { struct ad198x_spec *spec; + int board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; - init_MUTEX(&spec->amp_mutex); + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -863,7 +1347,7 @@ static int patch_ad1981(struct hda_codec *codec) spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; spec->num_adc_nids = 1; spec->adc_nids = ad1981_adc_nids; - spec->capsrc_nids = ad1981_adc_nids; + spec->capsrc_nids = ad1981_capsrc_nids; spec->input_mux = &ad1981_capture_source; spec->num_mixers = 1; spec->mixers[0] = ad1981_mixers; @@ -873,6 +1357,21 @@ static int patch_ad1981(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; + /* override some parameters */ + board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl); + switch (board_config) { + case AD1981_HP: + spec->mixers[0] = ad1981_hp_mixers; + spec->num_init_verbs = 2; + spec->init_verbs[1] = ad1981_hp_init_verbs; + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1981_hp_capture_source; + + codec->patch_ops.init = ad1981_hp_init; + codec->patch_ops.unsol_event = ad1981_hp_unsol_event; + break; + } + return 0; } @@ -1060,44 +1559,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, spec->num_channel_mode, &spec->multiout.max_channels); } -/* - * EAPD control - */ -static int ad1988_eapd_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int ad1988_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = ! spec->cur_eapd; - return 0; -} - -static int ad1988_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int eapd; - eapd = ! ucontrol->value.enumerated.item[0]; - if (eapd == spec->cur_eapd && ! codec->in_resume) - return 0; - spec->cur_eapd = eapd; - snd_hda_codec_write(codec, 0x12 /* port-D */, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 0; -} - /* 6-stack mode */ static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), @@ -1220,9 +1681,10 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "External Amplifier", - .info = ad1988_eapd_info, - .get = ad1988_eapd_get, - .put = ad1988_eapd_put, + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x12 | (1 << 8), /* port-D, inversed */ }, { } /* end */ @@ -1795,14 +2257,11 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, idx = ad1988_pin_idx(pin); nid = ad1988_idx_to_dac(codec, idx); - if (! spec->multiout.dac_nids[0]) { - /* use this as the primary output */ - spec->multiout.dac_nids[0] = nid; - if (! spec->multiout.num_dacs) - spec->multiout.num_dacs = 1; - } else - /* specify the DAC as the extra output */ + /* specify the DAC as the extra output */ + if (! spec->multiout.hp_nid) spec->multiout.hp_nid = nid; + else + spec->multiout.extra_out_nid[0] = nid; /* control HP volume/switch on the output mixer amp */ sprintf(name, "%s Playback Volume", pfx); if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, @@ -1921,7 +2380,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) struct ad198x_spec *spec = codec->spec; hda_nid_t pin; - pin = spec->autocfg.speaker_pin; + pin = spec->autocfg.speaker_pins[0]; if (pin) /* connect to front */ ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); pin = spec->autocfg.hp_pin; @@ -1970,13 +2429,13 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) return err; if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) return err; - if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && - ! spec->autocfg.hp_pin) + if (! spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */ if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin, + (err = ad1988_auto_create_extra_out(codec, + spec->autocfg.speaker_pins[0], "Speaker")) < 0 || - (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin, + (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin, "Headphone")) < 0 || (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) return err; @@ -2032,7 +2491,7 @@ static int patch_ad1988(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - init_MUTEX(&spec->amp_mutex); + mutex_init(&spec->amp_mutex); codec->spec = spec; if (codec->revision_id == AD1988A_REV2) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b76755264730..4c6c9ec8ea5b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6,6 +6,7 @@ * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw> * PeiSen Hou <pshou@realtek.com.tw> * Takashi Iwai <tiwai@suse.de> + * Jonathan Woithe <jwoithe@physics.adelaide.edu.au> * * This driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,6 +51,7 @@ enum { ALC880_UNIWILL_DIG, ALC880_CLEVO, ALC880_TCL_S700, + ALC880_LG, #ifdef CONFIG_SND_DEBUG ALC880_TEST, #endif @@ -63,6 +65,10 @@ enum { ALC260_HP, ALC260_HP_3013, ALC260_FUJITSU_S702X, + ALC260_ACER, +#ifdef CONFIG_SND_DEBUG + ALC260_TEST, +#endif ALC260_AUTO, ALC260_MODEL_LAST /* last tag */ }; @@ -70,6 +76,7 @@ enum { /* ALC262 models */ enum { ALC262_BASIC, + ALC262_FUJITSU, ALC262_AUTO, ALC262_MODEL_LAST /* last tag */ }; @@ -132,7 +139,7 @@ struct alc_spec { int num_channel_mode; /* PCM information */ - struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ + struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; @@ -140,6 +147,14 @@ struct alc_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[5]; + + /* hooks */ + void (*init_hook)(struct hda_codec *codec); + void (*unsol_event)(struct hda_codec *codec, unsigned int res); + + /* for pin sensing */ + unsigned int sense_updated: 1; + unsigned int jack_present: 1; }; /* @@ -158,6 +173,8 @@ struct alc_config_preset { unsigned int num_channel_mode; const struct hda_channel_mode *channel_mode; const struct hda_input_mux *input_mux; + void (*unsol_event)(struct hda_codec *, unsigned int); + void (*init_hook)(struct hda_codec *); }; @@ -218,56 +235,231 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va spec->num_channel_mode, &spec->multiout.max_channels); } - /* - * Control of pin widget settings via the mixer. Only boolean settings are - * supported, so VrefEn can't be controlled using these functions as they - * stand. + * Control the mode of pin widget settings via the mixer. "pc" is used + * instead of "%" to avoid consequences of accidently treating the % as + * being part of a format specifier. Maximum allowed length of a value is + * 63 characters plus NULL terminator. + * + * Note: some retasking pin complexes seem to ignore requests for input + * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these + * are requested. Therefore order this list so that this behaviour will not + * cause problems when mixer clients move through the enum sequentially. + * NIDs 0x0f and 0x10 have been observed to have this behaviour. */ -static int alc_pinctl_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static char *alc_pin_mode_names[] = { + "Mic 50pc bias", "Mic 80pc bias", + "Line in", "Line out", "Headphone out", +}; +static unsigned char alc_pin_mode_values[] = { + PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, +}; +/* The control can present all 5 options, or it can limit the options based + * in the pin being assumed to be exclusively an input or an output pin. + */ +#define ALC_PIN_DIR_IN 0x00 +#define ALC_PIN_DIR_OUT 0x01 +#define ALC_PIN_DIR_INOUT 0x02 + +/* Info about the pin modes supported by the three different pin directions. + * For each direction the minimum and maximum values are given. + */ +static signed char alc_pin_mode_dir_info[3][2] = { + { 0, 2 }, /* ALC_PIN_DIR_IN */ + { 3, 4 }, /* ALC_PIN_DIR_OUT */ + { 0, 4 }, /* ALC_PIN_DIR_INOUT */ +}; +#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) +#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) +#define alc_pin_mode_n_items(_dir) \ + (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) + +static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + unsigned int item_num = uinfo->value.enumerated.item; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; + uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); + + if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir)) + item_num = alc_pin_mode_min(dir); + strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); return 0; } -static int alc_pinctl_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + unsigned int i; struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = kcontrol->private_value & 0xffff; - long mask = (kcontrol->private_value >> 16) & 0xff; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; long *valp = ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00); - *valp = 0; - if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask) - *valp = 1; + /* Find enumerated value for current pinctl setting */ + i = alc_pin_mode_min(dir); + while (alc_pin_mode_values[i]!=pinctl && i<=alc_pin_mode_max(dir)) + i++; + *valp = i<=alc_pin_mode_max(dir)?i:alc_pin_mode_min(dir); return 0; } -static int alc_pinctl_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + signed int change; struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = kcontrol->private_value & 0xffff; - long mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00); - int change = ((pinctl & mask)!=0) != *valp; - if (change) + if (val<alc_pin_mode_min(dir) || val>alc_pin_mode_max(dir)) + val = alc_pin_mode_min(dir); + + change = pinctl != alc_pin_mode_values[val]; + if (change) { + /* Set pin mode to that requested */ snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, - *valp?(pinctl|mask):(pinctl&~mask)); + alc_pin_mode_values[val]); + + /* Also enable the retasking pin's input/output as required + * for the requested pin mode. Enum values of 2 or less are + * input modes. + * + * Dynamically switching the input/output buffers probably + * reduces noise slightly, particularly on input. However, + * havingboth input and output buffers enabled + * simultaneously doesn't seem to be problematic. + */ + if (val <= 2) { + snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + } else { + snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + } + } return change; } -#define ALC_PINCTL_SWITCH(xname, nid, mask) \ +#define ALC_PIN_MODE(xname, nid, dir) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = alc_pinctl_switch_info, \ - .get = alc_pinctl_switch_get, \ - .put = alc_pinctl_switch_put, \ - .private_value = (nid) | (mask<<16) } + .info = alc_pin_mode_info, \ + .get = alc_pin_mode_get, \ + .put = alc_pin_mode_put, \ + .private_value = nid | (dir<<16) } + +/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged + * together using a mask with more than one bit set. This control is + * currently used only by the ALC260 test model. At this stage they are not + * needed for any "production" models. + */ +#ifdef CONFIG_SND_DEBUG +static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} +static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00); + *valp = (val & mask) != 0; + return 0; +} +static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int gpio_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00); + + /* Set/unset the masked GPIO bit(s) as needed */ + change = (val==0?0:mask) != (gpio_data & mask); + if (val==0) + gpio_data &= ~mask; + else + gpio_data |= mask; + snd_hda_codec_write(codec,nid,0,AC_VERB_SET_GPIO_DATA,gpio_data); + + return change; +} +#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = alc_gpio_data_info, \ + .get = alc_gpio_data_get, \ + .put = alc_gpio_data_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +/* A switch control to allow the enabling of the digital IO pins on the + * ALC260. This is incredibly simplistic; the intention of this control is + * to provide something in the test model allowing digital outputs to be + * identified if present. If models are found which can utilise these + * outputs a more complete mixer control can be devised for those models if + * necessary. + */ +#ifdef CONFIG_SND_DEBUG +static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} +static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00); + + *valp = (val & mask) != 0; + return 0; +} +static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00); + + /* Set/unset the masked control bit(s) as needed */ + change = (val==0?0:mask) != (ctrl_data & mask); + if (val==0) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + snd_hda_codec_write(codec,nid,0,AC_VERB_SET_DIGI_CONVERT_1,ctrl_data); + + return change; +} +#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = alc_spdif_ctrl_info, \ + .get = alc_spdif_ctrl_get, \ + .put = alc_spdif_ctrl_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ /* * set up from the preset table @@ -296,6 +488,9 @@ static void setup_preset(struct alc_spec *spec, const struct alc_config_preset * spec->num_adc_nids = preset->num_adc_nids; spec->adc_nids = preset->adc_nids; spec->dig_in_nid = preset->dig_in_nid; + + spec->unsol_event = preset->unsol_event; + spec->init_hook = preset->init_hook; } /* @@ -1098,6 +1293,141 @@ static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { }; /* + * LG m1 express dual + * + * Pin assignment: + * Rear Line-In/Out (blue): 0x14 + * Build-in Mic-In: 0x15 + * Speaker-out: 0x17 + * HP-Out (green): 0x1b + * Mic-In/Out (red): 0x19 + * SPDIF-Out: 0x1e + */ + +/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ +static hda_nid_t alc880_lg_dac_nids[3] = { + 0x05, 0x02, 0x03 +}; + +/* seems analog CD is not working */ +static struct hda_input_mux alc880_lg_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x5 }, + { "Internal Mic", 0x6 }, + }, +}; + +/* 2,4,6 channel modes */ +static struct hda_verb alc880_lg_ch2_init[] = { + /* set line-in and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static struct hda_verb alc880_lg_ch4_init[] = { + /* set line-in to out and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static struct hda_verb alc880_lg_ch6_init[] = { + /* set line-in and mic-in to output */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { } +}; + +static struct hda_channel_mode alc880_lg_ch_modes[3] = { + { 2, alc880_lg_ch2_init }, + { 4, alc880_lg_ch4_init }, + { 6, alc880_lg_ch6_init }, +}; + +static struct snd_kcontrol_new alc880_lg_mixer[] = { + /* FIXME: it's not really "master" but front channels */ + HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static struct hda_verb alc880_lg_init_verbs[] = { + /* set capture source to mic-in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* mute all amp mixer inputs */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + /* line-in to input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* built-in mic */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* speaker-out */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* mic-in to input */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* HP-out */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* jack sense */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_lg_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); +} + +static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == 0x01) + alc880_lg_automute(codec); +} + +/* + * Common callbacks */ static int alc_init(struct hda_codec *codec) @@ -1107,9 +1437,21 @@ static int alc_init(struct hda_codec *codec) for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); + + if (spec->init_hook) + spec->init_hook(codec); + return 0; } +static void alc_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct alc_spec *spec = codec->spec; + + if (spec->unsol_event) + spec->unsol_event(codec, res); +} + #ifdef CONFIG_PM /* * resume @@ -1250,6 +1592,13 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = { /* NID is set in alc_build_pcms */ }; +/* Used by alc_build_pcms to flag that a PCM has no playback stream */ +static struct hda_pcm_stream alc_pcm_null_playback = { + .substreams = 0, + .channels_min = 0, + .channels_max = 0, +}; + static int alc_build_pcms(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1280,6 +1629,23 @@ static int alc_build_pcms(struct hda_codec *codec) } } + /* If the use of more than one ADC is requested for the current + * model, configure a second analog capture-only PCM. + */ + if (spec->num_adc_nids > 1) { + codec->num_pcms++; + info++; + info->name = spec->stream_name_analog; + /* No playback stream for second PCM */ + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; + if (spec->stream_analog_capture) { + snd_assert(spec->adc_nids, return -EINVAL); + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; + } + } + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { codec->num_pcms++; info++; @@ -1322,6 +1688,7 @@ static struct hda_codec_ops alc_patch_ops = { .build_pcms = alc_build_pcms, .init = alc_init, .free = alc_free, + .unsol_event = alc_unsol_event, #ifdef CONFIG_PM .resume = alc_resume, #endif @@ -1340,13 +1707,15 @@ static hda_nid_t alc880_test_dac_nids[4] = { }; static struct hda_input_mux alc880_test_capture_source = { - .num_items = 5, + .num_items = 7, .items = { { "In-1", 0x0 }, { "In-2", 0x1 }, { "In-3", 0x2 }, { "In-4", 0x3 }, { "CD", 0x4 }, + { "Front", 0x5 }, + { "Surround", 0x6 }, }, }; @@ -1653,6 +2022,8 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0xa0a0, .pci_subdevice = 0x0560, + .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */ /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */ { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, /* note subvendor = 0 below */ @@ -1680,6 +2051,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG }, { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG }, { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */ + { .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */ { .modelname = "asus", .config = ALC880_ASUS }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, @@ -1693,6 +2065,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */ { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, @@ -1702,6 +2075,9 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 }, + { .modelname = "lg", .config = ALC880_LG }, + { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG }, + #ifdef CONFIG_SND_DEBUG { .modelname = "test", .config = ALC880_TEST }, #endif @@ -1879,6 +2255,19 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, }, + [ALC880_LG] = { + .mixers = { alc880_lg_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_lg_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), + .dac_nids = alc880_lg_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), + .channel_mode = alc880_lg_ch_modes, + .input_mux = &alc880_lg_capture_source, + .unsol_event = alc880_lg_unsol_event, + .init_hook = alc880_lg_automute, + }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { .mixers = { alc880_test_mixer }, @@ -2043,14 +2432,11 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, if (alc880_is_fixed_pin(pin)) { nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - if (! spec->multiout.dac_nids[0]) { - /* use this as the primary output */ - spec->multiout.dac_nids[0] = nid; - if (! spec->multiout.num_dacs) - spec->multiout.num_dacs = 1; - } else - /* specify the DAC as the extra output */ + /* specify the DAC as the extra output */ + if (! spec->multiout.hp_nid) spec->multiout.hp_nid = nid; + else + spec->multiout.extra_out_nid[0] = nid; /* control HP volume/switch on the output mixer amp */ nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); sprintf(name, "%s Playback Volume", pfx); @@ -2063,12 +2449,6 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, return err; } else if (alc880_is_multi_pin(pin)) { /* set manual connection */ - if (! spec->multiout.dac_nids[0]) { - /* use this as the primary output */ - spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin)); - if (! spec->multiout.num_dacs) - spec->multiout.num_dacs = 1; - } /* we have only a switch on HP-out PIN */ sprintf(name, "%s Playback Switch", pfx); if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, @@ -2152,7 +2532,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t pin; - pin = spec->autocfg.speaker_pin; + pin = spec->autocfg.speaker_pins[0]; if (pin) /* connect to front */ alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); pin = spec->autocfg.hp_pin; @@ -2188,15 +2568,15 @@ static int alc880_parse_auto_config(struct hda_codec *codec) if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc880_ignore)) < 0) return err; - if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && - ! spec->autocfg.hp_pin) + if (! spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */ if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || (err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, + (err = alc880_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], "Speaker")) < 0 || - (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, + (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin, "Headphone")) < 0 || (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) return err; @@ -2218,14 +2598,12 @@ static int alc880_parse_auto_config(struct hda_codec *codec) return 1; } -/* init callback for auto-configuration model -- overriding the default init */ -static int alc880_auto_init(struct hda_codec *codec) +/* additional initialization for auto-configuration model */ +static void alc880_auto_init(struct hda_codec *codec) { - alc_init(codec); alc880_auto_init_multi_out(codec); alc880_auto_init_extra_out(codec); alc880_auto_init_analog_input(codec); - return 0; } /* @@ -2292,7 +2670,7 @@ static int patch_alc880(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC880_AUTO) - codec->patch_ops.init = alc880_auto_init; + spec->init_hook = alc880_auto_init; return 0; } @@ -2322,6 +2700,14 @@ static hda_nid_t alc260_hp_adc_nids[2] = { 0x05, 0x04 }; +/* NIDs used when simultaneous access to both ADCs makes sense. Note that + * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. + */ +static hda_nid_t alc260_dual_adc_nids[2] = { + /* ADC0, ADC1 */ + 0x04, 0x05 +}; + #define ALC260_DIGOUT_NID 0x03 #define ALC260_DIGIN_NID 0x06 @@ -2335,14 +2721,28 @@ static struct hda_input_mux alc260_capture_source = { }, }; -/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack - * and the internal CD lines. +/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, + * headphone jack and the internal CD lines. */ static struct hda_input_mux alc260_fujitsu_capture_source = { - .num_items = 2, + .num_items = 3, .items = { { "Mic/Line", 0x0 }, { "CD", 0x4 }, + { "Headphone", 0x2 }, + }, +}; + +/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configutation to + * the Fujitsu S702x, but jacks are marked differently. We won't allow + * retasking the Headphone jack, so it won't be available here. + */ +static struct hda_input_mux alc260_acer_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, }, }; @@ -2363,6 +2763,7 @@ static struct hda_channel_mode alc260_modes[1] = { * HP: base_output + input + capture_alt * HP_3013: hp_3013 + input + capture * fujitsu: fujitsu + capture + * acer: acer + capture */ static struct snd_kcontrol_new alc260_base_output_mixer[] = { @@ -2408,11 +2809,12 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), - ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP), + ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), @@ -2420,6 +2822,22 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc260_acer_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), + { } /* end */ +}; + /* capture mixer elements */ static struct snd_kcontrol_new alc260_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), @@ -2629,52 +3047,327 @@ static struct hda_verb alc260_fujitsu_init_verbs[] = { {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Headphone/Line-out jack connects to Line1 pin; make it an output */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Ensure all other unused pins are disabled and muted. - * Note: trying to set widget 0x15 to anything blocks all audio - * output for some reason, so just leave that at the default. + /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Ensure all other unused pins are disabled and muted. */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Line1 pin widget takes its input from the OUT1 sum bus + * when acting as an output. + */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Line1 pin widget output buffer since it starts as an output. + * If the pin mode is changed by the user the pin mode control will + * take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute input buffer of pin widget used for Line-in (no equiv + * mixer ctrl) + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - line + * in (on mic1 pin) */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to line in (on mic1 pin) + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +/* Initialisation sequence for ALC260 as configured in Acer TravelMate and + * similar laptops (adapted from Fujitsu init verbs). + */ +static struct hda_verb alc260_acer_init_verbs[] = { + /* On TravelMate laptops, GPIO 0 enables the internal speaker and + * the headphone jack. Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Internal speaker/Headphone jack is connected to Line-out pin */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Internal microphone/Mic jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Line In jack is connected to Line1 pin */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Start with mixer outputs muted */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to line in (on mic1 pin) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to line (on line1 pin) + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ { } }; +/* Test configuration for debugging, modelled after the ALC880 test + * configuration. + */ +#ifdef CONFIG_SND_DEBUG +static hda_nid_t alc260_test_dac_nids[1] = { + 0x02, +}; +static hda_nid_t alc260_test_adc_nids[2] = { + 0x04, 0x05, +}; +/* This is a bit messy since the two input muxes in the ALC260 have slight + * variations in their signal assignments. The ideal way to deal with this + * is to extend alc_spec.input_mux to allow a different input MUX for each + * ADC. For the purposes of the test model it's sufficient to just list + * both options for affected signal indices. The separate input mux + * functionality only needs to be considered if a model comes along which + * actually uses signals 0x5, 0x6 and 0x7 for something which makes sense to + * record. + */ +static struct hda_input_mux alc260_test_capture_source = { + .num_items = 8, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "LINE-OUT pin (cap1), Mixer (cap2)", 0x5 }, + { "HP-OUT pin (cap1), LINE-OUT pin (cap2)", 0x6 }, + { "HP-OUT pin (cap2 only)", 0x7 }, + }, +}; +static struct snd_kcontrol_new alc260_test_mixer[] = { + /* Output driver widgets */ + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), + + /* Modes for retasking pin widgets */ + ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), + + /* Loopback mixer controls */ + HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), + HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), + + /* Controls for GPIO pins, assuming they are configured as outputs */ + ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), + + /* Switches to allow the digital IO pins to be enabled. The datasheet + * is ambigious as to which NID is which; testing on laptops which + * make this output available should provide clarification. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), + ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), + + { } /* end */ +}; +static struct hda_verb alc260_test_init_verbs[] = { + /* Enable all GPIOs as outputs with an initial value of 0 */ + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, + + /* Enable retasking pins as output, initially without power amp */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* Disable digital (SPDIF) pins initially, but users can enable + * them via a mixer switch. In the case of SPDIF-out, this initverb + * payload also sets the generation to 0, output to be in "consumer" + * PCM format, copyright asserted, no pre-emphasis and no validity + * control. + */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the + * OUT1 sum bus when acting as an output. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute retasking pin widget output buffers since the default + * state appears to be output. As the pin mode is changed by the + * user the pin mode control will take care of enabling the pin's + * input/output buffers as needed. + */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Also unmute the mono-out pin widget */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting (mic1 + * pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to mic1 pin + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; +#endif + static struct hda_pcm_stream alc260_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -2744,7 +3437,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, return err; } - nid = cfg->speaker_pin; + nid = cfg->speaker_pins[0]; if (nid) { err = alc260_add_playback_controls(spec, nid, "Speaker"); if (err < 0) @@ -2817,7 +3510,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) if (nid) alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); - nid = spec->autocfg.speaker_pin; + nid = spec->autocfg.speaker_pins[0]; if (nid) alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); @@ -2932,13 +3625,11 @@ static int alc260_parse_auto_config(struct hda_codec *codec) return 1; } -/* init callback for auto-configuration model -- overriding the default init */ -static int alc260_auto_init(struct hda_codec *codec) +/* additional initialization for auto-configuration model */ +static void alc260_auto_init(struct hda_codec *codec) { - alc_init(codec); alc260_auto_init_multi_out(codec); alc260_auto_init_analog_input(codec); - return 0; } /* @@ -2948,6 +3639,8 @@ static struct hda_board_config alc260_cfg_tbl[] = { { .modelname = "basic", .config = ALC260_BASIC }, { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb, .config = ALC260_BASIC }, /* Sony VAIO */ + { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, + .config = ALC260_BASIC }, /* CTL Travel Master U553W */ { .modelname = "hp", .config = ALC260_HP }, { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, @@ -2958,6 +3651,11 @@ static struct hda_board_config alc260_cfg_tbl[] = { { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP }, { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X }, { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X }, + { .modelname = "acer", .config = ALC260_ACER }, + { .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER }, +#ifdef CONFIG_SND_DEBUG + { .modelname = "test", .config = ALC260_TEST }, +#endif { .modelname = "auto", .config = ALC260_AUTO }, {} }; @@ -3009,12 +3707,38 @@ static struct alc_config_preset alc260_presets[] = { .init_verbs = { alc260_fujitsu_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_fujitsu_capture_source, }, + [ALC260_ACER] = { + .mixers = { alc260_acer_mixer, + alc260_capture_mixer }, + .init_verbs = { alc260_acer_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_acer_capture_source, + }, +#ifdef CONFIG_SND_DEBUG + [ALC260_TEST] = { + .mixers = { alc260_test_mixer, + alc260_capture_mixer }, + .init_verbs = { alc260_test_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), + .dac_nids = alc260_test_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), + .adc_nids = alc260_test_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_test_capture_source, + }, +#endif }; static int patch_alc260(struct hda_codec *codec) @@ -3059,7 +3783,7 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC260_AUTO) - codec->patch_ops.init = alc260_auto_init; + spec->init_hook = alc260_auto_init; return 0; } @@ -3534,14 +4258,12 @@ static int alc882_parse_auto_config(struct hda_codec *codec) return err; } -/* init callback for auto-configuration model -- overriding the default init */ -static int alc882_auto_init(struct hda_codec *codec) +/* additional initialization for auto-configuration model */ +static void alc882_auto_init(struct hda_codec *codec) { - alc_init(codec); alc882_auto_init_multi_out(codec); alc882_auto_init_hp_out(codec); alc882_auto_init_analog_input(codec); - return 0; } /* @@ -3608,7 +4330,7 @@ static int patch_alc882(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC882_AUTO) - codec->patch_ops.init = alc882_auto_init; + spec->init_hook = alc882_auto_init; return 0; } @@ -3644,19 +4366,9 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, { } /* end */ -}; - +}; + #define alc262_capture_mixer alc882_capture_mixer #define alc262_capture_alt_mixer alc882_capture_alt_mixer @@ -3739,6 +4451,129 @@ static struct hda_verb alc262_init_verbs[] = { { } }; +/* + * fujitsu model + * 0x14 = headphone/spdif-out, 0x15 = internal speaker + */ + +#define ALC_HP_EVENT 0x37 + +static struct hda_verb alc262_fujitsu_unsol_verbs[] = { + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static struct hda_input_mux alc262_fujitsu_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "CD", 0x4 }, + }, +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_fujitsu_automute(struct hda_codec *codec, int force) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + if (force || ! spec->sense_updated) { + unsigned int present; + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + spec->sense_updated = 1; + } + if (spec->jack_present) { + /* mute internal speaker */ + snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + 0x80, 0x80); + snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + 0x80, 0x80); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + 0x80, mute & 0x80); + mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0); + snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + 0x80, mute & 0x80); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc262_fujitsu_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC_HP_EVENT) + return; + alc262_fujitsu_automute(codec, 1); +} + +/* bind volumes of both NID 0x0c and 0x0d */ +static int alc262_fujitsu_master_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + return change; +} + +/* bind hp and internal speaker mute (with plug check) */ +static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + 0x80, valp[0] ? 0 : 0x80); + change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + 0x80, valp[1] ? 0 : 0x80); + if (change || codec->in_resume) + alc262_fujitsu_automute(codec, codec->in_resume); + return change; +} + +static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = alc262_fujitsu_master_vol_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_fujitsu_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + /* add playback controls from the parsed DAC table */ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { @@ -3759,7 +4594,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct return err; } - nid = cfg->speaker_pin; + nid = cfg->speaker_pins[0]; if (nid) { if (nid == 0x16) { if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", @@ -3769,10 +4604,6 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) return err; } else { - if (! cfg->line_out_pins[0]) - if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) - return err; if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch", HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) return err; @@ -3789,10 +4620,6 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) return err; } else { - if (! cfg->line_out_pins[0]) - if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) - return err; if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) return err; @@ -3886,8 +4713,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc262_ignore)) < 0) return err; - if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && - ! spec->autocfg.hp_pin) + if (! spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */ if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || (err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) @@ -3915,13 +4741,11 @@ static int alc262_parse_auto_config(struct hda_codec *codec) /* init callback for auto-configuration model -- overriding the default init */ -static int alc262_auto_init(struct hda_codec *codec) +static void alc262_auto_init(struct hda_codec *codec) { - alc_init(codec); alc262_auto_init_multi_out(codec); alc262_auto_init_hp_out(codec); alc262_auto_init_analog_input(codec); - return 0; } /* @@ -3929,6 +4753,8 @@ static int alc262_auto_init(struct hda_codec *codec) */ static struct hda_board_config alc262_cfg_tbl[] = { { .modelname = "basic", .config = ALC262_BASIC }, + { .modelname = "fujitsu", .config = ALC262_FUJITSU }, + { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, .config = ALC262_FUJITSU }, { .modelname = "auto", .config = ALC262_AUTO }, {} }; @@ -3944,6 +4770,18 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, }, + [ALC262_FUJITSU] = { + .mixers = { alc262_fujitsu_mixer }, + .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_fujitsu_capture_source, + .unsol_event = alc262_fujitsu_unsol_event, + }, }; static int patch_alc262(struct hda_codec *codec) @@ -4017,8 +4855,8 @@ static int patch_alc262(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC262_AUTO) - codec->patch_ops.init = alc262_auto_init; - + spec->init_hook = alc262_auto_init; + return 0; } @@ -4549,8 +5387,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc861_ignore)) < 0) return err; - if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && - ! spec->autocfg.hp_pin) + if (! spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */ if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || @@ -4579,15 +5416,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec) return 1; } -/* init callback for auto-configuration model -- overriding the default init */ -static int alc861_auto_init(struct hda_codec *codec) +/* additional initialization for auto-configuration model */ +static void alc861_auto_init(struct hda_codec *codec) { - alc_init(codec); alc861_auto_init_multi_out(codec); alc861_auto_init_hp_out(codec); alc861_auto_init_analog_input(codec); - - return 0; } @@ -4685,7 +5519,7 @@ static int patch_alc861(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC861_AUTO) - codec->patch_ops.init = alc861_auto_init; + spec->init_hook = alc861_auto_init; return 0; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 35c2823a0a2b..b56ca4019392 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -51,6 +51,7 @@ struct sigmatel_spec { unsigned int line_switch: 1; unsigned int mic_switch: 1; unsigned int alt_switch: 1; + unsigned int hp_detect: 1; /* playback */ struct hda_multi_out multiout; @@ -303,6 +304,12 @@ static struct hda_board_config stac922x_cfg_tbl[] = { .pci_subdevice = 0x0101, .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ { .pci_subvendor = PCI_VENDOR_ID_INTEL, + .pci_subdevice = 0x0202, + .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack, 9221 A1 */ + { .pci_subvendor = PCI_VENDOR_ID_INTEL, + .pci_subdevice = 0x0b0b, + .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack, 9221 A1 */ + { .pci_subvendor = PCI_VENDOR_ID_INTEL, .pci_subdevice = 0x0404, .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ { .pci_subvendor = PCI_VENDOR_ID_INTEL, @@ -691,13 +698,7 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct aut AC_VERB_GET_CONNECT_LIST, 0) & 0xff; } - if (cfg->line_outs) - spec->multiout.num_dacs = cfg->line_outs; - else if (cfg->hp_pin) { - spec->multiout.dac_nids[0] = snd_hda_codec_read(codec, cfg->hp_pin, 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - spec->multiout.num_dacs = 1; - } + spec->multiout.num_dacs = cfg->line_outs; return 0; } @@ -766,11 +767,13 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin return 0; wid_caps = get_wcaps(codec, pin); - if (wid_caps & AC_WCAP_UNSOL_CAP) + if (wid_caps & AC_WCAP_UNSOL_CAP) { /* Enable unsolicited responses on the HP widget */ snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_UNSOLICITED_ENABLE, STAC_UNSOL_ENABLE); + spec->hp_detect = 1; + } nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; for (i = 0; i < cfg->line_outs; i++) { @@ -804,9 +807,6 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const for (i = 0; i < AUTO_PIN_LAST; i++) { int index = -1; if (cfg->input_pins[i]) { - /* Enable active pin widget as an input */ - stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], AC_PINCTL_IN_EN); - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; for (j=0; j<spec->num_muxes; j++) { @@ -855,10 +855,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) return err; - if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) + if (! spec->autocfg.line_outs) return 0; /* can't find valid pin config */ - stac92xx_auto_init_multi_out(codec); - stac92xx_auto_init_hp_out(codec); if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) return err; if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) @@ -873,14 +871,10 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if (spec->multiout.max_channels > 2) spec->surr_switch = 1; - if (spec->autocfg.dig_out_pin) { + if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = dig_out; - stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); - } - if (spec->autocfg.dig_in_pin) { + if (spec->autocfg.dig_in_pin) spec->dig_in_nid = dig_in; - stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN); - } if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc; @@ -890,6 +884,29 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out return 1; } +/* add playback controls for HP output */ +static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, + struct auto_pin_cfg *cfg) +{ + struct sigmatel_spec *spec = codec->spec; + hda_nid_t pin = cfg->hp_pin; + unsigned int wid_caps; + + if (! pin) + return 0; + + wid_caps = get_wcaps(codec, pin); + if (wid_caps & AC_WCAP_UNSOL_CAP) { + /* Enable unsolicited responses on the HP widget */ + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + STAC_UNSOL_ENABLE); + spec->hp_detect = 1; + } + + return 0; +} + static int stac9200_parse_auto_config(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -901,14 +918,13 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) return err; - if (spec->autocfg.dig_out_pin) { + if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) + return err; + + if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = 0x05; - stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); - } - if (spec->autocfg.dig_in_pin) { + if (spec->autocfg.dig_in_pin) spec->dig_in_nid = 0x04; - stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN); - } if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc; @@ -921,9 +937,31 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) static int stac92xx_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; snd_hda_sequence_write(codec, spec->init); + /* set up pins */ + if (spec->hp_detect) { + /* fake event to set up pins */ + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + } else { + stac92xx_auto_init_multi_out(codec); + stac92xx_auto_init_hp_out(codec); + } + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (cfg->input_pins[i]) + stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], + AC_PINCTL_IN_EN); + } + if (cfg->dig_out_pin) + stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, + AC_PINCTL_OUT_EN); + if (cfg->dig_in_pin) + stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, + AC_PINCTL_IN_EN); + return 0; } @@ -1142,6 +1180,166 @@ static int patch_stac927x(struct hda_codec *codec) } /* + * STAC 7661(?) hack + */ + +/* static config for Sony VAIO FE550G */ +static hda_nid_t vaio_dacs[] = { 0x2 }; +#define VAIO_HP_DAC 0x5 +static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; +static hda_nid_t vaio_mux_nids[] = { 0x15 }; + +static struct hda_input_mux vaio_mux = { + .num_items = 2, + .items = { + /* { "HP", 0x0 }, + { "Unknown", 0x1 }, */ + { "Mic", 0x2 }, + { "PCM", 0x3 }, + } +}; + +static struct hda_verb vaio_init[] = { + {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ + {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ + {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */ + {} +}; + +/* bind volumes of both NID 0x02 and 0x05 */ +static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + return change; +} + +/* bind volumes of both NID 0x02 and 0x05 */ +static int vaio_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, + 0x80, valp[0] & 0x80); + change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, + 0x80, valp[1] & 0x80); + snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, + 0x80, valp[0] & 0x80); + snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, + 0x80, valp[1] & 0x80); + return change; +} + +static struct snd_kcontrol_new vaio_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = vaio_master_vol_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = vaio_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + }, + /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = stac92xx_mux_enum_info, + .get = stac92xx_mux_enum_get, + .put = stac92xx_mux_enum_put, + }, + {} +}; + +static struct hda_codec_ops stac7661_patch_ops = { + .build_controls = stac92xx_build_controls, + .build_pcms = stac92xx_build_pcms, + .init = stac92xx_init, + .free = stac92xx_free, +#ifdef CONFIG_PM + .resume = stac92xx_resume, +#endif +}; + +enum { STAC7661_VAIO }; + +static struct hda_board_config stac7661_cfg_tbl[] = { + { .modelname = "vaio", .config = STAC7661_VAIO }, + { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, + .config = STAC7661_VAIO }, + { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, + .config = STAC7661_VAIO }, + {} +}; + +static int patch_stac7661(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + int board_config; + + board_config = snd_hda_check_board_config(codec, stac7661_cfg_tbl); + if (board_config < 0) + /* unknown config, let generic-parser do its job... */ + return snd_hda_parse_generic_codec(codec); + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + switch (board_config) { + case STAC7661_VAIO: + spec->mixer = vaio_mixer; + spec->init = vaio_init; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs); + spec->multiout.dac_nids = vaio_dacs; + spec->multiout.hp_nid = VAIO_HP_DAC; + spec->num_adcs = ARRAY_SIZE(vaio_adcs); + spec->adc_nids = vaio_adcs; + spec->input_mux = &vaio_mux; + spec->mux_nids = vaio_mux_nids; + break; + } + + codec->patch_ops = stac7661_patch_ops; + return 0; +} + + +/* * patch entries */ struct hda_codec_preset snd_hda_preset_sigmatel[] = { @@ -1162,5 +1360,6 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, + { .id = 0x83847661, .name = "STAC7661", .patch = patch_stac7661 }, {} /* terminator */ }; diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 8809812a1c22..7e6608b14abc 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -53,6 +53,8 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include "ice1712.h" @@ -210,14 +212,14 @@ static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short vol; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F); ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F); if (kcontrol->private_value & AUREON_AC97_STEREO) ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -252,11 +254,11 @@ static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -288,11 +290,11 @@ static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ct { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -322,36 +324,48 @@ static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned { unsigned int tmp; int i; + unsigned int mosi, clk; tmp = snd_ice1712_gpio_read(ice); - snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK| - AUREON_WM_CS|AUREON_CS8415_CS)); - tmp |= AUREON_WM_RW; + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) { + snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS)); + mosi = PRODIGY_SPI_MOSI; + clk = PRODIGY_SPI_CLK; + } + else { + snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK| + AUREON_WM_CS|AUREON_CS8415_CS)); + mosi = AUREON_SPI_MOSI; + clk = AUREON_SPI_CLK; + + tmp |= AUREON_WM_RW; + } + tmp &= ~cs; snd_ice1712_gpio_write(ice, tmp); udelay(1); for (i = bits - 1; i >= 0; i--) { - tmp &= ~AUREON_SPI_CLK; + tmp &= ~clk; snd_ice1712_gpio_write(ice, tmp); udelay(1); if (data & (1 << i)) - tmp |= AUREON_SPI_MOSI; + tmp |= mosi; else - tmp &= ~AUREON_SPI_MOSI; + tmp &= ~mosi; snd_ice1712_gpio_write(ice, tmp); udelay(1); - tmp |= AUREON_SPI_CLK; + tmp |= clk; snd_ice1712_gpio_write(ice, tmp); udelay(1); } - tmp &= ~AUREON_SPI_CLK; + tmp &= ~clk; tmp |= cs; snd_ice1712_gpio_write(ice, tmp); udelay(1); - tmp |= AUREON_SPI_CLK; + tmp |= clk; snd_ice1712_gpio_write(ice, tmp); udelay(1); } @@ -440,7 +454,9 @@ static unsigned short wm_get(struct snd_ice1712 *ice, int reg) */ static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) { - aureon_spi_write(ice, AUREON_WM_CS, (reg << 9) | (val & 0x1ff), 16); + aureon_spi_write(ice, + (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS), + (reg << 9) | (val & 0x1ff), 16); } /* @@ -474,11 +490,11 @@ static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -543,9 +559,9 @@ static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -768,11 +784,11 @@ static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short val; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; val = val > PCM_MIN ? (val - PCM_MIN) : 0; ucontrol->value.integer.value[0] = val; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -813,12 +829,12 @@ static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va unsigned short val; int i; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (i = 0; i < 2; i++) { val = wm_get(ice, WM_ADC_GAIN + i); ucontrol->value.integer.value[i] = ~val>>5 & 0x1; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -860,13 +876,13 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val int i, idx; unsigned short vol; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (i = 0; i < 2; i++) { idx = WM_ADC_GAIN + i; vol = wm_get(ice, idx) & 0x1f; ucontrol->value.integer.value[i] = vol; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -937,11 +953,11 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short val; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); val = wm_get(ice, WM_ADC_MUX); - ucontrol->value.integer.value[0] = val & 7; - ucontrol->value.integer.value[1] = (val >> 4) & 7; - up(&ice->gpio_mutex); + ucontrol->value.enumerated.item[0] = val & 7; + ucontrol->value.enumerated.item[1] = (val >> 4) & 7; + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -954,8 +970,8 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val snd_ice1712_save_gpio_status(ice); oval = wm_get(ice, WM_ADC_MUX); nval = oval & ~0x77; - nval |= ucontrol->value.integer.value[0] & 7; - nval |= (ucontrol->value.integer.value[1] & 7) << 4; + nval |= ucontrol->value.enumerated.item[0] & 7; + nval |= (ucontrol->value.enumerated.item[1] & 7) << 4; change = (oval != nval); if (change) wm_put(ice, WM_ADC_MUX, nval); @@ -995,7 +1011,7 @@ static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e //snd_ice1712_save_gpio_status(ice); //val = aureon_cs8415_get(ice, CS8415_CTRL2); - ucontrol->value.integer.value[0] = ice->spec.aureon.cs8415_mux; + ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux; //snd_ice1712_restore_gpio_status(ice); return 0; } @@ -1009,12 +1025,12 @@ static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e snd_ice1712_save_gpio_status(ice); oval = aureon_cs8415_get(ice, CS8415_CTRL2); nval = oval & ~0x07; - nval |= ucontrol->value.integer.value[0] & 7; + nval |= ucontrol->value.enumerated.item[0] & 7; change = (oval != nval); if (change) aureon_cs8415_put(ice, CS8415_CTRL2, nval); snd_ice1712_restore_gpio_status(ice); - ice->spec.aureon.cs8415_mux = ucontrol->value.integer.value[0]; + ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0]; return change; } @@ -1659,7 +1675,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) return err; } } - else { + else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) { err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice)); if (err < 0) @@ -1667,7 +1683,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) } } - { + if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { unsigned char id; snd_ice1712_save_gpio_status(ice); id = aureon_cs8415_get(ice, CS8415_ID); @@ -1822,7 +1838,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) udelay(1); /* initialize WM8770 codec */ - if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71) + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 || + ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) p = wm_inits_prodigy; else p = wm_inits_aureon; @@ -1830,11 +1847,13 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) wm_put(ice, p[0], p[1]); /* initialize CS8415A codec */ - for (p = cs_inits; *p != (unsigned short)-1; p++) - aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); - ice->spec.aureon.cs8415_mux = 1; + if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { + for (p = cs_inits; *p != (unsigned short)-1; p++) + aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); + ice->spec.aureon.cs8415_mux = 1; - aureon_set_headphone_amp(ice, 1); + aureon_set_headphone_amp(ice, 1); + } snd_ice1712_restore_gpio_status(ice); @@ -1902,6 +1921,23 @@ static unsigned char prodigy71_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE2 */ }; +static unsigned char prodigy71lt_eeprom[] __devinitdata = { + 0x0b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */ + 0x80, /* ACLINK: I2S */ + 0xfc, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDUF: out-en, out-int */ + 0x00, /* GPIO_DIR */ + 0x07, /* GPIO_DIR1 */ + 0x00, /* GPIO_DIR2 */ + 0xff, /* GPIO_MASK */ + 0xf8, /* GPIO_MASK1 */ + 0xff, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + + /* entry point */ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { { @@ -1944,5 +1980,15 @@ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { .eeprom_data = prodigy71_eeprom, .driver = "Prodigy71", /* should be identical with Aureon71 */ }, + { + .subvendor = VT1724_SUBDEVICE_PRODIGY71LT, + .name = "Audiotrak Prodigy 7.1 LT", + .model = "prodigy71lt", + .chip_init = aureon_init, + .build_controls = aureon_add_controls, + .eeprom_size = sizeof(prodigy71lt_eeprom), + .eeprom_data = prodigy71lt_eeprom, + .driver = "Prodigy71LT", + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h index 95d515f36f23..98a6752280f2 100644 --- a/sound/pci/ice1712/aureon.h +++ b/sound/pci/ice1712/aureon.h @@ -27,12 +27,14 @@ #define AUREON_DEVICE_DESC "{Terratec,Aureon 5.1 Sky},"\ "{Terratec,Aureon 7.1 Space},"\ "{Terratec,Aureon 7.1 Universe}," \ - "{AudioTrak,Prodigy 7.1}," + "{AudioTrak,Prodigy 7.1}," \ + "{AudioTrak,Prodigy 7.1 LT}," #define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */ #define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */ #define VT1724_SUBDEVICE_AUREON71_UNIVERSE 0x3b155311 /* Aureon 7.1 Universe */ #define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */ +#define VT1724_SUBDEVICE_PRODIGY71LT 0x32315441 /* PRODIGY 7.1 LT */ extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; @@ -53,4 +55,8 @@ extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; #define AUREON_AC97_DATA_HIGH (1 << 8) #define AUREON_AC97_DATA_MASK 0xFF +#define PRODIGY_WM_CS (1 << 8) +#define PRODIGY_SPI_MOSI (1 << 10) +#define PRODIGY_SPI_CLK (1 << 9) + #endif /* __SOUND_AUREON_H */ diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 9a51d34e6817..af659800c9b0 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -28,6 +28,8 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/cs8427.h> #include <sound/asoundef.h> @@ -130,13 +132,13 @@ static int ap_cs8427_sendbytes(struct snd_i2c_device *device, unsigned char *byt int res = count; unsigned char tmp; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); tmp = ap_cs8427_codec_select(ice); ap_cs8427_write_byte(ice, (device->addr << 1) | 0, tmp); /* address + write mode */ while (count-- > 0) ap_cs8427_write_byte(ice, *bytes++, tmp); ap_cs8427_codec_deassert(ice, tmp); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return res; } @@ -147,13 +149,13 @@ static int ap_cs8427_readbytes(struct snd_i2c_device *device, unsigned char *byt int res = count; unsigned char tmp; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); tmp = ap_cs8427_codec_select(ice); ap_cs8427_write_byte(ice, (device->addr << 1) | 1, tmp); /* address + read mode */ while (count-- > 0) *bytes++ = ap_cs8427_read_byte(ice, tmp); ap_cs8427_codec_deassert(ice, tmp); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return res; } @@ -180,7 +182,7 @@ static void snd_ice1712_delta_cs8403_spdif_write(struct snd_ice1712 *ice, unsign /* send byte to transmitter */ mask1 = ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK; mask2 = ICE1712_DELTA_SPDIF_OUT_STAT_DATA; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); for (idx = 7; idx >= 0; idx--) { tmp &= ~(mask1 | mask2); @@ -194,7 +196,7 @@ static void snd_ice1712_delta_cs8403_spdif_write(struct snd_ice1712 *ice, unsign } tmp &= ~mask1; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } @@ -296,14 +298,14 @@ static void delta_1010_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) if (rate == 0) /* no hint - S/PDIF input is master, simply return */ return; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); tmp2 = tmp & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp2 |= ICE1712_DELTA_DFS; if (tmp != tmp2) snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp2); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } /* @@ -318,9 +320,9 @@ static void delta_ak4524_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) return; /* check before reset ak4524 to avoid unnecessary clicks */ - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); tmp2 = tmp & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp2 |= ICE1712_DELTA_DFS; @@ -329,12 +331,12 @@ static void delta_ak4524_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) /* do it again */ snd_akm4xxx_reset(ak, 1); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp |= ICE1712_DELTA_DFS; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); snd_akm4xxx_reset(ak, 0); } @@ -391,6 +393,37 @@ static void delta_setup_spdif(struct snd_ice1712 *ice, int rate) snd_ice1712_delta_cs8403_spdif_write(ice, tmp); } +static int snd_ice1712_delta1010lt_wordclock_status_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + char reg = 0x10; // cs8427 receiver error register + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + + if (snd_i2c_sendbytes(ice->cs8427, ®, 1) != 1) + snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); + snd_i2c_readbytes(ice->cs8427, ®, 1); + ucontrol->value.integer.value[0] = (reg ? 1 : 0); + return 0; +} + +static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata = +{ + .access = (SNDRV_CTL_ELEM_ACCESS_READ), + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Word Clock Status", + .info = snd_ice1712_delta1010lt_wordclock_status_info, + .get = snd_ice1712_delta1010lt_wordclock_status_get, +}; /* * initialize the chips on M-Audio cards @@ -620,7 +653,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0); static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata = -ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0); +ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0); static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata = @@ -653,6 +686,9 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta1010lt_wordclock_select, ice)); if (err < 0) return err; + err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta1010lt_wordclock_status, ice)); + if (err < 0) + return err; break; } diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 3f2f918536f5..3f27d04e7d3c 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c @@ -27,6 +27,8 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include "ice1712.h" @@ -48,31 +50,31 @@ static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, un static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) { - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) { - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) { - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) { - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); /* select box */ ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); @@ -115,12 +117,12 @@ static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, i ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) { - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); /* select box */ ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); @@ -141,15 +143,15 @@ static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) { - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index ef6f18558c95..672e198317e1 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -53,8 +53,10 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/cs8427.h> #include <sound/info.h> @@ -82,10 +84,11 @@ MODULE_SUPPORTED_DEVICE("{" static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ static char *model[SNDRV_CARDS]; -static int omni[SNDRV_CARDS]; /* Delta44 & 66 Omni I/O support */ +static int omni[SNDRV_CARDS]; /* Delta44 & 66 Omni I/O support */ static int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transciever reset timeout value in msec */ +static int dxr_enable[SNDRV_CARDS]; /* DXR enable for DMX6FIRE */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard."); @@ -99,6 +102,8 @@ module_param_array(cs8427_timeout, int, NULL, 0444); MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); +module_param_array(dxr_enable, int, NULL, 0444); +MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); static struct pci_device_id snd_ice1712_ids[] = { @@ -316,7 +321,6 @@ static void snd_ice1712_set_gpio_data(struct snd_ice1712 *ice, unsigned int val) inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ } - /* * * CS8427 interface @@ -396,6 +400,20 @@ int __devinit snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr) return 0; } +static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdif_is_master) +{ + /* change CS8427 clock source too */ + if (ice->cs8427) + snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master); + /* notify ak4524 chip as well */ + if (spdif_is_master) { + unsigned int i; + for (i = 0; i < ice->akm_codecs; i++) { + if (ice->akm[i].ops.set_rate_val) + ice->akm[i].ops.set_rate_val(&ice->akm[i], 0); + } + } +} /* * Interrupt handler @@ -1567,6 +1585,9 @@ static void snd_ice1712_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, " CAPTURE : 0x%08x\n", inl(ICEMT(ice, ROUTE_CAPTURE))); snd_iprintf(buffer, " SPDOUT : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT))); snd_iprintf(buffer, " RATE : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE))); + snd_iprintf(buffer, " GPIO_DATA : 0x%02x\n", (unsigned)snd_ice1712_get_gpio_data(ice)); + snd_iprintf(buffer, " GPIO_WRITE_MASK : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK)); + snd_iprintf(buffer, " GPIO_DIRECTION : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION)); } static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice) @@ -1856,20 +1877,8 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, spin_unlock_irq(&ice->reg_lock); if ((oval & ICE1712_SPDIF_MASTER) != - (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) { - /* change CS8427 clock source too */ - if (ice->cs8427) { - snd_ice1712_cs8427_set_input_clock(ice, is_spdif_master(ice)); - } - /* notify ak4524 chip as well */ - if (is_spdif_master(ice)) { - unsigned int i; - for (i = 0; i < ice->akm_codecs; i++) { - if (ice->akm[i].ops.set_rate_val) - ice->akm[i].ops.set_rate_val(&ice->akm[i], 0); - } - } - } + (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) + snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice)); return change; } @@ -2388,7 +2397,13 @@ static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice) udelay(200); outb(ICE1712_NATIVE, ICEREG(ice, CONTROL)); udelay(200); - pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]); + if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && !ice->dxr_enable) { + /* Limit active ADCs and DACs to 6; */ + /* Note: DXR extension not supported */ + pci_write_config_byte(ice->pci, 0x60, 0x0a); + } else { + pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]); + } pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]); pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]); pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]); @@ -2524,6 +2539,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card, const char *modelname, int omni, int cs8427_timeout, + int dxr_enable, struct snd_ice1712 ** r_ice1712) { struct snd_ice1712 *ice; @@ -2538,8 +2554,8 @@ static int __devinit snd_ice1712_create(struct snd_card *card, if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 28 bits */ - if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; @@ -2556,10 +2572,11 @@ static int __devinit snd_ice1712_create(struct snd_card *card, else if (cs8427_timeout > 1000) cs8427_timeout = 1000; ice->cs8427_timeout = cs8427_timeout; + ice->dxr_enable = dxr_enable; spin_lock_init(&ice->reg_lock); - init_MUTEX(&ice->gpio_mutex); - init_MUTEX(&ice->i2c_mutex); - init_MUTEX(&ice->open_mutex); + mutex_init(&ice->gpio_mutex); + mutex_init(&ice->i2c_mutex); + mutex_init(&ice->open_mutex); ice->gpio.set_mask = snd_ice1712_set_gpio_mask; ice->gpio.set_dir = snd_ice1712_set_gpio_dir; ice->gpio.set_data = snd_ice1712_set_gpio_data; @@ -2658,7 +2675,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, strcpy(card->shortname, "ICEnsemble ICE1712"); if ((err = snd_ice1712_create(card, pci, model[dev], omni[dev], - cs8427_timeout[dev], &ice)) < 0) { + cs8427_timeout[dev], dxr_enable[dev], + &ice)) < 0) { snd_card_free(card); return err; } @@ -2735,6 +2753,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, } } + snd_ice1712_set_input_clock_source(ice, 0); + sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, ice->port, ice->irq); diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index ce96b3bb6531..f9b22d4a3932 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -325,6 +325,7 @@ struct snd_ice1712 { unsigned int pro_volumes[20]; unsigned int omni: 1; /* Delta Omni I/O */ + unsigned int dxr_enable: 1; /* Terratec DXR enable for DMX6FIRE */ unsigned int vt1724: 1; unsigned int vt1720: 1; unsigned int has_spdif: 1; /* VT1720/4 - has SPDIF I/O */ @@ -334,7 +335,7 @@ struct snd_ice1712 { unsigned int num_total_adcs; /* total ADCs */ unsigned int cur_rate; /* current rate */ - struct semaphore open_mutex; + struct mutex open_mutex; struct snd_pcm_substream *pcm_reserved[4]; struct snd_pcm_hw_constraint_list *hw_rates; /* card-specific rate constraints */ @@ -342,7 +343,7 @@ struct snd_ice1712 { struct snd_akm4xxx *akm; struct snd_ice1712_spdif spdif; - struct semaphore i2c_mutex; /* I2C mutex for ICE1724 registers */ + struct mutex i2c_mutex; /* I2C mutex for ICE1724 registers */ struct snd_i2c_bus *i2c; /* I2C bus */ struct snd_i2c_device *cs8427; /* CS8427 I2C device */ unsigned int cs8427_timeout; /* CS8427 reset timeout in HZ/100 */ @@ -360,7 +361,7 @@ struct snd_ice1712 { void (*set_pro_rate)(struct snd_ice1712 *ice, unsigned int rate); void (*i2s_mclk_changed)(struct snd_ice1712 *ice); } gpio; - struct semaphore gpio_mutex; + struct mutex gpio_mutex; /* other board-specific data */ union { @@ -423,7 +424,7 @@ static inline unsigned int snd_ice1712_gpio_read(struct snd_ice1712 *ice) */ static inline void snd_ice1712_save_gpio_status(struct snd_ice1712 *ice) { - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ice->gpio.saved[0] = ice->gpio.direction; ice->gpio.saved[1] = ice->gpio.write_mask; } @@ -434,7 +435,7 @@ static inline void snd_ice1712_restore_gpio_status(struct snd_ice1712 *ice) ice->gpio.set_mask(ice, ice->gpio.saved[1]); ice->gpio.direction = ice->gpio.saved[0]; ice->gpio.write_mask = ice->gpio.saved[1]; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } /* for bit controls */ diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 71f08c036019..fce616c2761f 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -30,6 +30,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/info.h> #include <sound/mpu401.h> @@ -487,7 +488,7 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, int i, chs; chs = params_channels(hw_params); - down(&ice->open_mutex); + mutex_lock(&ice->open_mutex); /* mark surround channels */ if (substream == ice->playback_pro_substream) { /* PDMA0 can be multi-channel up to 8 */ @@ -495,7 +496,7 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, for (i = 0; i < chs; i++) { if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) { - up(&ice->open_mutex); + mutex_unlock(&ice->open_mutex); return -EBUSY; } ice->pcm_reserved[i] = substream; @@ -510,7 +511,7 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, if (ice->playback_con_substream_ds[i] == substream) { if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) { - up(&ice->open_mutex); + mutex_unlock(&ice->open_mutex); return -EBUSY; } ice->pcm_reserved[i] = substream; @@ -518,7 +519,7 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, } } } - up(&ice->open_mutex); + mutex_unlock(&ice->open_mutex); snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } @@ -528,12 +529,12 @@ static int snd_vt1724_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); int i; - down(&ice->open_mutex); + mutex_lock(&ice->open_mutex); /* unmark surround channels */ for (i = 0; i < 3; i++) if (ice->pcm_reserved[i] == substream) ice->pcm_reserved[i] = NULL; - up(&ice->open_mutex); + mutex_unlock(&ice->open_mutex); return snd_pcm_lib_free_pages(substream); } @@ -778,7 +779,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); set_rate_constraints(ice, substream); - down(&ice->open_mutex); + mutex_lock(&ice->open_mutex); /* calculate the currently available channels */ for (chs = 0; chs < 3; chs++) { if (ice->pcm_reserved[chs]) @@ -788,7 +789,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) runtime->hw.channels_max = chs; if (chs > 2) /* channels must be even */ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); - up(&ice->open_mutex); + mutex_unlock(&ice->open_mutex); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, @@ -1128,13 +1129,13 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - down(&ice->open_mutex); + mutex_lock(&ice->open_mutex); /* already used by PDMA0? */ if (ice->pcm_reserved[substream->number]) { - up(&ice->open_mutex); + mutex_unlock(&ice->open_mutex); return -EBUSY; /* FIXME: should handle blocking mode properly */ } - up(&ice->open_mutex); + mutex_unlock(&ice->open_mutex); runtime->private_data = &vt1724_playback_dma_regs[substream->number]; ice->playback_con_substream_ds[substream->number] = substream; runtime->hw = snd_vt1724_2ch_stereo; @@ -1978,12 +1979,12 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, { unsigned char val; - down(&ice->i2c_mutex); + mutex_lock(&ice->i2c_mutex); outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); wait_i2c_busy(ice); val = inb(ICEREG1724(ice, I2C_DATA)); - up(&ice->i2c_mutex); + mutex_unlock(&ice->i2c_mutex); //printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); return val; } @@ -1991,14 +1992,14 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, void snd_vt1724_write_i2c(struct snd_ice1712 *ice, unsigned char dev, unsigned char addr, unsigned char data) { - down(&ice->i2c_mutex); + mutex_lock(&ice->i2c_mutex); wait_i2c_busy(ice); //printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(data, ICEREG1724(ice, I2C_DATA)); outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); wait_i2c_busy(ice); - up(&ice->i2c_mutex); + mutex_unlock(&ice->i2c_mutex); } static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, @@ -2229,9 +2230,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card, } ice->vt1724 = 1; spin_lock_init(&ice->reg_lock); - init_MUTEX(&ice->gpio_mutex); - init_MUTEX(&ice->open_mutex); - init_MUTEX(&ice->i2c_mutex); + mutex_init(&ice->gpio_mutex); + mutex_init(&ice->open_mutex); + mutex_init(&ice->i2c_mutex); ice->gpio.set_mask = snd_vt1724_set_gpio_mask; ice->gpio.set_dir = snd_vt1724_set_gpio_dir; ice->gpio.set_data = snd_vt1724_set_gpio_data; diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index ec3757834b93..502da1c8b5f7 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -39,6 +39,8 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include "ice1712.h" @@ -273,9 +275,9 @@ static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -584,11 +586,11 @@ static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short val; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; val = val > PCM_MIN ? (val - PCM_MIN) : 0; ucontrol->value.integer.value[0] = val; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 0dccd7707a4b..d23fb3fc2133 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -27,6 +27,8 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/info.h> @@ -124,13 +126,13 @@ static int wm_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short val; int i; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (i = 0; i < 2; i++) { val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff; val = val > DAC_MIN ? (val - DAC_MIN) : 0; ucontrol->value.integer.value[i] = val; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -140,7 +142,7 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short oval, nval; int i, idx, change = 0; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (i = 0; i < 2; i++) { nval = ucontrol->value.integer.value[i]; nval = (nval ? (nval + DAC_MIN) : 0) & 0xff; @@ -152,7 +154,7 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val change = 1; } } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return change; } @@ -179,13 +181,13 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short val; int i; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (i = 0; i < 2; i++) { val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; val = val > ADC_MIN ? (val - ADC_MIN) : 0; ucontrol->value.integer.value[i] = val; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -195,7 +197,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short ovol, nvol; int i, idx, change = 0; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (i = 0; i < 2; i++) { nvol = ucontrol->value.integer.value[i]; nvol = nvol ? (nvol + ADC_MIN) : 0; @@ -206,7 +208,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val change = 1; } } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return change; } @@ -227,9 +229,9 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int bit = kcontrol->private_value; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -240,7 +242,7 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short oval, nval; int change; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); nval = oval = wm_get(ice, WM_ADC_MUX); if (ucontrol->value.integer.value[0]) nval |= (1 << bit); @@ -250,7 +252,7 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val if (change) { wm_put(ice, WM_ADC_MUX, nval); } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -270,9 +272,9 @@ static int wm_bypass_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -282,7 +284,7 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu unsigned short val, oval; int change = 0; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); val = oval = wm_get(ice, WM_OUT_MUX); if (ucontrol->value.integer.value[0]) val |= 0x04; @@ -292,7 +294,7 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu wm_put(ice, WM_OUT_MUX, val); change = 1; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return change; } @@ -312,9 +314,9 @@ static int wm_chswap_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -324,7 +326,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu unsigned short val, oval; int change = 0; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); oval = wm_get(ice, WM_DAC_CTRL1); val = oval & 0x0f; if (ucontrol->value.integer.value[0]) @@ -336,7 +338,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu wm_put_nocache(ice, WM_DAC_CTRL1, val); change = 1; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return change; } @@ -449,9 +451,9 @@ static int cs_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); ucontrol->value.enumerated.item[0] = ice->gpio.saved[0]; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -461,14 +463,14 @@ static int cs_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu unsigned char val; int change = 0; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); if (ucontrol->value.enumerated.item[0] != ice->gpio.saved[0]) { ice->gpio.saved[0] = ucontrol->value.enumerated.item[0] & 3; val = 0x80 | (ice->gpio.saved[0] << 3); spi_write(ice, CS_DEV, 0x04, val); change = 1; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -488,10 +490,10 @@ static int pontis_gpio_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int pontis_gpio_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); /* 4-7 reserved */ ucontrol->value.integer.value[0] = (~ice->gpio.write_mask & 0xffff) | 0x00f0; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -500,22 +502,22 @@ static int pontis_gpio_mask_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int val; int changed; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); /* 4-7 reserved */ val = (~ucontrol->value.integer.value[0] & 0xffff) | 0x00f0; changed = val != ice->gpio.write_mask; ice->gpio.write_mask = val; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return changed; } static int pontis_gpio_dir_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); /* 4-7 reserved */ ucontrol->value.integer.value[0] = ice->gpio.direction & 0xff0f; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -524,23 +526,23 @@ static int pontis_gpio_dir_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int val; int changed; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); /* 4-7 reserved */ val = ucontrol->value.integer.value[0] & 0xff0f; changed = (val != ice->gpio.direction); ice->gpio.direction = val; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return changed; } static int pontis_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); ucontrol->value.integer.value[0] = snd_ice1712_gpio_read(ice) & 0xffff; - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return 0; } @@ -549,7 +551,7 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int val, nval; int changed = 0; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); val = snd_ice1712_gpio_read(ice) & 0xffff; @@ -558,7 +560,7 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el snd_ice1712_gpio_write(ice, nval); changed = 1; } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); return changed; } @@ -651,14 +653,14 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; char line[64]; unsigned int reg, val; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; if (reg <= 0x17 && val <= 0xffff) wm_put(ice, reg, val); } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) @@ -666,12 +668,12 @@ static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; int reg, val; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (reg = 0; reg <= 0x17; reg++) { val = wm_get(ice, reg); snd_iprintf(buffer, "%02x = %04x\n", reg, val); } - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void wm_proc_init(struct snd_ice1712 *ice) @@ -690,14 +692,14 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; int reg, val; - down(&ice->gpio_mutex); + mutex_lock(&ice->gpio_mutex); for (reg = 0; reg <= 0x26; reg++) { val = spi_read(ice, CS_DEV, reg); snd_iprintf(buffer, "%02x = %02x\n", reg, val); } val = spi_read(ice, CS_DEV, 0x7f); snd_iprintf(buffer, "%02x = %02x\n", 0x7f, val); - up(&ice->gpio_mutex); + mutex_unlock(&ice->gpio_mutex); } static void cs_proc_init(struct snd_ice1712 *ice) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 174237f4a22c..ebbf2cf4ca0f 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -178,6 +178,8 @@ DEFINE_REGSET(SP, 0x60); /* SPDIF out */ #define ICH_SAMPLE_CAP 0x00c00000 /* ICH4: sample capability bits (RO) */ #define ICH_SAMPLE_16_20 0x00400000 /* ICH4: 16- and 20-bit samples */ #define ICH_MULTICHAN_CAP 0x00300000 /* ICH4: multi-channel capability bits (RO) */ +#define ICH_SIS_TRI 0x00080000 /* SIS: tertiary resume irq */ +#define ICH_SIS_TCR 0x00040000 /* SIS: tertiary codec ready */ #define ICH_MD3 0x00020000 /* modem power down semaphore */ #define ICH_AD3 0x00010000 /* audio power down semaphore */ #define ICH_RCS 0x00008000 /* read completion status */ @@ -398,6 +400,10 @@ struct intel8x0 { struct snd_ac97_bus *ac97_bus; struct snd_ac97 *ac97[3]; unsigned int ac97_sdin[3]; + unsigned int max_codecs, ncodecs; + unsigned int *codec_bit; + unsigned int codec_isr_bits; + unsigned int codec_ready_bits; spinlock_t reg_lock; @@ -516,18 +522,6 @@ static void iaputword(struct intel8x0 *chip, u32 offset, u16 val) * access to AC97 codec via normal i/o (for ICH and SIS7012) */ -/* return the GLOB_STA bit for the corresponding codec */ -static unsigned int get_ich_codec_bit(struct intel8x0 *chip, unsigned int codec) -{ - static unsigned int codec_bit[3] = { - ICH_PCR, ICH_SCR, ICH_TCR - }; - snd_assert(codec < 3, return ICH_PCR); - if (chip->device_type == DEVICE_INTEL_ICH4) - codec = chip->ac97_sdin[codec]; - return codec_bit[codec]; -} - static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int codec) { int time; @@ -537,9 +531,9 @@ static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int code if (chip->in_sdin_init) { /* we don't know the ready bit assignment at the moment */ /* so we check any */ - codec = ICH_PCR | ICH_SCR | ICH_TCR; + codec = chip->codec_isr_bits; } else { - codec = get_ich_codec_bit(chip, codec); + codec = chip->codec_bit[chip->ac97_sdin[codec]]; } /* codec ready ? */ @@ -596,7 +590,7 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { /* reset RCS and preserve other R/WC bits */ iputdword(chip, ICHREG(GLOB_STA), tmp & - ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); + ~(chip->codec_ready_bits | ICH_GSCI)); if (! chip->in_ac97_init) snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); res = 0xffff; @@ -605,7 +599,8 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, return res; } -static void snd_intel8x0_codec_read_test(struct intel8x0 *chip, unsigned int codec) +static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip, + unsigned int codec) { unsigned int tmp; @@ -614,7 +609,7 @@ static void snd_intel8x0_codec_read_test(struct intel8x0 *chip, unsigned int cod if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { /* reset RCS and preserve other R/WC bits */ iputdword(chip, ICHREG(GLOB_STA), tmp & - ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); + ~(chip->codec_ready_bits | ICH_GSCI)); } } } @@ -2078,23 +2073,24 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, if (chip->device_type != DEVICE_ALI) { glob_sta = igetdword(chip, ICHREG(GLOB_STA)); ops = &standard_bus_ops; - if (chip->device_type == DEVICE_INTEL_ICH4) { - codecs = 0; - if (glob_sta & ICH_PCR) - codecs++; - if (glob_sta & ICH_SCR) - codecs++; - if (glob_sta & ICH_TCR) - codecs++; - chip->in_sdin_init = 1; - for (i = 0; i < codecs; i++) { - snd_intel8x0_codec_read_test(chip, i); - chip->ac97_sdin[i] = igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK; - } - chip->in_sdin_init = 0; - } else { - codecs = glob_sta & ICH_SCR ? 2 : 1; + chip->in_sdin_init = 1; + codecs = 0; + for (i = 0; i < chip->max_codecs; i++) { + if (! (glob_sta & chip->codec_bit[i])) + continue; + if (chip->device_type == DEVICE_INTEL_ICH4) { + snd_intel8x0_codec_read_test(chip, codecs); + chip->ac97_sdin[codecs] = + igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK; + snd_assert(chip->ac97_sdin[codecs] < 3, + chip->ac97_sdin[codecs] = 0); + } else + chip->ac97_sdin[codecs] = i; + codecs++; } + chip->in_sdin_init = 0; + if (! codecs) + codecs = 1; } else { ops = &ali_bus_ops; codecs = 1; @@ -2120,6 +2116,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, else pbus->dra = 1; chip->ac97_bus = pbus; + chip->ncodecs = codecs; ac97.pci = chip->pci; for (i = 0; i < codecs; i++) { @@ -2264,7 +2261,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) end_time = jiffies + HZ; do { status = igetdword(chip, ICHREG(GLOB_STA)) & - (ICH_PCR | ICH_SCR | ICH_TCR); + chip->codec_isr_bits; if (status) break; schedule_timeout_uninterruptible(1); @@ -2276,32 +2273,27 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) return -EIO; } - if (chip->device_type == DEVICE_INTEL_ICH4) - /* ICH4 can have three codecs */ - nstatus = ICH_PCR | ICH_SCR | ICH_TCR; - else - /* others up to two codecs */ - nstatus = ICH_PCR | ICH_SCR; - /* wait for other codecs ready status. */ end_time = jiffies + HZ / 4; - while (status != nstatus && time_after_eq(end_time, jiffies)) { + while (status != chip->codec_isr_bits && + time_after_eq(end_time, jiffies)) { schedule_timeout_uninterruptible(1); - status |= igetdword(chip, ICHREG(GLOB_STA)) & nstatus; + status |= igetdword(chip, ICHREG(GLOB_STA)) & + chip->codec_isr_bits; } } else { /* resume phase */ int i; status = 0; - for (i = 0; i < 3; i++) + for (i = 0; i < chip->ncodecs; i++) if (chip->ac97[i]) - status |= get_ich_codec_bit(chip, i); + status |= chip->codec_bit[chip->ac97_sdin[i]]; /* wait until all the probed codecs are ready */ end_time = jiffies + HZ; do { nstatus = igetdword(chip, ICHREG(GLOB_STA)) & - (ICH_PCR | ICH_SCR | ICH_TCR); + chip->codec_isr_bits; if (status == nstatus) break; schedule_timeout_uninterruptible(1); @@ -2359,7 +2351,7 @@ static int snd_intel8x0_ali_chip_init(struct intel8x0 *chip, int probing) static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing) { - unsigned int i; + unsigned int i, timeout; int err; if (chip->device_type != DEVICE_ALI) { @@ -2377,6 +2369,15 @@ static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing) /* reset channels */ for (i = 0; i < chip->bdbars_count; i++) iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); + for (i = 0; i < chip->bdbars_count; i++) { + timeout = 100000; + while (--timeout != 0) { + if ((igetbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset) & ICH_RESETREGS) == 0) + break; + } + if (timeout == 0) + printk(KERN_ERR "intel8x0: reset of registers failed?\n"); + } /* initialize Buffer Descriptor Lists */ for (i = 0; i < chip->bdbars_count; i++) iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, @@ -2447,7 +2448,7 @@ static int intel8x0_suspend(struct pci_dev *pci, pm_message_t state) } } } - for (i = 0; i < 3; i++) + for (i = 0; i < chip->ncodecs; i++) snd_ac97_suspend(chip->ac97[i]); if (chip->device_type == DEVICE_INTEL_ICH4) chip->sdm_saved = igetbyte(chip, ICHREG(SDM)); @@ -2488,7 +2489,7 @@ static int intel8x0_resume(struct pci_dev *pci) if (chip->fix_nocache) fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1); - for (i = 0; i < 3; i++) + for (i = 0; i < chip->ncodecs; i++) snd_ac97_resume(chip->ac97[i]); /* refill nocache */ @@ -2619,12 +2620,20 @@ static void snd_intel8x0_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "Global status : 0x%08x\n", tmp); if (chip->device_type == DEVICE_INTEL_ICH4) snd_iprintf(buffer, "SDM : 0x%08x\n", igetdword(chip, ICHREG(SDM))); - snd_iprintf(buffer, "AC'97 codecs ready :%s%s%s%s\n", - tmp & ICH_PCR ? " primary" : "", - tmp & ICH_SCR ? " secondary" : "", - tmp & ICH_TCR ? " tertiary" : "", - (tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : ""); - if (chip->device_type == DEVICE_INTEL_ICH4) + snd_iprintf(buffer, "AC'97 codecs ready :"); + if (tmp & chip->codec_isr_bits) { + int i; + static const char *codecs[3] = { + "primary", "secondary", "tertiary" + }; + for (i = 0; i < chip->max_codecs; i++) + if (tmp & chip->codec_bit[i]) + snd_iprintf(buffer, " %s", codecs[i]); + } else + snd_iprintf(buffer, " none"); + snd_iprintf(buffer, "\n"); + if (chip->device_type == DEVICE_INTEL_ICH4 || + chip->device_type == DEVICE_SIS) snd_iprintf(buffer, "AC'97 codecs SDIN : %i %i %i\n", chip->ac97_sdin[0], chip->ac97_sdin[1], @@ -2653,6 +2662,13 @@ struct ich_reg_info { unsigned int offset; }; +static unsigned int ich_codec_bits[3] = { + ICH_PCR, ICH_SCR, ICH_TCR +}; +static unsigned int sis_codec_bits[3] = { + ICH_PCR, ICH_SCR, ICH_SIS_TCR +}; + static int __devinit snd_intel8x0_create(struct snd_card *card, struct pci_dev *pci, unsigned long device_type, @@ -2835,6 +2851,29 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, pci_set_master(pci); synchronize_irq(chip->irq); + switch(chip->device_type) { + case DEVICE_INTEL_ICH4: + /* ICH4 can have three codecs */ + chip->max_codecs = 3; + chip->codec_bit = ich_codec_bits; + chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_TRI; + break; + case DEVICE_SIS: + /* recent SIS7012 can have three codecs */ + chip->max_codecs = 3; + chip->codec_bit = sis_codec_bits; + chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_SIS_TRI; + break; + default: + /* others up to two codecs */ + chip->max_codecs = 2; + chip->codec_bit = ich_codec_bits; + chip->codec_ready_bits = ICH_PRI | ICH_SRI; + break; + } + for (i = 0; i < chip->max_codecs; i++) + chip->codec_isr_bits |= chip->codec_bit[i]; + if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) { snd_intel8x0_free(chip); return err; diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 4eddb512c12f..4721c096335e 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/wait.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/info.h> @@ -325,7 +326,7 @@ struct snd_korg1212 { int irq; spinlock_t lock; - struct semaphore open_mutex; + struct mutex open_mutex; struct timer_list timer; /* timer callback for checking ack of stop request */ int stop_pending_cnt; /* counter for stop pending check */ @@ -667,13 +668,13 @@ static int snd_korg1212_OpenCard(struct snd_korg1212 * korg1212) { K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt); - down(&korg1212->open_mutex); + mutex_lock(&korg1212->open_mutex); if (korg1212->opencnt++ == 0) { snd_korg1212_TurnOffIdleMonitor(korg1212); snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN); } - up(&korg1212->open_mutex); + mutex_unlock(&korg1212->open_mutex); return 1; } @@ -682,9 +683,9 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212) K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt); - down(&korg1212->open_mutex); + mutex_lock(&korg1212->open_mutex); if (--(korg1212->opencnt)) { - up(&korg1212->open_mutex); + mutex_unlock(&korg1212->open_mutex); return 0; } @@ -695,7 +696,7 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212) K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard - RC = %d [%s]\n", rc, stateName[korg1212->cardState]); if (rc != K1212_CMDRET_Success) { - up(&korg1212->open_mutex); + mutex_unlock(&korg1212->open_mutex); return 0; } } else if (korg1212->cardState > K1212_STATE_SETUP) { @@ -707,7 +708,7 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212) snd_korg1212_setCardState(korg1212, K1212_STATE_READY); } - up(&korg1212->open_mutex); + mutex_unlock(&korg1212->open_mutex); return 0; } @@ -2179,7 +2180,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * init_waitqueue_head(&korg1212->wait); spin_lock_init(&korg1212->lock); - init_MUTEX(&korg1212->open_mutex); + mutex_init(&korg1212->open_mutex); init_timer(&korg1212->timer); korg1212->timer.function = snd_korg1212_timer_func; korg1212->timer.data = (unsigned long)korg1212; diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index d3ef0cc6c4f9..8bc084956c28 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -37,6 +37,7 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/moduleparam.h> @@ -2657,8 +2658,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, return -EIO; /* check, if we can restrict PCI DMA transfers to 28 bits */ - if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index b218e1d20c78..43ee3b2b948f 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -25,7 +25,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <sound/core.h> #include <sound/initval.h> #include <sound/info.h> @@ -589,7 +591,7 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, /* set up format for the stream */ format = params_format(hw); - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); /* update the stream levels */ if( stream->pcm_number <= MIXART_PCM_DIGITAL ) { @@ -628,7 +630,7 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, bufferinfo[i].available_length, subs->number); } - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return err; } @@ -700,7 +702,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs) int err = 0; int pcm_number; - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; @@ -758,7 +760,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs) } _exit_open: - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return err; } @@ -775,7 +777,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs) int err = 0; int pcm_number; - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; @@ -836,7 +838,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs) } _exit_open: - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return err; } @@ -849,7 +851,7 @@ static int snd_mixart_close(struct snd_pcm_substream *subs) struct mixart_mgr *mgr = chip->mgr; struct mixart_stream *stream = subs->runtime->private_data; - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number); @@ -868,7 +870,7 @@ static int snd_mixart_close(struct snd_pcm_substream *subs) stream->status = MIXART_STREAM_STATUS_FREE; stream->substream = NULL; - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return 0; } @@ -1288,7 +1290,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, pci_set_master(pci); /* check if we can restrict PCI DMA transfers to 32 bits */ - if (pci_set_dma_mask(pci, 0xffffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; @@ -1335,12 +1337,12 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, mgr->msg_fifo_writeptr = 0; spin_lock_init(&mgr->msg_lock); - init_MUTEX(&mgr->msg_mutex); + mutex_init(&mgr->msg_mutex); init_waitqueue_head(&mgr->msg_sleep); atomic_set(&mgr->msg_processed, 0); /* init setup mutex*/ - init_MUTEX(&mgr->setup_mutex); + mutex_init(&mgr->setup_mutex); /* init message taslket */ tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr); diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h index 3e84863ca02c..561634d5c007 100644 --- a/sound/pci/mixart/mixart.h +++ b/sound/pci/mixart/mixart.h @@ -24,6 +24,7 @@ #define __SOUND_MIXART_H #include <linux/interrupt.h> +#include <linux/mutex.h> #include <sound/pcm.h> #define MIXART_DRIVER_VERSION 0x000100 /* 0.1.0 */ @@ -92,9 +93,9 @@ struct mixart_mgr { spinlock_t lock; /* interrupt spinlock */ spinlock_t msg_lock; /* mailbox spinlock */ - struct semaphore msg_mutex; /* mutex for blocking_requests */ + struct mutex msg_mutex; /* mutex for blocking_requests */ - struct semaphore setup_mutex; /* mutex used in hw_params, open and close */ + struct mutex setup_mutex; /* mutex used in hw_params, open and close */ /* hardware interface */ unsigned int dsp_loaded; /* bit flags of loaded dsp indices */ @@ -107,7 +108,7 @@ struct mixart_mgr { int sample_rate; int ref_count_rate; - struct semaphore mixer_mutex; /* mutex for mixer */ + struct mutex mixer_mutex; /* mutex for mixer */ }; diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 07c707d7ebbf..406ac3a9d42a 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -22,6 +22,8 @@ #include <sound/driver.h> #include <linux/interrupt.h> +#include <linux/mutex.h> + #include <asm/io.h> #include <sound/core.h> #include "mixart.h" @@ -239,7 +241,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int wait_queue_t wait; long timeout; - down(&mgr->msg_mutex); + mutex_lock(&mgr->msg_mutex); init_waitqueue_entry(&wait, current); @@ -248,7 +250,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ if (err) { spin_unlock_irq(&mgr->msg_lock); - up(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_mutex); return err; } @@ -260,7 +262,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int if (! timeout) { /* error - no ack */ - up(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_mutex); snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame); return -EIO; } @@ -276,7 +278,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int if( request->message_id != resp.message_id ) snd_printk(KERN_ERR "REPONSE ERROR!\n"); - up(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_mutex); return err; } @@ -292,7 +294,7 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL); snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL); - down(&mgr->msg_mutex); + mutex_lock(&mgr->msg_mutex); init_waitqueue_entry(&wait, current); @@ -301,7 +303,7 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ if(err) { spin_unlock_irq(&mgr->msg_lock); - up(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_mutex); return err; } @@ -313,12 +315,12 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, if (! timeout) { /* error - no ack */ - up(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_mutex); snd_printk(KERN_ERR "error: notification %x not received\n", notif_event); return -EIO; } - up(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_mutex); return 0; } diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 36a7e9ddfb15..ed47b732c103 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -24,6 +24,8 @@ #include <linux/time.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/mutex.h> + #include <sound/core.h> #include "mixart.h" #include "mixart_core.h" @@ -353,7 +355,7 @@ static int mixart_analog_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if(kcontrol->private_value == 0) { /* playback */ ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; @@ -361,7 +363,7 @@ static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -371,7 +373,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e int changed = 0; int is_capture, i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); is_capture = (kcontrol->private_value != 0); for(i=0; i<2; i++) { int new_volume = ucontrol->value.integer.value[i]; @@ -382,7 +384,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e } } if(changed) mixart_update_analog_audio_level(chip, is_capture); - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -408,10 +410,10 @@ static int mixart_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -419,7 +421,7 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int i, changed = 0; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for(i=0; i<2; i++) { if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; @@ -427,7 +429,7 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele } } if(changed) mixart_update_analog_audio_level(chip, 0); /* update playback levels */ - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -817,7 +819,7 @@ static int mixart_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem int *stored_volume; int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK; int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if(is_capture) { if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */ else stored_volume = chip->digital_capture_volume[0]; /* analog capture */ @@ -828,7 +830,7 @@ static int mixart_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem } ucontrol->value.integer.value[0] = stored_volume[0]; ucontrol->value.integer.value[1] = stored_volume[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -841,7 +843,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK; int* stored_volume; int i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if(is_capture) { if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */ else stored_volume = chip->digital_capture_volume[0]; /* analog capture */ @@ -860,7 +862,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem if(is_capture) mixart_update_capture_stream_level(chip, is_aes); else mixart_update_playback_stream_level(chip, is_aes, idx); } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -880,12 +882,12 @@ static int mixart_pcm_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if(kcontrol->private_value & MIXART_VOL_AES_MASK) /* AES playback */ idx += MIXART_PLAYBACK_STREAMS; ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -897,7 +899,7 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int i, j; snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); j = idx; if(is_aes) j += MIXART_PLAYBACK_STREAMS; for(i=0; i<2; i++) { @@ -907,7 +909,7 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ } } if(changed) mixart_update_playback_stream_level(chip, is_aes, idx); - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -956,10 +958,10 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel) static int mixart_monitor_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -968,7 +970,7 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int changed = 0; int i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for(i=0; i<2; i++) { if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; @@ -976,7 +978,7 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ changed = 1; } } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -995,10 +997,10 @@ static struct snd_kcontrol_new mixart_control_monitor_vol = { static int mixart_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_active[0]; ucontrol->value.integer.value[1] = chip->monitoring_active[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -1007,7 +1009,7 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int changed = 0; int i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for(i=0; i<2; i++) { if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { chip->monitoring_active[i] = ucontrol->value.integer.value[i]; @@ -1029,7 +1031,7 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e } } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return (changed != 0); } @@ -1059,7 +1061,7 @@ int snd_mixart_create_mixer(struct mixart_mgr *mgr) struct snd_mixart *chip; int err, i; - init_MUTEX(&mgr->mixer_mutex); /* can be in another place */ + mutex_init(&mgr->mixer_mutex); /* can be in another place */ for(i=0; i<mgr->num_cards; i++) { struct snd_kcontrol_new temp; diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 0d0ff54f0fc6..cc297abc9d11 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -32,6 +32,8 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -226,6 +228,7 @@ struct nm256 { unsigned int use_cache: 1; /* use one big coef. table */ unsigned int reset_workaround: 1; /* Workaround for some laptops to avoid freeze */ unsigned int reset_workaround_2: 1; /* Extended workaround for some other laptops to avoid freeze */ + unsigned int in_resume: 1; int mixer_base; /* register offset of ac97 mixer */ int mixer_status_offset; /* offset of mixer status reg. */ @@ -235,11 +238,12 @@ struct nm256 { int irq_acks; irqreturn_t (*interrupt)(int, void *, struct pt_regs *); int badintrcount; /* counter to check bogus interrupts */ - struct semaphore irq_mutex; + struct mutex irq_mutex; struct nm256_stream streams[2]; struct snd_ac97 *ac97; + unsigned short *ac97_regs; /* register caches, only for valid regs */ struct snd_pcm *pcm; @@ -459,32 +463,32 @@ snd_nm256_set_format(struct nm256 *chip, struct nm256_stream *s, /* acquire interrupt */ static int snd_nm256_acquire_irq(struct nm256 *chip) { - down(&chip->irq_mutex); + mutex_lock(&chip->irq_mutex); if (chip->irq < 0) { if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ, chip->card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq); - up(&chip->irq_mutex); + mutex_unlock(&chip->irq_mutex); return -EBUSY; } chip->irq = chip->pci->irq; } chip->irq_acks++; - up(&chip->irq_mutex); + mutex_unlock(&chip->irq_mutex); return 0; } /* release interrupt */ static void snd_nm256_release_irq(struct nm256 *chip) { - down(&chip->irq_mutex); + mutex_lock(&chip->irq_mutex); if (chip->irq_acks > 0) chip->irq_acks--; if (chip->irq_acks == 0 && chip->irq >= 0) { free_irq(chip->irq, chip); chip->irq = -1; } - up(&chip->irq_mutex); + mutex_unlock(&chip->irq_mutex); } /* @@ -1151,23 +1155,63 @@ snd_nm256_ac97_ready(struct nm256 *chip) return 0; } +/* + * Initial register values to be written to the AC97 mixer. + * While most of these are identical to the reset values, we do this + * so that we have most of the register contents cached--this avoids + * reading from the mixer directly (which seems to be problematic, + * probably due to ignorance). + */ + +struct initialValues { + unsigned short reg; + unsigned short value; +}; + +static struct initialValues nm256_ac97_init_val[] = +{ + { AC97_MASTER, 0x8000 }, + { AC97_HEADPHONE, 0x8000 }, + { AC97_MASTER_MONO, 0x8000 }, + { AC97_PC_BEEP, 0x8000 }, + { AC97_PHONE, 0x8008 }, + { AC97_MIC, 0x8000 }, + { AC97_LINE, 0x8808 }, + { AC97_CD, 0x8808 }, + { AC97_VIDEO, 0x8808 }, + { AC97_AUX, 0x8808 }, + { AC97_PCM, 0x8808 }, + { AC97_REC_SEL, 0x0000 }, + { AC97_REC_GAIN, 0x0B0B }, + { AC97_GENERAL_PURPOSE, 0x0000 }, + { AC97_3D_CONTROL, 0x8000 }, + { AC97_VENDOR_ID1, 0x8384 }, + { AC97_VENDOR_ID2, 0x7609 }, +}; + +static int nm256_ac97_idx(unsigned short reg) +{ + int i; + for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++) + if (nm256_ac97_init_val[i].reg == reg) + return i; + return -1; +} + /* + * some nm256 easily crash when reading from mixer registers + * thus we're treating it as a write-only mixer and cache the + * written values */ static unsigned short snd_nm256_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct nm256 *chip = ac97->private_data; - int res; + int idx = nm256_ac97_idx(reg); - if (reg >= 128) + if (idx < 0) return 0; - - if (! snd_nm256_ac97_ready(chip)) - return 0; - res = snd_nm256_readw(chip, chip->mixer_base + reg); - /* Magic delay. Bleah yucky. */ - msleep(1); - return res; + return chip->ac97_regs[idx]; } /* @@ -1178,8 +1222,12 @@ snd_nm256_ac97_write(struct snd_ac97 *ac97, { struct nm256 *chip = ac97->private_data; int tries = 2; + int idx = nm256_ac97_idx(reg); u32 base; + if (idx < 0) + return; + base = chip->mixer_base; snd_nm256_ac97_ready(chip); @@ -1188,12 +1236,32 @@ snd_nm256_ac97_write(struct snd_ac97 *ac97, while (tries-- > 0) { snd_nm256_writew(chip, base + reg, val); msleep(1); /* a little delay here seems better.. */ - if (snd_nm256_ac97_ready(chip)) + if (snd_nm256_ac97_ready(chip)) { + /* successful write: set cache */ + chip->ac97_regs[idx] = val; return; + } } snd_printd("nm256: ac97 codec not ready..\n"); } +/* static resolution table */ +static struct snd_ac97_res_table nm256_res_table[] = { + { AC97_MASTER, 0x1f1f }, + { AC97_HEADPHONE, 0x1f1f }, + { AC97_MASTER_MONO, 0x001f }, + { AC97_PC_BEEP, 0x001f }, + { AC97_PHONE, 0x001f }, + { AC97_MIC, 0x001f }, + { AC97_LINE, 0x1f1f }, + { AC97_CD, 0x1f1f }, + { AC97_VIDEO, 0x1f1f }, + { AC97_AUX, 0x1f1f }, + { AC97_PCM, 0x1f1f }, + { AC97_REC_GAIN, 0x0f0f }, + { } /* terminator */ +}; + /* initialize the ac97 into a known state */ static void snd_nm256_ac97_reset(struct snd_ac97 *ac97) @@ -1211,6 +1279,16 @@ snd_nm256_ac97_reset(struct snd_ac97 *ac97) snd_nm256_writeb(chip, 0x6cc, 0x80); snd_nm256_writeb(chip, 0x6cc, 0x0); } + if (! chip->in_resume) { + int i; + for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++) { + /* preload the cache, so as to avoid even a single + * read of the mixer regs + */ + snd_nm256_ac97_write(ac97, nm256_ac97_init_val[i].reg, + nm256_ac97_init_val[i].value); + } + } } /* create an ac97 mixer interface */ @@ -1219,32 +1297,25 @@ snd_nm256_mixer(struct nm256 *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; - int i, err; + int err; static struct snd_ac97_bus_ops ops = { .reset = snd_nm256_ac97_reset, .write = snd_nm256_ac97_write, .read = snd_nm256_ac97_read, }; - /* looks like nm256 hangs up when unexpected registers are touched... */ - static int mixer_regs[] = { - AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO, - AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD, - AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL, - AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL, - /*AC97_EXTENDED_ID,*/ - AC97_VENDOR_ID1, AC97_VENDOR_ID2, - -1 - }; + + chip->ac97_regs = kcalloc(sizeof(short), + ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL); + if (! chip->ac97_regs) + return -ENOMEM; if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) return err; memset(&ac97, 0, sizeof(ac97)); ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */ - ac97.limited_regs = 1; - for (i = 0; mixer_regs[i] >= 0; i++) - set_bit(mixer_regs[i], ac97.reg_accessed); ac97.private_data = chip; + ac97.res_table = nm256_res_table; pbus->no_vra = 1; err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); if (err < 0) @@ -1329,6 +1400,7 @@ static int nm256_resume(struct pci_dev *pci) int i; /* Perform a full reset on the hardware */ + chip->in_resume = 1; pci_restore_state(pci); pci_enable_device(pci); snd_nm256_init_chip(chip); @@ -1346,6 +1418,7 @@ static int nm256_resume(struct pci_dev *pci) } snd_power_change_state(card, SNDRV_CTL_POWER_D0); + chip->in_resume = 0; return 0; } #endif /* CONFIG_PM */ @@ -1370,6 +1443,7 @@ static int snd_nm256_free(struct nm256 *chip) free_irq(chip->irq, chip); pci_disable_device(chip->pci); + kfree(chip->ac97_regs); kfree(chip); return 0; } @@ -1407,7 +1481,7 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, chip->use_cache = use_cache; spin_lock_init(&chip->reg_lock); chip->irq = -1; - init_MUTEX(&chip->irq_mutex); + mutex_init(&chip->irq_mutex); /* store buffer sizes in bytes */ chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = playback_bufsize * 1024; diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index b2cba75b6b16..f679779d96e3 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -26,8 +26,11 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/initval.h> #include <sound/info.h> @@ -518,7 +521,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) struct timeval my_tv1, my_tv2; do_gettimeofday(&my_tv1); #endif - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); /* check the pipes concerned and build pipe_array */ for (i = 0; i < mgr->num_cards; i++) { @@ -537,7 +540,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) } } if (capture_mask == 0 && playback_mask == 0) { - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); snd_printk(KERN_ERR "pcxhr_trigger_tasklet : no pipes\n"); return; } @@ -548,7 +551,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) /* synchronous stop of all the pipes concerned */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err) { - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n", playback_mask, capture_mask); return; @@ -592,7 +595,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) /* synchronous start of all the pipes concerned */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); if (err) { - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n", playback_mask, capture_mask); return; @@ -619,7 +622,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) } spin_unlock_irqrestore(&mgr->lock, flags); - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); #ifdef CONFIG_SND_DEBUG_DETECT do_gettimeofday(&my_tv2); @@ -728,7 +731,7 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) } */ - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); do { /* if the stream was stopped before, format and buffer were reset */ @@ -755,7 +758,7 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) } } while(0); /* do only once (so we can use break instead of goto) */ - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return err; } @@ -780,7 +783,7 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs, /* set up format for the stream */ format = params_format(hw); - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); stream->channels = channels; stream->format = format; @@ -789,7 +792,7 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs, /* err = pcxhr_set_format(stream); if(err) { - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return err; } */ @@ -801,7 +804,7 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs, err = pcxhr_update_r_buffer(stream); } */ - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return err; } @@ -847,7 +850,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) struct pcxhr_stream *stream; int is_capture; - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); /* copy the struct snd_pcm_hardware struct */ runtime->hw = pcxhr_caps; @@ -871,7 +874,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) /* streams in use */ snd_printk(KERN_ERR "pcxhr_open chip%d subs%d in use\n", chip->chip_idx, subs->number); - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return -EBUSY; } @@ -887,7 +890,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) &external_rate) || external_rate == 0) { /* cannot detect the external clock rate */ - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return -EBUSY; } runtime->hw.rate_min = runtime->hw.rate_max = external_rate; @@ -905,7 +908,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) mgr->ref_count_rate++; - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return 0; } @@ -916,7 +919,7 @@ static int pcxhr_close(struct snd_pcm_substream *subs) struct pcxhr_mgr *mgr = chip->mgr; struct pcxhr_stream *stream = subs->runtime->private_data; - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number); @@ -929,7 +932,7 @@ static int pcxhr_close(struct snd_pcm_substream *subs) stream->status = PCXHR_STREAM_STATUS_FREE; stream->substream = NULL; - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); return 0; } @@ -1215,7 +1218,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id pci_set_master(pci); /* check if we can restrict PCI DMA transfers to 32 bits */ - if (pci_set_dma_mask(pci, 0xffffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; @@ -1264,7 +1267,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id spin_lock_init(&mgr->msg_lock); /* init setup mutex*/ - init_MUTEX(&mgr->setup_mutex); + mutex_init(&mgr->setup_mutex); /* init taslket */ tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr); diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h index 049f2b3f2867..652064787a55 100644 --- a/sound/pci/pcxhr/pcxhr.h +++ b/sound/pci/pcxhr/pcxhr.h @@ -24,6 +24,7 @@ #define __SOUND_PCXHR_H #include <linux/interrupt.h> +#include <linux/mutex.h> #include <sound/pcm.h> #define PCXHR_DRIVER_VERSION 0x000804 /* 0.8.4 */ @@ -76,8 +77,8 @@ struct pcxhr_mgr { spinlock_t lock; /* interrupt spinlock */ spinlock_t msg_lock; /* message spinlock */ - struct semaphore setup_mutex; /* mutex used in hw_params, open and close */ - struct semaphore mixer_mutex; /* mutex for mixer */ + struct mutex setup_mutex; /* mutex used in hw_params, open and close */ + struct mutex mixer_mutex; /* mutex for mixer */ /* hardware interface */ unsigned int dsp_loaded; /* bit flags of loaded dsp indices */ diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index fa0d27e2c79b..fdc652c6992d 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -1176,7 +1176,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id, struct pt_regs *regs) mgr->dsp_time_last = dsp_time_new; if (timer_toggle == mgr->timer_toggle) - snd_printk(KERN_ERR "ERROR TIMER TOGGLE\n"); + snd_printdd("ERROR TIMER TOGGLE\n"); mgr->timer_toggle = timer_toggle; reg &= ~PCXHR_IRQ_TIMER; diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 760e733ac25e..94e63a1e90d9 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -25,6 +25,7 @@ #include <linux/time.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/mutex.h> #include <sound/core.h> #include "pcxhr.h" #include "pcxhr_hwdep.h" @@ -92,7 +93,7 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if (kcontrol->private_value == 0) { /* playback */ ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; @@ -100,7 +101,7 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -111,7 +112,7 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, int changed = 0; int is_capture, i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); is_capture = (kcontrol->private_value != 0); for (i = 0; i < 2; i++) { int new_volume = ucontrol->value.integer.value[i]; @@ -123,7 +124,7 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, pcxhr_update_analog_audio_level(chip, is_capture, i); } } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -150,10 +151,10 @@ static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -162,7 +163,7 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int i, changed = 0; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for(i = 0; i < 2; i++) { if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; @@ -170,7 +171,7 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, pcxhr_update_analog_audio_level(chip, 0, i); /* update playback levels */ } } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -299,14 +300,14 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, int *stored_volume; int is_capture = kcontrol->private_value; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if (is_capture) stored_volume = chip->digital_capture_volume; /* digital capture */ else stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ ucontrol->value.integer.value[0] = stored_volume[0]; ucontrol->value.integer.value[1] = stored_volume[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -320,7 +321,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, int *stored_volume; int i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if (is_capture) stored_volume = chip->digital_capture_volume; /* digital capture */ else @@ -335,7 +336,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, } if (! is_capture && changed) pcxhr_update_playback_stream_level(chip, idx); /* update playback volume */ - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -356,10 +357,10 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -370,7 +371,7 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int i, j; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); j = idx; for (i = 0; i < 2; i++) { if (chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) { @@ -380,7 +381,7 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v } if (changed) pcxhr_update_playback_stream_level(chip, idx); - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -402,10 +403,10 @@ static int pcxhr_monitor_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -416,7 +417,7 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, int changed = 0; int i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for (i = 0; i < 2; i++) { if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; @@ -426,7 +427,7 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, changed = 1; } } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -446,10 +447,10 @@ static int pcxhr_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_active[0]; ucontrol->value.integer.value[1] = chip->monitoring_active[1]; - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -460,7 +461,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, int changed = 0; int i; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for (i = 0; i < 2; i++) { if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { chip->monitoring_active[i] = ucontrol->value.integer.value[i]; @@ -474,7 +475,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, /* update right monitoring volume and mute */ pcxhr_update_audio_pipe_level(chip, 0, 1); - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return (changed != 0); } @@ -571,13 +572,13 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int ret = 0; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { chip->audio_capture_source = ucontrol->value.enumerated.item[0]; pcxhr_set_audio_source(chip); ret = 1; } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return ret; } @@ -636,9 +637,9 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); int rate, ret = 0; - down(&mgr->mixer_mutex); + mutex_lock(&mgr->mixer_mutex); if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { - down(&mgr->setup_mutex); + mutex_lock(&mgr->setup_mutex); mgr->use_clock_type = ucontrol->value.enumerated.item[0]; if (mgr->use_clock_type) pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate); @@ -649,10 +650,10 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, if (mgr->sample_rate) mgr->sample_rate = rate; } - up(&mgr->setup_mutex); + mutex_unlock(&mgr->setup_mutex); ret = 1; /* return 1 even if the set was not done. ok ? */ } - up(&mgr->mixer_mutex); + mutex_unlock(&mgr->mixer_mutex); return ret; } @@ -685,7 +686,7 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); int i, err, rate; - down(&mgr->mixer_mutex); + mutex_lock(&mgr->mixer_mutex); for(i = 0; i < 3 + mgr->capture_chips; i++) { if (i == PCXHR_CLOCK_TYPE_INTERNAL) rate = mgr->sample_rate_real; @@ -696,7 +697,7 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, } ucontrol->value.integer.value[i] = rate; } - up(&mgr->mixer_mutex); + mutex_unlock(&mgr->mixer_mutex); return 0; } @@ -765,7 +766,7 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v unsigned char aes_bits; int i, err; - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for(i = 0; i < 5; i++) { if (kcontrol->private_value == 0) /* playback */ aes_bits = chip->aes_bits[i]; @@ -776,7 +777,7 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v } ucontrol->value.iec958.status[i] = aes_bits; } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -828,14 +829,14 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, int i, changed = 0; /* playback */ - down(&chip->mgr->mixer_mutex); + mutex_lock(&chip->mgr->mixer_mutex); for (i = 0; i < 5; i++) { if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]); changed = 1; } } - up(&chip->mgr->mixer_mutex); + mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -916,7 +917,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) struct snd_pcxhr *chip; int err, i; - init_MUTEX(&mgr->mixer_mutex); /* can be in another place */ + mutex_init(&mgr->mixer_mutex); /* can be in another place */ for (i = 0; i < mgr->num_cards; i++) { struct snd_kcontrol_new temp; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 103b4d715ff4..980b9cd689dd 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -474,7 +474,7 @@ static inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg) static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan, unsigned int in) { - if (chan > HDSPM_MIXER_CHANNELS || in > HDSPM_MIXER_CHANNELS) + if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) return 0; return hdspm->mixer->ch[chan].in[in]; @@ -483,7 +483,7 @@ static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan, static inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan, unsigned int pb) { - if (chan > HDSPM_MIXER_CHANNELS || pb > HDSPM_MIXER_CHANNELS) + if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) return 0; return hdspm->mixer->ch[chan].pb[pb]; } diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index cf09ea99755c..46c6982c9e88 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -27,6 +27,8 @@ #include <asm/io.h> #include <linux/pci.h> #include <linux/time.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/trident.h> @@ -201,16 +203,16 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident, - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); blk = search_empty(hdr, runtime->dma_bytes); if (blk == NULL) { - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } if (lastpg(blk) - firstpg(blk) >= sgbuf->pages) { snd_printk(KERN_ERR "page calculation doesn't match: allocated pages = %d, trident = %d/%d\n", sgbuf->pages, firstpg(blk), lastpg(blk)); __snd_util_mem_free(hdr, blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } @@ -221,12 +223,12 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident, unsigned long ptr = (unsigned long)sgbuf->table[idx].buf; if (! is_valid_page(addr)) { __snd_util_mem_free(hdr, blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } set_tlb_bus(trident, page, ptr, addr); } - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return blk; } @@ -248,10 +250,10 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident, hdr = trident->tlb.memhdr; snd_assert(hdr != NULL, return NULL); - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); blk = search_empty(hdr, runtime->dma_bytes); if (blk == NULL) { - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } @@ -262,12 +264,12 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident, ptr += SNDRV_TRIDENT_PAGE_SIZE, addr += SNDRV_TRIDENT_PAGE_SIZE) { if (! is_valid_page(addr)) { __snd_util_mem_free(hdr, blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } set_tlb_bus(trident, page, ptr, addr); } - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return blk; } @@ -300,13 +302,13 @@ int snd_trident_free_pages(struct snd_trident *trident, snd_assert(blk != NULL, return -EINVAL); hdr = trident->tlb.memhdr; - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); /* reset TLB entries */ for (page = firstpg(blk); page <= lastpg(blk); page++) set_silent_tlb(trident, page); /* free memory block */ __snd_util_mem_free(hdr, blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return 0; } @@ -332,18 +334,18 @@ snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size) struct snd_util_memblk *blk; struct snd_util_memhdr *hdr = hw->tlb.memhdr; - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); blk = __snd_util_mem_alloc(hdr, size); if (blk == NULL) { - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } if (synth_alloc_pages(hw, blk)) { __snd_util_mem_free(hdr, blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return NULL; } - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return blk; } @@ -356,10 +358,10 @@ snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk) { struct snd_util_memhdr *hdr = hw->tlb.memhdr; - down(&hdr->block_mutex); + mutex_lock(&hdr->block_mutex); synth_free_pages(hw, blk); __snd_util_mem_free(hdr, blk); - up(&hdr->block_mutex); + mutex_unlock(&hdr->block_mutex); return 0; } diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 423741371191..1957d29c119e 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2375,8 +2375,10 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ { .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */ { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */ + { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */ { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */ { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ + { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */ { .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC }, /* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */ diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index c705af409b0f..9b6d345b83a6 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -24,6 +24,8 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/mutex.h> + #include <sound/core.h> #include <sound/control.h> #include <asm/io.h> @@ -861,10 +863,10 @@ static int vx_input_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); struct snd_vx222 *chip = (struct snd_vx222 *)_chip; - down(&_chip->mixer_mutex); + mutex_lock(&_chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->input_level[0]; ucontrol->value.integer.value[1] = chip->input_level[1]; - up(&_chip->mixer_mutex); + mutex_unlock(&_chip->mixer_mutex); return 0; } @@ -872,16 +874,16 @@ static int vx_input_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); struct snd_vx222 *chip = (struct snd_vx222 *)_chip; - down(&_chip->mixer_mutex); + mutex_lock(&_chip->mixer_mutex); if (chip->input_level[0] != ucontrol->value.integer.value[0] || chip->input_level[1] != ucontrol->value.integer.value[1]) { chip->input_level[0] = ucontrol->value.integer.value[0]; chip->input_level[1] = ucontrol->value.integer.value[1]; vx2_set_input_level(chip); - up(&_chip->mixer_mutex); + mutex_unlock(&_chip->mixer_mutex); return 1; } - up(&_chip->mixer_mutex); + mutex_unlock(&_chip->mixer_mutex); return 0; } @@ -907,14 +909,14 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); struct snd_vx222 *chip = (struct snd_vx222 *)_chip; - down(&_chip->mixer_mutex); + mutex_lock(&_chip->mixer_mutex); if (chip->mic_level != ucontrol->value.integer.value[0]) { chip->mic_level = ucontrol->value.integer.value[0]; vx2_set_input_level(chip); - up(&_chip->mixer_mutex); + mutex_unlock(&_chip->mixer_mutex); return 1; } - up(&_chip->mixer_mutex); + mutex_unlock(&_chip->mixer_mutex); return 0; } diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index dab9b8310341..db57ce939fa8 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -49,6 +49,7 @@ static long mpu_port[SNDRV_CARDS]; static long joystick_port[SNDRV_CARDS]; #endif static int rear_switch[SNDRV_CARDS]; +static int rear_swap[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 }; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard."); @@ -66,6 +67,8 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address"); #endif module_param_array(rear_switch, bool, NULL, 0444); MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); +module_param_array(rear_swap, bool, NULL, 0444); +MODULE_PARM_DESC(rear_swap, "Swap rear channels (must be enabled for correct IEC958 (S/PDIF)) output"); static struct pci_device_id snd_ymfpci_ids[] = { { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* YMF724 */ @@ -295,7 +298,7 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, snd_card_free(card); return err; } - if ((err = snd_ymfpci_mixer(chip, rear_switch[dev])) < 0) { + if ((err = snd_ymfpci_mixer(chip, rear_switch[dev], rear_swap[dev])) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index a1aa74b79b3d..8ac5ab50b5c7 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -536,15 +536,30 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int } } if (ypcm->output_rear) { - if (use_left) { - bank->eff2_gain = - bank->eff2_gain_end = vol_left; - } - if (use_right) { - bank->eff3_gain = - bank->eff3_gain_end = vol_right; - } - } + if (!ypcm->swap_rear) { + if (use_left) { + bank->eff2_gain = + bank->eff2_gain_end = vol_left; + } + if (use_right) { + bank->eff3_gain = + bank->eff3_gain_end = vol_right; + } + } else { + /* The SPDIF out channels seem to be swapped, so we have + * to swap them here, too. The rear analog out channels + * will be wrong, but otherwise AC3 would not work. + */ + if (use_left) { + bank->eff3_gain = + bank->eff3_gain_end = vol_left; + } + if (use_right) { + bank->eff2_gain = + bank->eff2_gain_end = vol_right; + } + } + } } } @@ -894,6 +909,7 @@ static int snd_ymfpci_playback_open(struct snd_pcm_substream *substream) ypcm = runtime->private_data; ypcm->output_front = 1; ypcm->output_rear = chip->mode_dup4ch ? 1 : 0; + ypcm->swap_rear = chip->rear_swap; spin_lock_irq(&chip->reg_lock); if (ypcm->output_rear) { ymfpci_open_extension(chip); @@ -1734,7 +1750,7 @@ static void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97) chip->ac97 = NULL; } -int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) +int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap) { struct snd_ac97_template ac97; struct snd_kcontrol *kctl; @@ -1746,6 +1762,7 @@ int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) .read = snd_ymfpci_codec_read, }; + chip->rear_swap = rear_swap; if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0) return err; chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus; @@ -2293,6 +2310,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card, return -EIO; } + chip->rear_swap = 1; if ((err = snd_ymfpci_ac3_init(chip)) < 0) { snd_ymfpci_free(chip); return err; |