From 9bccb3edd7abd721d87a336317efeef910ffef72 Mon Sep 17 00:00:00 2001 From: "GL.iNet-Xinfa.Deng" Date: Thu, 27 May 2021 15:02:55 +0800 Subject: [PATCH] fix: sfax8-factory-read use source code Signed-off-by: GL.iNet-Xinfa.Deng --- .../package/kernel/sfax8-factory-read/Makefile | 10 +- .../sfax8-factory-read/src/sf_factory_read_entry.c | 823 +++++++++++++++++++++ .../src/sf_factory_read_pl_ref.h | 64 ++ .../sfax8-factory-read/src/sf_factory_read_sysfs.c | 610 +++++++++++++++ .../sfax8-factory-read/src/sf_factory_read_sysfs.h | 45 ++ .../sfax8-factory-read/src/sfax8_factory_read.h | 117 +++ .../sfax8-factory-read/src/sfax8_factory_read.ko | Bin 27608 -> 0 bytes 7 files changed, 1664 insertions(+), 5 deletions(-) create mode 100755 openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_entry.c create mode 100755 openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_pl_ref.h create mode 100755 openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.c create mode 100755 openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.h create mode 100755 openwrt-18.06/package/kernel/sfax8-factory-read/src/sfax8_factory_read.h delete mode 100755 openwrt-18.06/package/kernel/sfax8-factory-read/src/sfax8_factory_read.ko diff --git a/openwrt-18.06/package/kernel/sfax8-factory-read/Makefile b/openwrt-18.06/package/kernel/sfax8-factory-read/Makefile index 5fdfac1..55709d6 100755 --- a/openwrt-18.06/package/kernel/sfax8-factory-read/Makefile +++ b/openwrt-18.06/package/kernel/sfax8-factory-read/Makefile @@ -41,22 +41,22 @@ EXTRA_CFLAGS:= \ $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \ $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \ -NOSTDINC_FLAGS = \ - -I$(PKG_BUILD_DIR) - MAKE_OPTS:= \ ARCH="$(LINUX_KARCH)" \ CROSS_COMPILE="$(TARGET_CROSS)" \ SUBDIRS="$(PKG_BUILD_DIR)" \ EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ - NOSTDINC_FLAGS="$(NOSTDINC_FLAGS)" \ $(EXTRA_KCONFIG) define Build/Prepare - $(CP) ./src/sfax8_factory_read.ko $(PKG_BUILD_DIR)/ + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + $(MAKE_OPTS) \ + modules endef $(eval $(call KernelPackage,sfax8-factory-read)) diff --git a/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_entry.c b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_entry.c new file mode 100755 index 0000000..267c6ef --- /dev/null +++ b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_entry.c @@ -0,0 +1,823 @@ +/* + * sf_factory_read_entry.c - Support to read value from factory block. + * This driver provide an interface between factory block and our net driver(ethernet,wireless), + * to simplify the process of reading from factory. + * For example, sf rf driver gets XO config value from factory through MTD. + * + * Copyright (C) 2017 Shanghai Siflower Communication Technology Co., Ltd. + * + * Author: Zhengjinyang Jiang + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sfax8_factory_read.h" +#include +#include "sf_factory_read_pl_ref.h" +#ifdef CONFIG_SF16A18_FACTORY_READ_SYSFS_DEBUG +#include "sf_factory_read_sysfs.h" +#endif +struct sfax8_factory_read_context *f_read_ctx; + +int get_value_through_mtd(struct device_node *np, + const char *name, int start_offset, size_t len, unsigned char *buffer) +{ + struct device_node *mtd_np = NULL; + size_t retlen; + int size, ret, offset; + struct mtd_info *mtd; + const char *part; + const char part_temp[] = "factory"; + const __be32 *list; + phandle phandle; + unsigned char * pmac = NULL; + uint32_t mac_inc = 0; + + if(name != NULL){ + if(!strcasecmp(name,"mtd-mac-address")){ + pmac = (unsigned char *)buffer; + } + + if(!np){ + printk("error! device node is null\n"); + return -1; + } + list = of_get_property(np, name, &size); + if (!list || (size != (2 * sizeof(*list)))) + return -2; + + phandle = be32_to_cpup(list++); + if (phandle) + mtd_np = of_find_node_by_phandle(phandle); + + if (!mtd_np) + return -3; + + part = of_get_property(mtd_np, "label", NULL); + if (!part) + part = mtd_np->name; + mtd = get_mtd_device_nm(part); + offset = be32_to_cpup(list); + } + else{ + mtd = get_mtd_device_nm(part_temp); + offset = start_offset; + } + if (IS_ERR(mtd)) + return PTR_ERR(mtd); + + ret = mtd_read(mtd, offset, len, &retlen, (unsigned char *) buffer); + put_mtd_device(mtd); + + if((name != NULL) && (!strcasecmp(name,"mtd-mac-address"))){ + if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc)) + pmac[5] += mac_inc; + } + return ret; +} + +static void inc_sf_mac_addr(char *mac, int inc) +{ + unsigned int mac_calc[MACADDR_SIZE] = {0}; + int i = 0; + for(i = 0 ; i < MACADDR_SIZE ; i++) + { + mac_calc[i] = (unsigned int)(mac[i]) & 0xFF; + } + mac_calc[MACADDR_SIZE - 1] += inc; + mac_calc[MACADDR_SIZE - 2] += ((mac_calc[MACADDR_SIZE - 1] & (0x100)) >> 8); + mac[MACADDR_SIZE - 1] = mac_calc[MACADDR_SIZE - 1] & (0xff); + + mac_calc[MACADDR_SIZE - 3] += ((mac_calc[MACADDR_SIZE - 2] & (0x100)) >> 8); + mac[MACADDR_SIZE - 2] = mac_calc[MACADDR_SIZE - 2] & (0xff); + mac[MACADDR_SIZE - 3] = mac_calc[MACADDR_SIZE - 3] & (0xff); + //the first 3 char is reserved +} + +/* +static int is_valid_sf_address(const unsigned char * mac) +{ + //10:16:88 or A8:5A:F3 + return ((mac[0] == 0x10) && (mac[1] == 0x16) && (mac[2] == 0x88)) || + ((mac[0] == 0xA8) && (mac[1] == 0x5A) && (mac[2] == 0xF3)); +} +*/ + +static int set_sf_address(char * mac) +{ + //10:16:88 + mac[0] = 0x10; + mac[1] = 0x16; + mac[2] = 0x88; + return 0; +} + +static int set_mac_address_mtd(struct device_node *np,const char *name,char *mac) +{ + struct device_node *mtd_np = NULL; + size_t retlen; + int size, ret, offset; + struct mtd_info *mtd; + const char *part; + const __be32 *list; + phandle phandle; + unsigned char *buf = NULL; + struct erase_info ei; + + if(name != NULL){ + if(!np){ + printk("error! device node is null\n"); + return -1; + } + list = of_get_property(np, name, &size); + if (!list || (size != (2 * sizeof(*list)))) + return -2; + + phandle = be32_to_cpup(list++); + if (phandle) + mtd_np = of_find_node_by_phandle(phandle); + + if (!mtd_np) + return -3; + + part = of_get_property(mtd_np, "label", NULL); + if (!part) + part = mtd_np->name; + mtd = get_mtd_device_nm(part); + offset = be32_to_cpup(list); + }else{ + return -1; + } + if (IS_ERR(mtd)) + return PTR_ERR(mtd); + + + buf = kmalloc(mtd->erasesize, GFP_KERNEL); + ret = mtd_read(mtd, offset - (offset % mtd->erasesize), mtd->erasesize, &retlen, buf); + + ei.mtd = mtd; + ei.callback = NULL; + ei.addr = 0; + ei.len = mtd->erasesize; + ei.priv = 0; + ret = mtd_erase(mtd, &ei); + memcpy(buf + (offset % mtd->erasesize),mac,MACADDR_SIZE); + ret = mtd_write(mtd, offset - (offset % mtd->erasesize), mtd->erasesize, &retlen, buf); + kfree(buf); + put_mtd_device(mtd); + return ret; +} + +#define SUPPORT_WIFI_VIF_CNT 4 + +static void handle_macaddr_internal(struct device_node *np,struct sfax8_factory_read_context *priv) +{ + //last char of wifi base address must be 4 aligned in current version + unsigned int last_char = (unsigned int)priv->macaddr[5]; + unsigned int inc_lb = (SUPPORT_WIFI_VIF_CNT - (last_char % SUPPORT_WIFI_VIF_CNT)) % SUPPORT_WIFI_VIF_CNT; + int rc = 0; + + if (!is_valid_ether_addr(priv->macaddr)) { + //10:16:88 + eth_random_addr(priv->macaddr); + set_sf_address(priv->macaddr); + rc = set_mac_address_mtd(np,"mtd-mac-address",priv->macaddr); + printk("error: generated random MAC address rc=%d!!\n",rc); + } + memcpy(priv->macaddr0,priv->macaddr,MACADDR_SIZE); + memcpy(priv->wifi_lb_macaddr,priv->macaddr,MACADDR_SIZE); + memcpy(priv->wifi_hb_macaddr,priv->macaddr,MACADDR_SIZE); + memcpy(priv->wan_macaddr,priv->macaddr,MACADDR_SIZE); + + // gl.inet mac config + inc_sf_mac_addr(priv->wifi_lb_macaddr,2); + inc_sf_mac_addr(priv->wifi_hb_macaddr,3); + return; + + //for lb wifi address + if(inc_lb != 0) inc_sf_mac_addr(priv->wifi_lb_macaddr,inc_lb); + //for hb wifi address + inc_sf_mac_addr(priv->wifi_hb_macaddr,inc_lb + SUPPORT_WIFI_VIF_CNT); + //move eth address to end to avoid conflict with wifi address + if(inc_lb == 0){ + //pick the last 2 address as lan/wan address + inc_sf_mac_addr(priv->macaddr,8); + inc_sf_mac_addr(priv->wan_macaddr,9); + }else if(inc_lb == 3 || inc_lb == 2){ + //pick the first 2 address as lan/wan address + inc_sf_mac_addr(priv->wan_macaddr,1); + }else if(inc_lb == 1){ + //pick the first addres as lan + //pick the last addres as wan + inc_sf_mac_addr(priv->wan_macaddr,9); + }else{ + printk("handle_macaddr_internal should nerver get here %d!!!\n",inc_lb); + } +} + +static int save_value_from_factory_to_host(struct platform_device *pdev, + struct sfax8_factory_read_context *priv) +{ + int ret = 0; + unsigned char *buffer; + struct device_node *np = pdev->dev.of_node; + // get mac address + if ((ret = get_value_through_mtd(np, "mtd-mac-address", 0, MACADDR_SIZE, + priv->macaddr))) { + printk("get mac address through mtd failed! ret %d\n",ret); + } else { + //handle mac address internal + handle_macaddr_internal(np,priv); + } + priv->exist_flag |= (1 << READ_MAC_ADDRESS); + printk("macaddr is %x %x %x %x %x %x\n",priv->macaddr[0],priv->macaddr[1],priv->macaddr[2],priv->macaddr[3],priv->macaddr[4],priv->macaddr[5]); + + // get sn number + if ((ret = get_value_through_mtd( + np, "mtd-sn-number", 0, SN_SIZE, priv->sn))) + printk("get sn number through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_SN); + printk("sn is %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", + priv->sn[0],priv->sn[1],priv->sn[2],priv->sn[3],priv->sn[4],priv->sn[5], + priv->sn[6],priv->sn[7],priv->sn[8],priv->sn[9],priv->sn[10],priv->sn[11], + priv->sn[12],priv->sn[13],priv->sn[14],priv->sn[15]); + // get sn flag + if ((ret = get_value_through_mtd(np, "mtd-sn-flag", 0, SN_FLAG_SIZE, + &priv->sn_flag))) + printk("get sn flag through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_SN_FLAG); + printk("sn_flag is 0x%x\n", priv->sn_flag); + + // get pcba boot mark + if ((ret = get_value_through_mtd(np, "mtd-pcba-boot", 0, PCBA_BOOT_SIZE, + priv->pcba_boot))) + printk("get pcba boot mark through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_PCBA_BOOT); + + // get hardware version flag + if ((ret = get_value_through_mtd(np, "mtd-hardware-ver-flag", 0, + HARDWARE_VER_FLAG_SIZE, priv->hw_ver_flag))) + printk("get hardware version flag through mtd failed! ret %d\n", + ret); + priv->exist_flag |= (1 << READ_HARDWARE_VER_FLAG); + printk("hardware version flag is %.2s\n", priv->hw_ver_flag); + // get hardware version + if ((ret = get_value_through_mtd(np, "mtd-hardware-ver", 0, + HARDWARE_VER_SIZE, priv->hw_ver))) + printk("get hardware version through mtd failed! ret %d\n", + ret); + priv->exist_flag |= (1 << READ_HARDWARE_VER); + printk("hardware version is %.32s\n", priv->hw_ver); + + // get model version flag + if ((ret = get_value_through_mtd(np, "mtd-model-ver-flag", 0, + MODEL_VER_FLAG_SIZE, priv->model_ver_flag))) + printk("get model version flag through mtd failed! ret %d\n", + ret); + priv->exist_flag |= (1 << READ_MODEL_VER_FLAG); + printk("model version flag is %.2s\n", priv->model_ver_flag); + // get model version + if ((ret = get_value_through_mtd(np, "mtd-model-ver", 0, MODEL_VER_SIZE, + priv->model_ver))) + printk("get model version through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_MODEL_VER); + printk("model version is %.32s\n", priv->model_ver); + + // get counrty id + if ((ret = get_value_through_mtd(np, "mtd-country-id", 0, + COUNTRYID_SIZE, priv->countryID))) + printk("get country ID through mtd failed! ret %d\n", ret); + if ((priv->countryID[0] >= 'A') && (priv->countryID[0] <= 'z') && + (priv->countryID[1] >= 'A') && + (priv->countryID[1] <= 'z')) { + priv->exist_flag |= (1 << READ_COUNTRY_ID); + } else { + printk("can not find an vaild country ID[%.2s], use default " + "value[CN]\n", + priv->countryID); + priv->countryID[0] = 'C'; + priv->countryID[1] = 'N'; + } + printk("countryID is %.2s\n", priv->countryID); + + // get HW feature + buffer = kmalloc(sizeof(char) * HW_FEATURE_SIZE, GFP_KERNEL); + if ((ret = get_value_through_mtd( + np, "mtd-hw-feature", 0, HW_FEATURE_SIZE, buffer))) + printk("get HW feature through mtd failed! ret %d\n", ret); + priv->hw_feature = (buffer[3] << 24) | (buffer[2] << 16) | + (buffer[1] << 8) | buffer[0]; + priv->exist_flag |= (1 << READ_HW_FEATURE); + printk("HW feature is %#x\n", priv->hw_feature); + kfree(buffer); + + // get vender flag + if ((ret = get_value_through_mtd(np, "mtd-vender-flag", 0, + VENDER_FLAG_SIZE, priv->vender_flag))) + printk("get vender flag through mtd failed! ret %d\n", + ret); + priv->exist_flag |= (1 << READ_VENDER_FLAG); + printk("vender flag is %.2s\n", priv->vender_flag); + // get vender + if ((ret = get_value_through_mtd(np, "mtd-vender", 0, VENDER_SIZE, + priv->vender))) + printk("get vender through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_VENDER); + printk("vender is %.16s\n", priv->vender); + + // get product key flag + if ((ret = get_value_through_mtd(np, "mtd-product-key-flag", 0, + PRODUCT_KEY_FLAG_SIZE, priv->product_key_flag))) + printk("get product key flag through mtd failed! ret %d\n", + ret); + priv->exist_flag |= (1 << READ_PRODUCT_KEY_FLAG); + printk("product key flag is %.2s\n", priv->product_key_flag); + // get product key + if ((ret = get_value_through_mtd(np, "mtd-product-key", 0, PRODUCT_KEY_SIZE, + priv->product_key))) + printk("get product key through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_PRODUCT_KEY); + printk("product key is %.16s\n", priv->product_key); + + // get login info flag + if ((ret = get_value_through_mtd(np, "mtd-login-info-flag", 0, + LOGIN_INFO_FLAG_SIZE, priv->login_info_flag))) + printk("get login info flag through mtd failed! ret %d\n", + ret); + priv->exist_flag |= (1 << READ_LOGIN_INFO_FLAG); + printk("login info flag is %.2s\n", priv->login_info_flag); + // get login info + if ((ret = get_value_through_mtd(np, "mtd-login-info", 0, LOGIN_INFO_SIZE, + (unsigned char *)&priv->login_info))) + printk("get login info through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_LOGIN_INFO); + printk("login info is %#x\n", priv->login_info); + + // get rom type flag + if ((ret = get_value_through_mtd(np, "mtd-rom-type-flag", 0, + ROM_TYPE_FLAG_SIZE, priv->rom_type_flag))) + printk("get rom type flag through mtd failed! ret %d\n", + ret); + priv->exist_flag |= (1 << READ_ROM_TYPE_FLAG); + printk("rom type flag is %.2s\n", priv->rom_type_flag); + // get rom type + if ((ret = get_value_through_mtd(np, "mtd-rom-type", 0, ROM_TYPE_SIZE, + (unsigned char *)&priv->rom_type))) + printk("get rom type through mtd failed! ret %d\n", ret); + priv->exist_flag |= (1 << READ_ROM_TYPE); + printk("rom type is %#x\n", priv->rom_type); + + // get wifi version + if ((ret = get_value_through_mtd(np, "mtd-wifi-version", 0, + WIFI_VERSION_SIZE, priv->wifi_version))) + printk("get wifi version failed! ret %d\n", ret); + //check if some value have been saved in flash through a mark value "XO" or "V2" + if ((priv->wifi_version[0] == 'X' && priv->wifi_version[1] == 'O') || + (priv->wifi_version[0] == 'V')) { + priv->exist_flag |= 1 << READ_WIFI_VERSION; + printk("get wifi version %.2s\n", priv->wifi_version); + } else { + printk("Do not find XO cali value in factory, mark is %.2s\n", + priv->wifi_version); + return 0; + } + + // get wifi info + if ((ret = get_value_through_mtd(np, "mtd-wifi-info", 0, WIFI_INFO_SIZE, + priv->wifi_info))) + printk("get wifi info through mtd failed! ret %d\n", ret); + /* XO value is the first two bytes in wifi_info */ + priv->exist_flag |= (1 << READ_RF_XO_CONFIG); + priv->exist_flag |= (1 << READ_WIFI_INFO); + + // RM#9069 get cooling temp + if ((ret = get_value_through_mtd(np, "mtd-cooling-temp", 0, COOLING_TEMP_SIZE, + priv->cooling_temp))) + printk("get cooling temp through mtd failed! ret %d\n", ret); + + priv->exist_flag |= (1 << READ_COOLING_TEMP); + + return 0; +} + +int sf_get_value_from_factory(enum sfax8_factory_read_action action, + void *buffer, + int len) +{ + int length = len; + if (!buffer) { + printk("buffer is null\n"); + return -1; + } + switch (action) { + case READ_MAC_ADDRESS: + if (!(f_read_ctx->exist_flag & (1 << READ_MAC_ADDRESS))) { + printk("Can not find mac address!\n"); + return -2; + } + if (len > MACADDR_SIZE) { + length = MACADDR_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->macaddr, length); + break; + case READ_WAN_MAC_ADDRESS: + if (!(f_read_ctx->exist_flag & (1 << READ_MAC_ADDRESS))) { + printk("Can not find mac address!\n"); + return -2; + } + if (len > MACADDR_SIZE) { + length = MACADDR_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->wan_macaddr, length); + break; + case READ_WIFI_LB_MAC_ADDRESS: + if (!(f_read_ctx->exist_flag & (1 << READ_MAC_ADDRESS))) { + printk("Can not find mac address!\n"); + return -2; + } + if (len > MACADDR_SIZE) { + length = MACADDR_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->wifi_lb_macaddr, length); + break; + case READ_WIFI_HB_MAC_ADDRESS: + if (!(f_read_ctx->exist_flag & (1 << READ_MAC_ADDRESS))) { + printk("Can not find mac address!\n"); + return -2; + } + if (len > MACADDR_SIZE) { + length = MACADDR_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->wifi_hb_macaddr, length); + break; + case READ_SN: + if (!(f_read_ctx->exist_flag & (1 << READ_SN))) { + printk("Can not find sn number!\n"); + return -2; + } + if (len > SN_SIZE) { + length = SN_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->sn, length); + break; + case READ_SN_FLAG: + if (!(f_read_ctx->exist_flag & (1 << READ_SN_FLAG))) { + printk("Can not find sn flag!\n"); + return -2; + } + if (len > SN_FLAG_SIZE) { + length = SN_FLAG_SIZE; + printk("Your length is larger than max %d\n", length); + } + *(unsigned char *)buffer = f_read_ctx->sn_flag; + break; + case READ_PCBA_BOOT: + if (!(f_read_ctx->exist_flag & (1 << READ_PCBA_BOOT))) { + printk("Can not find pcab boot mark!\n"); + return -2; + } + if (len > PCBA_BOOT_SIZE) { + length = PCBA_BOOT_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->pcba_boot, length); + break; + case READ_HARDWARE_VER_FLAG: + if (!(f_read_ctx->exist_flag & (1 << READ_HARDWARE_VER_FLAG))) { + printk("Can not find hardware version flag!\n"); + return -2; + } + if (len > HARDWARE_VER_FLAG_SIZE) { + length = HARDWARE_VER_FLAG_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->hw_ver_flag, length); + break; + case READ_HARDWARE_VER: + if (!(f_read_ctx->exist_flag & (1 << READ_HARDWARE_VER))) { + printk("Can not find hardware version!\n"); + return -2; + } + if (len > HARDWARE_VER_SIZE) { + length = HARDWARE_VER_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->hw_ver, length); + break; + case READ_MODEL_VER_FLAG: + if (!(f_read_ctx->exist_flag & (1 << READ_MODEL_VER_FLAG))) { + printk("Can not find model version flag!\n"); + return -2; + } + if (len > MODEL_VER_FLAG_SIZE) { + length = MODEL_VER_FLAG_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->model_ver_flag, length); + break; + case READ_MODEL_VER: + if (!(f_read_ctx->exist_flag & (1 << READ_MODEL_VER))) { + printk("Can not find model version!\n"); + return -2; + } + if (len > MODEL_VER_SIZE) { + length = MODEL_VER_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->model_ver, length); + break; + case READ_COUNTRY_ID: + if (!(f_read_ctx->exist_flag & (1 << READ_COUNTRY_ID))) { + printk("Can not find country id!\n"); + return -2; + } + if (len > COUNTRYID_SIZE) { + length = COUNTRYID_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->countryID, length); + break; + case READ_HW_FEATURE: + if (!(f_read_ctx->exist_flag & (1 << READ_HW_FEATURE))) { + printk("Can not find hw feature!\n"); + return -2; + } + if (len > HW_FEATURE_SIZE) { + length = HW_FEATURE_SIZE; + printk("Your length is larger than max %d\n", length); + } + *(unsigned int *)buffer = f_read_ctx->hw_feature; + break; + case READ_VENDER_FLAG: + if (!(f_read_ctx->exist_flag & (1 << READ_VENDER_FLAG))) { + printk("Can not find vender flag!\n"); + return -2; + } + if (len > VENDER_FLAG_SIZE) { + length = VENDER_FLAG_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->vender_flag, length); + break; + case READ_VENDER: + if (!(f_read_ctx->exist_flag & (1 << READ_VENDER))) { + printk("Can not find vender!\n"); + return -2; + } + if (len > VENDER_SIZE) { + length = VENDER_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->vender, length); + break; + case READ_PRODUCT_KEY_FLAG: + if (!(f_read_ctx->exist_flag & (1 << READ_PRODUCT_KEY_FLAG))) { + printk("Can not find product key flag!\n"); + return -2; + } + if (len > PRODUCT_KEY_FLAG_SIZE) { + length = PRODUCT_KEY_FLAG_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->product_key_flag, length); + break; + case READ_PRODUCT_KEY: + if (!(f_read_ctx->exist_flag & (1 << READ_PRODUCT_KEY))) { + printk("Can not find product key!\n"); + return -2; + } + if (len > PRODUCT_KEY_SIZE) { + length = PRODUCT_KEY_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->product_key, length); + break; + case READ_LOGIN_INFO_FLAG: + if (!(f_read_ctx->exist_flag & (1 << READ_LOGIN_INFO_FLAG))) { + printk("Can not find log info flag!\n"); + return -2; + } + if (len > LOGIN_INFO_FLAG_SIZE) { + length = LOGIN_INFO_FLAG_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->login_info_flag, length); + break; + case READ_LOGIN_INFO: + if (!(f_read_ctx->exist_flag & (1 << READ_LOGIN_INFO))) { + printk("Can not find login info!\n"); + return -2; + } + if (len > LOGIN_INFO_SIZE) { + length = LOGIN_INFO_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, &f_read_ctx->login_info, length); + break; + case READ_ROM_TYPE_FLAG: + if (!(f_read_ctx->exist_flag & (1 << READ_ROM_TYPE_FLAG))) { + printk("Can not find rom type flag!\n"); + return -2; + } + if (len > ROM_TYPE_FLAG_SIZE) { + length = ROM_TYPE_FLAG_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->rom_type_flag, length); + break; + case READ_ROM_TYPE: + if (!(f_read_ctx->exist_flag & (1 << READ_ROM_TYPE))) { + printk("Can not find rom type!\n"); + return -2; + } + if (len > ROM_TYPE_SIZE) { + length = ROM_TYPE_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, &f_read_ctx->rom_type, length); + break; + case READ_WIFI_VERSION: + if (!(f_read_ctx->exist_flag & (1 << READ_WIFI_VERSION))) { + printk("Can not find wifi version!\n"); + return -2; + } + if (len > WIFI_VERSION_SIZE) { + length = WIFI_VERSION_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->wifi_version, length); + break; + case READ_WIFI_INFO: + if (!(f_read_ctx->exist_flag & (1 << READ_WIFI_INFO))) { + printk("Can not find wifi info!\n"); + return -2; + } + if (len > WIFI_INFO_SIZE) { + length = WIFI_INFO_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->wifi_info, length); + break; + case READ_RF_XO_CONFIG: + if (!(f_read_ctx->exist_flag & (1 << READ_RF_XO_CONFIG))) { + printk("Can not find XO config!\n"); + return -2; + } + if (len > XO_CONFIG_SIZE) { + length = XO_CONFIG_SIZE; + printk("Your length is larger than max %d\n", length); + } + /* XO value is the first two bytes of wifi_info */ + memcpy(buffer, f_read_ctx->wifi_info, length); + break; + case READ_COOLING_TEMP: + if (!(f_read_ctx->exist_flag & (1 << READ_COOLING_TEMP))) { + printk("Can not find cooling temperature!\n"); + return -2; + } + if (len > COOLING_TEMP_SIZE) { + length = COOLING_TEMP_SIZE; + printk("Your length is larger than max %d\n", length); + } + memcpy(buffer, f_read_ctx->cooling_temp, length); + break; + default: + printk("unknow action %d\n", action); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sf_get_value_from_factory); + +static int sfax8_factory_read_os_resources_get(struct platform_device *pdev, + struct sfax8_factory_read_context **p_priv) +{ + struct sfax8_factory_read_context *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, + sizeof(struct sfax8_factory_read_context), GFP_KERNEL); + if (!priv) { + printk("can not allocate memory!\n"); + ret = -ENOMEM; + return ret; + } + + priv->np = pdev->dev.of_node; + *p_priv = priv; + f_read_ctx = priv; + platform_set_drvdata(pdev, priv); + return 0; +} + +static int sfax8_factory_read_os_resources_free(struct platform_device *pdev, struct sfax8_factory_read_context *priv) +{ + devm_kfree(&pdev->dev, priv); + f_read_ctx = NULL; + return 0; +} + +/* + * * func:this is sfax8_factory_read module's probe function, it's do the following things: + * 1,set the private data to the platform drivers + * 2,copy value from factory + * 3,create the dbg fs node + * params: struct platform_device *pdev + * return: + * 0 means successful, otherwise failed + * */ +int sfax8_factory_read_probe(struct platform_device *pdev) +{ + int ret = 0; + struct sfax8_factory_read_context *priv; + printk("%s...\n", __func__); + /*Step1:set the platform priv data*/ + if((ret = sfax8_factory_read_os_resources_get(pdev, &priv))){ + printk("sfax8_factory_read_os_resources_get failed, %d!\n", ret); + return ret; + } + /*Step2:copy value from factory*/ + if((ret = save_value_from_factory_to_host(pdev, priv))){ + printk("save_value_from_factory_to_host failed, %d!\n", ret); + goto ERROR; + } +#ifdef CONFIG_SF16A18_FACTORY_READ_SYSFS_DEBUG + /*Step3:create the dbg fs node*/ + if((ret = sf_factory_read_sysfs_register(pdev, "sfax8_factory_read"))){ + printk("save_value_from_factory_to_host failed, %d!\n", ret); + goto ERROR; + } +#endif + return 0; +ERROR: + sfax8_factory_read_os_resources_free(pdev, priv); + return ret; +} + + +int sfax8_factory_read_remove(struct platform_device *pdev) +{ + struct sfax8_factory_read_context *priv; + printk("%s...\n", __func__); + priv = (struct sfax8_factory_read_context *)platform_get_drvdata(pdev); + +#ifdef CONFIG_SF16A18_FACTORY_READ_SYSFS_DEBUG + sf_factory_read_sysfs_unregister(pdev); +#endif + sfax8_factory_read_os_resources_free(pdev, priv); + return 0; +} + +/* *********************************************************************Register Platform Drivers******************************************************/ +static const struct of_device_id sfax8_factory_read_of_match[] = { + { + .compatible = "siflower,sfax8-factory-read", + }, + {}, +}; + +static struct platform_driver sfax8_factory_read_driver = { + .probe = sfax8_factory_read_probe, + .remove = sfax8_factory_read_remove, + .driver = { + .name = "sfax8_factory_read", + .of_match_table = sfax8_factory_read_of_match, + }, +}; + +static int __init sfax8_factory_read_init(void) +{ + return platform_driver_register(&sfax8_factory_read_driver); +} + +static void __exit sfax8_factory_read_exit(void) +{ + platform_driver_unregister(&sfax8_factory_read_driver); +} + +module_init(sfax8_factory_read_init); +module_exit(sfax8_factory_read_exit); + +MODULE_AUTHOR("Zhengjinyang Jiang "); +MODULE_DESCRIPTION("Get value from factory"); +MODULE_LICENSE("GPL"); diff --git a/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_pl_ref.h b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_pl_ref.h new file mode 100755 index 0000000..5fb5204 --- /dev/null +++ b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_pl_ref.h @@ -0,0 +1,64 @@ +/* + * ===================================================================================== + * + * Filename: sf_factory_read_pl_ref.h + * + * Description: all statement reference with the platform are defined here + * Version: 1.0 + * Created: 12/30/2016 02:34:36 PM + * Revision: none + * Compiler: gcc + * + * Author: franklin (), franklin.wang@siflower.com.cn + * Company: Siflower Communication Tenology Co.,Ltd + * + * ===================================================================================== + */ + +#ifndef _SF_FFACTORY_READ_PL_REF_H_ +#define _SF_FFACTORY_READ_PL_REF_H_ + +#include +#include "sfax8_factory_read.h" + +//SF factory_read PRIVATE PLATFORM DRIVER DATA +struct sfax8_factory_read_context { + //main lan eth macaddr + unsigned char macaddr[MACADDR_SIZE]; + unsigned char sn[SN_SIZE]; + unsigned char sn_flag; + unsigned char pcba_boot[PCBA_BOOT_SIZE]; + unsigned char hw_ver_flag[HARDWARE_VER_FLAG_SIZE]; + unsigned char hw_ver[HARDWARE_VER_SIZE]; + unsigned char model_ver_flag[MODEL_VER_FLAG_SIZE]; + unsigned char model_ver[MODEL_VER_SIZE]; + unsigned char countryID[COUNTRYID_SIZE]; + uint32_t hw_feature; + unsigned char vender_flag[VENDER_FLAG_SIZE]; + unsigned char vender[VENDER_SIZE]; + unsigned char product_key_flag[PRODUCT_KEY_FLAG_SIZE]; + unsigned char product_key[PRODUCT_KEY_SIZE]; + unsigned char login_info_flag[LOGIN_INFO_FLAG_SIZE]; + uint32_t login_info; + unsigned char rom_type_flag[ROM_TYPE_FLAG_SIZE]; + uint32_t rom_type; + unsigned char wifi_version[WIFI_VERSION_SIZE]; + unsigned char wifi_info[WIFI_INFO_SIZE]; + unsigned int exist_flag; + bool cali_exist; + unsigned char wifi_lb_macaddr[MACADDR_SIZE]; + unsigned char wifi_hb_macaddr[MACADDR_SIZE]; + unsigned char wan_macaddr[MACADDR_SIZE]; + unsigned char macaddr0[MACADDR_SIZE]; + unsigned char cooling_temp[COOLING_TEMP_SIZE]; + + //the debug fs root node + struct dentry *debugfs; + + //the fs root node + uint32_t start_offset; + uint32_t len; + + struct device_node *np; +}; +#endif diff --git a/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.c b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.c new file mode 100755 index 0000000..fa7369b --- /dev/null +++ b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.c @@ -0,0 +1,610 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "sfax8_factory_read.h" + +#include "sf_factory_read_sysfs.h" +#include "sf_factory_read_pl_ref.h" + +/* some macros taken from iwlwifi */ +#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ + if (!debugfs_create_file(#name, mode, parent, fr_ctx, \ + &sf_factory_read_dbgfs_##name##_ops)) \ + goto err; \ +} while (0) + +#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ +} while (0) + +#define DEBUGFS_ADD_X64(name, parent, ptr) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_x64(#name, S_IWUSR | S_IRUSR, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ +} while (0) + +#define DEBUGFS_ADD_U64(name, parent, ptr, mode) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_u64(#name, mode, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ +} while (0) + +#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ +} while (0) + +#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_u32(#name, mode, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ +} while (0) + +/* file operation */ +#define DEBUGFS_READ_FUNC(name) \ + static ssize_t sf_factory_read_dbgfs_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos); + +#define DEBUGFS_WRITE_FUNC(name) \ + static ssize_t sf_factory_read_dbgfs_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos); + + +#define DEBUGFS_READ_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ +static const struct file_operations sf_factory_read_dbgfs_##name##_ops = { \ + .read = sf_factory_read_dbgfs_##name##_read, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +}; + +#define DEBUGFS_WRITE_FILE_OPS(name) \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations sf_factory_read_dbgfs_##name##_ops = { \ + .write = sf_factory_read_dbgfs_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +}; + + +#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations sf_factory_read_dbgfs_##name##_ops = { \ + .write = sf_factory_read_dbgfs_##name##_write, \ + .read = sf_factory_read_dbgfs_##name##_read, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +}; + +#define MACADDR_HDR "macaddress : %2x %2x %2x %2x %2x %2x\n" +#define MACADDR_HDR_MAX_LEN (sizeof(MACADDR_HDR) + 16) + +#define SN_HDR "SN : %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n" +#define SN_HDR_MAX_LEN (sizeof(SN_HDR) + 16) + +#define SN_FLAG_HDR "SN flag: %2x\n" +#define SN_FLAG_HDR_MAX_LEN (sizeof(SN_FLAG_HDR) + 16) + +#define PCBA_BOOT_HDR "PCBA value : %.4s\n" +#define PCBA_BOOT_HDR_MAX_LEN (sizeof(PCBA_BOOT_HDR) + 16) + +#define COUNTRYID_HDR "Country ID : %.2s\n" +#define COUNTRYID_HDR_MAX_LEN (sizeof(COUNTRYID_HDR) + 16) + +#define HW_VER_HDR "Hardware version : %.32s\n" +#define HW_VER_HDR_MAX_LEN (sizeof(HW_VER_HDR) + 16) + +#define HW_FEATURE_HDR "Hardware feature : %#x\n" +#define HW_FEATURE_HDR_MAX_LEN (sizeof(HW_FEATURE_HDR) + 16) + +#define EXIST_HDR "Exist flag : %8x\n" +#define EXIST_HDR_MAX_LEN (sizeof(EXIST_HDR) + 16) + +extern int get_value_through_mtd(struct device_node *np,const char *name, int start_offset, size_t len, unsigned char *buffer); + +static ssize_t sf_factory_read_dbgfs_stats_read(struct file *file, + char __user *user_buf, + size_t count, + loff_t *ppos) +{ + struct sfax8_factory_read_context *fr_ctx = file->private_data; + char *buf; + int res; + ssize_t read; + size_t bufsz = (MACADDR_HDR_MAX_LEN + SN_HDR_MAX_LEN + + SN_FLAG_HDR_MAX_LEN + COUNTRYID_HDR_MAX_LEN + + EXIST_HDR_MAX_LEN + + HW_VER_HDR_MAX_LEN + HW_FEATURE_HDR_MAX_LEN); + + /*everything is read out in one go*/ + if (*ppos) + return 0; + if (!fr_ctx) + return 0; + + bufsz = min_t(size_t, bufsz, count); + buf = kzalloc(bufsz, GFP_ATOMIC); + if (buf == NULL) + return 0; + + bufsz--; + + res = scnprintf(buf, bufsz, MACADDR_HDR SN_HDR COUNTRYID_HDR HW_VER_HDR + HW_FEATURE_HDR "\n", + fr_ctx->macaddr[0], fr_ctx->macaddr[1], + fr_ctx->macaddr[2], fr_ctx->macaddr[3], + fr_ctx->macaddr[4], fr_ctx->macaddr[5], fr_ctx->sn[0], + fr_ctx->sn[1], fr_ctx->sn[2], fr_ctx->sn[3], + fr_ctx->sn[4], fr_ctx->sn[5], fr_ctx->sn[6], + fr_ctx->sn[7], fr_ctx->sn[8], fr_ctx->sn[9], + fr_ctx->sn[10], fr_ctx->sn[11], fr_ctx->sn[12], + fr_ctx->sn[13], fr_ctx->sn[14], fr_ctx->sn[15], + fr_ctx->countryID, fr_ctx->hw_ver, fr_ctx->hw_feature); + + read = simple_read_from_buffer(user_buf, count, ppos, buf, res); + kfree(buf); + + return read; +} +DEBUGFS_READ_FILE_OPS(stats); + +static ssize_t sf_factory_read_dbgfs_memory_read(struct file *file, + char __user *user_buf, + size_t count, + loff_t *ppos) +{ + struct sfax8_factory_read_context *fr_ctx = file->private_data; + char *buf; + unsigned char *data; + int res, i; + ssize_t read; + size_t bufsz; + + /*everything is read out in one go*/ + if(*ppos) + return 0; + if(!fr_ctx) + return 0; + if((!fr_ctx->start_offset) && (!fr_ctx->len)){ + printk("do not find start point and length!\n"); + return 0; + } + + bufsz = 16; + + buf = kzalloc(fr_ctx->len, GFP_ATOMIC); + if(buf == NULL) + return 0; + + res = 0; + data = kzalloc(fr_ctx->len, GFP_ATOMIC); + if(data == NULL){ + printk("data is null!\n"); + } + + if(fr_ctx->np == NULL){ + printk("device node is null!\n"); + return 0; + } + + get_value_through_mtd(NULL, NULL, fr_ctx->start_offset, fr_ctx->len, data); + for(i = 0; i < fr_ctx->len; i++){ + res += scnprintf(&buf[res], min_t(size_t, bufsz - 1, count - res), + "[%d]:%x\n", i, data[i]); + } + + read = simple_read_from_buffer(user_buf, count, ppos, buf, res); + kfree(data); + kfree(buf); + + return read; +} +DEBUGFS_READ_FILE_OPS(memory); + +static ssize_t sf_factory_read_dbgfs_start_len_read(struct file *file, + char __user *user_buf, + size_t count, + loff_t *ppos) +{ + struct sfax8_factory_read_context *fr_ctx = file->private_data; + char *buf; + int res; + ssize_t read; + size_t bufsz = 32; + /*everything is read out in one go*/ + if(*ppos) + return 0; + if(!fr_ctx) + return 0; + + bufsz = min_t(size_t, bufsz, count); + buf = kmalloc(bufsz, GFP_ATOMIC); + if(buf == NULL) + return 0; + + bufsz--; + + res = scnprintf(buf, bufsz, "start:%d len:%d\n", fr_ctx->start_offset, fr_ctx->len); + + read = simple_read_from_buffer(user_buf, count, ppos, buf, res); + kfree(buf); + + return read; +} + +static ssize_t sf_factory_read_dbgfs_start_len_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct sfax8_factory_read_context *fr_ctx = file->private_data; + + char buf[32]; + int val,length; + size_t len = min_t(size_t, count, sizeof(buf) - 1); + + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + if(!fr_ctx) + return -EFAULT; + + buf[len] = '\0'; + + if (sscanf(buf, "%d %d", &val, &length)){ + printk("%d %d\n",val,length); + fr_ctx->start_offset = val; + fr_ctx->len = length; + }else{ + printk("can not sscanf the buf!\n"); + return -EFAULT; + } + + return count; +} +DEBUGFS_READ_WRITE_FILE_OPS(start_len); + +static ssize_t sf_factory_read_countryid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + + return sprintf(buf, "%c%c\n",fr_ctx->countryID[0], fr_ctx->countryID[1]); +} + +static ssize_t sf_factory_read_macaddr_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n",fr_ctx->macaddr[0], fr_ctx->macaddr[1], fr_ctx->macaddr[2],\ + fr_ctx->macaddr[3],fr_ctx->macaddr[4], fr_ctx->macaddr[5]); +} + +static ssize_t sf_factory_read_macaddr0_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n",fr_ctx->macaddr0[0], fr_ctx->macaddr0[1], fr_ctx->macaddr0[2],\ + fr_ctx->macaddr0[3],fr_ctx->macaddr0[4], fr_ctx->macaddr0[5]); +} + +static ssize_t sf_factory_read_macaddr_wan_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n",fr_ctx->wan_macaddr[0], fr_ctx->wan_macaddr[1], fr_ctx->wan_macaddr[2],\ + fr_ctx->wan_macaddr[3],fr_ctx->wan_macaddr[4], fr_ctx->wan_macaddr[5]); +} + +static ssize_t sf_factory_read_macaddr_lb_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n",fr_ctx->wifi_lb_macaddr[0], fr_ctx->wifi_lb_macaddr[1], fr_ctx->wifi_lb_macaddr[2],\ + fr_ctx->wifi_lb_macaddr[3],fr_ctx->wifi_lb_macaddr[4], fr_ctx->wifi_lb_macaddr[5]); +} + +static ssize_t sf_factory_read_macaddr_hb_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n",fr_ctx->wifi_hb_macaddr[0], fr_ctx->wifi_hb_macaddr[1], fr_ctx->wifi_hb_macaddr[2],\ + fr_ctx->wifi_hb_macaddr[3],fr_ctx->wifi_hb_macaddr[4], fr_ctx->wifi_hb_macaddr[5]); +} + +static ssize_t sf_factory_read_sn_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n",\ + fr_ctx->sn[0], fr_ctx->sn[1], fr_ctx->sn[2],fr_ctx->sn[3],\ + fr_ctx->sn[4], fr_ctx->sn[5], fr_ctx->sn[6], fr_ctx->sn[7],\ + fr_ctx->sn[8], fr_ctx->sn[9],fr_ctx->sn[10], fr_ctx->sn[11],\ + fr_ctx->sn[12], fr_ctx->sn[13],fr_ctx->sn[14], fr_ctx->sn[15]); +} + +static ssize_t sf_factory_read_sn_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "0x%02x\n",fr_ctx->sn_flag); +} + +static ssize_t sf_factory_read_hw_ver_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + + return sprintf(buf, "%.2s\n", fr_ctx->hw_ver_flag); +} + +static ssize_t sf_factory_read_hw_ver_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.32s\n", fr_ctx->hw_ver); +} + +static ssize_t sf_factory_read_model_ver_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.2s\n", fr_ctx->model_ver_flag); +} + +static ssize_t sf_factory_read_model_ver_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.32s\n", fr_ctx->model_ver); +} + +static ssize_t sf_factory_read_vender_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.2s\n", fr_ctx->vender_flag); +} + +static ssize_t sf_factory_read_vender_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.16s\n", fr_ctx->vender); +} + +static ssize_t sf_factory_read_product_key_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.2s\n", fr_ctx->product_key_flag); +} + +static ssize_t sf_factory_read_login_info_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%#x\n", fr_ctx->login_info); +} + +static ssize_t sf_factory_read_login_info_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.2s\n", fr_ctx->login_info_flag); +} + +static ssize_t sf_factory_read_rom_type_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%#x\n", fr_ctx->rom_type); +} + +static ssize_t sf_factory_read_rom_type_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.2s\n", fr_ctx->rom_type_flag); +} + +static ssize_t sf_factory_read_product_key_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%.32s\n", fr_ctx->product_key); +} +static ssize_t sf_factory_read_hw_feature_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sfax8_factory_read_context *fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata(to_platform_device(dev)); + if (!fr_ctx) { + printk("fr_ctx is null!!!\n"); + return 0; + } + return sprintf(buf, "%#x\n",fr_ctx->hw_feature); +} + +static DEVICE_ATTR(countryid, S_IRUSR, sf_factory_read_countryid_show, NULL); +static DEVICE_ATTR(macaddr, S_IRUSR, sf_factory_read_macaddr_show, NULL); +static DEVICE_ATTR(macaddr_wan, S_IRUSR, sf_factory_read_macaddr_wan_show, NULL); +static DEVICE_ATTR(macaddr_lb, S_IRUSR, sf_factory_read_macaddr_lb_show, NULL); +static DEVICE_ATTR(macaddr_hb, S_IRUSR, sf_factory_read_macaddr_hb_show, NULL); +static DEVICE_ATTR(macaddr0, S_IRUSR, sf_factory_read_macaddr0_show, NULL); +static DEVICE_ATTR(sn, S_IRUSR, sf_factory_read_sn_show, NULL); +static DEVICE_ATTR(sn_flag, S_IRUSR, sf_factory_read_sn_flag_show, NULL); +static DEVICE_ATTR(hw_ver_flag, S_IRUSR, sf_factory_read_hw_ver_flag_show, NULL); +static DEVICE_ATTR(hw_ver, S_IRUSR, sf_factory_read_hw_ver_show, NULL); +static DEVICE_ATTR(model_ver_flag, S_IRUSR, sf_factory_read_model_ver_flag_show, NULL); +static DEVICE_ATTR(model_ver, S_IRUSR, sf_factory_read_model_ver_show, NULL); +static DEVICE_ATTR(hw_feature, S_IRUSR, sf_factory_read_hw_feature_show, NULL); +static DEVICE_ATTR(vender_flag, S_IRUSR, sf_factory_read_vender_flag_show, NULL); +static DEVICE_ATTR(vender, S_IRUSR, sf_factory_read_vender_show, NULL); +static DEVICE_ATTR(product_key_flag, S_IRUSR, sf_factory_read_product_key_flag_show, NULL); +static DEVICE_ATTR(product_key, S_IRUSR, sf_factory_read_product_key_show, NULL); +static DEVICE_ATTR(login_info_flag, S_IRUSR, sf_factory_read_login_info_flag_show, NULL); +static DEVICE_ATTR(login_info, S_IRUSR, sf_factory_read_login_info_show, NULL); +static DEVICE_ATTR(rom_type_flag, S_IRUSR, sf_factory_read_rom_type_flag_show, NULL); +static DEVICE_ATTR(rom_type, S_IRUSR, sf_factory_read_rom_type_show, NULL); + +static struct attribute *factory_read_attr[] = { + &dev_attr_countryid.attr, + &dev_attr_macaddr.attr, + &dev_attr_macaddr_wan.attr, + &dev_attr_macaddr_lb.attr, + &dev_attr_macaddr_hb.attr, + &dev_attr_macaddr0.attr, + &dev_attr_sn.attr, + &dev_attr_sn_flag.attr, + &dev_attr_hw_ver_flag.attr, + &dev_attr_hw_ver.attr, + &dev_attr_model_ver_flag.attr, + &dev_attr_model_ver.attr, + &dev_attr_hw_feature.attr, + &dev_attr_vender_flag.attr, + &dev_attr_vender.attr, + &dev_attr_product_key_flag.attr, + &dev_attr_product_key.attr, + &dev_attr_login_info_flag.attr, + &dev_attr_login_info.attr, + &dev_attr_rom_type_flag.attr, + &dev_attr_rom_type.attr, + NULL, +}; + +static const struct attribute_group factory_read_attribute_group = { + .attrs = factory_read_attr, +}; + +int sf_factory_read_sysfs_register(struct platform_device *pdev, char *parent) +{ + struct sfax8_factory_read_context *fr_ctx; + struct dentry *dir_drv; + + fr_ctx = (struct sfax8_factory_read_context *)platform_get_drvdata( + pdev); + // 1.register debugfs + printk("%s, parent :%s\n", __func__, + (parent == NULL) ? "NULL" : parent); + if (!parent) + dir_drv = debugfs_create_dir("sfax8_factory_read", NULL); + else + dir_drv = debugfs_create_dir(parent, NULL); + if (!dir_drv) { + printk("debug fs create directory failed!\n"); + goto err; + } + fr_ctx->debugfs = dir_drv; + + DEBUGFS_ADD_FILE(stats, dir_drv, S_IRUSR); + DEBUGFS_ADD_FILE(memory, dir_drv, S_IRUSR); + DEBUGFS_ADD_FILE(start_len, dir_drv, S_IWUSR | S_IRUSR); + // 2.register sysfs + return sysfs_create_group( + &(pdev->dev.kobj), &factory_read_attribute_group); + +err: + if (dir_drv) + debugfs_remove_recursive(dir_drv); + fr_ctx->debugfs = NULL; + return -1; +} + +int sf_factory_read_sysfs_unregister(struct platform_device *pdev) +{ + struct sfax8_factory_read_context *fr_ctx = + (struct sfax8_factory_read_context *) + platform_get_drvdata(pdev); + if (fr_ctx == NULL) { + printk("invalid platform driver private data!\n"); + return -1; + } + if (!fr_ctx->debugfs) { + printk("already removed!\n"); + return -2; + } + debugfs_remove_recursive(fr_ctx->debugfs); + + sysfs_remove_group(&(pdev->dev.kobj), &factory_read_attribute_group); + return 0; +} diff --git a/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.h b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.h new file mode 100755 index 0000000..7f7eb15 --- /dev/null +++ b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sf_factory_read_sysfs.h @@ -0,0 +1,45 @@ + +/* + * ===================================================================================== + * + * Filename: rf_sysfs.h + * + * Description: this is used for system debug fs for rf, this functions will be implemented: + * 1,read/write rf register + * 2,force to do calibrations and get the calibration data + * 3,how many bandband are successfully registered + * + * + * Version: 1.0 + * Created: 11/7/2018 09:42:52 AM + * Revision: none + * Compiler: gcc + * + * Author: star , star.jiang@siflower.com.cn + * Company: Siflower Communication Tenology Co.,Ltd + * + * ===================================================================================== + */ +#ifndef _FACTORY_READ_SYSFS_H_ +#define _FACTORY_READ_SYSFS_H_ +#include + +/*func: + * create a sysfs debug node with a specified parent node + * if the parent is not exsit, just create it + * params: + * struct platform_driver *pdev + * char *parent + * return: + * 0 successful, otherwise failed + **/ +int sf_factory_read_sysfs_register(struct platform_device *pdev, char *parent); + +/*func: + * destroy the sysfs created + * params: + * struct platform_driver *pdev + * + **/ +int sf_factory_read_sysfs_unregister(struct platform_device *pdev); +#endif diff --git a/openwrt-18.06/package/kernel/sfax8-factory-read/src/sfax8_factory_read.h b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sfax8_factory_read.h new file mode 100755 index 0000000..5e1c4ae --- /dev/null +++ b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sfax8_factory_read.h @@ -0,0 +1,117 @@ +/* + * ===================================================================================== + * + * Filename: sfax8_factory_read.h + * + * Description: + * + * Version: 1.0 + * Created: 2018年11月05日 20时22分03秒 + * Revision: none + * Compiler: gcc + * + * Author: star (), star.jiang@siflower.com.cn + * Company: Siflower + * + * ===================================================================================== + */ +#ifndef _SFAX8_FACTORY_READ_H_ +#define _SFAX8_FACTORY_READ_H_ + +//size unit: BYTE +#define MACADDR_SIZE 6 +#define SN_SIZE 16 +#define SN_FLAG_SIZE 1 +#define PCBA_BOOT_SIZE 4 +#define HARDWARE_VER_FLAG_SIZE 2 +#define HARDWARE_VER_SIZE 32 +#define MODEL_VER_FLAG_SIZE 2 +#define MODEL_VER_SIZE 32 +#define COUNTRYID_SIZE 2 +#define HW_FEATURE_SIZE 4 +#define VENDER_FLAG_SIZE 2 +#define VENDER_SIZE 16 +#define PRODUCT_KEY_FLAG_SIZE 2 +#define PRODUCT_KEY_SIZE 32 +#define LOGIN_INFO_FLAG_SIZE 2 +#define LOGIN_INFO_SIZE 4 +#define ROM_TYPE_FLAG_SIZE 2 +#define ROM_TYPE_SIZE 4 +#define WIFI_VERSION_SIZE 2 +#define WIFI_INFO_SIZE 2046 +#define XO_CONFIG_SIZE 2 +#define COOLING_TEMP_SIZE 4 +/** +* @name HW feature definitions +*
+*   Bits	Name		Value
+*  --------------------------------
+*  31:02				Reserved
+*  --------------------------------
+*  02	 HOTSINK_EXIST	1->hw has hotsink
+*						0->no hotsink
+*  --------------------------------
+*  01	 32K_BY_GPIO	1->hw connect GPIO to 32k low power pin
+*						0->no this connection
+*  --------------------------------
+*  00	 32K_BY_PMU		1->hw could provide 32K low power clock by PMU or by external CLK
+*						0->can not provide
+* 
+*/ +// field definitions +//32K_BY_PMU field mask +#define HW_FEATURE_32K_BY_PMU_MASK ((uint32_t)0x00000001) +//32K_BY_PMU LSB position +#define HW_FEATURE_32K_BY_PMU_LSB 0 +//32K_BY_GPIO field mask +#define HW_FEATURE_32K_BY_GPIO_MASK ((uint32_t)0x00000002) +//32K_BY_GPIO LSB position +#define HW_FEATURE_32K_BY_GPIO_LSB 1 +//HOTSINK_EXISTfield mask +#define HW_FEATURE_HOTSINK_EXIST_MASK ((uint32_t)0x00000004) +//HOTSINK_EXIST LSB position +#define HW_FEATURE_HOTSINK_EXIST_LSB 2 + +/*@name login info definitions + * + * Bits Name Value + * 0 telnetd 0->enable telnetd, 1->disable it + * 1 ssh 0->disable ssh, 1->enable it (haven't accomplished now) + * 2 serial port 0->disable serial port, 1->disable it (haven't accomplished now)) + * + * */ + +enum sfax8_factory_read_action { + //for eth basic address + READ_MAC_ADDRESS, + //for wifi lb basic address + READ_WIFI_LB_MAC_ADDRESS, + //for wifi hb bsic address + READ_WIFI_HB_MAC_ADDRESS, + //for wan basic address + READ_WAN_MAC_ADDRESS, + READ_SN, + READ_SN_FLAG, + READ_PCBA_BOOT, + READ_HARDWARE_VER_FLAG, + READ_HARDWARE_VER, + READ_MODEL_VER_FLAG, + READ_MODEL_VER, + READ_COUNTRY_ID, + READ_HW_FEATURE, + READ_VENDER_FLAG, + READ_VENDER, + READ_PRODUCT_KEY_FLAG, + READ_PRODUCT_KEY, + READ_LOGIN_INFO_FLAG, + READ_LOGIN_INFO, + READ_ROM_TYPE_FLAG, + READ_ROM_TYPE, + READ_WIFI_VERSION, + READ_RF_XO_CONFIG, + READ_WIFI_INFO, + READ_COOLING_TEMP, +}; + +int sf_get_value_from_factory(enum sfax8_factory_read_action action, void *buffer, int len); +#endif diff --git a/openwrt-18.06/package/kernel/sfax8-factory-read/src/sfax8_factory_read.ko b/openwrt-18.06/package/kernel/sfax8-factory-read/src/sfax8_factory_read.ko deleted file mode 100755 index 472b735faf06792f439235eb2295c634aeff1391..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@wt&=*TuA%T?G6)M6GxY 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 ZwKRz^7T^kVX1^?S=#B1HYo=50e*@I&^?U#T -- 2.7.4