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 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 57 static void power_init(struct power_module *module) 58 { 59 ALOGI("%s", __func__); 60 socket_init(); 61 } 62 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 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 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 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 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 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