mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 05:39:54 -04:00
misc: cs40l20: Validate wavetable version and size
* Added a means to reject user-provided wavetables that do not match the algorithm ID and revision advertised by the firmware. * Added a means to calculate the maximum allowable wavetable size for a given revision of firmware, and then reject user-provided wavetables that exceed the calculated limit. Change-Id: Ib1d04bdc5f8d6c2150cd1d313a3f61178adeffe6 Signed-off-by: Jeff LaBundy <jeff.labundy@cirrus.com> Signed-off-by: Ravi Vembu <raviv@motorola.com>
This commit is contained in:
parent
81adc68352
commit
a67e3232cb
2 changed files with 121 additions and 14 deletions
|
|
@ -53,6 +53,10 @@ struct cs40l20_private {
|
|||
unsigned int cp_trigger_index;
|
||||
unsigned int cp_trailer_index;
|
||||
unsigned int num_waves;
|
||||
unsigned int vibegen_id;
|
||||
unsigned int vibegen_rev;
|
||||
unsigned int wt_limit_xm;
|
||||
unsigned int wt_limit_ym;
|
||||
bool vibe_init_success;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct cs40l20_platform_data pdata;
|
||||
|
|
@ -732,7 +736,8 @@ static int cs40l20_coeff_init(struct cs40l20_private *cs40l20)
|
|||
struct regmap *regmap = cs40l20->regmap;
|
||||
struct device *dev = cs40l20->dev;
|
||||
struct cs40l20_coeff_desc *coeff_desc;
|
||||
unsigned int val, num_algos, algo_id, xm_base, ym_base;
|
||||
unsigned int val, num_algos, algo_id, algo_rev;
|
||||
unsigned int xm_base, xm_size, ym_base, ym_size;
|
||||
unsigned int reg = CS40L20_XM_FW_ID;
|
||||
|
||||
ret = regmap_read(regmap, CS40L20_XM_FW_REV, &val);
|
||||
|
|
@ -759,24 +764,48 @@ static int cs40l20_coeff_init(struct cs40l20_private *cs40l20)
|
|||
|
||||
/* add one extra iteration to account for system algorithm */
|
||||
for (i = 0; i < (num_algos + 1); i++) {
|
||||
ret = regmap_read(regmap, reg, &algo_id);
|
||||
ret = regmap_read(regmap,
|
||||
reg + CS40L20_ALGO_ID_OFFSET, &algo_id);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read algo. %d ID\n", i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, reg + 8, &xm_base);
|
||||
ret = regmap_read(regmap,
|
||||
reg + CS40L20_ALGO_REV_OFFSET, &algo_rev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read algo. %d revision\n", i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap,
|
||||
reg + CS40L20_ALGO_XM_BASE_OFFSET, &xm_base);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read algo. %d XM_BASE\n", i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, reg + 16, &ym_base);
|
||||
ret = regmap_read(regmap,
|
||||
reg + CS40L20_ALGO_XM_SIZE_OFFSET, &xm_size);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read algo. %d XM_SIZE\n", i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap,
|
||||
reg + CS40L20_ALGO_YM_BASE_OFFSET, &ym_base);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read algo. %d YM_BASE\n", i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap,
|
||||
reg + CS40L20_ALGO_YM_SIZE_OFFSET, &ym_size);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read algo. %d YM_SIZE\n", i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_for_each_entry(coeff_desc,
|
||||
&cs40l20->coeff_desc_head, list) {
|
||||
|
||||
|
|
@ -788,12 +817,21 @@ static int cs40l20_coeff_init(struct cs40l20_private *cs40l20)
|
|||
coeff_desc->reg = CS40L20_DSP1_XMEM_UNPACK24_0
|
||||
+ xm_base * 4
|
||||
+ coeff_desc->block_offset * 4;
|
||||
break;
|
||||
if (!strcmp(coeff_desc->name, "WAVETABLE")) {
|
||||
cs40l20->wt_limit_xm = (xm_size
|
||||
- coeff_desc->block_offset) * 4;
|
||||
cs40l20->vibegen_id = algo_id;
|
||||
cs40l20->vibegen_rev = algo_rev;
|
||||
}
|
||||
break;
|
||||
case CS40L20_YM_UNPACKED_TYPE:
|
||||
coeff_desc->reg = CS40L20_DSP1_YMEM_UNPACK24_0
|
||||
+ ym_base * 4
|
||||
+ coeff_desc->block_offset * 4;
|
||||
break;
|
||||
if (!strcmp(coeff_desc->name, "WAVETABLEYM"))
|
||||
cs40l20->wt_limit_ym = (ym_size
|
||||
- coeff_desc->block_offset) * 4;
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Found control %s at 0x%08X\n",
|
||||
|
|
@ -802,9 +840,9 @@ static int cs40l20_coeff_init(struct cs40l20_private *cs40l20)
|
|||
|
||||
/* system algo. contains one extra register (num. algos.) */
|
||||
if (i)
|
||||
reg += CS40L20_XM_ALGO_ENTRY_SIZE;
|
||||
reg += CS40L20_ALGO_ENTRY_SIZE;
|
||||
else
|
||||
reg += (CS40L20_XM_ALGO_ENTRY_SIZE + 4);
|
||||
reg += (CS40L20_ALGO_ENTRY_SIZE + 4);
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, reg, &val);
|
||||
|
|
@ -813,11 +851,15 @@ static int cs40l20_coeff_init(struct cs40l20_private *cs40l20)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (val != CS40L20_XM_LIST_TERM) {
|
||||
if (val != CS40L20_ALGO_LIST_TERM) {
|
||||
dev_err(dev, "Invalid list terminator: 0x%X\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_info(dev, "Maximum wavetable size: %d bytes (XM), %d bytes (YM)\n",
|
||||
cs40l20->wt_limit_xm / 4 * 3,
|
||||
cs40l20->wt_limit_ym / 4 * 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -907,6 +949,7 @@ static void cs40l20_waveform_load(const struct firmware *fw, void *context)
|
|||
struct device *dev = cs40l20->dev;
|
||||
unsigned int pos = CS40L20_WT_FILE_HEADER_SIZE;
|
||||
unsigned int block_type, block_length;
|
||||
unsigned int algo_id, algo_rev;
|
||||
|
||||
if (!fw) {
|
||||
dev_warn(dev, "Using default wavetable\n");
|
||||
|
|
@ -927,8 +970,22 @@ static void cs40l20_waveform_load(const struct firmware *fw, void *context)
|
|||
|
||||
block_type = fw->data[pos]
|
||||
+ (fw->data[pos + 1] << 8);
|
||||
pos += (CS40L20_WT_DBLK_TYPE_SIZE
|
||||
+ CS40L20_WT_DBLK_UNUSED_SIZE);
|
||||
pos += CS40L20_WT_DBLK_TYPE_SIZE;
|
||||
|
||||
algo_id = fw->data[pos]
|
||||
+ (fw->data[pos + 1] << 8)
|
||||
+ (fw->data[pos + 2] << 16)
|
||||
+ (fw->data[pos + 3] << 24);
|
||||
pos += CS40L20_WT_ALGO_ID_SIZE;
|
||||
|
||||
algo_rev = fw->data[pos]
|
||||
+ (fw->data[pos + 1] << 8)
|
||||
+ (fw->data[pos + 2] << 16)
|
||||
+ (fw->data[pos + 3] << 24);
|
||||
pos += CS40L20_WT_ALGO_REV_SIZE;
|
||||
|
||||
/* sample rate is not used here */
|
||||
pos += CS40L20_WT_SAMPLE_RATE_SIZE;
|
||||
|
||||
block_length = fw->data[pos]
|
||||
+ (fw->data[pos + 1] << 8)
|
||||
|
|
@ -938,6 +995,27 @@ static void cs40l20_waveform_load(const struct firmware *fw, void *context)
|
|||
|
||||
switch (block_type) {
|
||||
case CS40L20_XM_UNPACKED_TYPE:
|
||||
if (algo_id != cs40l20->vibegen_id) {
|
||||
dev_err(dev, "Invalid algo. ID: 0x%06X\n",
|
||||
algo_id);
|
||||
goto err_rls_fw;
|
||||
}
|
||||
|
||||
if (algo_rev != cs40l20->vibegen_rev) {
|
||||
dev_err(dev, "Invalid algo. rev.: %d.%d.%d\n",
|
||||
(algo_rev & 0xFF0000) >> 16,
|
||||
(algo_rev & 0xFF00) >> 8,
|
||||
algo_rev & 0xFF);
|
||||
goto err_rls_fw;
|
||||
}
|
||||
|
||||
if (block_length > cs40l20->wt_limit_xm) {
|
||||
dev_err(dev,
|
||||
"Wavetable too large: %d bytes (XM)\n",
|
||||
block_length / 4 * 3);
|
||||
goto err_rls_fw;
|
||||
}
|
||||
|
||||
ret = cs40l20_raw_write(cs40l20,
|
||||
cs40l20_dsp_reg(cs40l20, "WAVETABLE",
|
||||
CS40L20_XM_UNPACKED_TYPE),
|
||||
|
|
@ -950,6 +1028,27 @@ static void cs40l20_waveform_load(const struct firmware *fw, void *context)
|
|||
}
|
||||
break;
|
||||
case CS40L20_YM_UNPACKED_TYPE:
|
||||
if (algo_id != cs40l20->vibegen_id) {
|
||||
dev_err(dev, "Invalid algo. ID: 0x%06X\n",
|
||||
algo_id);
|
||||
goto err_rls_fw;
|
||||
}
|
||||
|
||||
if (algo_rev != cs40l20->vibegen_rev) {
|
||||
dev_err(dev, "Invalid algo. rev.: %d.%d.%d\n",
|
||||
(algo_rev & 0xFF0000) >> 16,
|
||||
(algo_rev & 0xFF00) >> 8,
|
||||
algo_rev & 0xFF);
|
||||
goto err_rls_fw;
|
||||
}
|
||||
|
||||
if (block_length > cs40l20->wt_limit_ym) {
|
||||
dev_err(dev,
|
||||
"Wavetable too large: %d bytes (YM)\n",
|
||||
block_length / 4 * 3);
|
||||
goto err_rls_fw;
|
||||
}
|
||||
|
||||
ret = cs40l20_raw_write(cs40l20,
|
||||
cs40l20_dsp_reg(cs40l20, "WAVETABLEYM",
|
||||
CS40L20_YM_UNPACKED_TYPE),
|
||||
|
|
|
|||
|
|
@ -687,14 +687,22 @@
|
|||
#define CS40L20_WT_FILE_HEADER_SIZE 16
|
||||
#define CS40L20_WT_DBLK_OFFSET_SIZE 2
|
||||
#define CS40L20_WT_DBLK_TYPE_SIZE 2
|
||||
#define CS40L20_WT_DBLK_UNUSED_SIZE 12
|
||||
#define CS40L20_WT_ALGO_ID_SIZE 4
|
||||
#define CS40L20_WT_ALGO_REV_SIZE 4
|
||||
#define CS40L20_WT_SAMPLE_RATE_SIZE 4
|
||||
#define CS40L20_WT_DBLK_LENGTH_SIZE 4
|
||||
|
||||
#define CS40L20_XM_FW_ID (CS40L20_DSP1_XMEM_UNPACK24_0 + 12)
|
||||
#define CS40L20_XM_FW_REV (CS40L20_DSP1_XMEM_UNPACK24_0 + 16)
|
||||
#define CS40L20_XM_NUM_ALGOS (CS40L20_DSP1_XMEM_UNPACK24_0 + 36)
|
||||
#define CS40L20_XM_ALGO_ENTRY_SIZE 24
|
||||
#define CS40L20_XM_LIST_TERM 0xBEDEAD
|
||||
#define CS40L20_ALGO_ID_OFFSET 0
|
||||
#define CS40L20_ALGO_REV_OFFSET 4
|
||||
#define CS40L20_ALGO_XM_BASE_OFFSET 8
|
||||
#define CS40L20_ALGO_XM_SIZE_OFFSET 12
|
||||
#define CS40L20_ALGO_YM_BASE_OFFSET 16
|
||||
#define CS40L20_ALGO_YM_SIZE_OFFSET 20
|
||||
#define CS40L20_ALGO_ENTRY_SIZE 24
|
||||
#define CS40L20_ALGO_LIST_TERM 0xBEDEAD
|
||||
|
||||
#define CS40L20_NUM_ALGOS_MAX 16
|
||||
#define CS40L20_FW_REV_MIN 0x000300
|
||||
|
|
|
|||
Loading…
Reference in a new issue