305 lines
7 KiB
C
305 lines
7 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
/*
|
||
|
* Copyright (C) 2021 MediaTek Inc.
|
||
|
*/
|
||
|
#include <net/genetlink.h>
|
||
|
#include <linux/kobject.h>
|
||
|
#include <linux/netlink.h>
|
||
|
#include <linux/socket.h>
|
||
|
#include <linux/skbuff.h>
|
||
|
#include <linux/proc_fs.h>
|
||
|
#include <linux/module.h>
|
||
|
|
||
|
#include "frs.h"
|
||
|
#include "fpsgo_common.h"
|
||
|
#include "fstb.h"
|
||
|
|
||
|
#define EARA_MAX_COUNT 10
|
||
|
#define EARA_PROC_NAME_LEN 16
|
||
|
#define TAG "FRS"
|
||
|
|
||
|
static int frs_nl_id = 31;
|
||
|
module_param(frs_nl_id, int, 0644);
|
||
|
struct frs_info frs_data;
|
||
|
struct _EARA_THRM_PACKAGE {
|
||
|
__s32 type;
|
||
|
__s32 request;
|
||
|
__s32 is_camera;
|
||
|
__s32 pair_pid[EARA_MAX_COUNT];
|
||
|
__u64 pair_bufid[EARA_MAX_COUNT];
|
||
|
__s32 pair_tfps[EARA_MAX_COUNT];
|
||
|
__s32 pair_rfps[EARA_MAX_COUNT];
|
||
|
__s32 pair_diff[EARA_MAX_COUNT];
|
||
|
__s32 pair_hwui[EARA_MAX_COUNT];
|
||
|
char proc_name[EARA_MAX_COUNT][EARA_PROC_NAME_LEN];
|
||
|
};
|
||
|
|
||
|
struct _EARA_THRM_ENABLE {
|
||
|
__s32 type;
|
||
|
__s32 enable;
|
||
|
__s32 pid;
|
||
|
};
|
||
|
|
||
|
static int eara_enable;
|
||
|
static DEFINE_MUTEX(pre_lock);
|
||
|
static struct sock *frs_nl_sk;
|
||
|
static int eara_pid = -1;
|
||
|
|
||
|
static void set_tfps_diff(int max_cnt, int *pid, unsigned long long *buf_id, int *tfps, int *diff)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
mutex_lock(&pre_lock);
|
||
|
|
||
|
if (!eara_enable) {
|
||
|
mutex_unlock(&pre_lock);
|
||
|
return;
|
||
|
}
|
||
|
mutex_unlock(&pre_lock);
|
||
|
|
||
|
for (i = 0; i < max_cnt; i++) {
|
||
|
if (pid[i] == 0)
|
||
|
break;
|
||
|
pr_debug(TAG "Set %d %llu: %d\n", pid[i], buf_id[i], diff[i]);
|
||
|
eara2fstb_tfps_mdiff(pid[i], buf_id[i], diff[i], tfps[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void switch_eara(int enable, int pid)
|
||
|
{
|
||
|
pr_debug(TAG "%s enable:%d\n", __func__, enable);
|
||
|
mutex_lock(&pre_lock);
|
||
|
eara_enable = enable;
|
||
|
eara_pid = pid;
|
||
|
mutex_unlock(&pre_lock);
|
||
|
|
||
|
}
|
||
|
|
||
|
int pre_change_single_event(int pid, unsigned long long bufID,
|
||
|
int target_fps)
|
||
|
{
|
||
|
struct _EARA_THRM_PACKAGE change_msg;
|
||
|
int ret = 0;
|
||
|
|
||
|
mutex_lock(&pre_lock);
|
||
|
if (!eara_enable) {
|
||
|
mutex_unlock(&pre_lock);
|
||
|
return -1;
|
||
|
}
|
||
|
mutex_unlock(&pre_lock);
|
||
|
|
||
|
memset(&change_msg, 0, sizeof(struct _EARA_THRM_PACKAGE));
|
||
|
change_msg.request = 1;
|
||
|
change_msg.pair_pid[0] = pid;
|
||
|
change_msg.pair_bufid[0] = bufID;
|
||
|
change_msg.pair_tfps[0] = target_fps;
|
||
|
ret = eara_nl_send_to_user((void *)&change_msg, sizeof(struct _EARA_THRM_PACKAGE));
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int pre_change_event(void)
|
||
|
{
|
||
|
struct _EARA_THRM_PACKAGE change_msg;
|
||
|
int ret = 0;
|
||
|
|
||
|
pr_debug("eara_enable %d\n", eara_enable);
|
||
|
mutex_lock(&pre_lock);
|
||
|
if (!eara_enable) {
|
||
|
mutex_unlock(&pre_lock);
|
||
|
return -1;
|
||
|
}
|
||
|
mutex_unlock(&pre_lock);
|
||
|
memset(&change_msg, 0, sizeof(struct _EARA_THRM_PACKAGE));
|
||
|
eara2fstb_get_tfps(EARA_MAX_COUNT, &(change_msg.is_camera), change_msg.pair_pid,
|
||
|
change_msg.pair_bufid, change_msg.pair_tfps, change_msg.pair_rfps,
|
||
|
change_msg.pair_hwui, change_msg.proc_name);
|
||
|
ret = eara_nl_send_to_user((void *)&change_msg, sizeof(struct _EARA_THRM_PACKAGE));
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int eara_nl_send_to_user(void *buf, int size)
|
||
|
{
|
||
|
struct sk_buff *skb;
|
||
|
struct nlmsghdr *nlh;
|
||
|
|
||
|
int len = NLMSG_SPACE(size);
|
||
|
void *data;
|
||
|
int ret;
|
||
|
|
||
|
if (frs_nl_sk == NULL)
|
||
|
return -1;
|
||
|
|
||
|
skb = alloc_skb(len, GFP_ATOMIC);
|
||
|
if (!skb)
|
||
|
return -1;
|
||
|
nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, size+1, 0);
|
||
|
data = NLMSG_DATA(nlh);
|
||
|
memcpy(data, buf, size);
|
||
|
NETLINK_CB(skb).portid = 0; /* from kernel */
|
||
|
NETLINK_CB(skb).dst_group = 0; /* unicast */
|
||
|
|
||
|
pr_debug(TAG "Netlink_unicast size=%d\n", size);
|
||
|
|
||
|
ret = netlink_unicast(frs_nl_sk, skb, eara_pid, MSG_DONTWAIT);
|
||
|
if (ret < 0) {
|
||
|
pr_debug(TAG "Send to pid %d failed %d\n", eara_pid, ret);
|
||
|
return -1;
|
||
|
}
|
||
|
pr_debug(TAG "Netlink_unicast- ret=%d\n", ret);
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
static void eara_nl_data_handler(struct sk_buff *skb)
|
||
|
{
|
||
|
u32 pid;
|
||
|
kuid_t uid;
|
||
|
int seq;
|
||
|
void *data;
|
||
|
struct nlmsghdr *nlh;
|
||
|
struct _EARA_THRM_PACKAGE *change_msg;
|
||
|
struct _EARA_THRM_ENABLE *enable_msg;
|
||
|
//int size = 0;
|
||
|
|
||
|
nlh = (struct nlmsghdr *)skb->data;
|
||
|
pid = NETLINK_CREDS(skb)->pid;
|
||
|
uid = NETLINK_CREDS(skb)->uid;
|
||
|
seq = nlh->nlmsg_seq;
|
||
|
|
||
|
/*tsta_dprintk(
|
||
|
*"[ta_nl_data_handler] recv skb from user space uid:%d pid:%d seq:%d\n"
|
||
|
* ,uid, pid, seq);
|
||
|
*/
|
||
|
data = NLMSG_DATA(nlh);
|
||
|
change_msg = (struct _EARA_THRM_PACKAGE *) NLMSG_DATA(nlh);
|
||
|
enable_msg = (struct _EARA_THRM_ENABLE *) NLMSG_DATA(nlh);
|
||
|
if (change_msg->type == 0)
|
||
|
set_tfps_diff(EARA_MAX_COUNT, change_msg->pair_pid,
|
||
|
change_msg->pair_bufid, change_msg->pair_tfps, change_msg->pair_diff);
|
||
|
else
|
||
|
switch_eara(enable_msg->enable, enable_msg->pid);
|
||
|
}
|
||
|
|
||
|
|
||
|
int eara_netlink_init(void)
|
||
|
{
|
||
|
/*add by willcai for the userspace to kernelspace*/
|
||
|
struct netlink_kernel_cfg cfg = {
|
||
|
.input = eara_nl_data_handler,
|
||
|
};
|
||
|
|
||
|
frs_nl_sk = NULL;
|
||
|
frs_nl_sk = netlink_kernel_create(&init_net, frs_nl_id, &cfg);
|
||
|
|
||
|
pr_debug(TAG "netlink_kernel_create protol= %d\n", frs_nl_id);
|
||
|
|
||
|
if (frs_nl_sk == NULL) {
|
||
|
pr_debug(TAG "netlink_kernel_create fail\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static ssize_t frs_nl_id_show(struct kobject *kobj,
|
||
|
struct kobj_attribute *attr, char *buf)
|
||
|
{
|
||
|
int len = 0;
|
||
|
|
||
|
len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", frs_nl_id);
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
static ssize_t frs_info_show(struct kobject *kobj,
|
||
|
struct kobj_attribute *attr, char *buf)
|
||
|
{
|
||
|
int len = 0;
|
||
|
|
||
|
len += snprintf(buf + len, PAGE_SIZE - len, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
|
||
|
frs_data.enable,
|
||
|
frs_data.activated, frs_data.pid,
|
||
|
frs_data.target_fps, frs_data.diff,
|
||
|
frs_data.tpcb, frs_data.tpcb_slope,
|
||
|
frs_data.ap_headroom, frs_data.n_sec_to_ttpcb);
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
static ssize_t frs_info_store(struct kobject *kobj,
|
||
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
||
|
{
|
||
|
int enable, act, target_fps, tpcb, tpcb_slope;
|
||
|
int ap_headroom, n_sec_to_ttpcb;
|
||
|
int pid, diff;
|
||
|
int ret;
|
||
|
|
||
|
ret = sscanf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d", &enable, &act, &pid, &target_fps,
|
||
|
&diff, &tpcb, &tpcb_slope, &ap_headroom, &n_sec_to_ttpcb);
|
||
|
if (ret == 9) {
|
||
|
if ((ap_headroom >= -1000) && (ap_headroom <= 1000)) {
|
||
|
frs_data.ap_headroom = ap_headroom;
|
||
|
} else {
|
||
|
pr_info("[%s] invalid ap head room input\n", __func__);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
frs_data.enable = enable;
|
||
|
frs_data.activated = act;
|
||
|
frs_data.tpcb = tpcb;
|
||
|
frs_data.pid = pid;
|
||
|
frs_data.target_fps = target_fps;
|
||
|
frs_data.diff = diff;
|
||
|
frs_data.tpcb_slope = tpcb_slope;
|
||
|
frs_data.n_sec_to_ttpcb = n_sec_to_ttpcb;
|
||
|
} else {
|
||
|
pr_info("[%s] invalid input\n", __func__);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static struct kobj_attribute frs_nl_id_attr = __ATTR_RO(frs_nl_id);
|
||
|
static struct kobj_attribute frs_info_attr = __ATTR_RW(frs_info);
|
||
|
static struct attribute *thermal_attrs[] = {
|
||
|
&frs_nl_id_attr.attr,
|
||
|
&frs_info_attr.attr,
|
||
|
NULL
|
||
|
};
|
||
|
static struct attribute_group thermal_attr_group = {
|
||
|
.name = "thermal",
|
||
|
.attrs = thermal_attrs,
|
||
|
};
|
||
|
|
||
|
void __exit eara_thrm_pre_exit(void)
|
||
|
{
|
||
|
eara_pre_change_fp = NULL;
|
||
|
eara_pre_change_single_fp = NULL;
|
||
|
}
|
||
|
|
||
|
int __init eara_thrm_pre_init(void)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
eara_pre_change_fp = pre_change_event;
|
||
|
eara_pre_change_single_fp = pre_change_single_event;
|
||
|
eara_netlink_init();
|
||
|
|
||
|
ret = sysfs_create_group(kernel_kobj, &thermal_attr_group);
|
||
|
if (ret) {
|
||
|
pr_info(TAG, "failed to create thermal sysfs, ret=%d!\n", ret);
|
||
|
return ret;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
module_init(eara_thrm_pre_init);
|
||
|
module_exit(eara_thrm_pre_exit);
|
||
|
MODULE_LICENSE("GPL");
|
||
|
MODULE_DESCRIPTION("MediaTek Frame Rate Smoother");
|
||
|
MODULE_AUTHOR("MediaTek Inc.");
|
||
|
|