diff options
Diffstat (limited to 'sound/soc/codecs/sigmadsp.c')
-rw-r--r-- | sound/soc/codecs/sigmadsp.c | 54 |
1 files changed, 25 insertions, 29 deletions
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 76c77dc8ecf7..56546e2394ab 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -24,6 +24,8 @@ #define SIGMA_FW_CHUNK_TYPE_CONTROL 1 #define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2 +#define READBACK_CTRL_NAME "ReadBack" + struct sigmadsp_control { struct list_head head; uint32_t samplerates; @@ -31,6 +33,7 @@ struct sigmadsp_control { unsigned int num_bytes; const char *name; struct snd_kcontrol *kcontrol; + bool is_readback; bool cached; uint8_t cache[]; }; @@ -40,7 +43,7 @@ struct sigmadsp_data { uint32_t samplerates; unsigned int addr; unsigned int length; - uint8_t data[]; + uint8_t data[] __counted_by(length); }; struct sigma_fw_chunk { @@ -141,7 +144,8 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, if (ret == 0) { memcpy(ctrl->cache, data, ctrl->num_bytes); - ctrl->cached = true; + if (!ctrl->is_readback) + ctrl->cached = true; } mutex_unlock(&sigmadsp->lock); @@ -164,7 +168,8 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, } if (ret == 0) { - ctrl->cached = true; + if (!ctrl->is_readback) + ctrl->cached = true; memcpy(ucontrol->value.bytes.data, ctrl->cache, ctrl->num_bytes); } @@ -222,15 +227,22 @@ static int sigma_fw_load_control(struct sigmadsp *sigmadsp, if (!ctrl) return -ENOMEM; - name = kzalloc(name_len + 1, GFP_KERNEL); + name = kmemdup_nul(ctrl_chunk->name, name_len, GFP_KERNEL); if (!name) { ret = -ENOMEM; goto err_free_ctrl; } - memcpy(name, ctrl_chunk->name, name_len); - name[name_len] = '\0'; ctrl->name = name; + /* + * Readbacks doesn't work with non-volatile controls, since the + * firmware updates the control value without driver interaction. Mark + * the readbacks to ensure that the values are not cached. + */ + if (ctrl->name && strncmp(ctrl->name, READBACK_CTRL_NAME, + (sizeof(READBACK_CTRL_NAME) - 1)) == 0) + ctrl->is_readback = true; + ctrl->addr = le16_to_cpu(ctrl_chunk->addr); ctrl->num_bytes = num_bytes; ctrl->samplerates = le32_to_cpu(chunk->samplerates); @@ -258,7 +270,7 @@ static int sigma_fw_load_data(struct sigmadsp *sigmadsp, length -= sizeof(*data_chunk); - data = kzalloc(sizeof(*data) + length, GFP_KERNEL); + data = kzalloc(struct_size(data, data, length), GFP_KERNEL); if (!data) return -ENOMEM; @@ -401,7 +413,8 @@ static int process_sigma_action(struct sigmadsp *sigmadsp, if (len < 3) return -EINVAL; - data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL); + data = kzalloc(struct_size(data, data, size_sub(len, 2)), + GFP_KERNEL); if (!data) return -ENOMEM; @@ -657,36 +670,19 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, struct sigmadsp_control *ctrl, unsigned int samplerate_mask) { struct snd_card *card = sigmadsp->component->card->snd_card; - struct snd_kcontrol_volatile *vd; - struct snd_ctl_elem_id id; bool active; - bool changed = false; + int changed; active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask); - - down_write(&card->controls_rwsem); - if (!ctrl->kcontrol) { - up_write(&card->controls_rwsem); + if (!ctrl->kcontrol) return; - } - - id = ctrl->kcontrol->id; - vd = &ctrl->kcontrol->vd[0]; - if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) { - vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - changed = true; - } - up_write(&card->controls_rwsem); - - if (active && changed) { + changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active); + if (active && changed > 0) { mutex_lock(&sigmadsp->lock); if (ctrl->cached) sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); mutex_unlock(&sigmadsp->lock); } - - if (changed) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id); } /** |