147c4b0deSDaniel Lezcano // SPDX-License-Identifier: LGPL-2.1+ 247c4b0deSDaniel Lezcano // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> 347c4b0deSDaniel Lezcano #define _GNU_SOURCE 447c4b0deSDaniel Lezcano #include <errno.h> 547c4b0deSDaniel Lezcano #include <stdio.h> 647c4b0deSDaniel Lezcano #include <stdlib.h> 747c4b0deSDaniel Lezcano #include <unistd.h> 847c4b0deSDaniel Lezcano 947c4b0deSDaniel Lezcano #include <thermal.h> 1047c4b0deSDaniel Lezcano #include "thermal_nl.h" 1147c4b0deSDaniel Lezcano 1247c4b0deSDaniel Lezcano static struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { 1347c4b0deSDaniel Lezcano /* Thermal zone */ 1447c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED }, 1547c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 }, 1647c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 }, 1747c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED }, 1847c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 }, 1947c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 }, 2047c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 }, 2147c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 }, 2247c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 }, 2347c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 }, 2447c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING }, 2547c4b0deSDaniel Lezcano 2647c4b0deSDaniel Lezcano /* Governor(s) */ 2747c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED }, 2847c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING }, 2947c4b0deSDaniel Lezcano 3047c4b0deSDaniel Lezcano /* Cooling devices */ 3147c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED }, 3247c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 }, 3347c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 }, 3447c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 }, 3547c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING }, 3647c4b0deSDaniel Lezcano }; 3747c4b0deSDaniel Lezcano 3847c4b0deSDaniel Lezcano static int parse_tz_get(struct genl_info *info, struct thermal_zone **tz) 3947c4b0deSDaniel Lezcano { 4047c4b0deSDaniel Lezcano struct nlattr *attr; 4147c4b0deSDaniel Lezcano struct thermal_zone *__tz = NULL; 4247c4b0deSDaniel Lezcano size_t size = 0; 4347c4b0deSDaniel Lezcano int rem; 4447c4b0deSDaniel Lezcano 4547c4b0deSDaniel Lezcano nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_TZ], rem) { 4647c4b0deSDaniel Lezcano 4747c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_ID) { 4847c4b0deSDaniel Lezcano 4947c4b0deSDaniel Lezcano size++; 5047c4b0deSDaniel Lezcano 5147c4b0deSDaniel Lezcano __tz = realloc(__tz, sizeof(*__tz) * (size + 2)); 5247c4b0deSDaniel Lezcano if (!__tz) 5347c4b0deSDaniel Lezcano return THERMAL_ERROR; 5447c4b0deSDaniel Lezcano 5547c4b0deSDaniel Lezcano __tz[size - 1].id = nla_get_u32(attr); 5647c4b0deSDaniel Lezcano } 5747c4b0deSDaniel Lezcano 5847c4b0deSDaniel Lezcano 5947c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_NAME) 6047c4b0deSDaniel Lezcano nla_strlcpy(__tz[size - 1].name, attr, 6147c4b0deSDaniel Lezcano THERMAL_NAME_LENGTH); 6247c4b0deSDaniel Lezcano } 6347c4b0deSDaniel Lezcano 6447c4b0deSDaniel Lezcano if (__tz) 6547c4b0deSDaniel Lezcano __tz[size].id = -1; 6647c4b0deSDaniel Lezcano 6747c4b0deSDaniel Lezcano *tz = __tz; 6847c4b0deSDaniel Lezcano 6947c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 7047c4b0deSDaniel Lezcano } 7147c4b0deSDaniel Lezcano 7247c4b0deSDaniel Lezcano static int parse_cdev_get(struct genl_info *info, struct thermal_cdev **cdev) 7347c4b0deSDaniel Lezcano { 7447c4b0deSDaniel Lezcano struct nlattr *attr; 7547c4b0deSDaniel Lezcano struct thermal_cdev *__cdev = NULL; 7647c4b0deSDaniel Lezcano size_t size = 0; 7747c4b0deSDaniel Lezcano int rem; 7847c4b0deSDaniel Lezcano 7947c4b0deSDaniel Lezcano nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_CDEV], rem) { 8047c4b0deSDaniel Lezcano 8147c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_ID) { 8247c4b0deSDaniel Lezcano 8347c4b0deSDaniel Lezcano size++; 8447c4b0deSDaniel Lezcano 8547c4b0deSDaniel Lezcano __cdev = realloc(__cdev, sizeof(*__cdev) * (size + 2)); 8647c4b0deSDaniel Lezcano if (!__cdev) 8747c4b0deSDaniel Lezcano return THERMAL_ERROR; 8847c4b0deSDaniel Lezcano 8947c4b0deSDaniel Lezcano __cdev[size - 1].id = nla_get_u32(attr); 9047c4b0deSDaniel Lezcano } 9147c4b0deSDaniel Lezcano 9247c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_NAME) { 9347c4b0deSDaniel Lezcano nla_strlcpy(__cdev[size - 1].name, attr, 9447c4b0deSDaniel Lezcano THERMAL_NAME_LENGTH); 9547c4b0deSDaniel Lezcano } 9647c4b0deSDaniel Lezcano 9747c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_CUR_STATE) 9847c4b0deSDaniel Lezcano __cdev[size - 1].cur_state = nla_get_u32(attr); 9947c4b0deSDaniel Lezcano 10047c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_MAX_STATE) 10147c4b0deSDaniel Lezcano __cdev[size - 1].max_state = nla_get_u32(attr); 10247c4b0deSDaniel Lezcano } 10347c4b0deSDaniel Lezcano 10447c4b0deSDaniel Lezcano if (__cdev) 10547c4b0deSDaniel Lezcano __cdev[size].id = -1; 10647c4b0deSDaniel Lezcano 10747c4b0deSDaniel Lezcano *cdev = __cdev; 10847c4b0deSDaniel Lezcano 10947c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 11047c4b0deSDaniel Lezcano } 11147c4b0deSDaniel Lezcano 11247c4b0deSDaniel Lezcano static int parse_tz_get_trip(struct genl_info *info, struct thermal_zone *tz) 11347c4b0deSDaniel Lezcano { 11447c4b0deSDaniel Lezcano struct nlattr *attr; 11547c4b0deSDaniel Lezcano struct thermal_trip *__tt = NULL; 11647c4b0deSDaniel Lezcano size_t size = 0; 11747c4b0deSDaniel Lezcano int rem; 11847c4b0deSDaniel Lezcano 11947c4b0deSDaniel Lezcano nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_TZ_TRIP], rem) { 12047c4b0deSDaniel Lezcano 12147c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_ID) { 12247c4b0deSDaniel Lezcano 12347c4b0deSDaniel Lezcano size++; 12447c4b0deSDaniel Lezcano 12547c4b0deSDaniel Lezcano __tt = realloc(__tt, sizeof(*__tt) * (size + 2)); 12647c4b0deSDaniel Lezcano if (!__tt) 12747c4b0deSDaniel Lezcano return THERMAL_ERROR; 12847c4b0deSDaniel Lezcano 12947c4b0deSDaniel Lezcano __tt[size - 1].id = nla_get_u32(attr); 13047c4b0deSDaniel Lezcano } 13147c4b0deSDaniel Lezcano 13247c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_TYPE) 13347c4b0deSDaniel Lezcano __tt[size - 1].type = nla_get_u32(attr); 13447c4b0deSDaniel Lezcano 13547c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_TEMP) 13647c4b0deSDaniel Lezcano __tt[size - 1].temp = nla_get_u32(attr); 13747c4b0deSDaniel Lezcano 13847c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_HYST) 13947c4b0deSDaniel Lezcano __tt[size - 1].hyst = nla_get_u32(attr); 14047c4b0deSDaniel Lezcano } 14147c4b0deSDaniel Lezcano 14247c4b0deSDaniel Lezcano if (__tt) 14347c4b0deSDaniel Lezcano __tt[size].id = -1; 14447c4b0deSDaniel Lezcano 14547c4b0deSDaniel Lezcano tz->trip = __tt; 14647c4b0deSDaniel Lezcano 14747c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 14847c4b0deSDaniel Lezcano } 14947c4b0deSDaniel Lezcano 15047c4b0deSDaniel Lezcano static int parse_tz_get_temp(struct genl_info *info, struct thermal_zone *tz) 15147c4b0deSDaniel Lezcano { 15247c4b0deSDaniel Lezcano int id = -1; 15347c4b0deSDaniel Lezcano 15447c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_ID]) 15547c4b0deSDaniel Lezcano id = nla_get_u32(info->attrs[THERMAL_GENL_ATTR_TZ_ID]); 15647c4b0deSDaniel Lezcano 15747c4b0deSDaniel Lezcano if (tz->id != id) 15847c4b0deSDaniel Lezcano return THERMAL_ERROR; 15947c4b0deSDaniel Lezcano 16047c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_TEMP]) 16147c4b0deSDaniel Lezcano tz->temp = nla_get_u32(info->attrs[THERMAL_GENL_ATTR_TZ_TEMP]); 16247c4b0deSDaniel Lezcano 16347c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 16447c4b0deSDaniel Lezcano } 16547c4b0deSDaniel Lezcano 16647c4b0deSDaniel Lezcano static int parse_tz_get_gov(struct genl_info *info, struct thermal_zone *tz) 16747c4b0deSDaniel Lezcano { 16847c4b0deSDaniel Lezcano int id = -1; 16947c4b0deSDaniel Lezcano 17047c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_ID]) 17147c4b0deSDaniel Lezcano id = nla_get_u32(info->attrs[THERMAL_GENL_ATTR_TZ_ID]); 17247c4b0deSDaniel Lezcano 17347c4b0deSDaniel Lezcano if (tz->id != id) 17447c4b0deSDaniel Lezcano return THERMAL_ERROR; 17547c4b0deSDaniel Lezcano 17647c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_GOV_NAME]) { 17747c4b0deSDaniel Lezcano nla_strlcpy(tz->governor, 17847c4b0deSDaniel Lezcano info->attrs[THERMAL_GENL_ATTR_TZ_GOV_NAME], 17947c4b0deSDaniel Lezcano THERMAL_NAME_LENGTH); 18047c4b0deSDaniel Lezcano } 18147c4b0deSDaniel Lezcano 18247c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 18347c4b0deSDaniel Lezcano } 18447c4b0deSDaniel Lezcano 18547c4b0deSDaniel Lezcano static int handle_netlink(struct nl_cache_ops *unused, 18647c4b0deSDaniel Lezcano struct genl_cmd *cmd, 18747c4b0deSDaniel Lezcano struct genl_info *info, void *arg) 18847c4b0deSDaniel Lezcano { 18947c4b0deSDaniel Lezcano int ret; 19047c4b0deSDaniel Lezcano 19147c4b0deSDaniel Lezcano switch (cmd->c_id) { 19247c4b0deSDaniel Lezcano 19347c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_ID: 19447c4b0deSDaniel Lezcano ret = parse_tz_get(info, arg); 19547c4b0deSDaniel Lezcano break; 19647c4b0deSDaniel Lezcano 19747c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_CDEV_GET: 19847c4b0deSDaniel Lezcano ret = parse_cdev_get(info, arg); 19947c4b0deSDaniel Lezcano break; 20047c4b0deSDaniel Lezcano 20147c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_TEMP: 20247c4b0deSDaniel Lezcano ret = parse_tz_get_temp(info, arg); 20347c4b0deSDaniel Lezcano break; 20447c4b0deSDaniel Lezcano 20547c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_TRIP: 20647c4b0deSDaniel Lezcano ret = parse_tz_get_trip(info, arg); 20747c4b0deSDaniel Lezcano break; 20847c4b0deSDaniel Lezcano 20947c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_GOV: 21047c4b0deSDaniel Lezcano ret = parse_tz_get_gov(info, arg); 21147c4b0deSDaniel Lezcano break; 21247c4b0deSDaniel Lezcano 21347c4b0deSDaniel Lezcano default: 21447c4b0deSDaniel Lezcano return THERMAL_ERROR; 215f21b57ebSJiapeng Chong } 21647c4b0deSDaniel Lezcano 21747c4b0deSDaniel Lezcano return ret; 21847c4b0deSDaniel Lezcano } 21947c4b0deSDaniel Lezcano 22047c4b0deSDaniel Lezcano static struct genl_cmd thermal_cmds[] = { 22147c4b0deSDaniel Lezcano { 22247c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_ID, 22347c4b0deSDaniel Lezcano .c_name = (char *)"List thermal zones", 22447c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 22547c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 22647c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 22747c4b0deSDaniel Lezcano }, 22847c4b0deSDaniel Lezcano { 22947c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_GOV, 23047c4b0deSDaniel Lezcano .c_name = (char *)"Get governor", 23147c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 23247c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 23347c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 23447c4b0deSDaniel Lezcano }, 23547c4b0deSDaniel Lezcano { 23647c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_TEMP, 23747c4b0deSDaniel Lezcano .c_name = (char *)"Get thermal zone temperature", 23847c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 23947c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 24047c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 24147c4b0deSDaniel Lezcano }, 24247c4b0deSDaniel Lezcano { 24347c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_TRIP, 24447c4b0deSDaniel Lezcano .c_name = (char *)"Get thermal zone trip points", 24547c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 24647c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 24747c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 24847c4b0deSDaniel Lezcano }, 24947c4b0deSDaniel Lezcano { 25047c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_CDEV_GET, 25147c4b0deSDaniel Lezcano .c_name = (char *)"Get cooling devices", 25247c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 25347c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 25447c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 25547c4b0deSDaniel Lezcano }, 25647c4b0deSDaniel Lezcano }; 25747c4b0deSDaniel Lezcano 25847c4b0deSDaniel Lezcano static struct genl_ops thermal_cmd_ops = { 25947c4b0deSDaniel Lezcano .o_name = (char *)"thermal", 26047c4b0deSDaniel Lezcano .o_cmds = thermal_cmds, 26147c4b0deSDaniel Lezcano .o_ncmds = ARRAY_SIZE(thermal_cmds), 26247c4b0deSDaniel Lezcano }; 26347c4b0deSDaniel Lezcano 2641b78ac7eSDaniel Lezcano struct cmd_param { 2651b78ac7eSDaniel Lezcano int tz_id; 2661b78ac7eSDaniel Lezcano }; 2671b78ac7eSDaniel Lezcano 2681b78ac7eSDaniel Lezcano typedef int (*cmd_cb_t)(struct nl_msg *, struct cmd_param *); 2691b78ac7eSDaniel Lezcano 2701b78ac7eSDaniel Lezcano static int thermal_genl_tz_id_encode(struct nl_msg *msg, struct cmd_param *p) 2711b78ac7eSDaniel Lezcano { 2721b78ac7eSDaniel Lezcano if (p->tz_id >= 0 && nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) 2731b78ac7eSDaniel Lezcano return -1; 2741b78ac7eSDaniel Lezcano 2751b78ac7eSDaniel Lezcano return 0; 2761b78ac7eSDaniel Lezcano } 2771b78ac7eSDaniel Lezcano 2781b78ac7eSDaniel Lezcano static thermal_error_t thermal_genl_auto(struct thermal_handler *th, cmd_cb_t cmd_cb, 2791b78ac7eSDaniel Lezcano struct cmd_param *param, 2801b78ac7eSDaniel Lezcano int cmd, int flags, void *arg) 28147c4b0deSDaniel Lezcano { 282*cc08c2c8SDaniel Lezcano thermal_error_t ret = THERMAL_ERROR; 28347c4b0deSDaniel Lezcano struct nl_msg *msg; 28447c4b0deSDaniel Lezcano void *hdr; 28547c4b0deSDaniel Lezcano 28647c4b0deSDaniel Lezcano msg = nlmsg_alloc(); 28747c4b0deSDaniel Lezcano if (!msg) 28847c4b0deSDaniel Lezcano return THERMAL_ERROR; 28947c4b0deSDaniel Lezcano 29047c4b0deSDaniel Lezcano hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, thermal_cmd_ops.o_id, 29147c4b0deSDaniel Lezcano 0, flags, cmd, THERMAL_GENL_VERSION); 29247c4b0deSDaniel Lezcano if (!hdr) 293*cc08c2c8SDaniel Lezcano goto out; 29447c4b0deSDaniel Lezcano 2951b78ac7eSDaniel Lezcano if (cmd_cb && cmd_cb(msg, param)) 296*cc08c2c8SDaniel Lezcano goto out; 29747c4b0deSDaniel Lezcano 29847c4b0deSDaniel Lezcano if (nl_send_msg(th->sk_cmd, th->cb_cmd, msg, genl_handle_msg, arg)) 299*cc08c2c8SDaniel Lezcano goto out; 30047c4b0deSDaniel Lezcano 301*cc08c2c8SDaniel Lezcano ret = THERMAL_SUCCESS; 302*cc08c2c8SDaniel Lezcano out: 30347c4b0deSDaniel Lezcano nlmsg_free(msg); 30447c4b0deSDaniel Lezcano 305*cc08c2c8SDaniel Lezcano return ret; 30647c4b0deSDaniel Lezcano } 30747c4b0deSDaniel Lezcano 30847c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_tz(struct thermal_handler *th, struct thermal_zone **tz) 30947c4b0deSDaniel Lezcano { 3101b78ac7eSDaniel Lezcano return thermal_genl_auto(th, NULL, NULL, THERMAL_GENL_CMD_TZ_GET_ID, 31147c4b0deSDaniel Lezcano NLM_F_DUMP | NLM_F_ACK, tz); 31247c4b0deSDaniel Lezcano } 31347c4b0deSDaniel Lezcano 31447c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_cdev(struct thermal_handler *th, struct thermal_cdev **tc) 31547c4b0deSDaniel Lezcano { 3161b78ac7eSDaniel Lezcano return thermal_genl_auto(th, NULL, NULL, THERMAL_GENL_CMD_CDEV_GET, 31747c4b0deSDaniel Lezcano NLM_F_DUMP | NLM_F_ACK, tc); 31847c4b0deSDaniel Lezcano } 31947c4b0deSDaniel Lezcano 32047c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_trip(struct thermal_handler *th, struct thermal_zone *tz) 32147c4b0deSDaniel Lezcano { 3221b78ac7eSDaniel Lezcano struct cmd_param p = { .tz_id = tz->id }; 3231b78ac7eSDaniel Lezcano 3241b78ac7eSDaniel Lezcano return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, 3251b78ac7eSDaniel Lezcano THERMAL_GENL_CMD_TZ_GET_TRIP, 0, tz); 32647c4b0deSDaniel Lezcano } 32747c4b0deSDaniel Lezcano 32847c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_governor(struct thermal_handler *th, struct thermal_zone *tz) 32947c4b0deSDaniel Lezcano { 3301b78ac7eSDaniel Lezcano struct cmd_param p = { .tz_id = tz->id }; 3311b78ac7eSDaniel Lezcano 3321b78ac7eSDaniel Lezcano return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, 3331b78ac7eSDaniel Lezcano THERMAL_GENL_CMD_TZ_GET_GOV, 0, tz); 33447c4b0deSDaniel Lezcano } 33547c4b0deSDaniel Lezcano 33647c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th, struct thermal_zone *tz) 33747c4b0deSDaniel Lezcano { 3381b78ac7eSDaniel Lezcano struct cmd_param p = { .tz_id = tz->id }; 3391b78ac7eSDaniel Lezcano 3401b78ac7eSDaniel Lezcano return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, 3411b78ac7eSDaniel Lezcano THERMAL_GENL_CMD_TZ_GET_TEMP, 0, tz); 34247c4b0deSDaniel Lezcano } 34347c4b0deSDaniel Lezcano 34447c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_exit(struct thermal_handler *th) 34547c4b0deSDaniel Lezcano { 34647c4b0deSDaniel Lezcano if (genl_unregister_family(&thermal_cmd_ops)) 34747c4b0deSDaniel Lezcano return THERMAL_ERROR; 34847c4b0deSDaniel Lezcano 34947c4b0deSDaniel Lezcano nl_thermal_disconnect(th->sk_cmd, th->cb_cmd); 35047c4b0deSDaniel Lezcano 35147c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 35247c4b0deSDaniel Lezcano } 35347c4b0deSDaniel Lezcano 35447c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_init(struct thermal_handler *th) 35547c4b0deSDaniel Lezcano { 35647c4b0deSDaniel Lezcano int ret; 35747c4b0deSDaniel Lezcano int family; 35847c4b0deSDaniel Lezcano 35947c4b0deSDaniel Lezcano if (nl_thermal_connect(&th->sk_cmd, &th->cb_cmd)) 36047c4b0deSDaniel Lezcano return THERMAL_ERROR; 36147c4b0deSDaniel Lezcano 36247c4b0deSDaniel Lezcano ret = genl_register_family(&thermal_cmd_ops); 36347c4b0deSDaniel Lezcano if (ret) 36447c4b0deSDaniel Lezcano return THERMAL_ERROR; 36547c4b0deSDaniel Lezcano 36647c4b0deSDaniel Lezcano ret = genl_ops_resolve(th->sk_cmd, &thermal_cmd_ops); 36747c4b0deSDaniel Lezcano if (ret) 36847c4b0deSDaniel Lezcano return THERMAL_ERROR; 36947c4b0deSDaniel Lezcano 37047c4b0deSDaniel Lezcano family = genl_ctrl_resolve(th->sk_cmd, "nlctrl"); 37147c4b0deSDaniel Lezcano if (family != GENL_ID_CTRL) 37247c4b0deSDaniel Lezcano return THERMAL_ERROR; 37347c4b0deSDaniel Lezcano 37447c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 37547c4b0deSDaniel Lezcano } 376