From 1dcebc141d43ef7b3402c318215bc292256c273a Mon Sep 17 00:00:00 2001 From: Tom Richardson Date: Wed, 1 Jul 2020 09:57:20 -0400 Subject: [PATCH] Add fw_path param to avl62x1 Make string handling in avl68x2 a little safer --- availink/avl62x1/avl62x1_top.c | 138 +++++++++++++++++-------- availink/avl62x1/sdk_src/avl62x1_lib.h | 2 +- availink/avl68x2/avl68x2_top.c | 44 ++++---- 3 files changed, 120 insertions(+), 64 deletions(-) diff --git a/availink/avl62x1/avl62x1_top.c b/availink/avl62x1/avl62x1_top.c index ad12edc..09df6f3 100644 --- a/availink/avl62x1/avl62x1_top.c +++ b/availink/avl62x1/avl62x1_top.c @@ -71,12 +71,14 @@ } static struct avl62x1_bs_state bs_states[AVL_MAX_NUM_DEMODS] = {0}; -static struct avl62x1_priv *global_priv; //just for debug +static struct avl62x1_priv *global_priv = NULL; +static char sel_fw[256] = {0}; //--- module params --- static int debug = 0; static unsigned short bs_mode = 0; static int bs_min_sr = 1000000; +char fw_path[256] = {0}; //------------------- //---- character device stuff ---- @@ -504,7 +506,8 @@ static int acquire_dvbs_s2(struct dvb_frontend *fe) } static int set_dvb_mode(struct dvb_frontend *fe, - enum fe_delivery_system delsys) + enum fe_delivery_system delsys, + bool force_reload) { struct avl62x1_priv *priv = fe->demodulator_priv; uint16_t ret = AVL_EC_OK; @@ -512,7 +515,7 @@ static int set_dvb_mode(struct dvb_frontend *fe, struct avl62x1_ver_info ver_info; /* already in desired mode */ - if (priv->delivery_system == delsys) + if (!force_reload && (priv->delivery_system == delsys)) return 0; p_debug("initing demod for delsys=%d", delsys); @@ -1583,14 +1586,50 @@ static struct dvb_frontend_ops avl62x1_ops = { .get_frontend = get_frontend, }; +static int avl62x1_get_firmware(struct dvb_frontend *fe) { + unsigned int fw_maj, fw_min, fw_build; + int fw_status; + struct avl62x1_priv *priv = fe->demodulator_priv; + + fw_status = request_firmware(&priv->fw, + sel_fw, + priv->i2c->dev.parent); + if (fw_status != 0) + { + p_error("firmware file %s not found",sel_fw); + return fw_status; + } + + priv->chip->chip_priv->patch_data = (unsigned char *)(priv->fw->data); + fw_maj = priv->chip->chip_priv->patch_data[24]; //major rev + fw_min = priv->chip->chip_priv->patch_data[25]; //SDK-FW API rev + fw_build = (priv->chip->chip_priv->patch_data[26] << 8) | + priv->chip->chip_priv->patch_data[27]; //internal rev + if(fw_min != AVL62X1_VER_MINOR) + { + //SDK-FW API rev must match + p_error("Firmware version %d.%d.%d incompatible with this driver version", + fw_maj, fw_min, fw_build); + p_error("Firmware minor version must be %d", + AVL62X1_VER_MINOR); + release_firmware(priv->fw); + return 1; + } + else + { + p_info("Firmware version %d.%d.%d found", + fw_maj, fw_min, fw_build); + } + + return 0; +} + struct dvb_frontend *avl62x1_attach(struct avl62x1_config *config, struct i2c_adapter *i2c) { struct avl62x1_priv *priv; uint16_t ret; uint32_t id; - int fw_status; - unsigned int fw_maj, fw_min, fw_build; p_info("driver version %s\n", AVL62X1_VERSION); @@ -1663,51 +1702,20 @@ struct dvb_frontend *avl62x1_attach(struct avl62x1_config *config, p_info("found AVL62x1 id=0x%x", id); - fw_status = request_firmware(&priv->fw, - AVL62X1_FIRMWARE, - i2c->dev.parent); - if (fw_status != 0) - { - p_error("firmware file not found"); - goto err4; - } - else - { - priv->chip->chip_priv->patch_data = (unsigned char *)(priv->fw->data); - fw_maj = priv->chip->chip_priv->patch_data[24]; //major rev - fw_min = priv->chip->chip_priv->patch_data[25]; //SDK-FW API rev - fw_build = (priv->chip->chip_priv->patch_data[26] << 8) | - priv->chip->chip_priv->patch_data[27]; //internal rev - if(fw_min != AVL62X1_VER_MINOR) - { - //SDK-FW API rev must match - p_error("Firmware version %d.%d.%d incompatible with this driver version", - fw_maj, fw_min, fw_build); - p_error("Firmware minor version must be %d", - AVL62X1_VER_MINOR); - goto err5; - } - else + if(!avl62x1_get_firmware(&priv->frontend)) { + if(!set_dvb_mode(&priv->frontend, SYS_DVBS2, false)) { - p_info("Firmware version %d.%d.%d found", - fw_maj, fw_min, fw_build); - } - } - - if (!set_dvb_mode(&priv->frontend, SYS_DVBS2)) - { - p_info("Firmware booted"); - release_firmware(priv->fw); - init_avl62x1_i2cctl_device(priv); + p_info("Firmware booted"); + release_firmware(priv->fw); + init_avl62x1_i2cctl_device(priv); #if INCLUDE_STDOUT - init_avl62x1_stdout_device(priv); + init_avl62x1_stdout_device(priv); #endif - - return &priv->frontend; + + return &priv->frontend; + } } -err5: - release_firmware(priv->fw); err4: kfree(priv->chip->chip_pub); err3: @@ -1726,6 +1734,8 @@ static int __init mod_init(void) { p_debug(""); + global_priv = NULL; + for(i=0; i>i) & 1; bs_states[i].num_carriers = 0; @@ -1734,6 +1744,11 @@ static int __init mod_init(void) { bs_states[i].carriers = NULL; bs_states[i].streams = NULL; } + + if(strlen(sel_fw) == 0) { + strscpy(sel_fw, AVL62X1_FIRMWARE, sizeof(sel_fw)); + } + return 0; } module_init(mod_init); @@ -1794,6 +1809,39 @@ static const struct kernel_param_ops bs_min_sr_ops = { module_param_cb(bs_min_sr, &bs_min_sr_ops, &bs_min_sr, 0644); MODULE_PARM_DESC(bs_min_sr, " minimum symbol rate (Hz) for blindscan mode [1000000:55000000]"); +static int fw_path_set(const char *val, const struct kernel_param *kp) +{ + char *clean_val = strim((char *)val); + strscpy(sel_fw, clean_val, sizeof(sel_fw)); + strscpy(fw_path, clean_val, sizeof(fw_path)); + + if (global_priv != NULL) + { + if (!avl62x1_get_firmware(&global_priv->frontend)) + { + if (!set_dvb_mode(&global_priv->frontend, SYS_DVBS2, true)) + { + p_info("New firmware %s booted",sel_fw); + release_firmware(global_priv->fw); + } + } + } + + return 0; +} +static int fw_path_get(char *buffer, const struct kernel_param *kp) +{ + sprintf(buffer, "%s",sel_fw); + return strlen(buffer); +} +static const struct kernel_param_ops fw_path_ops = { + .set = fw_path_set, + .get = fw_path_get +}; +module_param_cb(fw_path, &fw_path_ops, fw_path, 0644); +MODULE_PARM_DESC(fw_path, ""); + + MODULE_DESCRIPTION("Availink AVL62X1 DVB-S/S2/S2X demodulator driver"); MODULE_AUTHOR("Availink, Inc. (gpl@availink.com)"); MODULE_LICENSE("GPL"); diff --git a/availink/avl62x1/sdk_src/avl62x1_lib.h b/availink/avl62x1/sdk_src/avl62x1_lib.h index 325b6e3..5788abc 100644 --- a/availink/avl62x1/sdk_src/avl62x1_lib.h +++ b/availink/avl62x1/sdk_src/avl62x1_lib.h @@ -19,7 +19,7 @@ //build number = increment on every change to implementation #define AVL62X1_VER_MAJOR 3 #define AVL62X1_VER_MINOR 8 -#define AVL62X1_VER_BUILD 4 +#define AVL62X1_VER_BUILD 5 #define AVL62X1_CHIP_ID 0x62615ca8 diff --git a/availink/avl68x2/avl68x2_top.c b/availink/avl68x2/avl68x2_top.c index 9e372c0..483dafa 100644 --- a/availink/avl68x2/avl68x2_top.c +++ b/availink/avl68x2/avl68x2_top.c @@ -628,19 +628,19 @@ static int avl68x2_get_firmware(struct dvb_frontend *fe, int force_fw) { case SYS_DVBS: case SYS_DVBS2: - strncpy(fw_path, sel_dvbsx_fw, 255); + strscpy(fw_path, sel_dvbsx_fw, sizeof(fw_path)); break; case SYS_ISDBT: - strncpy(fw_path, sel_isdbt_fw, 255); + strscpy(fw_path, sel_isdbt_fw, sizeof(fw_path)); break; case SYS_DVBC_ANNEX_A: //"DVB-C" case SYS_DVBC_ANNEX_B: //J.83-B - strncpy(fw_path, sel_dvbc_fw, 255); + strscpy(fw_path, sel_dvbc_fw, sizeof(fw_path)); break; case SYS_DVBT: case SYS_DVBT2: default: - strncpy(fw_path, sel_dvbtx_fw, 255); + strscpy(fw_path, sel_dvbtx_fw, sizeof(fw_path)); } fw_status = request_firmware(&priv->fw, fw_path, priv->i2c->dev.parent); @@ -2029,28 +2029,28 @@ struct dvb_frontend *avl68x2_attach(struct avl68x2_config *config, //C, I, S, T memcpy(&avl68x2_ops.delsys, delsys_b, sizeof(delsys_b)); - strncpy(feat_str,"DVB-C/Sx/Tx, J.83B, and ISDB-T",255); + strscpy(feat_str,"DVB-C/Sx/Tx, J.83B, and ISDB-T",sizeof(feat_str)); part_num = 6882; break; case 0xd: //C, I, S memcpy(&avl68x2_ops.delsys, delsys_d, sizeof(delsys_d)); - strncpy(feat_str,"DVB-C/Sx, J.83B, and ISDB-T",255); + strscpy(feat_str,"DVB-C/Sx, J.83B, and ISDB-T",sizeof(feat_str)); part_num = 6812; break; case 0xe: //C, T memcpy(&avl68x2_ops.delsys, delsys_e, sizeof(delsys_e)); - strncpy(feat_str,"DVB-C/Tx and J.83B",255); + strscpy(feat_str,"DVB-C/Tx and J.83B",sizeof(feat_str)); part_num = 6762; break; case 0xf: //C, S, T memcpy(&avl68x2_ops.delsys, delsys_f, sizeof(delsys_f)); - strncpy(feat_str,"DVB-C/Sx/Tx and J.83B",255); + strscpy(feat_str,"DVB-C/Sx/Tx and J.83B",sizeof(feat_str)); part_num = 6862; break; default: @@ -2117,16 +2117,16 @@ static int __init mod_init(void) { } if(strlen(sel_dvbsx_fw) == 0) { - strncpy(sel_dvbsx_fw, AVL68X2_DVBSX_FW, 255); + strscpy(sel_dvbsx_fw, AVL68X2_DVBSX_FW, sizeof(sel_dvbsx_fw)); } if(strlen(sel_dvbtx_fw) == 0) { - strncpy(sel_dvbtx_fw, AVL68X2_DVBTX_FW, 255); + strscpy(sel_dvbtx_fw, AVL68X2_DVBTX_FW, sizeof(sel_dvbtx_fw)); } if(strlen(sel_dvbc_fw) == 0) { - strncpy(sel_dvbc_fw, AVL68X2_DVBC_FW, 255); + strscpy(sel_dvbc_fw, AVL68X2_DVBC_FW, sizeof(sel_dvbc_fw)); } if(strlen(sel_isdbt_fw) == 0) { - strncpy(sel_isdbt_fw, AVL68X2_ISDBT_FW, 255); + strscpy(sel_isdbt_fw, AVL68X2_ISDBT_FW, sizeof(sel_isdbt_fw)); } return 0; @@ -2254,7 +2254,7 @@ MODULE_PARM_DESC(diseqc_voltage, " voltage control"); size_t get_fw_path(const char *val, const char *prefix, char **begin) { char *b = NULL; size_t len = 0; - b = strstr(val,prefix); + b = strstr(strim((char *)val),prefix); if(b != NULL) { len = strcspn(b,";"); p_debug("len %d",(int)len); @@ -2276,7 +2276,9 @@ static int fw_paths_set(const char *val, const struct kernel_param *kp) len = get_fw_path(val,"C=",&b); if(len != 0) { memset(sel_dvbc_fw,0,sizeof(sel_dvbc_fw)); - strncpy(sel_dvbc_fw,&b[2],len-2); + strscpy(sel_dvbc_fw, + &b[2], + min(len - 2, sizeof(sel_dvbc_fw))); p_info("set C=%s",sel_dvbc_fw); mode = AVL_DVBC; delsys = SYS_DVBC_ANNEX_A; @@ -2285,7 +2287,9 @@ static int fw_paths_set(const char *val, const struct kernel_param *kp) len = get_fw_path(val,"I=",&b); if(len != 0) { memset(sel_isdbt_fw,0,sizeof(sel_isdbt_fw)); - strncpy(sel_isdbt_fw,&b[2],len-2); + strscpy(sel_isdbt_fw, + &b[2], + min(len - 2, sizeof(sel_isdbt_fw))); p_info("set I=%s",sel_isdbt_fw); mode = AVL_ISDBT; delsys = SYS_ISDBT; @@ -2294,7 +2298,9 @@ static int fw_paths_set(const char *val, const struct kernel_param *kp) len = get_fw_path(val,"S=",&b); if(len != 0) { memset(sel_dvbsx_fw,0,sizeof(sel_dvbsx_fw)); - strncpy(sel_dvbsx_fw,&b[2],len-2); + strscpy(sel_dvbsx_fw, + &b[2], + min(len - 2, sizeof(sel_dvbsx_fw))); p_info("set S=%s",sel_dvbsx_fw); mode = AVL_DVBSX; delsys = SYS_DVBS2; @@ -2303,12 +2309,14 @@ static int fw_paths_set(const char *val, const struct kernel_param *kp) len = get_fw_path(val,"T=",&b); if(len != 0) { memset(sel_dvbtx_fw,0,sizeof(sel_dvbtx_fw)); - strncpy(sel_dvbtx_fw,&b[2],len-2); + strscpy(sel_dvbtx_fw, + &b[2], + min(len - 2, sizeof(sel_dvbtx_fw))); p_info("set T=%s",sel_dvbtx_fw); mode = AVL_DVBTX; delsys = SYS_DVBT2; } - strcpy(fw_paths,val); + strscpy(fw_paths,val,sizeof(fw_paths)); if(global_priv != NULL) { if(avl68x2_get_firmware(&global_priv->frontend,delsys))