c05564c4d8
Android 13
683 lines
18 KiB
C
Executable file
683 lines
18 KiB
C
Executable file
/* sec_nad.c
|
|
*
|
|
* Copyright (C) 2016 Samsung Electronics
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/sec_nad.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/sec_class.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/delay.h>
|
|
|
|
#define NAD_PRINT(format, ...) printk("[NAD] " format, ##__VA_ARGS__)
|
|
#define NAD_DEBUG
|
|
|
|
#define REBOOT "Reboot"
|
|
|
|
|
|
#define SMD_NAD_PROG "/system/bin/mnad/mtk_nad_exec.sh"
|
|
#define ETC_NAD_PROG "/system/bin/mnad/mtk_nad_exec.sh"
|
|
#define ERASE_NAD_PRG "/system/bin/mnad/remove_mtk_nad_files.sh"
|
|
|
|
#define SMD_NAD_RESULT "/sdcard/log/mtknad/NAD_SMD/test_result.csv"
|
|
#define ETC_NAD_RESULT "/sdcard/log/mtknad/NAD/test_result.csv"
|
|
|
|
#define SMD_NAD_LOGPATH "logPath:/sdcard/log/mtknad/NAD_SMD"
|
|
#define ETC_NAD_LOGPATH "logPath:/sdcard/log/mtknad/NAD"
|
|
|
|
struct kobj_uevent_env nad_uevent;
|
|
|
|
static void sec_nad_param_update(struct work_struct *work)
|
|
{
|
|
int ret = -1;
|
|
struct file *fp;
|
|
struct sec_nad_param *param_data = container_of(work, struct sec_nad_param, sec_nad_work);
|
|
|
|
NAD_PRINT("%s: set param at %s\n", __func__, param_data->state ? "write" : "read");
|
|
|
|
fp = filp_open(NAD_PARAM_NAME, O_RDWR | O_SYNC, 0);
|
|
if (IS_ERR(fp)) {
|
|
pr_err("%s: filp_open error %ld\n", __func__, PTR_ERR(fp));
|
|
|
|
/* Rerun workqueue when nad_refer read fail */
|
|
if(param_data->retry_cnt > param_data->curr_cnt) {
|
|
NAD_PRINT("retry count : %d\n", param_data->curr_cnt++);
|
|
schedule_delayed_work(&sec_nad_param_data.sec_nad_delay_work, HZ * 1);
|
|
}
|
|
goto complete_exit;
|
|
}
|
|
|
|
ret = fp->f_op->llseek(fp, param_data->offset, SEEK_SET);
|
|
if (ret < 0) {
|
|
pr_err("%s: llseek error %d!\n", __func__, ret);
|
|
goto close_fp_out;
|
|
}
|
|
|
|
switch(param_data->state){
|
|
case NAD_PARAM_WRITE:
|
|
ret = vfs_write(fp, (char*)&sec_nad_env, sizeof(struct nad_env), &(fp->f_pos));
|
|
|
|
NAD_PRINT("curr_step : %d\n", sec_nad_env.curr_step);
|
|
NAD_PRINT("nad_acat_remaining_count : %d\n", sec_nad_env.nad_acat_remaining_count);
|
|
NAD_PRINT("nad_dramtest_remaining_count : %d\n", sec_nad_env.nad_dramtest_remaining_count);
|
|
NAD_PRINT("nad_smd_result : %d\n", sec_nad_env.nad_smd_result);
|
|
NAD_PRINT("nad_dram_test_result : %d\n", sec_nad_env.nad_dram_test_result);
|
|
NAD_PRINT("nad_dram_fail_data : %d\n", sec_nad_env.nad_dram_fail_data);
|
|
NAD_PRINT("nad_dram_fail_address : 0x%016llx\n", sec_nad_env.nad_dram_fail_address);
|
|
|
|
if (ret < 0) pr_err("%s: write error! %d\n", __func__, ret);
|
|
break;
|
|
|
|
case NAD_PARAM_READ:
|
|
ret = vfs_read(fp, (char*)&sec_nad_env, sizeof(struct nad_env), &(fp->f_pos));
|
|
|
|
NAD_PRINT("curr_step : %d\n", sec_nad_env.curr_step);
|
|
NAD_PRINT("nad_acat_remaining_count : %d\n", sec_nad_env.nad_acat_remaining_count);
|
|
NAD_PRINT("nad_dramtest_remaining_count : %d\n", sec_nad_env.nad_dramtest_remaining_count);
|
|
NAD_PRINT("nad_smd_result : %d\n", sec_nad_env.nad_smd_result);
|
|
NAD_PRINT("nad_dram_test_result : %d\n", sec_nad_env.nad_dram_test_result);
|
|
NAD_PRINT("nad_dram_fail_data : %d\n", sec_nad_env.nad_dram_fail_data);
|
|
NAD_PRINT("nad_dram_fail_address : 0x%016llx\n", sec_nad_env.nad_dram_fail_address);
|
|
|
|
if (ret < 0) pr_err("%s: read error! %d\n", __func__, ret);
|
|
break;
|
|
}
|
|
|
|
close_fp_out:
|
|
if (fp) filp_close(fp, NULL);
|
|
complete_exit:
|
|
complete(&sec_nad_param_data.comp);
|
|
NAD_PRINT("%s: exit %d\n", __func__, ret);
|
|
return;
|
|
}
|
|
|
|
int sec_set_nad_param(int val)
|
|
{
|
|
int ret = -1;
|
|
|
|
mutex_lock(&sec_nad_param_lock);
|
|
|
|
switch(val) {
|
|
case NAD_PARAM_WRITE:
|
|
case NAD_PARAM_READ:
|
|
goto set_param;
|
|
default:
|
|
goto unlock_out;
|
|
}
|
|
|
|
set_param:
|
|
sec_nad_param_data.state = val;
|
|
schedule_work(&sec_nad_param_data.sec_nad_work);
|
|
wait_for_completion(&sec_nad_param_data.comp);
|
|
/* how to determine to return success or fail ? */
|
|
ret = 0;
|
|
unlock_out:
|
|
mutex_unlock(&sec_nad_param_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void sec_nad_init_update(struct work_struct *work)
|
|
{
|
|
int ret = -1;
|
|
|
|
NAD_PRINT("%s\n", __func__);
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_READ);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
}
|
|
|
|
static int Nad_Result(enum nad_enum_step mode)
|
|
{
|
|
int fd = 0;
|
|
int found = 0;
|
|
int fd_proc = 0;
|
|
int ret = NAD_CHECK_NONE;
|
|
char buf[512] = {'\0',};
|
|
char proc_buf[200] = {'\0',};
|
|
|
|
mm_segment_t old_fs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
|
|
fd_proc = sys_open("/proc/reset_reason", O_RDONLY, 0);
|
|
|
|
if (fd_proc >= 0) {
|
|
printk(KERN_DEBUG);
|
|
sys_read(fd_proc, proc_buf, 200);
|
|
|
|
NAD_PRINT("/proc/reset_reason value = %s\n", proc_buf);
|
|
sys_close(fd_proc);
|
|
}
|
|
|
|
if(mode == STEP_SMD_NAD_START) {
|
|
NAD_PRINT("checking SMD NAD result\n");
|
|
fd = sys_open(SMD_NAD_RESULT, O_RDONLY, 0);
|
|
}
|
|
else if(mode == STEP_ETC) {
|
|
NAD_PRINT("checking ACAT NAD result\n");
|
|
fd = sys_open(ETC_NAD_RESULT, O_RDONLY, 0);
|
|
}
|
|
|
|
if (fd >= 0) {
|
|
printk(KERN_DEBUG);
|
|
|
|
while(sys_read(fd, buf, 512))
|
|
{
|
|
char *ptr;
|
|
char *div = "\n";
|
|
char *tok = NULL;
|
|
|
|
ptr = buf;
|
|
while((tok = strsep(&ptr, div)) != NULL )
|
|
{
|
|
if((strstr(tok, "FAIL")))
|
|
{
|
|
NAD_PRINT("There is a FAIL in test_result.csv %d\n", ret);
|
|
ret = NAD_CHECK_FAIL;
|
|
found = 1;
|
|
break;
|
|
}
|
|
|
|
if((strstr(tok, "AllTestDone")))
|
|
{
|
|
NAD_PRINT("AllTestDone found in test_result.csv %d\n", ret);
|
|
ret = NAD_CHECK_PASS;
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(ret == NAD_CHECK_NONE)
|
|
{
|
|
if( !(strncasecmp(proc_buf, "KPON",4)) || !(strncasecmp(proc_buf, "DPON",4)) )
|
|
ret = NAD_CHECK_FAIL;
|
|
else
|
|
ret = NAD_CHECK_INCOMPLETED;
|
|
|
|
found = 1;
|
|
}
|
|
|
|
if(found)
|
|
break;
|
|
}
|
|
|
|
if (!found)
|
|
ret = NAD_CHECK_INCOMPLETED;
|
|
sys_close(fd);
|
|
}
|
|
else
|
|
{
|
|
NAD_PRINT("The File is not existed\n");
|
|
ret = NAD_CHECK_NONE;
|
|
}
|
|
|
|
set_fs(old_fs);
|
|
|
|
NAD_PRINT("The result is %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t show_nad_remain_count(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
char cnt[100] = {'0',};
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_READ);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
sprintf(cnt, "%d", sec_nad_env.nad_acat_remaining_count);
|
|
|
|
return sprintf(buf, cnt);
|
|
}
|
|
|
|
static DEVICE_ATTR(nad_remain_count, S_IRUGO, show_nad_remain_count, NULL);
|
|
|
|
static ssize_t show_ddrtest_remain_count(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
char cnt[100] = {'0',};
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_READ);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
sprintf(cnt, "%d", sec_nad_env.nad_dramtest_remaining_count);
|
|
|
|
return sprintf(buf, cnt);
|
|
}
|
|
|
|
static DEVICE_ATTR(nad_ddrtest_remain_count, S_IRUGO, show_ddrtest_remain_count, NULL);
|
|
|
|
static ssize_t show_nad_stat(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int dramscan_result = NAD_CHECK_NONE;
|
|
int hlos_result = NAD_CHECK_NONE;
|
|
int ret = 0;
|
|
|
|
NAD_PRINT("show_nad_stat\n");
|
|
ret = sec_set_nad_param(NAD_PARAM_READ);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
if(sec_nad_env.curr_step == STEP_SMD_NAD_DONE) {
|
|
dramscan_result = sec_nad_env.nad_smd_result & 0x3;
|
|
hlos_result = (sec_nad_env.nad_smd_result >> 2) & 0x3;
|
|
} else if (sec_nad_env.curr_step == STEP_SMD_NAD_START) {
|
|
dramscan_result = sec_nad_env.nad_smd_result & 0x3;
|
|
hlos_result = Nad_Result(STEP_SMD_NAD_START);
|
|
|
|
sec_nad_env.nad_smd_result = sec_nad_env.nad_smd_result + (hlos_result << 2);
|
|
sec_nad_env.curr_step = STEP_SMD_NAD_DONE;
|
|
}
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_WRITE);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
if(dramscan_result == NAD_CHECK_FAIL ||
|
|
hlos_result == NAD_CHECK_FAIL) {
|
|
char strResult[30] = { '\0', };
|
|
if (dramscan_result == NAD_CHECK_FAIL)
|
|
strcat(strResult, "[X]");
|
|
else
|
|
strcat(strResult, "[P]");
|
|
|
|
if(hlos_result == NAD_CHECK_FAIL)
|
|
strcat(strResult, "[X]");
|
|
else
|
|
strcat(strResult, "[P]");
|
|
|
|
return sprintf(buf, "NG_2.0_FAIL_%s\n", strResult);
|
|
}
|
|
else if (hlos_result == NAD_CHECK_PASS)
|
|
return sprintf(buf, "OK_2.0\n");
|
|
else if(hlos_result == NAD_CHECK_NONE && sec_nad_env.curr_step < STEP_SMD_NAD_START)
|
|
return sprintf(buf, "OK\n");
|
|
else // NAD test is not finished(in SMD F/T)
|
|
return sprintf(buf, "RE_WORK\n");
|
|
}
|
|
static DEVICE_ATTR(nad_stat, S_IRUGO, show_nad_stat, NULL);
|
|
|
|
static ssize_t show_nad_support(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
#if defined(CONFIG_MACH_MT6757) || defined(CONFIG_MACH_MT6768)
|
|
return sprintf(buf, "SUPPORT\n");
|
|
#else
|
|
return sprintf(buf, "NOT_SUPPORT\n");
|
|
#endif
|
|
}
|
|
static DEVICE_ATTR(nad_support, S_IRUGO, show_nad_support, NULL);
|
|
|
|
static ssize_t store_nad_end(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, nad_uevent.envp);
|
|
NAD_PRINT("Send to Process App for Nad test end : %s\n", __func__);
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(nad_end, S_IWUSR, NULL, store_nad_end);
|
|
|
|
static ssize_t store_nad_erase(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int ret = -1;
|
|
if (!strncmp(buf, "erase", 5)) {
|
|
char *argv[4] = { NULL, NULL, NULL, NULL };
|
|
char *envp[3] = { NULL, NULL, NULL };
|
|
int ret_userapp;
|
|
|
|
NAD_PRINT("store_nad_erase\n");
|
|
sec_nad_env.curr_step = 0;
|
|
sec_nad_env.nad_acat_remaining_count = 0;
|
|
sec_nad_env.nad_dramtest_remaining_count = 0;
|
|
sec_nad_env.nad_smd_result = 0;
|
|
sec_nad_env.nad_dram_test_result = 0;
|
|
sec_nad_env.nad_dram_fail_data = 0;
|
|
sec_nad_env.nad_dram_fail_address = 0;
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_WRITE);
|
|
if (ret < 0)
|
|
pr_err("%s: write error! %d\n", __func__, ret);
|
|
|
|
argv[0] = ERASE_NAD_PRG;
|
|
|
|
envp[0] = "HOME=/";
|
|
envp[1] = "PATH=/system/bin:/sbin:/bin:/usr/sbin:/usr/bin";
|
|
ret_userapp = call_usermodehelper( argv[0], argv, envp, UMH_WAIT_EXEC);
|
|
|
|
if(!ret_userapp)
|
|
{
|
|
NAD_PRINT("remove_mtk_nad_files.sh is executed. ret_userapp = %d\n", ret_userapp);
|
|
erase_pass = 1;
|
|
}
|
|
else
|
|
{
|
|
NAD_PRINT("remove_mtk_nad_files.sh is NOT executed. ret_userapp = %d\n", ret_userapp);
|
|
erase_pass = 0;
|
|
}
|
|
return count;
|
|
} else
|
|
return count;
|
|
}
|
|
|
|
static ssize_t show_nad_erase(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
if (erase_pass)
|
|
return sprintf(buf, "OK\n");
|
|
else
|
|
return sprintf(buf, "NG\n");
|
|
}
|
|
|
|
static DEVICE_ATTR(nad_erase, S_IRUGO | S_IWUSR, show_nad_erase, store_nad_erase);
|
|
|
|
static ssize_t show_nad_acat(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
if(Nad_Result(STEP_ETC) == NAD_CHECK_NONE){
|
|
NAD_PRINT("MTK_NAD No Run\n");
|
|
return sprintf(buf, "OK\n");
|
|
}else if(Nad_Result(STEP_ETC) == NAD_CHECK_FAIL){
|
|
NAD_PRINT("MTK_NAD fail\n");
|
|
return sprintf(buf, "NG_ACAT_ASV\n");
|
|
}else{
|
|
NAD_PRINT("MTK_NAD Passed\n");
|
|
return sprintf(buf, "OK_ACAT_NONE\n");
|
|
}
|
|
}
|
|
|
|
static void do_nad(int mode)
|
|
{
|
|
char *argv[4] = { NULL, NULL, NULL, NULL };
|
|
char *envp[3] = { NULL, NULL, NULL };
|
|
int ret_userapp;
|
|
|
|
envp[0] = "HOME=/";
|
|
envp[1] = "PATH=/system/bin:/sbin:/bin:/usr/sbin:/usr/bin";
|
|
|
|
switch (mode) {
|
|
case STEP_SMD_NAD_START:
|
|
argv[0] = SMD_NAD_PROG;
|
|
argv[1] = SMD_NAD_LOGPATH;
|
|
NAD_PRINT("SMD_NAD, nad_test_mode : %d\n", mode);
|
|
break;
|
|
default:
|
|
argv[0] = ETC_NAD_PROG;
|
|
argv[1] = REBOOT;
|
|
argv[2] = ETC_NAD_LOGPATH;
|
|
NAD_PRINT("ETC_NAD, nad_test_mode : %d\n", mode);
|
|
NAD_PRINT
|
|
("Setting an argument to reboot after NAD completes.\n");
|
|
break;
|
|
}
|
|
|
|
ret_userapp = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
|
|
|
|
if (!ret_userapp) {
|
|
NAD_PRINT("%s is executed. ret_userapp = %d\n", argv[0],
|
|
ret_userapp);
|
|
|
|
if (erase_pass)
|
|
erase_pass = 0;
|
|
} else {
|
|
NAD_PRINT("%s is NOT executed. ret_userapp = %d\n", argv[0],
|
|
ret_userapp);
|
|
}
|
|
}
|
|
|
|
|
|
static ssize_t store_nad_acat(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int ret = -1;
|
|
int idx = 0;
|
|
unsigned int nad_count = 0;
|
|
unsigned int dram_count = 0;
|
|
char temp[NAD_BUFF_SIZE*3];
|
|
char nad_cmd[NAD_CMD_LIST][NAD_BUFF_SIZE];
|
|
char *nad_ptr, *string;
|
|
NAD_PRINT("buf : %s count : %d\n", buf, (int)count);
|
|
if((int)count < NAD_BUFF_SIZE)
|
|
return -EINVAL;
|
|
|
|
/* Copy buf to nad temp */
|
|
strncpy(temp, buf, NAD_BUFF_SIZE*3);
|
|
string = temp;
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_READ);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
while(idx < NAD_CMD_LIST) {
|
|
nad_ptr = strsep(&string,",");
|
|
strcpy(nad_cmd[idx++], nad_ptr);
|
|
}
|
|
|
|
if (!strncmp(buf, "nad_acat", 8)) {
|
|
if(sec_nad_env.curr_step < STEP_SMD_NAD_START) ///////////// SMD NAD section //////////////
|
|
{
|
|
NAD_PRINT("1st boot at SMD\n");
|
|
sec_nad_env.curr_step = STEP_SMD_NAD_START;
|
|
sec_nad_env.nad_acat_remaining_count = 0x0;
|
|
sec_nad_env.nad_dramtest_remaining_count = 0x0;
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_WRITE);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
do_nad(STEP_SMD_NAD_START);
|
|
return count;
|
|
}
|
|
|
|
ret = sscanf(nad_cmd[1], "%d\n", &nad_count);
|
|
if (ret != 1)
|
|
return -EINVAL;
|
|
|
|
ret = sscanf(nad_cmd[2], "%d\n", &dram_count);
|
|
if (ret != 1)
|
|
return -EINVAL;
|
|
|
|
NAD_PRINT("ETC NAD, nad_acat%d,%d\n", nad_count, dram_count);
|
|
|
|
if( nad_count || dram_count) {
|
|
sec_nad_env.nad_acat_remaining_count = nad_count;
|
|
sec_nad_env.nad_dramtest_remaining_count = dram_count;
|
|
|
|
NAD_PRINT
|
|
("new cmd : nad_acat_remaining_count = %d, nad_dramtest_remaining_count = %d\n",
|
|
sec_nad_env.nad_acat_remaining_count,
|
|
sec_nad_env.nad_dramtest_remaining_count);
|
|
|
|
ret = sec_set_nad_param(NAD_PARAM_WRITE);
|
|
if (ret < 0)
|
|
pr_err("%s: write error! %d\n", __func__, ret);
|
|
} else {
|
|
if(sec_nad_env.curr_step >= STEP_SMD_NAD_START &&
|
|
Nad_Result(STEP_ETC) == NAD_CHECK_FAIL) {
|
|
pr_err("%s : nad test fail - set the remain counts to 0\n",
|
|
__func__);
|
|
sec_nad_env.nad_acat_remaining_count = 0;
|
|
sec_nad_env.nad_dramtest_remaining_count = 0;
|
|
|
|
// flushing to param partition
|
|
ret = sec_set_nad_param(NAD_PARAM_WRITE);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
goto err_out;
|
|
}
|
|
if (sec_nad_env.nad_acat_remaining_count > 0) {
|
|
NAD_PRINT("nad : nad_remain_count = %d, ddrtest_remain_count = %d\n",
|
|
sec_nad_env.nad_acat_remaining_count,
|
|
sec_nad_env.nad_dramtest_remaining_count);
|
|
|
|
sec_nad_env.nad_acat_remaining_count--;
|
|
ret = sec_set_nad_param(NAD_PARAM_WRITE);
|
|
if (ret < 0)
|
|
pr_err("%s: read error! %d\n", __func__, ret);
|
|
|
|
do_nad(STEP_ETC);
|
|
}
|
|
}
|
|
}
|
|
err_out:
|
|
return count;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR(nad_acat, S_IRUGO | S_IWUSR, show_nad_acat, store_nad_acat);
|
|
|
|
static ssize_t show_nad_dram(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
NAD_PRINT("%s\n", __func__);
|
|
|
|
if (sec_nad_env.nad_dram_test_result == NAD_CHECK_FAIL)
|
|
return sprintf(buf, "NG_DRAM_0x%0llx,0x%x\n",
|
|
sec_nad_env.nad_dram_fail_address,
|
|
sec_nad_env.nad_dram_fail_data);
|
|
else if (sec_nad_env.nad_dram_test_result == NAD_CHECK_PASS)
|
|
return sprintf(buf, "OK_DRAM\n");
|
|
else
|
|
return sprintf(buf, "NO_DRAMTEST\n");
|
|
}
|
|
|
|
static DEVICE_ATTR(nad_dram, S_IRUGO, show_nad_dram, NULL);
|
|
|
|
static int __init sec_nad_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
struct device* sec_nad;
|
|
|
|
NAD_PRINT("%s\n", __func__);
|
|
|
|
/* Skip nad init when device goes to low power charging */
|
|
if(lpcharge)
|
|
return ret;
|
|
|
|
sec_nad = sec_device_create(NULL, "sec_nad");
|
|
|
|
if (IS_ERR(sec_nad)) {
|
|
pr_err("%s Failed to create device(sec_nad)!\n", __func__);
|
|
return PTR_ERR(sec_nad);
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_remain_count);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_ddrtest_remain_count);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_stat);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_support);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_erase);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_acat);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_dram);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
ret = device_create_file(sec_nad, &dev_attr_nad_end);
|
|
if(ret) {
|
|
pr_err("%s: Failed to create device file\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
if(add_uevent_var(&nad_uevent, "NAD_TEST=%s", "DONE")) {
|
|
pr_err("%s : uevent NAD_TEST_AND_PASS is failed to add\n", __func__);
|
|
goto err_create_nad_sysfs;
|
|
}
|
|
|
|
/* Initialize nad param struct */
|
|
sec_nad_param_data.offset = NAD_ENV_DATA_OFFSET;
|
|
sec_nad_param_data.state = NAD_PARAM_EMPTY;
|
|
init_completion(&sec_nad_param_data.comp);
|
|
|
|
INIT_WORK(&sec_nad_param_data.sec_nad_work, sec_nad_param_update);
|
|
INIT_DELAYED_WORK(&sec_nad_param_data.sec_nad_delay_work, sec_nad_init_update);
|
|
|
|
schedule_delayed_work(&sec_nad_param_data.sec_nad_delay_work, HZ * 10);
|
|
|
|
sec_set_nad_param(NAD_PARAM_READ);
|
|
|
|
return 0;
|
|
err_create_nad_sysfs:
|
|
return ret;
|
|
}
|
|
|
|
static void __exit sec_nad_exit(void)
|
|
{
|
|
cancel_work_sync(&sec_nad_param_data.sec_nad_work);
|
|
cancel_delayed_work(&sec_nad_param_data.sec_nad_delay_work);
|
|
NAD_PRINT("%s: exit\n", __func__);
|
|
}
|
|
|
|
module_init(sec_nad_init);
|
|
module_exit(sec_nad_exit);
|