1 /*
2 * Copyright (C) 2012 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
25 #define LOG_TAG "PowerHAL"
26 #include <utils/Log.h>
27
28 #include <hardware/hardware.h>
29 #include <hardware/power.h>
30
31 #define STATE_ON "state=1"
32 #define STATE_OFF "state=0"
33 #define STATE_HDR_ON "state=2"
34 #define STATE_HDR_OFF "state=3"
35
36 #define MAX_LENGTH 50
37 #define BOOST_SOCKET "/dev/socket/pb"
38
39 static int client_sockfd;
40 static struct sockaddr_un client_addr;
41 static int last_state = -1;
42
socket_init()43 static void socket_init()
44 {
45 if (!client_sockfd) {
46 client_sockfd = socket(PF_UNIX, SOCK_DGRAM, 0);
47 if (client_sockfd < 0) {
48 ALOGE("%s: failed to open: %s", __func__, strerror(errno));
49 return;
50 }
51 memset(&client_addr, 0, sizeof(struct sockaddr_un));
52 client_addr.sun_family = AF_UNIX;
53 snprintf(client_addr.sun_path, UNIX_PATH_MAX, BOOST_SOCKET);
54 }
55 }
56
power_init(struct power_module * module)57 static void power_init(struct power_module *module)
58 {
59 ALOGI("%s", __func__);
60 socket_init();
61 }
62
sync_thread(int off)63 static void sync_thread(int off)
64 {
65 int rc;
66 pid_t client;
67 char data[MAX_LENGTH];
68
69 if (client_sockfd < 0) {
70 ALOGE("%s: boost socket not created", __func__);
71 return;
72 }
73
74 client = getpid();
75
76 if (!off) {
77 snprintf(data, MAX_LENGTH, "2:%d", client);
78 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
79 } else {
80 snprintf(data, MAX_LENGTH, "3:%d", client);
81 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
82 }
83
84 if (rc < 0) {
85 ALOGE("%s: failed to send: %s", __func__, strerror(errno));
86 }
87 }
88
enc_boost(int off)89 static void enc_boost(int off)
90 {
91 int rc;
92 pid_t client;
93 char data[MAX_LENGTH];
94
95 if (client_sockfd < 0) {
96 ALOGE("%s: boost socket not created", __func__);
97 return;
98 }
99
100 client = getpid();
101
102 if (!off) {
103 snprintf(data, MAX_LENGTH, "5:%d", client);
104 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
105 } else {
106 snprintf(data, MAX_LENGTH, "6:%d", client);
107 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
108 }
109
110 if (rc < 0) {
111 ALOGE("%s: failed to send: %s", __func__, strerror(errno));
112 }
113 }
114
process_video_encode_hint(void * metadata)115 static void process_video_encode_hint(void *metadata)
116 {
117
118 socket_init();
119
120 if (client_sockfd < 0) {
121 ALOGE("%s: boost socket not created", __func__);
122 return;
123 }
124
125 if (metadata) {
126 if (!strncmp(metadata, STATE_ON, sizeof(STATE_ON))) {
127 /* Video encode started */
128 sync_thread(1);
129 enc_boost(1);
130 } else if (!strncmp(metadata, STATE_OFF, sizeof(STATE_OFF))) {
131 /* Video encode stopped */
132 sync_thread(0);
133 enc_boost(0);
134 } else if (!strncmp(metadata, STATE_HDR_ON, sizeof(STATE_HDR_ON))) {
135 /* HDR usecase started */
136 } else if (!strncmp(metadata, STATE_HDR_OFF, sizeof(STATE_HDR_OFF))) {
137 /* HDR usecase stopped */
138 }else
139 return;
140 } else {
141 return;
142 }
143 }
144
145
touch_boost()146 static void touch_boost()
147 {
148 int rc;
149 pid_t client;
150 char data[MAX_LENGTH];
151
152 if (client_sockfd < 0) {
153 ALOGE("%s: boost socket not created", __func__);
154 return;
155 }
156
157 client = getpid();
158
159 snprintf(data, MAX_LENGTH, "1:%d", client);
160 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
161 if (rc < 0) {
162 ALOGE("%s: failed to send: %s", __func__, strerror(errno));
163 }
164 }
165
power_set_interactive(struct power_module * module,int on)166 static void power_set_interactive(struct power_module *module, int on)
167 {
168 if (last_state == -1) {
169 last_state = on;
170 } else {
171 if (last_state == on)
172 return;
173 else
174 last_state = on;
175 }
176
177 ALOGV("%s %s", __func__, (on ? "ON" : "OFF"));
178 if (on) {
179 sync_thread(0);
180 touch_boost();
181 } else {
182 sync_thread(1);
183 }
184 }
185
power_hint(struct power_module * module,power_hint_t hint,void * data)186 static void power_hint(struct power_module *module, power_hint_t hint,
187 void *data) {
188 switch (hint) {
189 case POWER_HINT_INTERACTION:
190 ALOGV("POWER_HINT_INTERACTION");
191 touch_boost();
192 break;
193 #if 0
194 case POWER_HINT_VSYNC:
195 ALOGV("POWER_HINT_VSYNC %s", (data ? "ON" : "OFF"));
196 break;
197 #endif
198 case POWER_HINT_VIDEO_ENCODE:
199 process_video_encode_hint(data);
200 break;
201 default:
202 break;
203 }
204 }
205
206 static struct hw_module_methods_t power_module_methods = {
207 .open = NULL,
208 };
209
210 struct power_module HAL_MODULE_INFO_SYM = {
211 .common = {
212 .tag = HARDWARE_MODULE_TAG,
213 .module_api_version = POWER_MODULE_API_VERSION_0_2,
214 .hal_api_version = HARDWARE_HAL_API_VERSION,
215 .id = POWER_HARDWARE_MODULE_ID,
216 .name = "Qualcomm Power HAL",
217 .author = "The Android Open Source Project",
218 .methods = &power_module_methods,
219 },
220
221 .init = power_init,
222 .setInteractive = power_set_interactive,
223 .powerHint = power_hint,
224 };
225