ALSA: hda - Protect user-defined arrays via mutex
The pincfgs, init_verbs and hints set by sysfs or patch might be changed dynamically on the fly, thus we need to protect it. Add a simple protection via a mutex. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
08fb0d0ee1
commit
09b70e8509
|
@ -1086,9 +1086,16 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
|
||||||
struct hda_pincfg *pin;
|
struct hda_pincfg *pin;
|
||||||
|
|
||||||
#ifdef CONFIG_SND_HDA_HWDEP
|
#ifdef CONFIG_SND_HDA_HWDEP
|
||||||
pin = look_up_pincfg(codec, &codec->user_pins, nid);
|
{
|
||||||
if (pin)
|
unsigned int cfg = 0;
|
||||||
return pin->cfg;
|
mutex_lock(&codec->user_mutex);
|
||||||
|
pin = look_up_pincfg(codec, &codec->user_pins, nid);
|
||||||
|
if (pin)
|
||||||
|
cfg = pin->cfg;
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
|
if (cfg)
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
pin = look_up_pincfg(codec, &codec->driver_pins, nid);
|
pin = look_up_pincfg(codec, &codec->driver_pins, nid);
|
||||||
if (pin)
|
if (pin)
|
||||||
|
|
|
@ -845,6 +845,7 @@ struct hda_codec {
|
||||||
struct snd_array cvt_setups; /* audio convert setups */
|
struct snd_array cvt_setups; /* audio convert setups */
|
||||||
|
|
||||||
#ifdef CONFIG_SND_HDA_HWDEP
|
#ifdef CONFIG_SND_HDA_HWDEP
|
||||||
|
struct mutex user_mutex;
|
||||||
struct snd_hwdep *hwdep; /* assigned hwdep device */
|
struct snd_hwdep *hwdep; /* assigned hwdep device */
|
||||||
struct snd_array init_verbs; /* additional init verbs */
|
struct snd_array init_verbs; /* additional init verbs */
|
||||||
struct snd_array hints; /* additional hints */
|
struct snd_array hints; /* additional hints */
|
||||||
|
|
|
@ -148,6 +148,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
|
||||||
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
|
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mutex_init(&codec->user_mutex);
|
||||||
snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
|
snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
|
||||||
snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
|
snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
|
||||||
snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
|
snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
|
||||||
|
@ -346,12 +347,14 @@ static ssize_t init_verbs_show(struct device *dev,
|
||||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||||
struct hda_codec *codec = hwdep->private_data;
|
struct hda_codec *codec = hwdep->private_data;
|
||||||
int i, len = 0;
|
int i, len = 0;
|
||||||
|
mutex_lock(&codec->user_mutex);
|
||||||
for (i = 0; i < codec->init_verbs.used; i++) {
|
for (i = 0; i < codec->init_verbs.used; i++) {
|
||||||
struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
|
struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
|
||||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||||
"0x%02x 0x%03x 0x%04x\n",
|
"0x%02x 0x%03x 0x%04x\n",
|
||||||
v->nid, v->verb, v->param);
|
v->nid, v->verb, v->param);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,12 +367,16 @@ static int parse_init_verbs(struct hda_codec *codec, const char *buf)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!nid || !verb)
|
if (!nid || !verb)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
mutex_lock(&codec->user_mutex);
|
||||||
v = snd_array_new(&codec->init_verbs);
|
v = snd_array_new(&codec->init_verbs);
|
||||||
if (!v)
|
if (!v) {
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
v->nid = nid;
|
v->nid = nid;
|
||||||
v->verb = verb;
|
v->verb = verb;
|
||||||
v->param = param;
|
v->param = param;
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,11 +399,13 @@ static ssize_t hints_show(struct device *dev,
|
||||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||||
struct hda_codec *codec = hwdep->private_data;
|
struct hda_codec *codec = hwdep->private_data;
|
||||||
int i, len = 0;
|
int i, len = 0;
|
||||||
|
mutex_lock(&codec->user_mutex);
|
||||||
for (i = 0; i < codec->hints.used; i++) {
|
for (i = 0; i < codec->hints.used; i++) {
|
||||||
struct hda_hint *hint = snd_array_elem(&codec->hints, i);
|
struct hda_hint *hint = snd_array_elem(&codec->hints, i);
|
||||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||||
"%s = %s\n", hint->key, hint->val);
|
"%s = %s\n", hint->key, hint->val);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,6 +440,7 @@ static int parse_hints(struct hda_codec *codec, const char *buf)
|
||||||
{
|
{
|
||||||
char *key, *val;
|
char *key, *val;
|
||||||
struct hda_hint *hint;
|
struct hda_hint *hint;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
buf = skip_spaces(buf);
|
buf = skip_spaces(buf);
|
||||||
if (!*buf || *buf == '#' || *buf == '\n')
|
if (!*buf || *buf == '#' || *buf == '\n')
|
||||||
|
@ -450,26 +460,31 @@ static int parse_hints(struct hda_codec *codec, const char *buf)
|
||||||
val = skip_spaces(val);
|
val = skip_spaces(val);
|
||||||
remove_trail_spaces(key);
|
remove_trail_spaces(key);
|
||||||
remove_trail_spaces(val);
|
remove_trail_spaces(val);
|
||||||
|
mutex_lock(&codec->user_mutex);
|
||||||
hint = get_hint(codec, key);
|
hint = get_hint(codec, key);
|
||||||
if (hint) {
|
if (hint) {
|
||||||
/* replace */
|
/* replace */
|
||||||
kfree(hint->key);
|
kfree(hint->key);
|
||||||
hint->key = key;
|
hint->key = key;
|
||||||
hint->val = val;
|
hint->val = val;
|
||||||
return 0;
|
goto unlock;
|
||||||
}
|
}
|
||||||
/* allocate a new hint entry */
|
/* allocate a new hint entry */
|
||||||
if (codec->hints.used >= MAX_HINTS)
|
if (codec->hints.used >= MAX_HINTS)
|
||||||
hint = NULL;
|
hint = NULL;
|
||||||
else
|
else
|
||||||
hint = snd_array_new(&codec->hints);
|
hint = snd_array_new(&codec->hints);
|
||||||
if (!hint) {
|
if (hint) {
|
||||||
kfree(key);
|
hint->key = key;
|
||||||
return -ENOMEM;
|
hint->val = val;
|
||||||
|
} else {
|
||||||
|
err = -ENOMEM;
|
||||||
}
|
}
|
||||||
hint->key = key;
|
unlock:
|
||||||
hint->val = val;
|
mutex_unlock(&codec->user_mutex);
|
||||||
return 0;
|
if (err)
|
||||||
|
kfree(key);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t hints_store(struct device *dev,
|
static ssize_t hints_store(struct device *dev,
|
||||||
|
@ -489,11 +504,13 @@ static ssize_t pin_configs_show(struct hda_codec *codec,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
int i, len = 0;
|
int i, len = 0;
|
||||||
|
mutex_lock(&codec->user_mutex);
|
||||||
for (i = 0; i < list->used; i++) {
|
for (i = 0; i < list->used; i++) {
|
||||||
struct hda_pincfg *pin = snd_array_elem(list, i);
|
struct hda_pincfg *pin = snd_array_elem(list, i);
|
||||||
len += sprintf(buf + len, "0x%02x 0x%08x\n",
|
len += sprintf(buf + len, "0x%02x 0x%08x\n",
|
||||||
pin->nid, pin->cfg);
|
pin->nid, pin->cfg);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,13 +545,16 @@ static ssize_t driver_pin_configs_show(struct device *dev,
|
||||||
|
|
||||||
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
|
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
|
||||||
{
|
{
|
||||||
int nid, cfg;
|
int nid, cfg, err;
|
||||||
|
|
||||||
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
|
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!nid)
|
if (!nid)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
|
mutex_lock(&codec->user_mutex);
|
||||||
|
err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t user_pin_configs_store(struct device *dev,
|
static ssize_t user_pin_configs_store(struct device *dev,
|
||||||
|
@ -600,16 +620,27 @@ EXPORT_SYMBOL_HDA(snd_hda_get_hint);
|
||||||
|
|
||||||
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
||||||
{
|
{
|
||||||
const char *p = snd_hda_get_hint(codec, key);
|
const char *p;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&codec->user_mutex);
|
||||||
|
p = snd_hda_get_hint(codec, key);
|
||||||
if (!p || !*p)
|
if (!p || !*p)
|
||||||
return -ENOENT;
|
ret = -ENOENT;
|
||||||
switch (toupper(*p)) {
|
else {
|
||||||
case 'T': /* true */
|
switch (toupper(*p)) {
|
||||||
case 'Y': /* yes */
|
case 'T': /* true */
|
||||||
case '1':
|
case 'Y': /* yes */
|
||||||
return 1;
|
case '1':
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
mutex_unlock(&codec->user_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
|
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
|
||||||
|
|
||||||
|
|
|
@ -4298,15 +4298,20 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
||||||
static inline int get_int_hint(struct hda_codec *codec, const char *key,
|
static inline int get_int_hint(struct hda_codec *codec, const char *key,
|
||||||
int *valp)
|
int *valp)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SND_HDA_RECONFIG
|
||||||
const char *p;
|
const char *p;
|
||||||
|
mutex_lock(&codec->user_mutex);
|
||||||
p = snd_hda_get_hint(codec, key);
|
p = snd_hda_get_hint(codec, key);
|
||||||
if (p) {
|
if (p) {
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
if (!strict_strtoul(p, 0, &val)) {
|
if (!strict_strtoul(p, 0, &val)) {
|
||||||
*valp = val;
|
*valp = val;
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&codec->user_mutex);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue