0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <errno.h>
0010 #include <fcntl.h>
0011 #include <getopt.h>
0012 #include <libgen.h>
0013 #include <limits.h>
0014 #include <stdio.h>
0015 #include <stdlib.h>
0016 #include <string.h>
0017 #include <signal.h>
0018 #include <unistd.h>
0019
0020 #include <syslog.h>
0021
0022 #include <sys/epoll.h>
0023 #include <sys/stat.h>
0024 #include <sys/types.h>
0025
0026 #include <thermal.h>
0027 #include "thermal-tools.h"
0028
0029 struct options {
0030 int loglevel;
0031 int logopt;
0032 int interactive;
0033 int daemonize;
0034 };
0035
0036 struct thermal_data {
0037 struct thermal_zone *tz;
0038 struct thermal_handler *th;
0039 };
0040
0041 static int show_trip(struct thermal_trip *tt, __maybe_unused void *arg)
0042 {
0043 INFO("trip id=%d, type=%d, temp=%d, hyst=%d\n",
0044 tt->id, tt->type, tt->temp, tt->hyst);
0045
0046 return 0;
0047 }
0048
0049 static int show_temp(struct thermal_zone *tz, __maybe_unused void *arg)
0050 {
0051 thermal_cmd_get_temp(arg, tz);
0052
0053 INFO("temperature: %d\n", tz->temp);
0054
0055 return 0;
0056 }
0057
0058 static int show_governor(struct thermal_zone *tz, __maybe_unused void *arg)
0059 {
0060 thermal_cmd_get_governor(arg, tz);
0061
0062 INFO("governor: '%s'\n", tz->governor);
0063
0064 return 0;
0065 }
0066
0067 static int show_tz(struct thermal_zone *tz, __maybe_unused void *arg)
0068 {
0069 INFO("thermal zone '%s', id=%d\n", tz->name, tz->id);
0070
0071 for_each_thermal_trip(tz->trip, show_trip, NULL);
0072
0073 show_temp(tz, arg);
0074
0075 show_governor(tz, arg);
0076
0077 return 0;
0078 }
0079
0080 static int tz_create(const char *name, int tz_id, __maybe_unused void *arg)
0081 {
0082 INFO("Thermal zone '%s'/%d created\n", name, tz_id);
0083
0084 return 0;
0085 }
0086
0087 static int tz_delete(int tz_id, __maybe_unused void *arg)
0088 {
0089 INFO("Thermal zone %d deleted\n", tz_id);
0090
0091 return 0;
0092 }
0093
0094 static int tz_disable(int tz_id, void *arg)
0095 {
0096 struct thermal_data *td = arg;
0097 struct thermal_zone *tz = thermal_zone_find_by_id(td->tz, tz_id);
0098
0099 INFO("Thermal zone %d ('%s') disabled\n", tz_id, tz->name);
0100
0101 return 0;
0102 }
0103
0104 static int tz_enable(int tz_id, void *arg)
0105 {
0106 struct thermal_data *td = arg;
0107 struct thermal_zone *tz = thermal_zone_find_by_id(td->tz, tz_id);
0108
0109 INFO("Thermal zone %d ('%s') enabled\n", tz_id, tz->name);
0110
0111 return 0;
0112 }
0113
0114 static int trip_high(int tz_id, int trip_id, int temp, void *arg)
0115 {
0116 struct thermal_data *td = arg;
0117 struct thermal_zone *tz = thermal_zone_find_by_id(td->tz, tz_id);
0118
0119 INFO("Thermal zone %d ('%s'): trip point %d crossed way up with %d °C\n",
0120 tz_id, tz->name, trip_id, temp);
0121
0122 return 0;
0123 }
0124
0125 static int trip_low(int tz_id, int trip_id, int temp, void *arg)
0126 {
0127 struct thermal_data *td = arg;
0128 struct thermal_zone *tz = thermal_zone_find_by_id(td->tz, tz_id);
0129
0130 INFO("Thermal zone %d ('%s'): trip point %d crossed way down with %d °C\n",
0131 tz_id, tz->name, trip_id, temp);
0132
0133 return 0;
0134 }
0135
0136 static int trip_add(int tz_id, int trip_id, int type, int temp, int hyst, __maybe_unused void *arg)
0137 {
0138 INFO("Trip point added %d: id=%d, type=%d, temp=%d, hyst=%d\n",
0139 tz_id, trip_id, type, temp, hyst);
0140
0141 return 0;
0142 }
0143
0144 static int trip_delete(int tz_id, int trip_id, __maybe_unused void *arg)
0145 {
0146 INFO("Trip point deleted %d: id=%d\n", tz_id, trip_id);
0147
0148 return 0;
0149 }
0150
0151 static int trip_change(int tz_id, int trip_id, int type, int temp,
0152 int hyst, __maybe_unused void *arg)
0153 {
0154 struct thermal_data *td = arg;
0155 struct thermal_zone *tz = thermal_zone_find_by_id(td->tz, tz_id);
0156
0157 INFO("Trip point changed %d: id=%d, type=%d, temp=%d, hyst=%d\n",
0158 tz_id, trip_id, type, temp, hyst);
0159
0160 tz->trip[trip_id].type = type;
0161 tz->trip[trip_id].temp = temp;
0162 tz->trip[trip_id].hyst = hyst;
0163
0164 return 0;
0165 }
0166
0167 static int cdev_add(const char *name, int cdev_id, int max_state, __maybe_unused void *arg)
0168 {
0169 INFO("Cooling device '%s'/%d (max state=%d) added\n", name, cdev_id, max_state);
0170
0171 return 0;
0172 }
0173
0174 static int cdev_delete(int cdev_id, __maybe_unused void *arg)
0175 {
0176 INFO("Cooling device %d deleted", cdev_id);
0177
0178 return 0;
0179 }
0180
0181 static int cdev_update(int cdev_id, int cur_state, __maybe_unused void *arg)
0182 {
0183 INFO("cdev:%d state:%d\n", cdev_id, cur_state);
0184
0185 return 0;
0186 }
0187
0188 static int gov_change(int tz_id, const char *name, __maybe_unused void *arg)
0189 {
0190 struct thermal_data *td = arg;
0191 struct thermal_zone *tz = thermal_zone_find_by_id(td->tz, tz_id);
0192
0193 INFO("%s: governor changed %s -> %s\n", tz->name, tz->governor, name);
0194
0195 strcpy(tz->governor, name);
0196
0197 return 0;
0198 }
0199
0200 static struct thermal_ops ops = {
0201 .events.tz_create = tz_create,
0202 .events.tz_delete = tz_delete,
0203 .events.tz_disable = tz_disable,
0204 .events.tz_enable = tz_enable,
0205 .events.trip_high = trip_high,
0206 .events.trip_low = trip_low,
0207 .events.trip_add = trip_add,
0208 .events.trip_delete = trip_delete,
0209 .events.trip_change = trip_change,
0210 .events.cdev_add = cdev_add,
0211 .events.cdev_delete = cdev_delete,
0212 .events.cdev_update = cdev_update,
0213 .events.gov_change = gov_change
0214 };
0215
0216 static int thermal_event(__maybe_unused int fd, __maybe_unused void *arg)
0217 {
0218 struct thermal_data *td = arg;
0219
0220 return thermal_events_handle(td->th, td);
0221 }
0222
0223 static void usage(const char *cmd)
0224 {
0225 printf("%s : A thermal monitoring engine based on notifications\n", cmd);
0226 printf("Usage: %s [options]\n", cmd);
0227 printf("\t-h, --help\t\tthis help\n");
0228 printf("\t-d, --daemonize\n");
0229 printf("\t-l <level>, --loglevel <level>\tlog level: ");
0230 printf("DEBUG, INFO, NOTICE, WARN, ERROR\n");
0231 printf("\t-s, --syslog\t\toutput to syslog\n");
0232 printf("\n");
0233 exit(0);
0234 }
0235
0236 static int options_init(int argc, char *argv[], struct options *options)
0237 {
0238 int opt;
0239
0240 struct option long_options[] = {
0241 { "help", no_argument, NULL, 'h' },
0242 { "daemonize", no_argument, NULL, 'd' },
0243 { "syslog", no_argument, NULL, 's' },
0244 { "loglevel", required_argument, NULL, 'l' },
0245 { 0, 0, 0, 0 }
0246 };
0247
0248 while (1) {
0249
0250 int optindex = 0;
0251
0252 opt = getopt_long(argc, argv, "l:dhs", long_options, &optindex);
0253 if (opt == -1)
0254 break;
0255
0256 switch (opt) {
0257 case 'l':
0258 options->loglevel = log_str2level(optarg);
0259 break;
0260 case 'd':
0261 options->daemonize = 1;
0262 break;
0263 case 's':
0264 options->logopt = TO_SYSLOG;
0265 break;
0266 case 'h':
0267 usage(basename(argv[0]));
0268 break;
0269 default:
0270 return -1;
0271 }
0272 }
0273
0274 return 0;
0275 }
0276
0277 enum {
0278 THERMAL_ENGINE_SUCCESS = 0,
0279 THERMAL_ENGINE_OPTION_ERROR,
0280 THERMAL_ENGINE_DAEMON_ERROR,
0281 THERMAL_ENGINE_LOG_ERROR,
0282 THERMAL_ENGINE_THERMAL_ERROR,
0283 THERMAL_ENGINE_MAINLOOP_ERROR,
0284 };
0285
0286 int main(int argc, char *argv[])
0287 {
0288 struct thermal_data td;
0289 struct options options = {
0290 .loglevel = LOG_INFO,
0291 .logopt = TO_STDOUT,
0292 };
0293
0294 if (options_init(argc, argv, &options)) {
0295 ERROR("Usage: %s --help\n", argv[0]);
0296 return THERMAL_ENGINE_OPTION_ERROR;
0297 }
0298
0299 if (options.daemonize && daemon(0, 0)) {
0300 ERROR("Failed to daemonize: %p\n");
0301 return THERMAL_ENGINE_DAEMON_ERROR;
0302 }
0303
0304 if (log_init(options.loglevel, basename(argv[0]), options.logopt)) {
0305 ERROR("Failed to initialize logging facility\n");
0306 return THERMAL_ENGINE_LOG_ERROR;
0307 }
0308
0309 td.th = thermal_init(&ops);
0310 if (!td.th) {
0311 ERROR("Failed to initialize the thermal library\n");
0312 return THERMAL_ENGINE_THERMAL_ERROR;
0313 }
0314
0315 td.tz = thermal_zone_discover(td.th);
0316 if (!td.tz) {
0317 ERROR("No thermal zone available\n");
0318 return THERMAL_ENGINE_THERMAL_ERROR;
0319 }
0320
0321 for_each_thermal_zone(td.tz, show_tz, td.th);
0322
0323 if (mainloop_init()) {
0324 ERROR("Failed to initialize the mainloop\n");
0325 return THERMAL_ENGINE_MAINLOOP_ERROR;
0326 }
0327
0328 if (mainloop_add(thermal_events_fd(td.th), thermal_event, &td)) {
0329 ERROR("Failed to setup the mainloop\n");
0330 return THERMAL_ENGINE_MAINLOOP_ERROR;
0331 }
0332
0333 INFO("Waiting for thermal events ...\n");
0334
0335 if (mainloop(-1)) {
0336 ERROR("Mainloop failed\n");
0337 return THERMAL_ENGINE_MAINLOOP_ERROR;
0338 }
0339
0340 return THERMAL_ENGINE_SUCCESS;
0341 }