From cb5b57a9a449adc7047b709adf25e489785f0bb4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 13 Apr 2015 13:28:04 +0100 Subject: [PATCH] ASoC: wm_adsp: Add support for rev 2 firmware file format Version 2 of the firmware file format includes length fields for the various strings associated with control creation, to reduce file size. However this does increase the parsing complexity slightly. This patch adds support for the revision of the file format. This patch also adds a new naming scheme for controls created from rev 2 firmware files. This version of the file format is commonly used to add multiple controls per algorithm per memory region and the old control naming scheme would cause multiple controls to have the same name in this case.. Note that the naming scheme for older firmware versions is left intact to ensure backwards compatibility. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 135 ++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 16b308a6bfbb..1c45d67cfb4f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -598,8 +598,31 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, return -EINVAL; } - snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x", - dsp->num, region_name, alg_region->alg); + switch (dsp->fw_ver) { + case 0: + case 1: + snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x", + dsp->num, region_name, alg_region->alg); + break; + default: + ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, + "DSP%d%c %.12s %x", dsp->num, *region_name, + wm_adsp_fw_text[dsp->fw], alg_region->alg); + + /* Truncate the subname from the start if it is too long */ + if (subname) { + int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; + int skip = 0; + + if (subname_len > avail) + skip = subname_len - avail; + + snprintf(name + ret, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s", + subname_len - skip, subname + skip); + } + break; + } list_for_each_entry(ctl, &dsp->ctl_list, list) { @@ -681,18 +704,73 @@ struct wm_coeff_parsed_coeff { int len; }; +static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) +{ + int length; + + switch (bytes) { + case 1: + length = **pos; + break; + case 2: + length = le16_to_cpu(*((u16 *)*pos)); + break; + default: + return 0; + } + + if (str) + *str = *pos + bytes; + + *pos += ((length + bytes) + 3) & ~0x03; + + return length; +} + +static int wm_coeff_parse_int(int bytes, const u8 **pos) +{ + int val = 0; + + switch (bytes) { + case 2: + val = le16_to_cpu(*((u16 *)*pos)); + break; + case 4: + val = le32_to_cpu(*((u32 *)*pos)); + break; + default: + break; + } + + *pos += bytes; + + return val; +} + static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data, struct wm_coeff_parsed_alg *blk) { const struct wmfw_adsp_alg_data *raw; - raw = (const struct wmfw_adsp_alg_data *)*data; - *data = raw->data; + switch (dsp->fw_ver) { + case 0: + case 1: + raw = (const struct wmfw_adsp_alg_data *)*data; + *data = raw->data; - blk->id = le32_to_cpu(raw->id); - blk->name = raw->name; - blk->name_len = strlen(raw->name); - blk->ncoeff = le32_to_cpu(raw->ncoeff); + blk->id = le32_to_cpu(raw->id); + blk->name = raw->name; + blk->name_len = strlen(raw->name); + blk->ncoeff = le32_to_cpu(raw->ncoeff); + break; + default: + blk->id = wm_coeff_parse_int(sizeof(raw->id), data); + blk->name_len = wm_coeff_parse_string(sizeof(u8), data, + &blk->name); + wm_coeff_parse_string(sizeof(u16), data, NULL); + blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data); + break; + } adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); @@ -703,17 +781,39 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, struct wm_coeff_parsed_coeff *blk) { const struct wmfw_adsp_coeff_data *raw; + const u8 *tmp; + int length; - raw = (const struct wmfw_adsp_coeff_data *)*data; - *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); + switch (dsp->fw_ver) { + case 0: + case 1: + raw = (const struct wmfw_adsp_coeff_data *)*data; + *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); - blk->offset = le16_to_cpu(raw->hdr.offset); - blk->mem_type = le16_to_cpu(raw->hdr.type); - blk->name = raw->name; - blk->name_len = strlen(raw->name); - blk->ctl_type = le16_to_cpu(raw->ctl_type); - blk->flags = le16_to_cpu(raw->flags); - blk->len = le32_to_cpu(raw->len); + blk->offset = le16_to_cpu(raw->hdr.offset); + blk->mem_type = le16_to_cpu(raw->hdr.type); + blk->name = raw->name; + blk->name_len = strlen(raw->name); + blk->ctl_type = le16_to_cpu(raw->ctl_type); + blk->flags = le16_to_cpu(raw->flags); + blk->len = le32_to_cpu(raw->len); + break; + default: + tmp = *data; + blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); + blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp); + length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp); + blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp, + &blk->name); + wm_coeff_parse_string(sizeof(u8), &tmp, NULL); + wm_coeff_parse_string(sizeof(u16), &tmp, NULL); + blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp); + blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp); + blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp); + + *data = *data + sizeof(raw->hdr) + length; + break; + } adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); @@ -812,6 +912,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) switch (header->ver) { case 0: case 1: + case 2: break; default: adsp_err(dsp, "%s: unknown file format %d\n",