mirror of
https://github.com/FUjr/gl-infra-builder.git
synced 2025-12-16 17:15:08 +00:00
1945 lines
72 KiB
Diff
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
|
|
|