mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-03 09:01:52 -05:00
topology: implement snd_tplg_decode
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
0ba4d6d9c0
commit
b6c9afb4f5
11 changed files with 1730 additions and 142 deletions
|
|
@ -621,8 +621,9 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
|
|||
tplg->channel_idx = 0;
|
||||
|
||||
/* set channel reg to default state */
|
||||
for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
|
||||
for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++) {
|
||||
ec->channel[j].reg = -1;
|
||||
}
|
||||
|
||||
tplg_dbg(" Control Enum: %s\n", elem->id);
|
||||
|
||||
|
|
@ -896,9 +897,14 @@ int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
|
||||
struct snd_tplg_ctl_template *t)
|
||||
static int init_ctl_hdr(snd_tplg_t *tplg,
|
||||
struct tplg_elem *parent,
|
||||
struct snd_soc_tplg_ctl_hdr *hdr,
|
||||
struct snd_tplg_ctl_template *t)
|
||||
{
|
||||
struct tplg_elem *elem;
|
||||
int err;
|
||||
|
||||
hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr);
|
||||
hdr->type = t->type;
|
||||
|
||||
|
|
@ -924,7 +930,7 @@ static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
|
|||
&& !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
|
||||
|
||||
struct snd_tplg_tlv_template *tlvt = t->tlv;
|
||||
struct snd_soc_tplg_ctl_tlv *tlv = &hdr->tlv;
|
||||
struct snd_soc_tplg_ctl_tlv *tlv;
|
||||
struct snd_tplg_tlv_dbscale_template *scalet;
|
||||
struct snd_soc_tplg_tlv_dbscale *scale;
|
||||
|
||||
|
|
@ -933,6 +939,17 @@ static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
elem = tplg_elem_new_common(tplg, NULL, parent->id,
|
||||
SND_TPLG_TYPE_TLV);
|
||||
if (!elem)
|
||||
return -ENOMEM;
|
||||
|
||||
tlv = elem->tlv;
|
||||
|
||||
err = tplg_ref_add(parent, SND_TPLG_TYPE_TLV, parent->id);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
|
||||
tlv->type = tlvt->type;
|
||||
|
||||
|
|
@ -957,10 +974,10 @@ static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
|
|||
}
|
||||
|
||||
int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
|
||||
struct tplg_elem **e)
|
||||
struct tplg_elem **e)
|
||||
{
|
||||
struct snd_soc_tplg_private *priv = mixer->priv;
|
||||
struct snd_soc_tplg_mixer_control *mc;
|
||||
struct snd_soc_tplg_private *priv;
|
||||
struct tplg_elem *elem;
|
||||
int ret, i, num_channels;
|
||||
|
||||
|
|
@ -979,7 +996,7 @@ int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
|
|||
/* init new mixer */
|
||||
mc = elem->mixer_ctrl;
|
||||
mc->size = elem->size;
|
||||
ret = init_ctl_hdr(&mc->hdr, &mixer->hdr);
|
||||
ret = init_ctl_hdr(tplg, elem, &mc->hdr, &mixer->hdr);
|
||||
if (ret < 0) {
|
||||
tplg_elem_free(elem);
|
||||
return ret;
|
||||
|
|
@ -1000,25 +1017,20 @@ int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
|
|||
for (i = 0; i < num_channels; i++) {
|
||||
struct snd_tplg_channel_elem *channel = &mixer->map->channel[i];
|
||||
|
||||
mc->channel[i].size = channel->size;
|
||||
mc->channel[i].size = sizeof(mc->channel[0]);
|
||||
mc->channel[i].reg = channel->reg;
|
||||
mc->channel[i].shift = channel->shift;
|
||||
mc->channel[i].id = channel->id;
|
||||
}
|
||||
|
||||
/* priv data */
|
||||
if (priv) {
|
||||
mc = realloc(mc, elem->size + priv->size);
|
||||
if (!mc) {
|
||||
tplg_elem_free(elem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
elem->mixer_ctrl = mc;
|
||||
elem->size += priv->size;
|
||||
mc->priv.size = priv->size;
|
||||
memcpy(mc->priv.data, priv->data, priv->size);
|
||||
}
|
||||
priv = mixer->priv;
|
||||
if (priv && priv->size > 0) {
|
||||
ret = tplg_add_data(tplg, elem, priv,
|
||||
sizeof(*priv) + priv->size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (e)
|
||||
*e = elem;
|
||||
|
|
@ -1026,11 +1038,12 @@ int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
|
|||
}
|
||||
|
||||
int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
|
||||
struct tplg_elem **e)
|
||||
struct tplg_elem **e)
|
||||
{
|
||||
struct snd_soc_tplg_enum_control *ec;
|
||||
struct snd_soc_tplg_private *priv;
|
||||
struct tplg_elem *elem;
|
||||
int ret, i, num_items;
|
||||
int ret, i, num_items, num_channels;
|
||||
|
||||
tplg_dbg(" Control Enum: %s\n", enum_ctl->hdr.name);
|
||||
|
||||
|
|
@ -1046,7 +1059,7 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
|
|||
|
||||
ec = elem->enum_ctrl;
|
||||
ec->size = elem->size;
|
||||
ret = init_ctl_hdr(&ec->hdr, &enum_ctl->hdr);
|
||||
ret = init_ctl_hdr(tplg, elem, &ec->hdr, &enum_ctl->hdr);
|
||||
if (ret < 0) {
|
||||
tplg_elem_free(elem);
|
||||
return ret;
|
||||
|
|
@ -1058,6 +1071,22 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
|
|||
ec->mask = enum_ctl->mask;
|
||||
ec->count = enum_ctl->items;
|
||||
|
||||
/* set channel reg to default state */
|
||||
for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
|
||||
ec->channel[i].reg = -1;
|
||||
|
||||
num_channels = enum_ctl->map ? enum_ctl->map->num_channels : 0;
|
||||
ec->num_channels = num_channels;
|
||||
|
||||
for (i = 0; i < num_channels; i++) {
|
||||
struct snd_tplg_channel_elem *channel = &enum_ctl->map->channel[i];
|
||||
|
||||
ec->channel[i].size = sizeof(ec->channel[0]);
|
||||
ec->channel[i].reg = channel->reg;
|
||||
ec->channel[i].shift = channel->shift;
|
||||
ec->channel[i].id = channel->id;
|
||||
}
|
||||
|
||||
if (enum_ctl->texts != NULL) {
|
||||
for (i = 0; i < num_items; i++) {
|
||||
if (enum_ctl->texts[i] != NULL)
|
||||
|
|
@ -1077,21 +1106,13 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
|
|||
}
|
||||
}
|
||||
|
||||
if (enum_ctl->priv != NULL) {
|
||||
ec = realloc(ec,
|
||||
elem->size + enum_ctl->priv->size);
|
||||
if (!ec) {
|
||||
tplg_elem_free(elem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
elem->enum_ctrl = ec;
|
||||
elem->size += enum_ctl->priv->size;
|
||||
|
||||
memcpy(ec->priv.data, enum_ctl->priv->data,
|
||||
enum_ctl->priv->size);
|
||||
|
||||
ec->priv.size = enum_ctl->priv->size;
|
||||
/* priv data */
|
||||
priv = enum_ctl->priv;
|
||||
if (priv && priv->size > 0) {
|
||||
ret = tplg_add_data(tplg, elem, priv,
|
||||
sizeof(*priv) + priv->size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (e)
|
||||
|
|
@ -1100,9 +1121,10 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
|
|||
}
|
||||
|
||||
int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
|
||||
struct tplg_elem **e)
|
||||
struct tplg_elem **e)
|
||||
{
|
||||
struct snd_soc_tplg_bytes_control *be;
|
||||
struct snd_soc_tplg_private *priv;
|
||||
struct tplg_elem *elem;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1120,7 +1142,7 @@ int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
|
|||
|
||||
be = elem->bytes_ext;
|
||||
be->size = elem->size;
|
||||
ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr);
|
||||
ret = init_ctl_hdr(tplg, elem, &be->hdr, &bytes_ctl->hdr);
|
||||
if (ret < 0) {
|
||||
tplg_elem_free(elem);
|
||||
return ret;
|
||||
|
|
@ -1133,20 +1155,13 @@ int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
|
|||
be->ext_ops.put = bytes_ctl->ext_ops.put;
|
||||
be->ext_ops.get = bytes_ctl->ext_ops.get;
|
||||
|
||||
if (bytes_ctl->priv != NULL) {
|
||||
be = realloc(be,
|
||||
elem->size + bytes_ctl->priv->size);
|
||||
if (!be) {
|
||||
tplg_elem_free(elem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
elem->bytes_ext = be;
|
||||
elem->size += bytes_ctl->priv->size;
|
||||
|
||||
memcpy(be->priv.data, bytes_ctl->priv->data,
|
||||
bytes_ctl->priv->size);
|
||||
|
||||
be->priv.size = bytes_ctl->priv->size;
|
||||
/* priv data */
|
||||
priv = bytes_ctl->priv;
|
||||
if (priv && priv->size > 0) {
|
||||
ret = tplg_add_data(tplg, elem, priv,
|
||||
sizeof(*priv) + priv->size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check on TLV bytes control */
|
||||
|
|
@ -1184,3 +1199,330 @@ int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
|
|||
{
|
||||
return tplg_add_bytes(tplg, t->bytes_ctl, NULL);
|
||||
}
|
||||
|
||||
int tplg_decode_control_mixer1(snd_tplg_t *tplg,
|
||||
struct list_head *heap,
|
||||
struct snd_tplg_mixer_template *mt,
|
||||
size_t pos,
|
||||
void *bin, size_t size)
|
||||
{
|
||||
struct snd_soc_tplg_mixer_control *mc = bin;
|
||||
struct snd_tplg_channel_map_template *map;
|
||||
struct snd_tplg_tlv_dbscale_template *db;
|
||||
int i;
|
||||
|
||||
if (size < sizeof(*mc)) {
|
||||
SNDERR("mixer: small size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tplg_dv(tplg, pos, "mixer: size %d TLV size %d private size %d",
|
||||
mc->size, mc->hdr.tlv.size, mc->priv.size);
|
||||
if (size != mc->size + mc->priv.size) {
|
||||
SNDERR("mixer: unexpected element size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(mt, 0, sizeof(*mt));
|
||||
mt->hdr.type = mc->hdr.type;
|
||||
mt->hdr.name = mc->hdr.name;
|
||||
mt->hdr.access = mc->hdr.access;
|
||||
mt->hdr.ops.get = mc->hdr.ops.get;
|
||||
mt->hdr.ops.put = mc->hdr.ops.put;
|
||||
mt->hdr.ops.info = mc->hdr.ops.info;
|
||||
mt->min = mc->min;
|
||||
mt->max = mc->max;
|
||||
mt->platform_max = mc->platform_max;
|
||||
tplg_dv(tplg, pos, "mixer: name '%s' access 0x%x",
|
||||
mt->hdr.name, mt->hdr.access);
|
||||
if (mc->num_channels > 0) {
|
||||
map = tplg_calloc(heap, sizeof(*map));
|
||||
map->num_channels = mc->num_channels;
|
||||
for (i = 0; i < map->num_channels; i++) {
|
||||
map->channel[i].reg = mc->channel[i].reg;
|
||||
map->channel[i].shift = mc->channel[i].shift;
|
||||
map->channel[i].id = mc->channel[i].id;
|
||||
}
|
||||
mt->map = map;
|
||||
}
|
||||
if (mc->hdr.tlv.size == 0) {
|
||||
/* nothing */
|
||||
} else if (mc->hdr.tlv.size == sizeof(struct snd_soc_tplg_ctl_tlv)) {
|
||||
if (mc->hdr.tlv.type != SNDRV_CTL_TLVT_DB_SCALE) {
|
||||
SNDERR("mixer: unknown TLV type %d",
|
||||
mc->hdr.tlv.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
db = tplg_calloc(heap, sizeof(*db));
|
||||
if (db == NULL)
|
||||
return -ENOMEM;
|
||||
mt->hdr.tlv_scale = db;
|
||||
db->hdr.type = mc->hdr.tlv.type;
|
||||
db->min = mc->hdr.tlv.scale.min;
|
||||
db->step = mc->hdr.tlv.scale.step;
|
||||
db->mute = mc->hdr.tlv.scale.mute;
|
||||
tplg_dv(tplg, pos, "mixer: dB scale TLV: min %d step %d mute %d",
|
||||
db->min, db->step, db->mute);
|
||||
} else {
|
||||
SNDERR("mixer: wrong TLV size %d", mc->hdr.tlv.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mt->priv = &mc->priv;
|
||||
tplg_dv(tplg, pos + offsetof(struct snd_soc_tplg_mixer_control, priv),
|
||||
"mixer: private start");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tplg_decode_control_mixer(snd_tplg_t *tplg,
|
||||
size_t pos,
|
||||
struct snd_soc_tplg_hdr *hdr,
|
||||
void *bin, size_t size)
|
||||
{
|
||||
struct list_head heap;
|
||||
snd_tplg_obj_template_t t;
|
||||
struct snd_tplg_mixer_template mt;
|
||||
struct snd_soc_tplg_mixer_control *mc;
|
||||
size_t size2;
|
||||
int err;
|
||||
|
||||
err = tplg_decode_template(tplg, pos, hdr, &t);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
next:
|
||||
if (size < sizeof(*mc)) {
|
||||
SNDERR("mixer: small size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
INIT_LIST_HEAD(&heap);
|
||||
mc = bin;
|
||||
size2 = mc->size + mc->priv.size;
|
||||
if (size2 > size) {
|
||||
SNDERR("mixer: wrong element size (%d, priv %d)",
|
||||
mc->size, mc->priv.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = tplg_decode_control_mixer1(tplg, &heap, &mt, pos, bin, size2);
|
||||
if (err >= 0) {
|
||||
t.mixer = &mt;
|
||||
err = snd_tplg_add_object(tplg, &t);
|
||||
}
|
||||
tplg_free(&heap);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
bin += size2;
|
||||
size -= size2;
|
||||
pos += size2;
|
||||
|
||||
if (size > 0)
|
||||
goto next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tplg_decode_control_enum1(snd_tplg_t *tplg,
|
||||
struct list_head *heap,
|
||||
struct snd_tplg_enum_template *et,
|
||||
size_t pos,
|
||||
void *bin, size_t size)
|
||||
{
|
||||
struct snd_soc_tplg_enum_control *ec = bin;
|
||||
struct snd_tplg_channel_map_template cmt;
|
||||
int i;
|
||||
|
||||
if (size < sizeof(*ec)) {
|
||||
SNDERR("enum: small size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tplg_dv(tplg, pos, "enum: size %d private size %d",
|
||||
ec->size, ec->priv.size);
|
||||
if (size != ec->size + ec->priv.size) {
|
||||
SNDERR("enum: unexpected element size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ec->num_channels > SND_TPLG_MAX_CHAN ||
|
||||
ec->num_channels > SND_SOC_TPLG_MAX_CHAN) {
|
||||
SNDERR("enum: unexpected channel count %d", ec->num_channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ec->items > SND_SOC_TPLG_NUM_TEXTS) {
|
||||
SNDERR("enum: unexpected texts count %d", ec->items);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(et, 0, sizeof(*et));
|
||||
et->hdr.type = ec->hdr.type;
|
||||
et->hdr.name = ec->hdr.name;
|
||||
et->hdr.access = ec->hdr.access;
|
||||
et->hdr.ops.get = ec->hdr.ops.get;
|
||||
et->hdr.ops.put = ec->hdr.ops.put;
|
||||
et->hdr.ops.info = ec->hdr.ops.info;
|
||||
et->mask = ec->mask;
|
||||
|
||||
if (ec->items > 0) {
|
||||
et->items = ec->items;
|
||||
et->texts = tplg_calloc(heap, sizeof(char *) * ec->items);
|
||||
if (!et->texts)
|
||||
return -ENOMEM;
|
||||
for (i = 0; ec->items; i++) {
|
||||
unsigned int j = i * sizeof(int) * ENUM_VAL_SIZE;
|
||||
et->texts[i] = ec->texts[i];
|
||||
et->values[i] = (int *)&ec->values[j];
|
||||
}
|
||||
}
|
||||
|
||||
et->map = &cmt;
|
||||
memset(&cmt, 0, sizeof(cmt));
|
||||
cmt.num_channels = ec->num_channels;
|
||||
for (i = 0; i < cmt.num_channels; i++) {
|
||||
struct snd_tplg_channel_elem *channel = &cmt.channel[i];
|
||||
tplg_dv(tplg, pos + ((void *)&ec->channel[i] - (void *)ec),
|
||||
"enum: channel size %d", ec->channel[i].size);
|
||||
channel->reg = ec->channel[i].reg;
|
||||
channel->shift = ec->channel[i].shift;
|
||||
channel->id = ec->channel[i].id;
|
||||
}
|
||||
|
||||
et->priv = &ec->priv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tplg_decode_control_enum(snd_tplg_t *tplg,
|
||||
size_t pos,
|
||||
struct snd_soc_tplg_hdr *hdr,
|
||||
void *bin, size_t size)
|
||||
{
|
||||
struct list_head heap;
|
||||
snd_tplg_obj_template_t t;
|
||||
struct snd_tplg_enum_template et;
|
||||
struct snd_soc_tplg_enum_control *ec;
|
||||
size_t size2;
|
||||
int err;
|
||||
|
||||
err = tplg_decode_template(tplg, pos, hdr, &t);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
next:
|
||||
if (size < sizeof(*ec)) {
|
||||
SNDERR("enum: small size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
INIT_LIST_HEAD(&heap);
|
||||
ec = bin;
|
||||
size2 = ec->size + ec->priv.size;
|
||||
if (size2 > size) {
|
||||
SNDERR("enum: wrong element size (%d, priv %d)",
|
||||
ec->size, ec->priv.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = tplg_decode_control_enum1(tplg, &heap, &et, pos, bin, size);
|
||||
if (err >= 0) {
|
||||
t.enum_ctl = &et;
|
||||
err = snd_tplg_add_object(tplg, &t);
|
||||
}
|
||||
tplg_free(&heap);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
bin += size2;
|
||||
size -= size2;
|
||||
pos += size2;
|
||||
|
||||
if (size > 0)
|
||||
goto next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tplg_decode_control_bytes1(snd_tplg_t *tplg,
|
||||
struct snd_tplg_bytes_template *bt,
|
||||
size_t pos,
|
||||
void *bin, size_t size)
|
||||
{
|
||||
struct snd_soc_tplg_bytes_control *bc = bin;
|
||||
|
||||
if (size < sizeof(*bc)) {
|
||||
SNDERR("bytes: small size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tplg_dv(tplg, pos, "control bytes: size %d private size %d",
|
||||
bc->size, bc->priv.size);
|
||||
if (size != bc->size + bc->priv.size) {
|
||||
SNDERR("bytes: unexpected element size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(bt, 0, sizeof(*bt));
|
||||
bt->hdr.type = bc->hdr.type;
|
||||
bt->hdr.name = bc->hdr.name;
|
||||
bt->hdr.access = bc->hdr.access;
|
||||
bt->hdr.ops.get = bc->hdr.ops.get;
|
||||
bt->hdr.ops.put = bc->hdr.ops.put;
|
||||
bt->hdr.ops.info = bc->hdr.ops.info;
|
||||
bt->max = bc->max;
|
||||
bt->mask = bc->mask;
|
||||
bt->base = bc->base;
|
||||
bt->num_regs = bc->num_regs;
|
||||
bt->ext_ops.get = bc->ext_ops.get;
|
||||
bt->ext_ops.put = bc->ext_ops.put;
|
||||
bt->ext_ops.info = bc->ext_ops.info;
|
||||
tplg_dv(tplg, pos, "control bytes: name '%s' access 0x%x",
|
||||
bt->hdr.name, bt->hdr.access);
|
||||
|
||||
bt->priv = &bc->priv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tplg_decode_control_bytes(snd_tplg_t *tplg,
|
||||
size_t pos,
|
||||
struct snd_soc_tplg_hdr *hdr,
|
||||
void *bin, size_t size)
|
||||
{
|
||||
snd_tplg_obj_template_t t;
|
||||
struct snd_tplg_bytes_template bt;
|
||||
struct snd_soc_tplg_bytes_control *bc;
|
||||
size_t size2;
|
||||
int err;
|
||||
|
||||
err = tplg_decode_template(tplg, pos, hdr, &t);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
next:
|
||||
if (size < sizeof(*bc)) {
|
||||
SNDERR("bytes: small size %d", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
bc = bin;
|
||||
size2 = bc->size + bc->priv.size;
|
||||
if (size2 > size) {
|
||||
SNDERR("bytes: wrong element size (%d, priv %d)",
|
||||
bc->size, bc->priv.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = tplg_decode_control_bytes1(tplg, &bt, pos, bin, size);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
t.bytes_ctl = &bt;
|
||||
err = snd_tplg_add_object(tplg, &t);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
bin += size2;
|
||||
size -= size2;
|
||||
pos += size2;
|
||||
|
||||
if (size > 0)
|
||||
goto next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue