blob: 8c147935dfc7b124a0de5776319804ee42b378dd [file] [log] [blame]
#include "lynq-qser-autosuspend.h"
#include <stdio.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/epoll.h>
#include <linux/input.h>
#include "mbtk_type.h"
#include "mbtk_log.h"
#include "mbtk_info_api.h"
#include "mbtk_power.h"
/*
This module is system sleep, the system cannot sleep when the lock exists
To verify whether it is in sleep state, it is necessary to test the power consumption
Power management principle, as long as a wakelock lock exists, the system will not enter the Suspend state
So the name can be arbitrarily chosen to indicate that such a lock is needed so that the system does not sleep
*/
#if defined(MBTK_PLATFORM_KERNEL_5)
#define MTBK_POWERIND "/system/etc/powerind" //1806
#elif defined(MBTK_PLATFORM_KERNEL_3)
#define MTBK_POWERIND "/etc/powerind" //1803
#endif
static bool call_Off = FALSE;
static bool nw_off = FALSE;
static bool sms_off = FALSE;
static bool data_off = FALSE;
static pthread_t lpm_t;
static int edge_t = 0;
static int epoll_fd_t = -1;
static int fd_t = -1;
static int socket_t[2];
typedef struct{
qser_lpm_wakeupin_data_t wakeupin;
qser_lpm_wakeupout_data_t wakeupout;
qser_lpm_Handler_t wakehandle;
}lynq_wake_t;
static lynq_wake_t lpm_init;
typedef struct
{
int fd;
char name[64];
} lock_name;
#define LOCK_MAX_SIZE 129
lock_name lynq_lock_name[LOCK_MAX_SIZE]={0};
static bool autosleep_enable = FALSE;
static mbtk_info_handle_t* whitelist_info_handle = NULL;
static int powerrind_get()
{
char buffer[4];
int ret = 0;
int fd = open(MTBK_POWERIND, O_RDWR | O_SYNC, 0662);
if (fd != -1)
{
read(fd, buffer, strlen(buffer)+1);
close(fd);
}
ret = atoi(buffer);
return ret;
}
#if 1
static int sleep_epoll_deregister(int epoll_fd,int fd )
{
int ret;
do {
ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
} while (ret < 0 && errno == EINTR);
return ret;
}
static int sleep_epoll_register(int epoll_fd, int fd)
{
struct epoll_event ev;
int ret, flags;
/* important: make the fd non-blocking */
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
ev.events = EPOLLIN;
ev.data.fd = fd;
do {
ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
} while (ret < 0 && errno == EINTR);
return ret;
}
#endif
int qser_autosuspend_enable(char enable)
{
//UNUSED(enable);
if((enable == 1) || enable == '1')
{
//if(!mbtk_system_sleep())
if(!access("/sys/power/autosleep", W_OK))
{
system("echo mem > /sys/power/autosleep");
autosleep_enable = TRUE;
return 0;
}
else
{
LOGE("/sys/power/autosleep can not write.");
return -1;
}
}
else if((enable == 0) || enable == '0')
{
if(!access("/sys/power/autosleep", W_OK))
{
system("echo off > /sys/power/autosleep");
autosleep_enable = FALSE;
return 0;
}
else
{
LOGE("/sys/power/autosleep can not write.");
return -1;
}
}
else
{
LOGE("qser_autosuspend_enablecan enable err.");
return -1;
}
return 0;
}
int qser_wakelock_create(const char* name , size_t len)
{
//UNUSED(name);
//UNUSED(len);
int len_t;
/*
if(!autosleep_enable) {
LOGE("Autosleep not enable.");
return -1;
}
*/
len_t = strlen(name);
if((name != NULL) && (len < 33) && (len_t < 33))
{
int i;
//name
for(i=1 ;i<LOCK_MAX_SIZE;i++)
{
if(strcmp(lynq_lock_name[i].name, name) == 0)
{
LOGE("Repeated names.");
return -1;
}
}
for(i=1 ;i<LOCK_MAX_SIZE;i++)
{
if(lynq_lock_name[i].fd == 0)
break;
}
if (i >= LOCK_MAX_SIZE)
{
LOGE("Fd is full.");
return -1;
}
memcpy(lynq_lock_name[i].name, name, strlen(name)+1);
lynq_lock_name[i].fd = i;
return lynq_lock_name[i].fd -1;//Starting from scratch
}
else
return -1;
return -1;
}
int qser_wakelock_lock(int fd)
{
//UNUSED(fd);
/*
if(!autosleep_enable) {
LOGE("Autosleep not enable.");
return -1;
}
*/
int i;
for(i=1;i<LOCK_MAX_SIZE;i++)
{
if(lynq_lock_name[i].fd -1 == fd)
break;
}
if(i == LOCK_MAX_SIZE)
{
LOGE("LOCK_MAX_SIZE is full\n");
return -1;
}
if(!access("/sys/power/wake_lock", W_OK))
{
char cmd[128]={0};
sprintf(cmd, "echo %s > /sys/power/wake_lock", lynq_lock_name[i].name);
system(cmd);
return 0;
}
else
{
LOGE("/sys/power/wake_lock can not write.");
return -1;
}
return 0;
}
int qser_wakelock_unlock(int fd)
{
//UNUSED(fd);
/*
if(!autosleep_enable) {
LOGE("Autosleep not enable.");
return -1;
}
*/
int i;
for(i=1;i<LOCK_MAX_SIZE;i++)
{
if(lynq_lock_name[i].fd -1 == fd)
break;
}
if(i == LOCK_MAX_SIZE)
{
LOGE("LOCK_MAX_SIZE is full\n");
return -1;
}
if(!access("/sys/power/wake_unlock", W_OK))
{
char cmd[128]={0};
sprintf(cmd, "echo %s > /sys/power/wake_unlock", lynq_lock_name[i].name);
system(cmd);
return 0;
}
else
{
LOGE("/sys/power/wake_unlock can not write.");
return -1;
}
return 0;
}
int qser_wakelock_destroy(int fd)
{
//UNUSED(fd);
/*
if(!autosleep_enable) {
LOGE("Autosleep not enable.");
return -1;
}
*/
int i;
for(i=1;i<LOCK_MAX_SIZE;i++)
{
if(lynq_lock_name[i].fd -1 == fd)
break;
}
if(i == LOCK_MAX_SIZE)
{
LOGE("LOCK_MAX_SIZE is full\n");
return -1;
}
else
{
lynq_lock_name[i].fd = 0;
memset(lynq_lock_name[i].name, 0, 64);
return 0;
}
return 0;
}
void *threadFunction(void *arg)
{
int pinValue;
int i;
char buf[8] = {0};
struct input_event ev_input = { 0 };
const int size = sizeof(struct input_event);
epoll_fd_t = epoll_create(2);
/*
struct epoll_event event;
memset(&event, 0, sizeof(struct epoll_event));
event.events = EPOLLIN | EPOLLET;
event.data.fd = open("/dev/input/event0", O_RDONLY); // 根据实际情况指定正确的GPIO设备文件名
fd_t = event.data.fd;
if (epoll_ctl(epoll_fd_t, EPOLL_CTL_ADD, event.data.fd, &event) == -1)
{
LOGE("Failed to add GPIO device file.");
return NULL;
}
memset(&event, 0, sizeof(struct epoll_event));
event.events = EPOLLIN | EPOLLET;
event.data.fd = socket_t[0];
LOGE("threadFunction event.data.fd =[%d] ", event.data.fd);
if (epoll_ctl(epoll_fd_t, EPOLL_CTL_ADD, event.data.fd, &event) == -1)
{
LOGE("Failed to add GPIO device file.");
return NULL;
}
*/
#if defined(MBTK_SG_SUPPORT)
fd_t = open("/dev/input/event1", O_RDONLY);
LOGI("init sg pthread_event");
#else
fd_t = open("/dev/input/event0", O_RDONLY);
#endif
sleep_epoll_register(epoll_fd_t, fd_t);
sleep_epoll_register(epoll_fd_t, socket_t[1]);
while (true)
{
struct epoll_event events[2];
struct epoll_event ev;
int cmd = 0;
int numEvents = epoll_wait(epoll_fd_t, events, 2, -1);
for (i = 0; i < numEvents; ++i)
{
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP))
{
LOGE("Error on GPIO device.");
return NULL;
}
else if ((events[i].events & EPOLLIN) || (events[i].events & EPOLLET))
{
//handleInterrupt(events[i].data.fd);
if (events[i].data.fd == socket_t[1])
{
memset(buf, 0, sizeof(buf));
read(socket_t[1], buf, sizeof(buf));
if (1 == atoi(buf))
{
if(close(fd_t) == 0)
LOGI("close(fd_t)ing");
sleep_epoll_deregister(epoll_fd_t, socket_t[1]);
sleep_epoll_deregister(epoll_fd_t, fd_t);
/*
memset(&ev, 0, sizeof(struct epoll_event));
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = socket_t[1];
epoll_ctl( epoll_fd_t, EPOLL_CTL_DEL, ev.data.fd, &ev);
memset(&ev, 0, sizeof(struct epoll_event));
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = fd_t;
epoll_ctl( epoll_fd_t, EPOLL_CTL_DEL, ev.data.fd, &ev);
*/
LOGI("do pthread_exit");
return NULL;
}
}
else if (events[i].data.fd == fd_t)
{
LOGI("go pthread_event");
memset(&ev_input, 0x00, size);
read(fd_t, &ev_input, size);
LOGI("ev_input type = %x, code = %x, value = %x", ev_input.type, ev_input.code,ev_input.value);
if (ev_input.code == 2)
{
LOGI(">>>>ev_input.value = [%d]",ev_input.value);
pinValue = (int)ev_input.value;
edge_t = pinValue;
lpm_init.wakehandle(edge_t);
}
}
else
{
LOGE("Unknown events[i].data.fd = %d", events[i].data.fd);
}
}
}
}
return NULL;
}
int qser_lpm_init(qser_lpm_Handler_t qser_lpm_handler, qser_pm_cfg_t *qser_lpm_cfg)
{
//UNUSED(qser_lpm_handler);
//UNUSED(qser_lpm_cfg);
if (socketpair( AF_LOCAL, SOCK_STREAM, 0, socket_t ) < 0 )
{
LOGE("[qser_lpm_init] could not create thread control socket pair: %s", strerror(errno));
/*close the control socket pair && Retry again.*/
if(socket_t[0] > 0)
{
close(socket_t[0] );
socket_t[0] = -1;
}
if(socket_t[1] > 0)
{
close(socket_t[1] );
socket_t[1] = -1;
}
return -1;
}
lpm_init.wakeupin.wakeupin_pin = qser_lpm_cfg->wakeupin.wakeupin_pin;
LOGI(">>pin = %d",lpm_init.wakeupin.wakeupin_pin);
lpm_init.wakeupin.wakeupin_edge = qser_lpm_cfg->wakeupin.wakeupin_edge;
LOGI(">>edge = %d",lpm_init.wakeupin.wakeupin_edge);
edge_t = qser_lpm_cfg->wakeupin.wakeupin_edge;//保留原始状态值 0 or 1
lpm_init.wakehandle = qser_lpm_handler;
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
{
LOGE("pthread_attr_setdetachstate() fail");
return -1;
}
if(pthread_create(&lpm_t, &thread_attr, threadFunction, NULL))
//if(pthread_create(&lpm_t, NULL, threadFunction, NULL))
{
LOGE("qser_lpm_init can't create thread");
return -1;
}
pthread_attr_destroy(&thread_attr);
//if (edge_t != qser_lpm_cfg->wakeupin.wakeupin_edge)//说明有变化,并且和原来的值不相同
//qser_lpm_handler(edge_t);
return 0;
}
int qser_lpm_deinit(void)
{
char buf[4]={0};
if (fd_t == -1)
return 0;
if (fd_t != -1)
{
//char cmd = 1;
strcpy(buf, "1");
void* dummy = NULL;
write( socket_t[0], buf, sizeof(buf) );
//pthread_join(lpm_t, &dummy);
sleep(1);
// close the control socket pair
if(socket_t[0] > 0)
{
close(socket_t[0] );
socket_t[0] = -1;
}
if(socket_t[1] > 0)
{
close(socket_t[1] );
socket_t[1] = -1;
}
//重置还原
fd_t = -1;
}
return 0;
}
/*
例如AT*POWERIND=31,就相当于设置NETWORK、SIM、SMS、CS CALL、PS DATA变化时都不主动上报,
其中PS DATA目前暂时不支持,只是保留了这个标志位;
AP power state: 1~31 means suspend, bitmap: bit0 - NETWORK;bit1 - SIM;bit2 - SMS;bit3 - CS CALL;bit4 - PS DATA
0 means resume all.
目标文件"/system/etc/powerind"
如果bit0-bit3都配置可以采用的值是1-15,如果是当前采用NETWORK SMS CALL 则值的取值是 1 4 8 5 9 12 13
*/
int qser_whitelist_set(char* whitelish)
{
//UNUSED(whitelish);
uint32 on = 0;
int call_t, nw_t, data_t, sms_t, tmp;
int len = strlen(whitelish);
if (len != 4)
{
LOGE("whitelish num error num=[%d]",len);
return -1;
}
tmp = atoi(whitelish);
call_t = tmp/1000;
nw_t = tmp%1000/100;
data_t = tmp%1000%100/10;
sms_t = tmp%1000%100%10;
if (call_t == 1)
call_Off = TRUE;
else
call_Off = FALSE;
if (nw_t == 1)
nw_off = TRUE;
else
nw_off = FALSE;
if (data_t == 1)
data_off = TRUE;
else
data_off = FALSE;
if (sms_t == 1)
sms_off = TRUE;
else
sms_off = FALSE;
if (call_Off == FALSE && nw_off == FALSE && data_off == FALSE && sms_off == FALSE)
{
on = 29;//0000的情况,所有上报源都屏蔽,SIM的上报会一直被包含在内
}
else
{
if (call_Off == TRUE)
call_t = 8;
else
call_t = 0;
if (nw_off == TRUE)
nw_t = 1;
else
nw_t = 0;
if (data_off == TRUE)
data_t = 16;
else
data_t = 0;
if (sms_off == TRUE)
sms_t = 4;
else
sms_t = 0;
on = 29 - (call_t + nw_t + data_t + sms_t);//SIM的上报会一直被包含在内
}
if(whitelist_info_handle == NULL)
{
whitelist_info_handle = mbtk_info_handle_get();
if(whitelist_info_handle)
{
LOGI("creat whitelist_info_handle is success");
}
else
{
LOGE("creat whitelist_info_handle is fail");
return -1;
}
}
int err = mbtk_wakeup_state_set(whitelist_info_handle, on);
if(err)
{
LOGE("whitelist_info_handle Error : %d", err);
return -1;
}
return 0;
}
int qser_whitelist_get(char* whitelish)
{
//UNUSED(whitelish);
char list[10]={0};
int call_t, nw_t, data_t, sms_t;
int get_tmp;
get_tmp = powerrind_get();
//LOGI(">>>get_tmp: %d",get_tmp);
//call 8 nw 1 data 16 sms 4 SIM的上报会一直被包含在内
switch(get_tmp)
{
case 0:
sprintf(list, "%d%d%d%d", 1, 1, 1, 1);
break;
case 8:
sprintf(list, "%d%d%d%d", 0, 1, 1, 1);
break;
case 1:
sprintf(list, "%d%d%d%d", 1, 0, 1, 1);
break;
case 16:
sprintf(list, "%d%d%d%d", 1, 1, 0, 1);
break;
case 4:
sprintf(list, "%d%d%d%d", 1, 1, 1, 0);
break;
case 9:
sprintf(list, "%d%d%d%d", 0, 0, 1, 1);
break;
case 24:
sprintf(list, "%d%d%d%d", 0, 1, 0, 1);
break;
case 12:
sprintf(list, "%d%d%d%d", 0, 1, 1, 0);
break;
case 17:
sprintf(list, "%d%d%d%d", 1, 0, 0, 1);
break;
case 5:
sprintf(list, "%d%d%d%d", 1, 0, 1, 0);
break;
case 20:
sprintf(list, "%d%d%d%d", 1, 1, 0, 0);
break;
case 25:
sprintf(list, "%d%d%d%d", 0, 0, 0, 1);
break;
case 13:
sprintf(list, "%d%d%d%d", 0, 0, 1, 0);
break;
case 28:
sprintf(list, "%d%d%d%d", 0, 1, 0, 0);
break;
case 21:
sprintf(list, "%d%d%d%d", 1, 0, 0, 0);
break;
case 29:
sprintf(list, "%d%d%d%d", 0, 0, 0, 0);
break;
default :
LOGE("qser_whitelist_get is error");
break;
}
//LOGI(">>>get list: %s",list);
strncpy(whitelish, list, strlen(list));
if(whitelist_info_handle != NULL)
{
mbtk_info_handle_free(&whitelist_info_handle);
LOGI("deinit whitelist_info_handle is succuess");
}
return 0;
}