Currently the TLV topology structure is targeted at only supporting the DB scale data. This patch extends support for the other TLV types so they can be easily added at a later stage. TLV structure is moved to common topology control header since it's a common field for controls and can be processed in a general way. Users must set a proper access flag for a control since it's used to decide if the TLV field is valid and if a TLV callback is needed. Removed the following fields from topology TLV struct: - size/count: type can decide the size. - numid: not needed to initialize TLV for kcontrol. - data: replaced by the type specific struct. Added TLV structure to generic control header and removed TLV structure from mixer control.
Unified · Split
| @@ -137,11 +137,19 @@ struct snd_soc_tplg_private { · 136 unmodified lines | ||
| 137 | 137 | /* |
| 138 | 138 | * Kcontrol TLV data. |
| 139 | 139 | */ |
| 140 | +struct snd_soc_tplg_tlv_dbscale { | |
| 141 | + __le32 min; | |
| 142 | + __le32 step; | |
| 143 | + __le32 mute; | |
| 144 | +} __attribute__((packed)); | |
| 145 | + | |
| 140 | 146 | struct snd_soc_tplg_ctl_tlv { |
| 141 | − __le32 size; /* in bytes aligned to 4 */ | |
| 142 | − __le32 numid; /* control element numeric identification */ | |
| 143 | − __le32 count; /* number of elem in data array */ | |
| 144 | − __le32 data[SND_SOC_TPLG_TLV_SIZE]; | |
| 147 | + __le32 size; /* in bytes of this structure */ | |
| 148 | + __le32 type; /* SNDRV_CTL_TLVT_*, type of TLV */ | |
| 149 | + union { | |
| 150 | + __le32 data[SND_SOC_TPLG_TLV_SIZE]; | |
| 151 | + struct snd_soc_tplg_tlv_dbscale scale; | |
| 152 | + }; | |
| 145 | 153 | } __attribute__((packed)); |
| 146 | 154 | |
| 147 | 155 | /* |
| @@ -172,7 +180,7 @@ struct snd_soc_tplg_ctl_hdr { · 24 unmodified lines | ||
| 172 | 180 | char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
| 173 | 181 | __le32 access; |
| 174 | 182 | struct snd_soc_tplg_kcontrol_ops_id ops; |
| 175 | − __le32 tlv_size; /* non zero means control has TLV data */ | |
| 183 | + struct snd_soc_tplg_ctl_tlv tlv; | |
| 176 | 184 | } __attribute__((packed)); |
| 177 | 185 | |
| 178 | 186 | /* |
| @@ -260,7 +268,6 @@ struct snd_soc_tplg_mixer_control { · 81 unmodified lines | ||
| 260 | 268 | __le32 invert; |
| 261 | 269 | __le32 num_channels; |
| 262 | 270 | struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN]; |
| 263 | − struct snd_soc_tplg_ctl_tlv tlv; | |
| 264 | 271 | struct snd_soc_tplg_private priv; |
| 265 | 272 | } __attribute__((packed)); |
| 266 | 273 | |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <sound/soc.h> |
| 34 | 34 | #include <sound/soc-dapm.h> |
| 35 | 35 | #include <sound/soc-topology.h> |
| 36 | +#include <sound/tlv.h> | |
| 36 | 37 | |
| 37 | 38 | /* |
| 38 | 39 | * We make several passes over the data (since it wont necessarily be ordered) |
| @@ -579,28 +580,51 @@ static int soc_tplg_init_kcontrol(struct soc_tplg *tplg, · 540 unmodified lines | ||
| 579 | 580 | return 0; |
| 580 | 581 | } |
| 581 | 582 | |
| 583 | + | |
| 584 | +static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg, | |
| 585 | + struct snd_kcontrol_new *kc, struct snd_soc_tplg_tlv_dbscale *scale) | |
| 586 | +{ | |
| 587 | + unsigned int item_len = 2 * sizeof(unsigned int); | |
| 588 | + unsigned int *p; | |
| 589 | + | |
| 590 | + p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL); | |
| 591 | + if (!p) | |
| 592 | + return -ENOMEM; | |
| 593 | + | |
| 594 | + p[0] = SNDRV_CTL_TLVT_DB_SCALE; | |
| 595 | + p[1] = item_len; | |
| 596 | + p[2] = scale->min; | |
| 597 | + p[3] = (scale->step & TLV_DB_SCALE_MASK) | |
| 598 | + | (scale->mute ? TLV_DB_SCALE_MUTE : 0); | |
| 599 | + | |
| 600 | + kc->tlv.p = (void *)p; | |
| 601 | + return 0; | |
| 602 | +} | |
| 603 | + | |
| 582 | 604 | static int soc_tplg_create_tlv(struct soc_tplg *tplg, |
| 583 | − struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_tlv *tplg_tlv) | |
| 605 | + struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc) | |
| 584 | 606 | { |
| 585 | − struct snd_ctl_tlv *tlv; | |
| 586 | − int size; | |
| 607 | + struct snd_soc_tplg_ctl_tlv *tplg_tlv; | |
| 587 | 608 | |
| 588 | − if (tplg_tlv->count == 0) | |
| 609 | + if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)) | |
| 589 | 610 | return 0; |
| 590 | 611 | |
| 591 | − size = ((tplg_tlv->count + (sizeof(unsigned int) - 1)) & | |
| 592 | − ~(sizeof(unsigned int) - 1)); | |
| 593 | − tlv = kzalloc(sizeof(*tlv) + size, GFP_KERNEL); | |
| 594 | − if (tlv == NULL) | |
| 595 | − return -ENOMEM; | |
| 596 | − | |
| 597 | − dev_dbg(tplg->dev, " created TLV type %d size %d bytes\n", | |
| 598 | − tplg_tlv->numid, size); | |
| 612 | + if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { | |
| 613 | + kc->tlv.c = snd_soc_bytes_tlv_callback; | |
| 614 | + } else { | |
| 615 | + tplg_tlv = &tc->tlv; | |
| 616 | + switch (tplg_tlv->type) { | |
| 617 | + case SNDRV_CTL_TLVT_DB_SCALE: | |
| 618 | + return soc_tplg_create_tlv_db_scale(tplg, kc, | |
| 619 | + &tplg_tlv->scale); | |
| 599 | 620 | |
| 600 | − tlv->numid = tplg_tlv->numid; | |
| 601 | − tlv->length = size; | |
| 602 | − memcpy(&tlv->tlv[0], tplg_tlv->data, size); | |
| 603 | − kc->tlv.p = (void *)tlv; | |
| 621 | + /* TODO: add support for other TLV types */ | |
| 622 | + default: | |
| 623 | + dev_dbg(tplg->dev, "Unsupported TLV type %d\n", | |
| 624 | + tplg_tlv->type); | |
| 625 | + return -EINVAL; | |
| 626 | + } | |
| 627 | + } | |
| 604 | 628 | |
| 605 | 629 | return 0; |
| 606 | 630 | } |
| @@ -772,7 +796,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, · 165 unmodified lines | ||
| 772 | 796 | } |
| 773 | 797 | |
| 774 | 798 | /* create any TLV data */ |
| 775 | − soc_tplg_create_tlv(tplg, &kc, &mc->tlv); | |
| 799 | + soc_tplg_create_tlv(tplg, &kc, &mc->hdr); | |
| 776 | 800 | |
| 777 | 801 | /* register control here */ |
| 778 | 802 | err = soc_tplg_add_kcontrol(tplg, &kc, |