1572 lines
42 KiB
C

/*
* aw_acf_bin.c
*
* Copyright (c) 2021 AWINIC Technology CO., LTD
*
* Author: Barry <zhaozhongbo@awinic.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include "aw87xxx.h"
#include "aw_acf_bin.h"
#include "aw_monitor.h"
#include "aw_log.h"
#include "aw_bin_parse.h"
static char *g_profile_name[] = {"Music", "Voice", "Voip",
"Ringtone", "Ringtone_hs", "Lowpower", "Bypass", "Mmi",
"Fm", "Notification", "Receiver", "Off"};
static char *g_power_off_name[] = {"Off", "OFF", "off", "oFF", "power_down"};
static char *aw_get_prof_name(int profile)
{
if (profile < 0 || profile >= AW_PROFILE_MAX)
return "NULL";
else
return g_profile_name[profile];
}
/*************************************************************************
*
*acf check
*
*************************************************************************/
static int aw_crc8_check(const unsigned char *data, unsigned int data_size)
{
unsigned char crc_value = 0x00;
unsigned char *pdata;
int i;
unsigned char pdatabuf = 0;
pdata = (unsigned char *)data;
while (data_size--) {
pdatabuf = *pdata++;
for (i = 0; i < 8; i++) {
if ((crc_value ^ (pdatabuf)) & 0x01) {
crc_value ^= 0x18;
crc_value >>= 1;
crc_value |= 0x80;
} else {
crc_value >>= 1;
}
pdatabuf >>= 1;
}
}
return (int)crc_value;
}
static int aw_check_file_id(struct device *dev,
char *fw_data, int32_t file_id)
{
int32_t *acf_file_id = NULL;
acf_file_id = (int32_t *)fw_data;
if (*acf_file_id != file_id) {
AW_DEV_LOGE(dev, "file id [%x] check failed", *acf_file_id);
return -ENFILE;
}
return 0;
}
static int aw_check_header_size(struct device *dev,
char *fw_data, size_t fw_size)
{
if (fw_size < sizeof(struct aw_acf_hdr)) {
AW_DEV_LOGE(dev, "acf size check failed,size less-than aw_acf_hdr");
return -ENOEXEC;
}
return 0;
}
/***************************************************************************
* V0.0.0.1 version acf check
**************************************************************************/
static int aw_check_ddt_size_v_0_0_0_1(struct device *dev, char *fw_data)
{
struct aw_acf_hdr *acf_hdr = (struct aw_acf_hdr *)fw_data;
struct aw_acf_dde *acf_dde = NULL;
acf_dde = (struct aw_acf_dde *)(fw_data + acf_hdr->ddt_offset);
/* check ddt_size in acf_header is aqual to ddt_num multiply by dde_size */
if (acf_hdr->ddt_size != acf_hdr->dde_num * sizeof(struct aw_acf_dde)) {
AW_DEV_LOGE(dev, "acf ddt size check failed");
return -EINVAL;
}
return 0;
}
static int aw_check_data_size_v_0_0_0_1(struct device *dev,
char *fw_data, size_t fw_size)
{
int i = 0;
size_t data_size = 0;
struct aw_acf_hdr *acf_hdr = NULL;
struct aw_acf_dde *acf_dde = NULL;
acf_hdr = (struct aw_acf_hdr *)fw_data;
acf_dde = (struct aw_acf_dde *)(fw_data + acf_hdr->ddt_offset);
for (i = 0; i < acf_hdr->dde_num; ++i) {
if (acf_dde[i].data_size % 2) {
AW_DEV_LOGE(dev, "acf dde[%d].data_size[%d],dev_name[%s],data_type[%d], data_size check failed",
i, acf_dde[i].data_size, acf_dde[i].dev_name,
acf_dde[i].data_type);
return -EINVAL;
}
data_size += acf_dde[i].data_size;
}
/* Verify that the file size is equal to the header size plus */
/* the table size and data size */
if (fw_size != data_size + sizeof(struct aw_acf_hdr) + acf_hdr->ddt_size) {
AW_DEV_LOGE(dev, "acf size check failed");
AW_DEV_LOGE(dev, "fw_size=%ld,hdr_size and ddt size and data size =%ld",
(u_long)fw_size, (u_long)(data_size + sizeof(struct aw_acf_hdr) +
acf_hdr->ddt_size));
return -EINVAL;
}
return 0;
}
static int aw_check_data_crc_v_0_0_0_1(struct device *dev, char *fw_data)
{
int i = 0;
size_t crc_val = 0;
char *data = NULL;
struct aw_acf_hdr *acf_hdr = NULL;
struct aw_acf_dde *acf_dde = NULL;
acf_hdr = (struct aw_acf_hdr *)fw_data;
acf_dde = (struct aw_acf_dde *)(fw_data + acf_hdr->ddt_offset);
for (i = 0; i < acf_hdr->dde_num; ++i) {
data = fw_data + acf_dde[i].data_offset;
crc_val = aw_crc8_check(data, acf_dde[i].data_size);
if (crc_val != acf_dde[i].data_crc) {
AW_DEV_LOGE(dev, "acf dde_crc check failed");
return -EINVAL;
}
}
return 0;
}
static int aw_check_profile_id_v_0_0_0_1(struct device *dev, char *fw_data)
{
int i = 0;
struct aw_acf_hdr *acf_hdr = NULL;
struct aw_acf_dde *acf_dde = NULL;
acf_hdr = (struct aw_acf_hdr *)fw_data;
acf_dde = (struct aw_acf_dde *)(fw_data + acf_hdr->ddt_offset);
for (i = 0; i < acf_hdr->dde_num; ++i) {
if (acf_dde[i].data_type == AW_MONITOR)
continue;
if (acf_dde[i].dev_profile > AW_PROFILE_MAX) {
AW_DEV_LOGE(dev, "parse profile_id[%d] failed", acf_dde[i].dev_profile);
return -EINVAL;
}
}
return 0;
}
static int aw_check_data_v_0_0_0_1(struct device *dev,
char *fw_data, size_t size)
{
int ret = -1;
/* check file type id is awinic acf file */
ret = aw_check_file_id(dev, fw_data, AW_ACF_FILE_ID);
if (ret < 0)
return ret;
/* check ddt_size in header is equal to all ddt aize */
ret = aw_check_ddt_size_v_0_0_0_1(dev, fw_data);
if (ret < 0)
return ret;
/* Verify that the file size is equal to the header size plus */
/* the table size and data size */
ret = aw_check_data_size_v_0_0_0_1(dev, fw_data, size);
if (ret < 0)
return ret;
/* check crc in is equal to dde data crc */
ret = aw_check_data_crc_v_0_0_0_1(dev, fw_data);
if (ret < 0)
return ret;
/* check profile id is in profile_id_max */
ret = aw_check_profile_id_v_0_0_0_1(dev, fw_data);
if (ret < 0)
return ret;
AW_DEV_LOGI(dev, "acf fimware check succeed");
return 0;
}
/***************************************************************************
* V1.0.0.0 version acf chack
**************************************************************************/
static int aw_check_ddt_size_v_1_0_0_0(struct device *dev, char *fw_data)
{
struct aw_acf_hdr *acf_hdr = (struct aw_acf_hdr *)fw_data;
struct aw_acf_dde_v_1_0_0_0 *acf_dde = NULL;
acf_dde = (struct aw_acf_dde_v_1_0_0_0 *)(fw_data + acf_hdr->ddt_offset);
/* check ddt_size in acf_header is aqual to ddt_num multiply by dde_size */
if (acf_hdr->ddt_size != acf_hdr->dde_num * sizeof(struct aw_acf_dde_v_1_0_0_0)) {
AW_DEV_LOGE(dev, "acf ddt size check failed");
return -EINVAL;
}
return 0;
}
static int aw_check_data_size_v_1_0_0_0(struct device *dev,
char *fw_data, size_t fw_size)
{
int i = 0;
size_t data_size = 0;
struct aw_acf_hdr *acf_hdr = NULL;
struct aw_acf_dde_v_1_0_0_0 *acf_dde = NULL;
acf_hdr = (struct aw_acf_hdr *)fw_data;
acf_dde = (struct aw_acf_dde_v_1_0_0_0 *)(fw_data + acf_hdr->ddt_offset);
for (i = 0; i < acf_hdr->dde_num; ++i) {
if (acf_dde[i].data_size % 2) {
AW_DEV_LOGE(dev, "acf dde[%d].data_size[%d],dev_name[%s],data_type[%d], data_size check failed",
i, acf_dde[i].data_size, acf_dde[i].dev_name,
acf_dde[i].data_type);
return -EINVAL;
}
data_size += acf_dde[i].data_size;
}
/* Verify that the file size is equal to the header size plus */
/* the table size and data size */
if (fw_size != data_size + sizeof(struct aw_acf_hdr) + acf_hdr->ddt_size) {
AW_DEV_LOGE(dev, "acf size check failed");
AW_DEV_LOGE(dev, "fw_size=%ld,hdr_size and ddt size and data size =%ld",
(u_long)fw_size, (u_long)(data_size + sizeof(struct aw_acf_hdr) +
acf_hdr->ddt_size));
return -EINVAL;
}
return 0;
}
static int aw_check_data_crc_v_1_0_0_0(struct device *dev, char *fw_data)
{
int i = 0;
size_t crc_val = 0;
char *data = NULL;
struct aw_acf_hdr *acf_hdr = NULL;
struct aw_acf_dde_v_1_0_0_0 *acf_dde = NULL;
acf_hdr = (struct aw_acf_hdr *)fw_data;
acf_dde = (struct aw_acf_dde_v_1_0_0_0 *)(fw_data + acf_hdr->ddt_offset);
for (i = 0; i < acf_hdr->dde_num; ++i) {
data = fw_data + acf_dde[i].data_offset;
crc_val = aw_crc8_check(data, acf_dde[i].data_size);
if (crc_val != acf_dde[i].data_crc) {
AW_DEV_LOGE(dev, "acf dde_crc check failed");
return -EINVAL;
}
}
return 0;
}
static int aw_check_data_v_1_0_0_0(struct device *dev,
char *fw_data, size_t size)
{
int ret = -1;
/* check file type id is awinic acf file */
ret = aw_check_file_id(dev, fw_data, AW_ACF_FILE_ID);
if (ret < 0)
return ret;
/* check ddt_size in header is equal to all ddt aize */
ret = aw_check_ddt_size_v_1_0_0_0(dev, fw_data);
if (ret < 0)
return ret;
/* Verify that the file size is equal to the header size plus */
/* the table size and data size */
ret = aw_check_data_size_v_1_0_0_0(dev, fw_data, size);
if (ret < 0)
return ret;
/* check crc in is equal to dde data crc */
ret = aw_check_data_crc_v_1_0_0_0(dev, fw_data);
if (ret < 0)
return ret;
AW_DEV_LOGI(dev, "acf fimware check succeed");
return 0;
}
/***************************************************************************
* acf chack API
**************************************************************************/
static int aw_check_acf_firmware(struct device *dev,
char *fw_data, size_t size)
{
int ret = -1;
struct aw_acf_hdr *acf_hdr = NULL;
if (fw_data == NULL) {
AW_DEV_LOGE(dev, "fw_data is NULL,fw_data check failed");
return -ENODATA;
}
/* check file size is less-than header size */
ret = aw_check_header_size(dev, fw_data, size);
if (ret < 0)
return ret;
acf_hdr = (struct aw_acf_hdr *)fw_data;
AW_DEV_LOGI(dev, "project name: [%s]", acf_hdr->project);
AW_DEV_LOGI(dev, "custom name: [%s]", acf_hdr->custom);
AW_DEV_LOGI(dev, "version name: [%s]", acf_hdr->version);
AW_DEV_LOGI(dev, "author_id: [%d]", acf_hdr->author_id);
switch (acf_hdr->hdr_version) {
case AW_ACF_HDR_VER_0_0_0_1:
return aw_check_data_v_0_0_0_1(dev, fw_data, size);
case AW_ACF_HDR_VER_1_0_0_0:
return aw_check_data_v_1_0_0_0(dev, fw_data, size);
default:
AW_DEV_LOGE(dev, "unsupported hdr_version [0x%x]",
acf_hdr->hdr_version);
return -EINVAL;
}
return ret;
}
/*************************************************************************
*
*acf parse
*
*************************************************************************/
static int aw_parse_raw_reg(struct device *dev, uint8_t *data,
uint32_t data_len, struct aw_prof_desc *prof_desc)
{
AW_DEV_LOGD(dev, "data_size:%d enter", data_len);
prof_desc->data_container.data = data;
prof_desc->data_container.len = data_len;
prof_desc->prof_st = AW_PROFILE_OK;
return 0;
}
static int aw_parse_reg_with_hdr(struct device *dev, uint8_t *data,
uint32_t data_len, struct aw_prof_desc *prof_desc)
{
struct aw_bin *aw_bin = NULL;
int ret = -1;
AW_DEV_LOGD(dev, "data_size:%d enter", data_len);
aw_bin = kzalloc(data_len + sizeof(struct aw_bin), GFP_KERNEL);
if (aw_bin == NULL) {
AW_DEV_LOGE(dev, "devm_kzalloc aw_bin failed");
return -ENOMEM;
}
aw_bin->info.len = data_len;
memcpy(aw_bin->info.data, data, data_len);
ret = aw_parsing_bin_file(aw_bin);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse bin failed");
goto parse_bin_failed;
}
if ((aw_bin->all_bin_parse_num != 1) ||
(aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {
AW_DEV_LOGE(dev, "bin num or type error");
goto parse_bin_failed;
}
prof_desc->data_container.data =
data + aw_bin->header_info[0].valid_data_addr;
prof_desc->data_container.len = aw_bin->header_info[0].valid_data_len;
prof_desc->prof_st = AW_PROFILE_OK;
kfree(aw_bin);
aw_bin = NULL;
return 0;
parse_bin_failed:
kfree(aw_bin);
aw_bin = NULL;
return ret;
}
static int aw_parse_monitor_config(struct device *dev,
char *monitor_data, uint32_t data_len)
{
int ret = -1;
if (monitor_data == NULL || data_len == 0) {
AW_DEV_LOGE(dev, "no data to parse");
return -EBFONT;
}
ret = aw_monitor_bin_parse(dev, monitor_data, data_len);
if (ret < 0) {
AW_DEV_LOGE(dev, "monitor_config parse failed");
return ret;
}
AW_DEV_LOGI(dev, "monitor_bin parse succeed");
return 0;
}
static int aw_check_prof_str_is_off(char *profile_name)
{
int i = 0;
for (i = 0; i < AW_POWER_OFF_NAME_SUPPORT_COUNT; i++) {
if (strnstr(profile_name, g_power_off_name[i],
strlen(profile_name) + 1))
return 0;
}
return -EINVAL;
}
/***************************************************************************
* V0.0.0.1 version acf paese
**************************************************************************/
static int aw_check_product_name_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_acf_dde *prof_hdr)
{
int i = 0;
for (i = 0; i < acf_info->product_cnt; i++) {
if (0 == strcmp(acf_info->product_tab[i], prof_hdr->dev_name)) {
AW_DEV_LOGD(dev, "bin_dev_name:%s",
prof_hdr->dev_name);
return 0;
}
}
return -ENXIO;
}
static int aw_check_data_type_is_monitor_v_0_0_0_1(struct device *dev,
struct aw_acf_dde *prof_hdr)
{
if (prof_hdr->data_type == AW_MONITOR) {
AW_DEV_LOGD(dev, "bin data is monitor");
return 0;
}
return -ENXIO;
}
static int aw_parse_data_by_sec_type_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_acf_dde *prof_hdr,
struct aw_prof_desc *profile_prof_desc)
{
int ret = -1;
char *cfg_data = acf_info->fw_data + prof_hdr->data_offset;
switch (prof_hdr->data_type) {
case AW_BIN_TYPE_REG:
snprintf(profile_prof_desc->dev_name, sizeof(prof_hdr->dev_name),
"%s", prof_hdr->dev_name);
profile_prof_desc->prof_name = aw_get_prof_name(prof_hdr->dev_profile);
AW_DEV_LOGD(dev, "parse reg type data enter,profile=%s",
aw_get_prof_name(prof_hdr->dev_profile));
ret = aw_parse_raw_reg(dev, cfg_data, prof_hdr->data_size,
profile_prof_desc);
break;
case AW_BIN_TYPE_HDR_REG:
snprintf(profile_prof_desc->dev_name, sizeof(prof_hdr->dev_name),
"%s", prof_hdr->dev_name);
profile_prof_desc->prof_name = aw_get_prof_name(prof_hdr->dev_profile);
AW_DEV_LOGD(dev, "parse hdr_reg type data enter,profile=%s",
aw_get_prof_name(prof_hdr->dev_profile));
ret = aw_parse_reg_with_hdr(dev, cfg_data,
prof_hdr->data_size,
profile_prof_desc);
break;
case AW_MONITOR:
AW_DEV_LOGD(dev, "parse monitor type data enter");
ret = aw_parse_monitor_config(dev, cfg_data,
prof_hdr->data_size);
break;
}
return ret;
}
static int aw_parse_dev_type_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info, struct aw_all_prof_info *all_prof_info)
{
int i = 0;
int ret = -1;
int sec_num = 0;
uint8_t soft_off_enable = acf_info->aw_dev->soft_off_enable;
struct aw_prof_desc *prof_desc = NULL;
struct aw_acf_dde *acf_dde =
(struct aw_acf_dde *)(acf_info->fw_data + acf_info->acf_hdr.ddt_offset);
AW_DEV_LOGD(dev, "enter");
for (i = 0; i < acf_info->acf_hdr.dde_num; i++) {
if ((acf_info->aw_dev->i2c_bus == acf_dde[i].dev_bus) &&
(acf_info->aw_dev->i2c_addr == acf_dde[i].dev_addr) &&
(acf_dde[i].type == AW_DDE_DEV_TYPE_ID)) {
ret = aw_check_product_name_v_0_0_0_1(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
ret = aw_check_data_type_is_monitor_v_0_0_0_1(dev, &acf_dde[i]);
if (ret == 0) {
prof_desc = NULL;
} else {
prof_desc = &all_prof_info->prof_desc[acf_dde[i].dev_profile];
}
if (acf_dde[i].dev_profile == AW_PROFILE_OFF && !soft_off_enable) {
AW_DEV_LOGE(dev, "profile off is not allowed");
return -EINVAL;
}
ret = aw_parse_data_by_sec_type_v_0_0_0_1(dev, acf_info, &acf_dde[i],
prof_desc);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse dev type data failed");
return ret;
}
sec_num++;
}
}
if (sec_num == 0) {
AW_DEV_LOGD(dev, "get dev type num is %d, please use default",
sec_num);
return AW_DEV_TYPE_NONE;
}
return AW_DEV_TYPE_OK;
}
static int aw_parse_default_type_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info, struct aw_all_prof_info *all_prof_info)
{
int i = 0;
int ret = -1;
int sec_num = 0;
uint8_t soft_off_enable = acf_info->aw_dev->soft_off_enable;
struct aw_prof_desc *prof_desc = NULL;
struct aw_acf_dde *acf_dde =
(struct aw_acf_dde *)(acf_info->fw_data + acf_info->acf_hdr.ddt_offset);
AW_DEV_LOGD(dev, "enter");
for (i = 0; i < acf_info->acf_hdr.dde_num; i++) {
if ((acf_info->dev_index == acf_dde[i].dev_index) &&
(acf_dde[i].type == AW_DDE_DEV_DEFAULT_TYPE_ID)) {
ret = aw_check_product_name_v_0_0_0_1(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
ret = aw_check_data_type_is_monitor_v_0_0_0_1(dev, &acf_dde[i]);
if (ret == 0) {
prof_desc = NULL;
} else {
prof_desc = &all_prof_info->prof_desc[acf_dde[i].dev_profile];
}
if (acf_dde[i].dev_profile == AW_PROFILE_OFF && !soft_off_enable) {
AW_DEV_LOGE(dev, "profile off is not allowed");
return -EINVAL;
}
ret = aw_parse_data_by_sec_type_v_0_0_0_1(dev, acf_info, &acf_dde[i],
prof_desc);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse default type data failed");
return ret;
}
sec_num++;
}
}
if (sec_num == 0) {
AW_DEV_LOGE(dev, "get dev default type failed, get num[%d]",
sec_num);
return -EINVAL;
}
return 0;
}
static int aw_get_prof_count_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_all_prof_info *all_prof_info)
{
int i = 0;
int prof_count = 0;
uint8_t soft_off_enable = acf_info->aw_dev->soft_off_enable;
struct aw_prof_desc *prof_desc = all_prof_info->prof_desc;
for (i = 0; i < AW_PROFILE_MAX; i++) {
if (i == AW_PROFILE_OFF) {
if (!soft_off_enable && prof_desc[i].prof_st == AW_PROFILE_OK) {
AW_DEV_LOGE(dev, "profile_off is not allowed");
return -EINVAL;
} else if (soft_off_enable && prof_desc[i].prof_st == AW_PROFILE_WAIT) {
AW_DEV_LOGE(dev, "profile [Off] is necessary,but not found");
return -EINVAL;
} else {
prof_count++;
}
} else {
if (prof_desc[i].prof_st == AW_PROFILE_OK)
prof_count++;
}
}
AW_DEV_LOGI(dev, "get profile count=[%d]", prof_count);
return prof_count;
}
static int aw_set_prof_off_info_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_all_prof_info *all_prof_info,
int index)
{
uint8_t soft_off_enable = acf_info->aw_dev->soft_off_enable;
struct aw_prof_desc *prof_desc = all_prof_info->prof_desc;
struct aw_prof_info *prof_info = &acf_info->prof_info;
if (index >= prof_info->count) {
AW_DEV_LOGE(dev, "index[%d] is out of table,profile count[%d]",
index, prof_info->count);
return -EINVAL;
}
if (soft_off_enable && prof_desc[AW_PROFILE_OFF].prof_st == AW_PROFILE_OK) {
prof_info->prof_desc[index] = prof_desc[AW_PROFILE_OFF];
AW_DEV_LOGI(dev, "product=[%s]----profile=[%s]",
prof_info->prof_desc[index].dev_name,
aw_get_prof_name(AW_PROFILE_OFF));
} else if (!soft_off_enable) {
memset(&prof_info->prof_desc[index].data_container, 0,
sizeof(struct aw_data_container));
prof_info->prof_desc[index].prof_st = AW_PROFILE_WAIT;
prof_info->prof_desc[index].prof_name = aw_get_prof_name(AW_PROFILE_OFF);
AW_DEV_LOGI(dev, "set default power_off with no data to profile");
} else {
AW_DEV_LOGE(dev, "not init default power_off config");
return -EINVAL;
}
return 0;
}
static int aw_get_vaild_prof_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_all_prof_info *all_prof_info)
{
int i = 0;
int ret = 0;
int index = 0;
struct aw_prof_desc *prof_desc = all_prof_info->prof_desc;
struct aw_prof_info *prof_info = &acf_info->prof_info;
prof_info->count = 0;
ret = aw_get_prof_count_v_0_0_0_1(dev, acf_info, all_prof_info);
if (ret < 0)
return ret;
prof_info->count = ret;
prof_info->prof_desc = devm_kzalloc(dev,
prof_info->count * sizeof(struct aw_prof_desc),
GFP_KERNEL);
if (prof_info->prof_desc == NULL) {
AW_DEV_LOGE(dev, "prof_desc kzalloc failed");
return -ENOMEM;
}
for (i = 0; i < AW_PROFILE_MAX; i++) {
if (i != AW_PROFILE_OFF && prof_desc[i].prof_st == AW_PROFILE_OK) {
if (index >= prof_info->count) {
AW_DEV_LOGE(dev, "get profile index[%d] overflow count[%d]",
index, prof_info->count);
return -ENOMEM;
}
prof_info->prof_desc[index] = prof_desc[i];
AW_DEV_LOGI(dev, "product=[%s]----profile=[%s]",
prof_info->prof_desc[index].dev_name,
aw_get_prof_name(i));
index++;
}
}
ret = aw_set_prof_off_info_v_0_0_0_1(dev, acf_info, all_prof_info, index);
if (ret < 0)
return ret;
AW_DEV_LOGD(dev, "get vaild profile succeed");
return 0;
}
static int aw_set_prof_name_list_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info)
{
int i = 0;
int count = acf_info->prof_info.count;
struct aw_prof_info *prof_info = &acf_info->prof_info;
prof_info->prof_name_list = (char (*)[AW_PROFILE_STR_MAX])devm_kzalloc(dev,
count * (AW_PROFILE_STR_MAX), GFP_KERNEL);
if (prof_info->prof_name_list == NULL) {
AW_DEV_LOGE(dev, "prof_name_list devm_kzalloc failed");
return -ENOMEM;
}
for (i = 0; i < count; ++i) {
snprintf(prof_info->prof_name_list[i], AW_PROFILE_STR_MAX, "%s",
prof_info->prof_desc[i].prof_name);
AW_DEV_LOGI(dev, "index=[%d], profile_name=[%s]",
i, prof_info->prof_name_list[i]);
}
return 0;
}
static int aw_parse_acf_v_0_0_0_1(struct device *dev,
struct acf_bin_info *acf_info)
{
int ret = 0;
struct aw_all_prof_info all_prof_info;
AW_DEV_LOGD(dev, "enter");
acf_info->prof_info.status = AW_ACF_WAIT;
memset(&all_prof_info, 0, sizeof(struct aw_all_prof_info));
ret = aw_parse_dev_type_v_0_0_0_1(dev, acf_info, &all_prof_info);
if (ret < 0) {
return ret;
} else if (ret == AW_DEV_TYPE_NONE) {
AW_DEV_LOGD(dev, "get dev type num is 0, parse default dev type");
ret = aw_parse_default_type_v_0_0_0_1(dev, acf_info, &all_prof_info);
if (ret < 0)
return ret;
}
ret = aw_get_vaild_prof_v_0_0_0_1(dev, acf_info, &all_prof_info);
if (ret < 0) {
aw_acf_profile_free(dev, acf_info);
AW_DEV_LOGE(dev, "hdr_cersion[0x%x] parse failed",
acf_info->acf_hdr.hdr_version);
return ret;
}
ret = aw_set_prof_name_list_v_0_0_0_1(dev, acf_info);
if (ret < 0) {
aw_acf_profile_free(dev, acf_info);
AW_DEV_LOGE(dev, "creat prof_id_and_name_list failed");
return ret;
}
acf_info->prof_info.status = AW_ACF_UPDATE;
AW_DEV_LOGI(dev, "acf parse success");
return 0;
}
/***************************************************************************
* V1.0.0.0 version acf paese
**************************************************************************/
static int aw_check_product_name_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_acf_dde_v_1_0_0_0 *prof_hdr)
{
int i = 0;
for (i = 0; i < acf_info->product_cnt; i++) {
if (0 == strcmp(acf_info->product_tab[i], prof_hdr->dev_name)) {
AW_DEV_LOGI(dev, "bin_dev_name:%s", prof_hdr->dev_name);
return 0;
}
}
return -ENXIO;
}
static void aw_print_prof_off_name_can_support_v_1_0_0_0(struct device *dev)
{
int i = 0;
for (i = 0; i < AW_POWER_OFF_NAME_SUPPORT_COUNT; i++)
AW_DEV_LOGI(dev, "support prof_off_name have string:[%s]", g_power_off_name[i]);
}
static int aw_get_dde_type_info_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
int i;
int dev_num = 0;
int default_num = 0;
struct aw_acf_hdr *acf_hdr = (struct aw_acf_hdr *)acf_info->fw_data;
struct aw_prof_info *prof_info = &acf_info->prof_info;
struct aw_acf_dde_v_1_0_0_0 *acf_dde =
(struct aw_acf_dde_v_1_0_0_0 *)(acf_info->fw_data + acf_hdr->ddt_offset);
prof_info->prof_type = AW_DEV_NONE_TYPE_ID;
for (i = 0; i < acf_hdr->dde_num; i++) {
if (acf_dde[i].type == AW_DDE_DEV_TYPE_ID)
dev_num++;
if (acf_dde[i].type == AW_DDE_DEV_DEFAULT_TYPE_ID)
default_num++;
}
if (!(dev_num || default_num)) {
AW_DEV_LOGE(dev, "can't find scene");
return -EINVAL;
}
if (dev_num != 0)
prof_info->prof_type = AW_DDE_DEV_TYPE_ID;
else if (default_num != 0)
prof_info->prof_type = AW_DDE_DEV_DEFAULT_TYPE_ID;
return 0;
}
static int aw_parse_get_dev_type_prof_count_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
uint8_t soft_off_enable = acf_info->aw_dev->soft_off_enable;
struct aw_acf_hdr *acf_hdr = (struct aw_acf_hdr *)acf_info->fw_data;
struct aw_acf_dde_v_1_0_0_0 *acf_dde =
(struct aw_acf_dde_v_1_0_0_0 *)(acf_info->fw_data + acf_hdr->ddt_offset);
int i = 0;
int ret = 0;
int found_off_prof_flag = 0;
int count = acf_info->prof_info.count;
for (i = 0; i < acf_hdr->dde_num; ++i) {
if (((acf_dde[i].data_type == AW_BIN_TYPE_REG) ||
(acf_dde[i].data_type == AW_BIN_TYPE_HDR_REG)) &&
((acf_info->aw_dev->i2c_bus == acf_dde[i].dev_bus) &&
(acf_info->aw_dev->i2c_addr == acf_dde[i].dev_addr)) &&
(acf_info->aw_dev->chipid == acf_dde[i].chip_id)) {
ret = aw_check_product_name_v_1_0_0_0(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
ret = aw_check_prof_str_is_off(acf_dde[i].dev_profile_str);
if (ret == 0) {
found_off_prof_flag = AW_PROFILE_OK;
if (soft_off_enable) {
count++;
} else {
AW_DEV_LOGE(dev, "profile_off is not allowed");
return -EINVAL;
}
} else {
count++;
}
}
}
if (count == 0) {
AW_DEV_LOGE(dev, "can't find profile");
return -EINVAL;
}
if (!found_off_prof_flag && soft_off_enable) {
AW_DEV_LOGE(dev, "profile power off is necessary,but not found");
aw_print_prof_off_name_can_support_v_1_0_0_0(dev);
return -EINVAL;
}
if (!found_off_prof_flag && !soft_off_enable) {
count++;
AW_DEV_LOGD(dev, "set no config power off profile in count");
}
acf_info->prof_info.count = count;
AW_DEV_LOGI(dev, "profile dev_type profile count is %d", acf_info->prof_info.count);
return 0;
}
static int aw_parse_get_default_type_prof_count_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
uint8_t soft_off_enable = acf_info->aw_dev->soft_off_enable;
struct aw_acf_hdr *acf_hdr = (struct aw_acf_hdr *)acf_info->fw_data;
struct aw_acf_dde_v_1_0_0_0 *acf_dde =
(struct aw_acf_dde_v_1_0_0_0 *)(acf_info->fw_data + acf_hdr->ddt_offset);
int i = 0;
int ret = 0;
int found_off_prof_flag = 0;
int count = acf_info->prof_info.count;
for (i = 0; i < acf_hdr->dde_num; ++i) {
if (((acf_dde[i].data_type == AW_BIN_TYPE_REG) ||
(acf_dde[i].data_type == AW_BIN_TYPE_HDR_REG)) &&
(acf_info->dev_index == acf_dde[i].dev_index) &&
(acf_info->aw_dev->chipid == acf_dde[i].chip_id)) {
ret = aw_check_product_name_v_1_0_0_0(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
ret = aw_check_prof_str_is_off(acf_dde[i].dev_profile_str);
if (ret == 0) {
found_off_prof_flag = AW_PROFILE_OK;
if (soft_off_enable) {
count++;
} else {
AW_DEV_LOGE(dev, "profile_off is not allowed");
return -EINVAL;
}
} else {
count++;
}
}
}
if (count == 0) {
AW_DEV_LOGE(dev, "can't find profile");
return -EINVAL;
}
if (!found_off_prof_flag && soft_off_enable) {
AW_DEV_LOGE(dev, "profile power off is necessary,but not found");
aw_print_prof_off_name_can_support_v_1_0_0_0(dev);
return -EINVAL;
}
if (!found_off_prof_flag && !soft_off_enable) {
count++;
AW_DEV_LOGD(dev, "set no config power off profile in count");
}
acf_info->prof_info.count = count;
AW_DEV_LOGI(dev, "profile default_type profile count is %d", acf_info->prof_info.count);
return 0;
}
static int aw_parse_get_profile_count_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
int ret = 0;
ret = aw_get_dde_type_info_v_1_0_0_0(dev, acf_info);
if (ret < 0)
return ret;
if (acf_info->prof_info.prof_type == AW_DDE_DEV_TYPE_ID) {
ret = aw_parse_get_dev_type_prof_count_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse dev_type profile count failed");
return ret;
}
} else if (acf_info->prof_info.prof_type == AW_DDE_DEV_DEFAULT_TYPE_ID) {
ret = aw_parse_get_default_type_prof_count_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse default_type profile count failed");
return ret;
}
} else {
AW_DEV_LOGE(dev, "unsupport prof_type[0x%x]",
acf_info->prof_info.prof_type);
return -EINVAL;
}
AW_DEV_LOGI(dev, "profile count is %d", acf_info->prof_info.count);
return 0;
}
static int aw_parse_dev_type_prof_name_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
struct aw_acf_hdr *acf_hdr = (struct aw_acf_hdr *)acf_info->fw_data;
struct aw_acf_dde_v_1_0_0_0 *acf_dde =
(struct aw_acf_dde_v_1_0_0_0 *)(acf_info->fw_data + acf_hdr->ddt_offset);
struct aw_prof_info *prof_info = &acf_info->prof_info;
int i, ret, list_index = 0;
for (i = 0; i < acf_hdr->dde_num; ++i) {
if (((acf_dde[i].data_type == AW_BIN_TYPE_REG) ||
(acf_dde[i].data_type == AW_BIN_TYPE_HDR_REG)) &&
(acf_info->aw_dev->i2c_bus == acf_dde[i].dev_bus) &&
(acf_info->aw_dev->i2c_addr == acf_dde[i].dev_addr) &&
(acf_info->aw_dev->chipid == acf_dde[i].chip_id)) {
if (list_index > prof_info->count) {
AW_DEV_LOGE(dev, "%s:Alrealdy set list_index [%d], redundant profile [%s]exist\n",
__func__, list_index,
acf_dde[i].dev_profile_str);
return -EINVAL;
}
ret = aw_check_product_name_v_1_0_0_0(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
snprintf(prof_info->prof_name_list[list_index], AW_PROFILE_STR_MAX, "%s",
acf_dde[i].dev_profile_str);
AW_DEV_LOGI(dev, "profile_name=[%s]",
prof_info->prof_name_list[list_index]);
list_index++;
}
}
return 0;
}
static int aw_parse_default_type_prof_name_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
struct aw_acf_hdr *acf_hdr = (struct aw_acf_hdr *)acf_info->fw_data;
struct aw_acf_dde_v_1_0_0_0 *acf_dde =
(struct aw_acf_dde_v_1_0_0_0 *)(acf_info->fw_data + acf_hdr->ddt_offset);
struct aw_prof_info *prof_info = &acf_info->prof_info;
int i, ret, list_index = 0;
for (i = 0; i < acf_hdr->dde_num; ++i) {
if (((acf_dde[i].data_type == AW_BIN_TYPE_REG) ||
(acf_dde[i].data_type == AW_BIN_TYPE_HDR_REG)) &&
(acf_info->dev_index == acf_dde[i].dev_index) &&
(acf_info->aw_dev->chipid == acf_dde[i].chip_id)) {
if (list_index > prof_info->count) {
AW_DEV_LOGE(dev, "%s:Alrealdy set list_index [%d], redundant profile [%s]exist\n",
__func__, list_index,
acf_dde[i].dev_profile_str);
return -EINVAL;
}
ret = aw_check_product_name_v_1_0_0_0(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
snprintf(prof_info->prof_name_list[list_index], AW_PROFILE_STR_MAX, "%s",
acf_dde[i].dev_profile_str);
AW_DEV_LOGI(dev, "profile_name=[%s]",
prof_info->prof_name_list[list_index]);
list_index++;
}
}
return 0;
}
static int aw_parse_prof_name_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
int ret = 0;
int count = acf_info->prof_info.count;
struct aw_prof_info *prof_info = &acf_info->prof_info;
prof_info->prof_name_list = (char (*)[AW_PROFILE_STR_MAX])devm_kzalloc(dev,
count * (AW_PROFILE_STR_MAX), GFP_KERNEL);
if (prof_info->prof_name_list == NULL) {
AW_DEV_LOGE(dev, "prof_name_list devm_kzalloc failed");
return -ENOMEM;
}
if (acf_info->prof_info.prof_type == AW_DDE_DEV_TYPE_ID) {
ret = aw_parse_dev_type_prof_name_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse dev_type profile count failed");
return ret;
}
} else if (acf_info->prof_info.prof_type == AW_DDE_DEV_DEFAULT_TYPE_ID) {
ret = aw_parse_default_type_prof_name_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse default_type profile count failed");
return ret;
}
} else {
AW_DEV_LOGE(dev, "unsupport prof_type[0x%x]",
acf_info->prof_info.prof_type);
return -EINVAL;
}
AW_DEV_LOGI(dev, "profile name parse succeed");
return 0;
}
static int aw_search_prof_index_from_list_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_prof_desc **prof_desc,
struct aw_acf_dde_v_1_0_0_0 *prof_hdr)
{
int i = 0;
int count = acf_info->prof_info.count;
char (*prof_name_list)[AW_PROFILE_STR_MAX] = acf_info->prof_info.prof_name_list;
for (i = 0; i < count; i++) {
if (!strncmp(prof_name_list[i], prof_hdr->dev_profile_str, AW_PROFILE_STR_MAX)) {
*prof_desc = &(acf_info->prof_info.prof_desc[i]);
return 0;
}
}
if (i == count)
AW_DEV_LOGE(dev, "not find prof_id and prof_name in list");
return -EINVAL;
}
static int aw_parse_data_by_sec_type_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info,
struct aw_acf_dde_v_1_0_0_0 *prof_hdr)
{
int ret = -1;
char *cfg_data = acf_info->fw_data + prof_hdr->data_offset;
struct aw_prof_desc *prof_desc = NULL;
ret = aw_search_prof_index_from_list_v_1_0_0_0(dev, acf_info, &prof_desc, prof_hdr);
if (ret < 0)
return ret;
switch (prof_hdr->data_type) {
case AW_BIN_TYPE_REG:
snprintf(prof_desc->dev_name, sizeof(prof_hdr->dev_name),
"%s", prof_hdr->dev_name);
AW_DEV_LOGI(dev, "parse reg type data enter,product=[%s],prof_id=[%d],prof_name=[%s]",
prof_hdr->dev_name, prof_hdr->dev_profile,
prof_hdr->dev_profile_str);
prof_desc->prof_name = prof_hdr->dev_profile_str;
ret = aw_parse_raw_reg(dev, cfg_data, prof_hdr->data_size,
prof_desc);
break;
case AW_BIN_TYPE_HDR_REG:
snprintf(prof_desc->dev_name, sizeof(prof_hdr->dev_name),
"%s", prof_hdr->dev_name);
AW_DEV_LOGI(dev, "parse hdr_reg type data enter,product=[%s],prof_id=[%d],prof_name=[%s]",
prof_hdr->dev_name, prof_hdr->dev_profile,
prof_hdr->dev_profile_str);
prof_desc->prof_name = prof_hdr->dev_profile_str;
ret = aw_parse_reg_with_hdr(dev, cfg_data,
prof_hdr->data_size, prof_desc);
break;
}
return ret;
}
static int aw_parse_dev_type_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
int i = 0;
int ret;
int parse_prof_count = 0;
char *cfg_data = NULL;
struct aw_acf_dde_v_1_0_0_0 *acf_dde =
(struct aw_acf_dde_v_1_0_0_0 *)(acf_info->fw_data + acf_info->acf_hdr.ddt_offset);
AW_DEV_LOGD(dev, "enter");
for (i = 0; i < acf_info->acf_hdr.dde_num; i++) {
if ((acf_dde[i].type == AW_DDE_DEV_TYPE_ID) &&
(acf_info->aw_dev->i2c_bus == acf_dde[i].dev_bus) &&
(acf_info->aw_dev->i2c_addr == acf_dde[i].dev_addr) &&
(acf_info->aw_dev->chipid == acf_dde[i].chip_id)) {
ret = aw_check_product_name_v_1_0_0_0(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
if (acf_dde[i].data_type == AW_MONITOR) {
cfg_data = acf_info->fw_data + acf_dde[i].data_offset;
AW_DEV_LOGD(dev, "parse monitor type data enter");
ret = aw_parse_monitor_config(dev, cfg_data,
acf_dde[i].data_size);
} else {
ret = aw_parse_data_by_sec_type_v_1_0_0_0(dev, acf_info,
&acf_dde[i]);
if (ret < 0)
AW_DEV_LOGE(dev, "parse dev type data failed");
else
parse_prof_count++;
}
}
}
if (parse_prof_count == 0) {
AW_DEV_LOGE(dev, "get dev type num is %d, parse failed", parse_prof_count);
return -EINVAL;
}
return AW_DEV_TYPE_OK;
}
static int aw_parse_default_type_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
int i = 0;
int ret;
int parse_prof_count = 0;
char *cfg_data = NULL;
struct aw_acf_dde_v_1_0_0_0 *acf_dde =
(struct aw_acf_dde_v_1_0_0_0 *)(acf_info->fw_data + acf_info->acf_hdr.ddt_offset);
AW_DEV_LOGD(dev, "enter");
for (i = 0; i < acf_info->acf_hdr.dde_num; i++) {
if ((acf_dde[i].type == AW_DDE_DEV_DEFAULT_TYPE_ID) &&
(acf_info->dev_index == acf_dde[i].dev_index) &&
(acf_info->aw_dev->chipid == acf_dde[i].chip_id)) {
ret = aw_check_product_name_v_1_0_0_0(dev, acf_info, &acf_dde[i]);
if (ret < 0)
continue;
if (acf_dde[i].data_type == AW_MONITOR) {
cfg_data = acf_info->fw_data + acf_dde[i].data_offset;
AW_DEV_LOGD(dev, "parse monitor type data enter");
ret = aw_parse_monitor_config(dev, cfg_data,
acf_dde[i].data_size);
} else {
ret = aw_parse_data_by_sec_type_v_1_0_0_0(dev, acf_info,
&acf_dde[i]);
if (ret < 0)
AW_DEV_LOGE(dev, "parse default type data failed");
else
parse_prof_count++;
}
}
}
if (parse_prof_count == 0) {
AW_DEV_LOGE(dev, "get default type num is %d,parse failed", parse_prof_count);
return -EINVAL;
}
return AW_DEV_TYPE_OK;
}
static int aw_parse_by_hdr_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
int ret;
if (acf_info->prof_info.prof_type == AW_DDE_DEV_TYPE_ID) {
ret = aw_parse_dev_type_v_1_0_0_0(dev, acf_info);
if (ret < 0)
return ret;
} else if (acf_info->prof_info.prof_type == AW_DDE_DEV_DEFAULT_TYPE_ID) {
ret = aw_parse_default_type_v_1_0_0_0(dev, acf_info);
if (ret < 0)
return ret;
}
return 0;
}
static int aw_set_prof_off_info_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
uint8_t soft_off_enable = acf_info->aw_dev->soft_off_enable;
struct aw_prof_info *prof_info = &acf_info->prof_info;
int i = 0;
int ret = 0;
for (i = 0; i < prof_info->count; ++i) {
if (!(prof_info->prof_desc[i].prof_st) && !soft_off_enable) {
snprintf(prof_info->prof_name_list[i], AW_PROFILE_STR_MAX, "%s",
g_power_off_name[0]);
prof_info->prof_desc[i].prof_name = prof_info->prof_name_list[i];
prof_info->prof_desc[i].prof_st = AW_PROFILE_WAIT;
memset(&prof_info->prof_desc[i].data_container, 0,
sizeof(struct aw_data_container));
return 0;
}
ret = aw_check_prof_str_is_off(prof_info->prof_name_list[i]);
if (ret == 0) {
AW_DEV_LOGD(dev, "found profile off,data_len=[%d]",
prof_info->prof_desc[i].data_container.len);
return 0;
}
}
AW_DEV_LOGE(dev, "index[%d] is out of table,profile count[%d]",
i, prof_info->count);
return -EINVAL;
}
static int aw_parse_acf_v_1_0_0_0(struct device *dev,
struct acf_bin_info *acf_info)
{
struct aw_prof_info *prof_info = &acf_info->prof_info;
int ret;
ret = aw_parse_get_profile_count_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "get profile count failed");
return ret;
}
ret = aw_parse_prof_name_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "get profile count failed");
return ret;
}
acf_info->prof_info.prof_desc = devm_kzalloc(dev,
prof_info->count * sizeof(struct aw_prof_desc), GFP_KERNEL);
if (acf_info->prof_info.prof_desc == NULL) {
AW_DEV_LOGE(dev, "prof_desc devm_kzalloc failed");
return -ENOMEM;
}
ret = aw_parse_by_hdr_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "parse data failed");
return ret;
}
ret = aw_set_prof_off_info_v_1_0_0_0(dev, acf_info);
if (ret < 0) {
AW_DEV_LOGE(dev, "set profile off info failed");
return ret;
}
prof_info->status = AW_ACF_UPDATE;
AW_DEV_LOGI(dev, "acf paese succeed");
return 0;
}
/*************************************************************************
*
*acf parse API
*
*************************************************************************/
void aw_acf_profile_free(struct device *dev, struct acf_bin_info *acf_info)
{
struct aw_prof_info *prof_info = &acf_info->prof_info;
prof_info->count = 0;
prof_info->status = AW_ACF_WAIT;
memset(&acf_info->acf_hdr, 0, sizeof(struct aw_acf_hdr));
if (prof_info->prof_desc) {
devm_kfree(dev, prof_info->prof_desc);
prof_info->prof_desc = NULL;
}
if (prof_info->prof_name_list) {
devm_kfree(dev, prof_info->prof_name_list);
prof_info->prof_name_list = NULL;
}
if (acf_info->fw_data) {
vfree(acf_info->fw_data);
acf_info->fw_data = NULL;
}
}
int aw_acf_parse(struct device *dev, struct acf_bin_info *acf_info)
{
int ret = 0;
AW_DEV_LOGD(dev, "enter");
acf_info->prof_info.status = AW_ACF_WAIT;
ret = aw_check_acf_firmware(dev, acf_info->fw_data,
acf_info->fw_size);
if (ret < 0) {
AW_DEV_LOGE(dev, "load firmware check failed");
return -EINVAL;
}
memcpy(&acf_info->acf_hdr, acf_info->fw_data,
sizeof(struct aw_acf_hdr));
switch (acf_info->acf_hdr.hdr_version) {
case AW_ACF_HDR_VER_0_0_0_1:
return aw_parse_acf_v_0_0_0_1(dev, acf_info);
case AW_ACF_HDR_VER_1_0_0_0:
return aw_parse_acf_v_1_0_0_0(dev, acf_info);
default:
AW_DEV_LOGE(dev, "unsupported hdr_version [0x%x]",
acf_info->acf_hdr.hdr_version);
return -EINVAL;
}
return ret;
}
struct aw_prof_desc *aw_acf_get_prof_desc_form_name(struct device *dev,
struct acf_bin_info *acf_info, char *profile_name)
{
int i = 0;
struct aw_prof_desc *prof_desc = NULL;
struct aw_prof_info *prof_info = &acf_info->prof_info;
AW_DEV_LOGD(dev, "enter");
if (!acf_info->prof_info.status) {
AW_DEV_LOGE(dev, "profile_cfg not load");
return NULL;
}
for (i = 0; i < prof_info->count; i++) {
if (!strncmp(profile_name, prof_info->prof_desc[i].prof_name,
AW_PROFILE_STR_MAX)) {
prof_desc = &prof_info->prof_desc[i];
break;
}
}
if (i == prof_info->count) {
AW_DEV_LOGE(dev, "profile not found");
return NULL;
}
AW_DEV_LOGI(dev, "get prof desc down");
return prof_desc;
}
int aw_acf_get_prof_index_form_name(struct device *dev,
struct acf_bin_info *acf_info, char *profile_name)
{
int i = 0;
struct aw_prof_info *prof_info = &acf_info->prof_info;
if (!acf_info->prof_info.status) {
AW_DEV_LOGE(dev, "profile_cfg not load");
return -EINVAL;
}
for (i = 0; i < prof_info->count; i++) {
if (!strncmp(profile_name, prof_info->prof_name_list[i],
AW_PROFILE_STR_MAX)) {
return i;
}
}
AW_DEV_LOGE(dev, "profile_index not found");
return -EINVAL;
}
char *aw_acf_get_prof_name_form_index(struct device *dev,
struct acf_bin_info *acf_info, int index)
{
struct aw_prof_info *prof_info = &acf_info->prof_info;
if (!acf_info->prof_info.status) {
AW_DEV_LOGE(dev, "profile_cfg not load");
return NULL;
}
if (index >= prof_info->count || index < 0) {
AW_DEV_LOGE(dev, "profile_index out of table");
return NULL;
}
return prof_info->prof_desc[index].prof_name;
}
int aw_acf_get_profile_count(struct device *dev,
struct acf_bin_info *acf_info)
{
struct aw_prof_info *prof_info = &acf_info->prof_info;
if (!acf_info->prof_info.status) {
AW_DEV_LOGE(dev, "profile_cfg not load");
return -EINVAL;
}
if (prof_info->count > 0) {
return prof_info->count;
}
return -EINVAL;
}
char *aw_acf_get_prof_off_name(struct device *dev,
struct acf_bin_info *acf_info)
{
int i = 0;
int ret = 0;
struct aw_prof_info *prof_info = &acf_info->prof_info;
if (!acf_info->prof_info.status) {
AW_DEV_LOGE(dev, "profile_cfg not load");
return NULL;
}
for (i = 0; i < prof_info->count; i++) {
ret = aw_check_prof_str_is_off(prof_info->prof_name_list[i]);
if (ret == 0)
return prof_info->prof_name_list[i];
}
return NULL;
}
void aw_acf_init(struct aw_device *aw_dev, struct acf_bin_info *acf_info, int index)
{
acf_info->load_count = 0;
acf_info->prof_info.status = AW_ACF_WAIT;
acf_info->dev_index = index;
acf_info->aw_dev = aw_dev;
acf_info->product_cnt = aw_dev->product_cnt;
acf_info->product_tab = aw_dev->product_tab;
acf_info->prof_info.prof_desc = NULL;
acf_info->fw_data = NULL;
acf_info->fw_size = 0;
}