diff options
Diffstat (limited to 'sound/pci/ac97/ac97_codec.c')
-rw-r--r-- | sound/pci/ac97/ac97_codec.c | 68 |
1 files changed, 37 insertions, 31 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 3020ca2b602..278319bbdea 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) { |