/* * drivers/misc/sec_param.c * * Copyright (c) 2011 Samsung Electronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #define PARAM_RD 0 #define PARAM_WR 1 #define SEC_PARAM_FILE_NAME "/dev/block/platform/msm_sdcc.1/by-name/param" /* parameter block */ #if defined(CONFIG_PARAM_SIZE_983000) #define SEC_PARAM_FILE_SIZE 0x983000 /* 9.5MB */ #else #define SEC_PARAM_FILE_SIZE 0xA00000 /* 10MB */ #endif #define SEC_PARAM_FILE_OFFSET (SEC_PARAM_FILE_SIZE - 0x100000) /* single global instance */ struct sec_param_data *param_data; static bool param_sec_operation(void *value, int offset, int size, int direction) { /* Read from PARAM(parameter) partition */ struct file *filp; mm_segment_t fs; int ret = true; int flag = (direction == PARAM_WR) ? (O_RDWR | O_SYNC) : O_RDONLY; pr_debug("%s %p %x %d %d\n", __func__, value, offset, size, direction); filp = filp_open(SEC_PARAM_FILE_NAME, flag, 0); if (IS_ERR(filp)) { pr_err("%s: filp_open failed. (%ld)\n", __func__, PTR_ERR(filp)); return false; } fs = get_fs(); set_fs(get_ds()); ret = filp->f_op->llseek(filp, offset, SEEK_SET); if (ret < 0) { pr_err("%s FAIL LLSEEK\n", __func__); ret = false; goto param_sec_debug_out; } if (direction == PARAM_RD) ret = filp->f_op->read(filp, (char __user *)value, size, &filp->f_pos); else if (direction == PARAM_WR) ret = filp->f_op->write(filp, (char __user *)value, size, &filp->f_pos); param_sec_debug_out: set_fs(fs); filp_close(filp, NULL); return ret; } bool sec_open_param(void) { int ret = true; int offset = SEC_PARAM_FILE_OFFSET; if (param_data != NULL) return true; param_data = kmalloc(sizeof(struct sec_param_data), GFP_KERNEL); ret = param_sec_operation(param_data, offset, sizeof(struct sec_param_data), PARAM_RD); if (!ret) { kfree(param_data); param_data = NULL; pr_err("%s PARAM OPEN FAIL\n", __func__); return false; } return ret; } EXPORT_SYMBOL(sec_open_param); bool sec_get_param(enum sec_param_index index, void *value) { int ret = true; ret = sec_open_param(); if (!ret) return ret; switch (index) { case param_index_debuglevel: memcpy(value, &(param_data->debuglevel), sizeof(unsigned int)); break; case param_index_uartsel: memcpy(value, &(param_data->uartsel), sizeof(unsigned int)); break; case param_rory_control: memcpy(value, &(param_data->rory_control), sizeof(unsigned int)); break; case param_index_movinand_checksum_done: memcpy(value, &(param_data->movinand_checksum_done), sizeof(unsigned int)); break; case param_index_movinand_checksum_pass: memcpy(value, &(param_data->movinand_checksum_pass), sizeof(unsigned int)); break; #if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) case param_slideCount: memcpy(value, &(param_data->slideCount), sizeof(unsigned int)); break; #endif #if defined(CONFIG_GSM_MODEM_SPRD6500) || defined(CONFIG_SGLTE_QSC_MODEM) case param_update_cp_bin: memcpy(value, &(param_data->update_cp_bin), sizeof(unsigned int)); printk(KERN_INFO "param_data.update_cp_bin :[%d]!!", param_data->update_cp_bin); break; #endif #ifdef CONFIG_RTC_AUTO_PWRON_PARAM case param_index_boot_alarm_set: memcpy(value, &(param_data->boot_alarm_set), sizeof(unsigned int)); break; case param_index_boot_alarm_value_l: memcpy(value, &(param_data->boot_alarm_value_l), sizeof(unsigned int)); break; case param_index_boot_alarm_value_h: memcpy(value, &(param_data->boot_alarm_value_h), sizeof(unsigned int)); break; #endif #ifdef CONFIG_SEC_MONITOR_BATTERY_REMOVAL case param_index_normal_poweroff: memcpy(&(param_data->normal_poweroff), value, sizeof(unsigned int)); break; #endif #ifdef CONFIG_RESTART_REASON_SEC_PARAM case param_index_restart_reason: memcpy(value, &(param_data->param_restart_reason), sizeof(unsigned int)); break; #endif default: return false; } return true; } EXPORT_SYMBOL(sec_get_param); bool sec_set_param(enum sec_param_index index, void *value) { int ret = true; int offset = SEC_PARAM_FILE_OFFSET; ret = sec_open_param(); if (!ret) return ret; switch (index) { case param_index_debuglevel: memcpy(&(param_data->debuglevel), value, sizeof(unsigned int)); break; case param_index_uartsel: memcpy(&(param_data->uartsel), value, sizeof(unsigned int)); break; case param_rory_control: memcpy(&(param_data->rory_control), value, sizeof(unsigned int)); break; case param_index_movinand_checksum_done: memcpy(&(param_data->movinand_checksum_done), value, sizeof(unsigned int)); break; case param_index_movinand_checksum_pass: memcpy(&(param_data->movinand_checksum_pass), value, sizeof(unsigned int)); break; #if defined(CONFIG_MACH_APEXQ) || defined(CONFIG_MACH_AEGIS2) case param_slideCount: memcpy(&(param_data->slideCount), value, sizeof(unsigned int)); break; #endif #if defined(CONFIG_GSM_MODEM_SPRD6500) || defined(CONFIG_SGLTE_QSC_MODEM) case param_update_cp_bin: memcpy(&(param_data->update_cp_bin), value, sizeof(unsigned int)); break; #endif #ifdef CONFIG_RTC_AUTO_PWRON_PARAM case param_index_boot_alarm_set: memcpy(&(param_data->boot_alarm_set), value, sizeof(unsigned int)); break; case param_index_boot_alarm_value_l: memcpy(&(param_data->boot_alarm_value_l), value, sizeof(unsigned int)); break; case param_index_boot_alarm_value_h: memcpy(&(param_data->boot_alarm_value_h), value, sizeof(unsigned int)); break; #endif #ifdef CONFIG_SEC_MONITOR_BATTERY_REMOVAL case param_index_normal_poweroff: memcpy(&(param_data->normal_poweroff), value, sizeof(unsigned int)); break; #endif #ifdef CONFIG_RESTART_REASON_SEC_PARAM case param_index_restart_reason: memcpy(&(param_data->param_restart_reason), value, sizeof(unsigned int)); break; #endif default: return false; } return param_sec_operation(param_data, offset, sizeof(struct sec_param_data), PARAM_WR); } EXPORT_SYMBOL(sec_set_param); /* ########################################################## * # * # SEC PARAM Driver sysfs file * # 1. movinand_checksum_done_show * # 2. movinand_checksum_pass_show * ########################################################## * */ static struct class *sec_param_class; struct device *sec_param_dev; static ssize_t movinand_checksum_done_show (struct device *dev, struct device_attribute *attr, char *buf) { int ret = 0; sec_get_param(param_index_movinand_checksum_done, &ret); if (ret == 1 || ret == 0) { pr_err("checksum is not in valuable range.\n"); ret = 1; } return snprintf(buf, PAGE_SIZE, "%u\n", ret); } static DEVICE_ATTR(movinand_checksum_done, 0664, movinand_checksum_done_show, NULL); static ssize_t movinand_checksum_pass_show (struct device *dev, struct device_attribute *attr, char *buf) { int ret = 0; sec_get_param(param_index_movinand_checksum_pass, &ret); if (ret == 1 || ret == 0) { pr_err("checksum is not in valuable range.\n"); ret = 1; } return snprintf(buf, PAGE_SIZE, "%u\n", ret); } static DEVICE_ATTR(movinand_checksum_pass, 0664, movinand_checksum_pass_show, NULL); int sec_param_sysfs_init(void) { int ret = 0; sec_param_class = class_create(THIS_MODULE, "sec_param"); if (IS_ERR(sec_param_class)) { pr_err("Failed to create class(mdnie_class)!!\n"); ret = -1; goto failed_create_class; } sec_param_dev = device_create(sec_param_class, NULL, 0, NULL, "sec_param"); if (IS_ERR(sec_param_dev)) { printk(KERN_ERR "Failed to create device(sec_param_dev)!!"); ret = -1; goto failed_create_dev; } if (device_create_file(sec_param_dev, &dev_attr_movinand_checksum_done) < 0) { pr_err("Failed to create device file!(%s)!\n", dev_attr_movinand_checksum_done.attr.name); ret = -1; } if (device_create_file(sec_param_dev, &dev_attr_movinand_checksum_pass) < 0) { pr_err("Failed to create device file!(%s)!\n", dev_attr_movinand_checksum_pass.attr.name); ret = -1; } failed_create_class: return ret; failed_create_dev: class_destroy(sec_param_class); return ret; } module_init(sec_param_sysfs_init);