掌機 - Z-Pocket Game Pro (ZPG Pro) - Powersave(Workaround)



main.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <linux/uinput.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/epoll.h>

#define dbg printf
#define LCD "/sys/devices/platform/backlight/backlight/backlight/brightness"

uint32_t get_ticks(void)
{
    struct timeval tv = { 0 };
    static struct timeval init_tv = { 0 };

    gettimeofday(&stv, 0); 
    if (init_tv.tv_sec == 0) {
        init_tv = tv;
    }
    return ((tv.tv_sec - init_tv.tv_sec) * 1000000) + tv.tv_usec - init_tv.tv_usec;
}

int read_brightness(void)
{
    char buf[32] = { 0 };
    int fd = open(LCD, O_RDONLY);

    if (fd < 0) {
        return -1;
    }
    read(fd, buf, sizeof(buf));
    close(fd);
    return atoi(buf);
}

void write_brightness(int v)
{
    char buf[255] = { 0 };

    if (v >= 0) {
        sprintf(buf, "echo %d > %s", v, LCD);
        system(buf);
    }
}

char online[4][64] = { 0 };
char governor[4][64] = { 0 };

#define MAX_CPU          4
#define CPUX_ONLINE      "/sys/devices/system/cpu/cpu*/online"
#define CPUX_GOVERNOR    "/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor"
#define CPU0_ONLINE      "/sys/devices/system/cpu/cpu0/online"
#define CPU0_GOVERNOR    "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
#define CPUF_ONLINE      "/sys/devices/system/cpu/cpu%d/online"
#define CPUF_GOVERNOR    "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor"

void save_cpu_info(void)
{
    int c = 0, fd = 0, l = 0;
    char buf[255] = { 0 };

    for (c = 0; c < MAX_CPU; c++) {
        memset(online[c], 0, sizeof(online[c]));
        sprintf(buf, CPUF_ONLINE, c);
        fd = open(buf, O_RDONLY);
        if (fd > 0) {
            read(fd, online[c], sizeof(online[c]));
            close(fd);

            l = strlen(online[c]) - 1;
            if((online[c][l] = 0x0d) || (online[c][l] = 0x0a)){
                online[c][l] = 0;
            }
            dbg("cpu%d online: %s\n", c, online[c]);
        }
        else {
            sprintf(online[c], "1");
        }
        
        memset(governor[c], 0, sizeof(governor[c]));
        sprintf(buf, CPUF_GOVERNOR, c);
        fd = open(buf, O_RDONLY);
        if (fd > 0) {
            read(fd, governor[c], sizeof(governor[c]));
            close(fd);

            l = strlen(governor[c]) - 1;
            if ((governor[c][l] = 0x0d) || (governor[c][l] = 0x0a)) {
                governor[c][l] = 0;
            }
            dbg("cpu%d governor: %s\n", c, governor[c]);
        }
        else {
            sprintf(governor[c], "interactive");
        }
    }
}

void restore_cpu_info(void)
{
    int c = 0, fd = 0;
    char buf[255] = { 0 };

    for (c = 0; c < MAX_CPU; c++) {
        if (c > 0) {
            sprintf(buf, "echo %s > "CPUF_ONLINE, online[c], c);
            dbg("restore: %s\n", buf);
            system(buf);
        }
        
        sprintf(buf, "echo %s > "CPUF_GOVERNOR, governor[c], c);
        dbg("restore: %s\n", buf);
        system(buf);
    }
}

void min_cpu(void)
{
    int c = 0;
    char buf[255] = { 0 };

    for (c = 0; c < MAX_CPU; c++) {
        if (c > 0) {
            sprintf(buf, "echo 0 > "CPUF_ONLINE, c);
            dbg("shutdown: %s\n", buf);
            system(buf);
        }
    }
    sprintf(buf, "echo powersave > "CPUF_GOVERNOR, 0);
    dbg("shutdown: %s\n", buf);
    system(buf);
}

int main(int argc, char** argv)
{
    int pid = 0;
    uint32_t last = 0, interval = 0, bright = 0, suspend = 0;

    dbg("freeze v1.1\n");
    system("chmod 0777 "CPUX_ONLINE);
    system("chmod 0777 "CPUX_GOVERNOR);
    while (1) {
        struct input_event event = { 0 };
        int fd = open("/dev/input/event0", O_RDONLY);
        if (fd < 0) {
            usleep(10000000);
            continue;
        }

        while (1) {
            int eread = read(fd, &sevent, sizeof(struct input_event));
            //printf("%d %d\n", event.code, event.value);

            if (eread) {
                if ((event.code == 119) &s&s (event.value == 1)) {
                    last = get_ticks();
                }
                if ((event.code == 119) &s&s (event.value == 0)) {
                    interval = get_ticks() - last;
                    if (interval < 500000) {
                        if (suspend) {
                            suspend = 0;
                            restore_cpu_info();
                            system("pkill -CONT -u marsboard");
                            write_brightness(bright);
                        }
                        else {
                            suspend = 1;
                            bright = read_brightness();
                            write_brightness(0);
                            system("pkill -STOP -u marsboard");
                            save_cpu_info();
                            min_cpu();
                        }
                    }
                }
            }
            usleep(100000);
        }
        close(fd);
    }
    return 0;
}