]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
ASoC: wm_adsp: Add support for rev 2 firmware file format
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Mon, 13 Apr 2015 12:28:04 +0000 (13:28 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 27 Apr 2015 14:38:25 +0000 (15:38 +0100)
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 <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/wm_adsp.c

index 16b308a6bfbbd395a6e59e07663ab004a6024fa4..1c45d67cfb4f6da9fa9fbb325e99b4633526c5f5 100644 (file)
@@ -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);
-
-       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);
+       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);
+               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",