gl-infra-builder-FUjr/patches-siflower-18.x/0103-fix-sfax8-factory-read-use-source-code.patch
Yejiang Luo 05061483d8 improve siflower target
Signed-off-by: Yejiang Luo <luoyejiang@gl-inet.com>
2021-06-01 11:30:34 +08:00

1945 lines
72 KiB
Diff

From 9bccb3edd7abd721d87a336317efeef910ffef72 Mon Sep 17 00:00:00 2001
From: "GL.iNet-Xinfa.Deng" <xinfa.deng@gl-inet.com>
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 <xinfa.deng@gl-inet.com>
---
.../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 <star.jiang@siflower.com.cn>
+ *
+ * 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 <linux/string.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include "sfax8_factory_read.h"
+#include <linux/etherdevice.h>
+#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 <star.jiang@siflower.com.cn>");
+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 <linux/device.h>
+#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 <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/debugfs.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#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 <linux/platform_device.h>
+
+/*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
+* <pre>
+* 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
+* </pre>
+*/
+// 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$@<O00001
literal 27608
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
ZwKRz^7T^kVX1^?S=#B1HYo=50e*@I&^?U#T
--
2.7.4