#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>
{ 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", patch_lm4550, NULL }, // volume wrap fix
+{ 0x4e534350, 0xffffffff, "LM4550", NULL, NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
{ 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH },
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF
{ 0x56494170, 0xffffffff, "VIA1617A", patch_vt1617a, NULL }, // modified VT1616 with S/PDIF
-{ 0x56494182, 0xffffffff, "VIA1618", NULL, NULL },
{ 0x57454301, 0xffffffff, "W83971D", NULL, NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", NULL, NULL },
{ 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
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:
{
if (!snd_ac97_valid_reg(ac97, reg))
return;
- mutex_lock(&ac97->reg_mutex);
+ down(&ac97->reg_mutex);
ac97->regs[reg] = value;
ac97->bus->ops->write(ac97, reg, value);
set_bit(reg, ac97->reg_accessed);
- mutex_unlock(&ac97->reg_mutex);
+ up(&ac97->reg_mutex);
}
/**
if (!snd_ac97_valid_reg(ac97, reg))
return -EINVAL;
- mutex_lock(&ac97->reg_mutex);
+ down(&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);
- mutex_unlock(&ac97->reg_mutex);
+ up(&ac97->reg_mutex);
return change;
}
if (!snd_ac97_valid_reg(ac97, reg))
return -EINVAL;
- mutex_lock(&ac97->reg_mutex);
+ down(&ac97->reg_mutex);
change = snd_ac97_update_bits_nolock(ac97, reg, mask, value);
- mutex_unlock(&ac97->reg_mutex);
+ up(&ac97->reg_mutex);
return change;
}
int change;
unsigned short old, new, cfg;
- mutex_lock(&ac97->page_mutex);
+ down(&ac97->page_mutex);
old = ac97->spec.ad18xx.pcmreg[codec];
new = (old & ~mask) | value;
change = old != new;
if (change) {
- mutex_lock(&ac97->reg_mutex);
+ down(&ac97->reg_mutex);
cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG);
ac97->spec.ad18xx.pcmreg[codec] = new;
/* select single codec */
/* select all codecs */
ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG,
cfg | 0x7000);
- mutex_unlock(&ac97->reg_mutex);
+ up(&ac97->reg_mutex);
}
- mutex_unlock(&ac97->page_mutex);
+ up(&ac97->page_mutex);
return change;
}
(ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
(reg >= 0x60 && reg < 0x70)) {
unsigned short page = (kcontrol->private_value >> 26) & 0x0f;
- mutex_lock(&ac97->page_mutex); /* lock paging */
+ down(&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);
}
{
if (page_save >= 0) {
snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
- mutex_unlock(&ac97->page_mutex); /* unlock paging */
+ up(&ac97->page_mutex); /* unlock paging */
}
}
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ac97->reg_mutex);
+ down(&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;
- mutex_unlock(&ac97->reg_mutex);
+ up(&ac97->reg_mutex);
return 0;
}
}
}
- mutex_lock(&ac97->reg_mutex);
+ down(&ac97->reg_mutex);
change = ac97->spdif_status != new;
ac97->spdif_status = new;
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
}
}
- mutex_unlock(&ac97->reg_mutex);
+ up(&ac97->reg_mutex);
return change;
}
value = (ucontrol->value.integer.value[0] & mask);
- mutex_lock(&ac97->reg_mutex);
+ down(&ac97->reg_mutex);
mask <<= shift;
value <<= shift;
old = snd_ac97_read_cache(ac97, reg);
if (extst & AC97_EA_SPDIF)
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
}
- mutex_unlock(&ac97->reg_mutex);
+ up(&ac97->reg_mutex);
return change;
}
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
int codec = kcontrol->private_value & 3;
- mutex_lock(&ac97->page_mutex);
+ down(&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);
- mutex_unlock(&ac97->page_mutex);
+ up(&ac97->page_mutex);
return 0;
}
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 */
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;
static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);
-static void snd_ctl_elem_remove(struct snd_card *card,
- struct snd_kcontrol *kcontrol)
-{
- struct snd_kcontrol *kct;
- struct snd_ctl_elem_id id = kcontrol->id;
-
- down_write(&card->controls_rwsem);
-
- if ((kct = snd_ctl_find_id(card, &id)))
- snd_ctl_remove(card, kct);
-
- up_write(&card->controls_rwsem);
-}
-
static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
{
struct snd_card *card = ac97->bus->card;
init_val = 0x9f9f;
else
init_val = 0x9f1f;
- for (idx = 0; idx < 2; idx++) {
- struct snd_kcontrol *kctrl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97);
- snd_ctl_elem_remove(card, kctrl);
- if ((err = snd_ctl_add(card, kctrl)) < 0)
+ for (idx = 0; idx < 2; idx++)
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0)
return err;
- }
ac97->spec.ad18xx.pcmreg[0] = init_val;
if (ac97->scaps & AC97_SCAP_SURROUND_DAC) {
- for (idx = 0; idx < 2; idx++) {
- struct snd_kcontrol *kctrl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97);
- snd_ctl_elem_remove(card, kctrl);
- if ((err = snd_ctl_add(card, kctrl)) < 0)
+ for (idx = 0; idx < 2; idx++)
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0)
return err;
- }
ac97->spec.ad18xx.pcmreg[1] = init_val;
}
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) {
- for (idx = 0; idx < 2; idx++) {
- struct snd_kcontrol *kctrl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97);
- snd_ctl_elem_remove(card, kctrl);
- if ((err = snd_ctl_add(card, kctrl)) < 0)
+ for (idx = 0; idx < 2; idx++)
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0)
return err;
- }
- for (idx = 0; idx < 2; idx++) {
- struct snd_kcontrol *kctrl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97);
- snd_ctl_elem_remove(card, kctrl);
- if ((err = snd_ctl_add(card, kctrl)) < 0)
+ for (idx = 0; idx < 2; idx++)
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0)
return err;
- }
ac97->spec.ad18xx.pcmreg[2] = init_val;
}
snd_ac97_write_cache(ac97, AC97_PCM, init_val);
ac97->num = template->num;
ac97->addr = template->addr;
ac97->scaps = template->scaps;
- ac97->res_table = template->res_table;
+ ac97->limited_regs = template->limited_regs;
+ memcpy(ac97->reg_accessed, template->reg_accessed, sizeof(ac97->reg_accessed));
bus->codec[ac97->num] = ac97;
- mutex_init(&ac97->reg_mutex);
- mutex_init(&ac97->page_mutex);
+ init_MUTEX(&ac97->reg_mutex);
+ init_MUTEX(&ac97->page_mutex);
#ifdef CONFIG_PCI
if (ac97->pci) {