123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- #include "sec_battery_vote.h"
- #include <linux/slab.h>
- #include <linux/mutex.h>
- #include <linux/debugfs.h>
- static struct dentry *debug_root;
- static struct dentry *status_all;
- static LIST_HEAD(vote_list);
- static DEFINE_MUTEX(vote_lock);
- struct sec_voter {
- int enable;
- int value;
- int pri;
- };
- struct sec_vote {
- const char * name;
- int type;
- int num;
- struct sec_voter *voter;
- const char ** voter_name;
- int id;
- int res;
- int init_val;
- struct mutex lock;
- void * data;
- int(*cb)(void *data, int value);
- struct list_head list;
- struct dentry * root;
- struct dentry * status_ent;
- int force_set;
- int force_val;
- struct dentry * force_set_ent;
- };
- const char * none_str = "None";
- const char * force_str = "Force";
- static int select_min(struct sec_voter *voter, int max, int *id, int *res)
- {
- int i;
- int pri = INT_MIN;
- *res = INT_MAX;
- *id = -EINVAL;
- for (i = 0; i < max; i++) {
- if (voter[i].enable) {
- if (pri < voter[i].pri) {
- *res = voter[i].value;
- pri = voter[i].pri;
- *id = i;
- } else if (pri > voter[i].pri) {
- continue;
- } else if (*res > voter[i].value) {
- *res = voter[i].value;
- *id = i;
- }
- }
- }
- return 0;
- }
- static int select_max(struct sec_voter *voter, int max, int *id, int *res)
- {
- int i;
- int pri = INT_MIN;
- *res = INT_MIN;
- *id = -EINVAL;
- for (i = 0; i < max; i++) {
- if (voter[i].enable) {
- if (pri < voter[i].pri) {
- *res = voter[i].value;
- pri = voter[i].pri;
- *id = i;
- } else if (pri > voter[i].pri) {
- continue;
- } else if (*res < voter[i].value) {
- *res = voter[i].value;
- *id = i;
- }
- }
- }
- return 0;
- }
- static int select_enable(struct sec_voter * voter, int max, int * id, int * res)
- {
- int i;
- *res = 0;
- *id = -EINVAL;
- for (i = 0; i < max; i++) {
- if (voter[i].enable) {
- *res = voter[i].enable;
- *id = i;
- break;
- }
- }
- return 0;
- }
- static int select_vote_value(struct sec_vote * vote, int * id, int * res)
- {
- int ret = 0;
- switch (vote->type) {
- case SEC_VOTE_MIN:
- select_min(vote->voter, vote->num, id, res);
- if (*res == INT_MAX)
- *res = vote->init_val;
- break;
- case SEC_VOTE_MAX:
- select_max(vote->voter, vote->num, id, res);
- if (*res == INT_MIN)
- *res = vote->init_val;
- break;
- case SEC_VOTE_EN:
- select_enable(vote->voter, vote->num, id, res);
- break;
- default:
- pr_err("%s type invalid\n", __func__);
- ret = -EINVAL;
- }
- return ret;
- }
- int get_sec_vote(struct sec_vote * vote, const char ** name, int * value)
- {
- mutex_lock(&vote->lock);
- if (vote->id >= 0) {
- *name = vote->voter_name[vote->id];
- }
- else {
- *name = none_str;
- }
- *value = vote->res;
- mutex_unlock(&vote->lock);
- return 0;
- }
- EXPORT_SYMBOL(get_sec_vote);
- int get_sec_vote_result(struct sec_vote *vote)
- {
- int v;
- mutex_lock(&vote->lock);
- if (vote->force_set)
- v = vote->force_val;
- else
- v = vote->res;
- mutex_unlock(&vote->lock);
- return v;
- }
- EXPORT_SYMBOL(get_sec_vote_result);
- const char* get_sec_keyvoter_name(struct sec_vote *vote)
- {
- const char * str;
- mutex_lock(&vote->lock);
- if (vote->force_set)
- str = force_str;
- else
- str = (vote->id >= 0)?vote->voter_name[vote->id]: none_str;
- mutex_unlock(&vote->lock);
- return str;
- }
- EXPORT_SYMBOL(get_sec_keyvoter_name);
- int get_sec_voter_status(struct sec_vote *vote, int id, int * v)
- {
- if (id >= vote->num || id < 0)
- return -EINVAL;
- mutex_lock(&vote->lock);
- if (vote->type == SEC_VOTE_EN)
- *v = vote->voter[id].enable;
- else if (vote->voter[id].enable)
- *v = vote->voter[id].value;
- else
- *v = INT_MIN;
- mutex_unlock(&vote->lock);
- return (*v == INT_MIN) ? -EINVAL : 0;
- }
- EXPORT_SYMBOL(get_sec_voter_status);
- int show_sec_vote_status(char *buf, unsigned int p_size)
- {
- struct sec_vote *vote;
- int i, j = 0;
- char *type_str = "Unkonwn";
- if (list_empty(&vote_list)) {
- j += scnprintf(buf + j, p_size - j, "No vote\n");
- return j;
- }
- mutex_lock(&vote_lock);
- list_for_each_entry(vote, &vote_list, list) {
- mutex_lock(&vote->lock);
- for (i = 0; i < vote->num; i++) {
- if (vote->voter[i].enable) {
- j += scnprintf(buf + j, p_size - j, "%s: %s:\t\t\ten=%d v=%d p=%d\n",
- vote->name,
- vote->voter_name[i],
- vote->voter[i].enable,
- vote->voter[i].value,
- vote->voter[i].pri);
- }
- }
- switch (vote->type) {
- case SEC_VOTE_MIN:
- type_str = "Min";
- break;
- case SEC_VOTE_MAX:
- type_str = "Max";
- break;
- case SEC_VOTE_EN:
- type_str = "Set_any";
- break;
- default:
- type_str = "Invalid";
- }
- j += scnprintf(buf + j, p_size - j, "%s: INIT: v=%d\n",
- vote->name, vote->init_val);
- if (vote->force_set) {
- j += scnprintf(buf + j, p_size - j, "%s: voter=%s type=%s v=%d\n",
- vote->name, force_str, type_str, vote->force_val);
- } else {
- j += scnprintf(buf + j, p_size - j, "%s: voter=%s type=%s v=%d\n",
- vote->name,
- (vote->id >= 0) ? vote->voter_name[vote->id] : none_str,
- type_str, vote->res);
- }
- mutex_unlock(&vote->lock);
- }
- mutex_unlock(&vote_lock);
- return j;
- }
- EXPORT_SYMBOL(show_sec_vote_status);
- static int show_vote_clients(struct seq_file *m, void *data)
- {
- struct sec_vote *vote = m->private;
- int i;
- char *type_str = "Unkonwn";
- mutex_lock(&vote->lock);
- for (i = 0; i < vote->num; i++) {
- if (vote->voter[i].enable) {
- seq_printf(m, "%s: %s:\t\t\ten=%d v=%d p=%d\n",
- vote->name,
- vote->voter_name[i],
- vote->voter[i].enable,
- vote->voter[i].value,
- vote->voter[i].pri);
- }
- }
- switch (vote->type) {
- case SEC_VOTE_MIN:
- type_str = "Min";
- break;
- case SEC_VOTE_MAX:
- type_str = "Max";
- break;
- case SEC_VOTE_EN:
- type_str = "Set_any";
- break;
- default:
- type_str = "Invalid";
- }
- seq_printf(m, "%s: INIT: v=%d\n",
- vote->name, vote->init_val);
- if (vote->force_set) {
- seq_printf(m, "%s: voter=%s type=%s v=%d\n",
- vote->name, force_str, type_str, vote->force_val);
- } else {
- seq_printf(m, "%s: voter=%s type=%s v=%d\n",
- vote->name,
- (vote->id >= 0)?vote->voter_name[vote->id]: none_str,
- type_str, vote->res);
- }
- mutex_unlock(&vote->lock);
- return 0;
- }
- static int vote_status_open(struct inode *inode, struct file *file)
- {
- struct sec_vote *vote = inode->i_private;
- return single_open(file, show_vote_clients, vote);
- }
- static const struct file_operations vote_status_ops = {
- .owner = THIS_MODULE,
- .open = vote_status_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int show_all_clients(struct seq_file *m, void *data)
- {
- struct sec_vote *vote;
- int i;
- char *type_str = "Unkonwn";
- if (list_empty(&vote_list)) {
- seq_printf(m, "No vote\n");
- return 0;
- }
- mutex_lock(&vote_lock);
- list_for_each_entry(vote, &vote_list, list) {
- mutex_lock(&vote->lock);
- for (i = 0; i < vote->num; i++) {
- if (vote->voter[i].enable) {
- seq_printf(m, "%s: %s:\t\t\ten=%d v=%d p=%d\n",
- vote->name,
- vote->voter_name[i],
- vote->voter[i].enable,
- vote->voter[i].value,
- vote->voter[i].pri);
- }
- }
- switch (vote->type) {
- case SEC_VOTE_MIN:
- type_str = "Min";
- break;
- case SEC_VOTE_MAX:
- type_str = "Max";
- break;
- case SEC_VOTE_EN:
- type_str = "Set_any";
- break;
- default:
- type_str = "Invalid";
- }
- seq_printf(m, "%s: INIT: v=%d\n",
- vote->name, vote->init_val);
- if (vote->force_set) {
- seq_printf(m, "%s: voter=%s type=%s v=%d\n",
- vote->name, force_str, type_str, vote->force_val);
- } else {
- seq_printf(m, "%s: voter=%s type=%s v=%d\n",
- vote->name,
- (vote->id >= 0)?vote->voter_name[vote->id]: none_str,
- type_str, vote->res);
- }
- mutex_unlock(&vote->lock);
- }
- mutex_unlock(&vote_lock);
- return 0;
- }
- static int vote_status_all_open(struct inode *inode, struct file *file)
- {
- return single_open(file, show_all_clients, NULL);
- }
- static const struct file_operations vote_status_all_ops = {
- .owner = THIS_MODULE,
- .open = vote_status_all_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int force_get(void *data, u64 *val)
- {
- struct sec_vote *vote = data;
- *val = vote->force_set;
- return 0;
- }
- static int force_set(void *data, u64 val)
- {
- struct sec_vote *vote = data;
- mutex_lock(&vote->lock);
- vote->force_set = val;
- if (!vote->cb)
- goto out;
- if (vote->force_set) {
- vote->res = vote->cb(vote->data, vote->force_val);
- } else {
- vote->res = vote->cb(vote->data, vote->res);
- }
- out:
- mutex_unlock(&vote->lock);
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(vote_force_ops, force_get, force_set, "%lld\n");
- struct sec_vote *find_vote(const char *name)
- {
- struct sec_vote *vote;
- list_for_each_entry(vote, &vote_list, list) {
- if (strcmp(vote->name, name) == 0) {
- return vote;
- }
- }
- return NULL;
- }
- EXPORT_SYMBOL(find_vote);
- struct sec_vote *sec_vote_init(const char *name, int type, int num, int init_val,
- const char **voter_name, int(*cb)(void *data, int value), void *data)
- {
- struct sec_vote * vote = NULL;
- struct sec_voter * voter = NULL;
- mutex_lock(&vote_lock);
- vote = find_vote(name);
- if (vote) {
- pr_info("%s: %s exist \n", __func__, name);
- goto err;
- }
- if (voter_name == NULL) {
- pr_info("%s: Please add voter name list \n", __func__);
- goto err;
- }
- vote = kzalloc(sizeof(struct sec_vote), GFP_KERNEL);
- if (!vote) {
- pr_info("%s: mem aloocate fail \n", __func__);
- goto err;
- }
- vote->name = name;
- vote->type = type;
- voter = kzalloc(sizeof(struct sec_voter) * num, GFP_KERNEL);
- if (!voter) {
- pr_info("%s: mem aloocate fail \n", __func__);
- kfree(vote);
- goto err;
- }
- vote->voter = voter;
- vote->num = num;
- vote->voter_name = voter_name;
- vote->init_val = init_val;
- vote->cb = cb;
- vote->id = -EINVAL;
- vote->res = -EINVAL;
- vote->data = data;
- mutex_init(&vote->lock);
- if (debug_root == NULL) {
- debug_root = debugfs_create_dir("sec-vote", NULL);
- if (!debug_root) {
- pr_err("Couldn't create debug dir\n");
- } else {
- status_all = debugfs_create_file("status_all",
- S_IFREG | 0444,
- debug_root, NULL,
- &vote_status_all_ops);
- if (!status_all) {
- pr_err("Couldn't create status_all dbg file \n");
- }
- }
- }
- if (debug_root)
- vote->root = debugfs_create_dir(name, debug_root);
- if (!vote->root) {
- pr_err("Couldn't create debug dir %s\n", name);
- } else {
- vote->status_ent = debugfs_create_file("status", S_IFREG | 0444,
- vote->root, vote,
- &vote_status_ops);
- if (!vote->status_ent) {
- pr_err("Couldn't create status dbg file for %s\n", name);
- }
- debugfs_create_u32("force_val", S_IFREG | 0644,
- vote->root, &(vote->force_val));
- vote->force_set_ent = debugfs_create_file("force_set",
- S_IFREG | 0444,
- vote->root, vote,
- &vote_force_ops);
- if (!vote->force_set_ent) {
- pr_err("Couldn't create force_set dbg file for %s\n", name);
- }
- }
- pr_info("%s: %s \n", __func__, name);
- list_add(&vote->list, &vote_list);
- mutex_unlock(&vote_lock);
- return vote;
- err:
- mutex_unlock(&vote_lock);
- return NULL;
- }
- EXPORT_SYMBOL(sec_vote_init);
- void sec_vote_destroy(struct sec_vote *vote)
- {
- pr_info("%s: %s\n", __func__, vote->name);
- list_del(&vote->list);
- kfree(vote->voter);
- debugfs_remove_recursive(vote->root);
- mutex_destroy(&vote->lock);
- kfree(vote);
- }
- EXPORT_SYMBOL(sec_vote_destroy);
- void change_sec_voter_pri(struct sec_vote *vote, int event, int pri)
- {
- if (event >= vote->num) {
- pr_info("%s id Error(%d)\n", __func__, event);
- return;
- }
- mutex_lock(&vote->lock);
- vote->voter[event].pri = pri;
- mutex_unlock(&vote->lock);
- }
- EXPORT_SYMBOL(change_sec_voter_pri);
- void _sec_vote(struct sec_vote *vote, int event, int en, int value, const char *fname, int line)
- {
- int id, res, ret;
- if (event >= vote->num) {
- pr_info("%s id Error(%d)\n", __func__, event);
- return;
- }
- mutex_lock(&vote->lock);
- pr_debug("%s, %s en: %d->%d, v: %d->%d\n", vote->name,vote->voter_name[event],
- vote->voter[event].enable, en, vote->voter[event].value, value);
- if ((vote->voter[event].enable == en) &&
- (((vote->voter[event].value == value) || !en)))
- goto out;
- vote->voter[event].enable = en;
- vote->voter[event].value = value;
- ret = select_vote_value(vote, &id, &res);
- if (ret < 0)
- goto out;
- pr_info("%s(%s:%d): %s (%s, %d) -> (%s, %d)\n", __func__, fname, line, vote->name,
- (vote->id >= 0) ? vote->voter_name[vote->id] : none_str, vote->res,
- (id >= 0) ? vote->voter_name[id] : none_str, res);
- if (res != vote->res) {
- vote->id = id;
- vote->res = res;
- if (vote->force_set)
- pr_err("%s skip by force_set\n", __func__);
- else
- vote->res = vote->cb(vote->data, res);
- } else if (!en && (vote->id == event)) {
- vote->id = id;
- }
- out:
- mutex_unlock(&vote->lock);
- }
- EXPORT_SYMBOL(_sec_vote);
- void sec_vote_refresh(struct sec_vote *vote)
- {
- mutex_lock(&vote->lock);
- if (vote->res == -EINVAL && vote->id == -EINVAL) {
- pr_info("%s: skip. not used before\n", __func__);
- } else {
- if (vote->force_set) {
- pr_info("%s: refresh (%s, %d)\n", vote->name, force_str, vote->force_val);
- vote->res = vote->cb(vote->data, vote->force_val);
- } else {
- int id, res, ret;
- ret = select_vote_value(vote, &id, &res);
- pr_info("%s: refresh (%s, %d, %d)\n", vote->name,
- (id >= 0) ? vote->voter_name[id] : none_str, res, ret);
- if (ret < 0)
- goto out;
- vote->res = vote->cb(vote->data, res);
- }
- }
- out:
- mutex_unlock(&vote->lock);
- }
- EXPORT_SYMBOL(sec_vote_refresh);
- const char *get_sec_vote_name(struct sec_vote *vote)
- {
- return vote->name;
- }
- EXPORT_SYMBOL(get_sec_vote_name);
|