1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <errno.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <fcntl.h>
23 #include <dlfcn.h>
24 #include <cutils/uevent.h>
25 #include <errno.h>
26 #include <sys/poll.h>
27 #include <pthread.h>
28 #include <linux/netlink.h>
29 #include <stdlib.h>
30 #include <stdbool.h>
31
32 #define LOG_TAG "PowerHAL"
33 #include <utils/Log.h>
34
35 #include <hardware/hardware.h>
36 #include <hardware/power.h>
37
38 #define STATE_ON "state=1"
39 #define STATE_OFF "state=0"
40 #define STATE_HDR_ON "state=2"
41 #define STATE_HDR_OFF "state=3"
42
43 #define MAX_LENGTH 50
44 #define BOOST_SOCKET "/dev/socket/pb"
45
46 #define UEVENT_MSG_LEN 2048
47 #define TOTAL_CPUS 4
48 #define RETRY_TIME_CHANGING_FREQ 20
49 #define SLEEP_USEC_BETWN_RETRY 200
50 #define LOW_POWER_MAX_FREQ "1026000"
51 #define LOW_POWER_MIN_FREQ "384000"
52 #define NORMAL_MAX_FREQ "1512000"
53 #define UEVENT_STRING "online@/devices/system/cpu/"
54
55 static int client_sockfd;
56 static struct sockaddr_un client_addr;
57 static int last_state = -1;
58
59 static struct pollfd pfd;
60 static char *cpu_path_min[] = {
61 "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq",
62 "/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq",
63 "/sys/devices/system/cpu/cpu2/cpufreq/scaling_min_freq",
64 "/sys/devices/system/cpu/cpu3/cpufreq/scaling_min_freq",
65 };
66 static char *cpu_path_max[] = {
67 "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq",
68 "/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq",
69 "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq",
70 "/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq",
71 };
72 static bool freq_set[TOTAL_CPUS];
73 static bool low_power_mode = false;
74 static pthread_mutex_t low_power_mode_lock = PTHREAD_MUTEX_INITIALIZER;
75
socket_init()76 static void socket_init()
77 {
78 if (!client_sockfd) {
79 client_sockfd = socket(PF_UNIX, SOCK_DGRAM, 0);
80 if (client_sockfd < 0) {
81 ALOGE("%s: failed to open: %s", __func__, strerror(errno));
82 return;
83 }
84 memset(&client_addr, 0, sizeof(struct sockaddr_un));
85 client_addr.sun_family = AF_UNIX;
86 snprintf(client_addr.sun_path, UNIX_PATH_MAX, BOOST_SOCKET);
87 }
88 }
89
sysfs_write(const char * path,char * s)90 static int sysfs_write(const char *path, char *s)
91 {
92 char buf[80];
93 int len;
94 int fd = open(path, O_WRONLY);
95
96 if (fd < 0) {
97 strerror_r(errno, buf, sizeof(buf));
98 ALOGE("Error opening %s: %s\n", path, buf);
99 return -1;
100 }
101
102 len = write(fd, s, strlen(s));
103 if (len < 0) {
104 strerror_r(errno, buf, sizeof(buf));
105 ALOGE("Error writing to %s: %s\n", path, buf);
106 return -1;
107 }
108
109 close(fd);
110 return 0;
111 }
112
uevent_event()113 static int uevent_event()
114 {
115 char msg[UEVENT_MSG_LEN];
116 char *cp;
117 int n, cpu, ret, retry = RETRY_TIME_CHANGING_FREQ;
118
119 n = recv(pfd.fd, msg, UEVENT_MSG_LEN, MSG_DONTWAIT);
120 if (n <= 0) {
121 return -1;
122 }
123 if (n >= UEVENT_MSG_LEN) { /* overflow -- discard */
124 return -1;
125 }
126
127 cp = msg;
128
129 if (strstr(cp, UEVENT_STRING)) {
130 n = strlen(cp);
131 errno = 0;
132 cpu = strtol(cp + n - 1, NULL, 10);
133
134 if (errno == EINVAL || errno == ERANGE || cpu < 0 || cpu >= TOTAL_CPUS) {
135 return -1;
136 }
137
138 pthread_mutex_lock(&low_power_mode_lock);
139 if (low_power_mode && !freq_set[cpu]) {
140 while (retry) {
141 sysfs_write(cpu_path_min[cpu], LOW_POWER_MIN_FREQ);
142 ret = sysfs_write(cpu_path_max[cpu], LOW_POWER_MAX_FREQ);
143 if (!ret) {
144 freq_set[cpu] = true;
145 break;
146 }
147 usleep(SLEEP_USEC_BETWN_RETRY);
148 retry--;
149 }
150 } else if (!low_power_mode && freq_set[cpu]) {
151 while (retry) {
152 ret = sysfs_write(cpu_path_max[cpu], NORMAL_MAX_FREQ);
153 if (!ret) {
154 freq_set[cpu] = false;
155 break;
156 }
157 usleep(SLEEP_USEC_BETWN_RETRY);
158 retry--;
159 }
160 }
161 pthread_mutex_unlock(&low_power_mode_lock);
162 }
163 return 0;
164 }
165
thread_uevent(void * x)166 void *thread_uevent(__attribute__((unused)) void *x)
167 {
168 while (1) {
169 int nevents, ret;
170
171 nevents = poll(&pfd, 1, -1);
172
173 if (nevents == -1) {
174 if (errno == EINTR)
175 continue;
176 ALOGE("powerhal: thread_uevent: poll_wait failed\n");
177 break;
178 }
179 ret = uevent_event();
180 if (ret < 0)
181 ALOGE("Error processing the uevent event");
182 }
183 return NULL;
184 }
185
uevent_init()186 static void uevent_init()
187 {
188 struct sockaddr_nl client;
189 pthread_t tid;
190 pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
191
192 if (pfd.fd < 0) {
193 ALOGE("%s: failed to open: %s", __func__, strerror(errno));
194 return;
195 }
196 memset(&client, 0, sizeof(struct sockaddr_nl));
197 pthread_create(&tid, NULL, thread_uevent, NULL);
198 client.nl_family = AF_NETLINK;
199 client.nl_pid = tid;
200 client.nl_groups = -1;
201 pfd.events = POLLIN;
202 bind(pfd.fd, (void *)&client, sizeof(struct sockaddr_nl));
203 return;
204 }
205
power_init(struct power_module * module)206 static void power_init(__attribute__((unused)) struct power_module *module)
207 {
208 ALOGI("%s", __func__);
209 socket_init();
210 uevent_init();
211 }
212
sync_thread(int off)213 static void sync_thread(int off)
214 {
215 int rc;
216 pid_t client;
217 char data[MAX_LENGTH];
218
219 if (client_sockfd < 0) {
220 ALOGE("%s: boost socket not created", __func__);
221 return;
222 }
223
224 client = getpid();
225
226 if (!off) {
227 snprintf(data, MAX_LENGTH, "2:%d", client);
228 rc = sendto(client_sockfd, data, strlen(data), 0,
229 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
230 } else {
231 snprintf(data, MAX_LENGTH, "3:%d", client);
232 rc = sendto(client_sockfd, data, strlen(data), 0,
233 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
234 }
235
236 if (rc < 0) {
237 ALOGE("%s: failed to send: %s", __func__, strerror(errno));
238 }
239 }
240
enc_boost(int off)241 static void enc_boost(int off)
242 {
243 int rc;
244 pid_t client;
245 char data[MAX_LENGTH];
246
247 if (client_sockfd < 0) {
248 ALOGE("%s: boost socket not created", __func__);
249 return;
250 }
251
252 client = getpid();
253
254 if (!off) {
255 snprintf(data, MAX_LENGTH, "5:%d", client);
256 rc = sendto(client_sockfd, data, strlen(data), 0,
257 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
258 } else {
259 snprintf(data, MAX_LENGTH, "6:%d", client);
260 rc = sendto(client_sockfd, data, strlen(data), 0,
261 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
262 }
263
264 if (rc < 0) {
265 ALOGE("%s: failed to send: %s", __func__, strerror(errno));
266 }
267 }
268
process_video_encode_hint(void * metadata)269 static void process_video_encode_hint(void *metadata)
270 {
271
272 socket_init();
273
274 if (client_sockfd < 0) {
275 ALOGE("%s: boost socket not created", __func__);
276 return;
277 }
278
279 if (metadata) {
280 if (!strncmp(metadata, STATE_ON, sizeof(STATE_ON))) {
281 /* Video encode started */
282 sync_thread(1);
283 enc_boost(1);
284 } else if (!strncmp(metadata, STATE_OFF, sizeof(STATE_OFF))) {
285 /* Video encode stopped */
286 sync_thread(0);
287 enc_boost(0);
288 } else if (!strncmp(metadata, STATE_HDR_ON, sizeof(STATE_HDR_ON))) {
289 /* HDR usecase started */
290 } else if (!strncmp(metadata, STATE_HDR_OFF, sizeof(STATE_HDR_OFF))) {
291 /* HDR usecase stopped */
292 } else
293 return;
294 } else {
295 return;
296 }
297 }
298
299
touch_boost()300 static void touch_boost()
301 {
302 int rc;
303 pid_t client;
304 char data[MAX_LENGTH];
305
306 if (client_sockfd < 0) {
307 ALOGE("%s: boost socket not created", __func__);
308 return;
309 }
310
311 client = getpid();
312
313 snprintf(data, MAX_LENGTH, "1:%d", client);
314 rc = sendto(client_sockfd, data, strlen(data), 0,
315 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
316 if (rc < 0) {
317 ALOGE("%s: failed to send: %s", __func__, strerror(errno));
318 }
319 }
320
power_set_interactive(struct power_module * module,int on)321 static void power_set_interactive(__attribute__((unused)) struct power_module *module, int on)
322 {
323 if (last_state == -1) {
324 last_state = on;
325 } else {
326 if (last_state == on)
327 return;
328 else
329 last_state = on;
330 }
331
332 ALOGV("%s %s", __func__, (on ? "ON" : "OFF"));
333 if (on) {
334 sync_thread(0);
335 touch_boost();
336 } else {
337 sync_thread(1);
338 }
339 }
340
power_hint(struct power_module * module,power_hint_t hint,void * data)341 static void power_hint( __attribute__((unused)) struct power_module *module,
342 power_hint_t hint, __attribute__((unused)) void *data)
343 {
344 int cpu, ret;
345
346 switch (hint) {
347 case POWER_HINT_INTERACTION:
348 ALOGV("POWER_HINT_INTERACTION");
349 touch_boost();
350 break;
351 #if 0
352 case POWER_HINT_VSYNC:
353 ALOGV("POWER_HINT_VSYNC %s", (data ? "ON" : "OFF"));
354 break;
355 #endif
356 case POWER_HINT_VIDEO_ENCODE:
357 process_video_encode_hint(data);
358 break;
359
360 case POWER_HINT_LOW_POWER:
361 pthread_mutex_lock(&low_power_mode_lock);
362 if (data) {
363 low_power_mode = true;
364 for (cpu = 0; cpu < TOTAL_CPUS; cpu++) {
365 sysfs_write(cpu_path_min[cpu], LOW_POWER_MIN_FREQ);
366 ret = sysfs_write(cpu_path_max[cpu], LOW_POWER_MAX_FREQ);
367 if (!ret) {
368 freq_set[cpu] = true;
369 }
370 }
371 } else {
372 low_power_mode = false;
373 for (cpu = 0; cpu < TOTAL_CPUS; cpu++) {
374 ret = sysfs_write(cpu_path_max[cpu], NORMAL_MAX_FREQ);
375 if (!ret) {
376 freq_set[cpu] = false;
377 }
378 }
379 }
380 pthread_mutex_unlock(&low_power_mode_lock);
381 break;
382 default:
383 break;
384 }
385 }
386
387 static struct hw_module_methods_t power_module_methods = {
388 .open = NULL,
389 };
390
391 struct power_module HAL_MODULE_INFO_SYM = {
392 .common = {
393 .tag = HARDWARE_MODULE_TAG,
394 .module_api_version = POWER_MODULE_API_VERSION_0_2,
395 .hal_api_version = HARDWARE_HAL_API_VERSION,
396 .id = POWER_HARDWARE_MODULE_ID,
397 .name = "Flo/Deb Power HAL",
398 .author = "The Android Open Source Project",
399 .methods = &power_module_methods,
400 },
401
402 .init = power_init,
403 .setInteractive = power_set_interactive,
404 .powerHint = power_hint,
405 };
406