lin
2025-07-30 fcd736bf35fd93b563e9bbf594f2aa7b62028cc9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include <cutils/klog.h>
 
#include "aw_healthd.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/epoll.h>
#include <string.h>
#include <errno.h>
#include <sys/timerfd.h>
#include <android-base/logging.h>
#include <fcntl.h>
#define LOGE(x...) KLOG_ERROR("charger", x);
#define LOGW(x...) KLOG_WARNING("charger", x);
#define LOGV(x...) KLOG_DEBUG("charger", x);
#ifdef CHARGER_ENABLE_SUSPEND
#include <suspend/autosuspend.h>
#endif
#include <sys/reboot.h>
#include <hardware/sunxi_display2.h>
#include <pthread.h>
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
#define DISP_ID 0
static bool suspend_flag = false;
int backlight_on(int ret)
{
    unsigned long  args[3];
    int err = 0;
    int disp_fd;
    static int value;
    static int init_ok;
    if((disp_fd = open("/dev/disp", O_RDONLY)) < 0)
    {
        LOGW("backlight_on open disp_fd failed!\n");
        return -1;
    }
 
    pthread_mutex_lock(&g_lock);
    args[0] = DISP_ID;
    if (ret == 0) {
        args[1] = 0;
    } else {
        args[1] = 100;
    }
    if ((!init_ok) || (value != ret)){
        init_ok = 1;
        value = ret;
        LOGW("backlight_on set lcd%lu lcd_bl:%lu\n",args[0],args[1]);
        if(ioctl(disp_fd,DISP_GET_OUTPUT_TYPE,args) == DISP_OUTPUT_TYPE_LCD)
        {
            err = ioctl(disp_fd,DISP_LCD_SET_BRIGHTNESS,args);
        }
    }
    pthread_mutex_unlock(&g_lock);
 
    if(disp_fd)
        close(disp_fd);
    return err;
}
 
 
int request_suspend(bool enable)
{
 
    suspend_flag = enable;
    if (enable) {
        backlight_on(0);
        return autosuspend_enable();
    }
    else {
        backlight_on(1);
        return autosuspend_disable();
    }
}
 
#define WAKEALARM_PATH        "/sys/class/rtc/rtc0/wakealarm"
#define ALARM_IN_BOOTING_PATH        "/sys/module/rtc_sunxi/parameters/alarm_in_booting"
static int uevent_fd;
static int wakealarm_fd;
static int epollfd;
static pthread_t tid_alarm;
#define EPOLL_LISTEN_CNT 1
static long get_wakealarm_sec(void)
{
    int fd = 0, ret = 0;
    unsigned long wakealarm_time = 0;
    char buf[32] = { 0 };
 
    fd = open(WAKEALARM_PATH, O_RDWR);
    if (fd < 0) {
        LOGE("open %s failed, return=%d\n", WAKEALARM_PATH, fd);
        return fd;
    }
 
    ret = read(fd, buf, sizeof(buf));
    if (ret > 0) {
        wakealarm_time = strtoul(buf, NULL, 0);
        // Clean initial wakealarm.
        // We will set wakealarm again use timerfd_settime.
        // Initial wakealarm's time unit is second, have conflict with
        // nanosecond alarmtimer in alarmtimer_suspend().
        snprintf(buf, sizeof(buf), "0");
        write(fd, buf, strlen(buf) + 1);
 
        close(fd);
        return wakealarm_time;
    }
 
    close(fd);
    return ret;
}
 
static long is_alarm_in_booting(void)
{
    int fd = 0, ret = 0;
    unsigned long alarm_in_booting = 0;
    char buf[32] = { 0 };
 
    fd = open(ALARM_IN_BOOTING_PATH, O_RDONLY);
    if (fd < 0) {
        LOGE("open %s failed, return=%d\n", ALARM_IN_BOOTING_PATH, fd);
        return fd;
    }
 
    ret = read(fd, buf, sizeof(buf));
    if (ret > 0) {
        alarm_in_booting = strtoul(buf, NULL, 0);
    }
    LOG(WARNING) <<  __func__ <<" "<< __LINE__<<"alarm_in_booting: "<< alarm_in_booting << "\n";
    close(fd);
    return alarm_in_booting;
}
 
 
void *alarm_thread_handler(void *arg)
{
    (void)arg;
    int ret = 0;
    struct epoll_event events[EPOLL_LISTEN_CNT];
    struct timeval now_tv = { 0, 0 };
    while (true) {
        int nevents = epoll_wait(epollfd, events,  EPOLL_LISTEN_CNT, -1);
        if (nevents < 0) {
            LOG(WARNING) <<  __func__ <<" ++++"<< __LINE__ << " event:"<< nevents<< "errno: "<< errno << "\n";
            continue;
        }
        unsigned long long wakeups;
 
        if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
            LOGE("wakealarm_event: read wakealarm fd failed\n");
            continue;
        }
        gettimeofday(&now_tv, NULL);
        LOG(WARNING) <<  __func__ <<" " << "rebooting" << "now" << now_tv.tv_sec <<"\n";
        request_suspend(false);
        reboot(RB_AUTOBOOT);
    }
 
    return NULL;
}
 
 
static void init_shutdown_alarm(void)
{
    long alarm_secs, alarm_in_booting = 0;
    struct timeval now_tv = { 0, 0 };
    struct timespec ts;
    struct epoll_event ev;
    alarm_secs = get_wakealarm_sec();
    // have alarm irq in booting ?
    alarm_in_booting = is_alarm_in_booting();
    gettimeofday(&now_tv, NULL);
 
    LOG(WARNING) << "alarm_in_booting: "<< alarm_in_booting << "alarm_secs " << alarm_secs << "now" << now_tv.tv_sec << "\n";
    // alarm interval time == 0 and have no alarm irq in booting
    if (alarm_secs <= 0 && (alarm_in_booting != 1))
        return;
    if (alarm_secs)
        ts.tv_sec = alarm_secs;
    else
        ts.tv_sec = (long)now_tv.tv_sec + 1;
 
    ts.tv_nsec = 0;
 
    struct itimerspec spec;
    memset(&spec, 0, sizeof(spec));
    memcpy(&spec.it_value, &ts, sizeof(spec.it_value));
 
      //timerfd_init
    wakealarm_fd = timerfd_create(CLOCK_REALTIME_ALARM, 0);
    if (wakealarm_fd <= 0) {
        LOGE("%s, %d, alarm_fd=%d and exit\n", __func__, __LINE__, wakealarm_fd);
        return ;
    }
 
    if (timerfd_settime(wakealarm_fd, TFD_TIMER_ABSTIME, &spec, NULL) == -1){
        LOGE("timerfd_settime failed Error[%d:%s]\n",errno,strerror(errno));
        close(wakealarm_fd);
        return ;
    };
      //epoll_init
    epollfd = epoll_create(EPOLL_LISTEN_CNT);
    if (epollfd > 0) {
        ev.events = EPOLLIN | EPOLLWAKEUP;
        //add wakealarm_fd to epollfd
        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1) {
            LOGE("epoll_ctl failed; errno=%d\n", errno);
            return;
        }
    } else {
            LOGE("epoll_create failed; errno=%d\n", errno);
            return;
    }
    pthread_create(&tid_alarm, NULL, alarm_thread_handler, NULL);
    return;
}
void aw_healthd_init()
{
    init_shutdown_alarm();
}