1*47c4b0deSDaniel Lezcano // SPDX-License-Identifier: LGPL-2.1+ 2*47c4b0deSDaniel Lezcano // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> 3*47c4b0deSDaniel Lezcano #define _GNU_SOURCE 4*47c4b0deSDaniel Lezcano #include <errno.h> 5*47c4b0deSDaniel Lezcano #include <stdio.h> 6*47c4b0deSDaniel Lezcano #include <stdlib.h> 7*47c4b0deSDaniel Lezcano #include <unistd.h> 8*47c4b0deSDaniel Lezcano 9*47c4b0deSDaniel Lezcano #include <thermal.h> 10*47c4b0deSDaniel Lezcano #include "thermal_nl.h" 11*47c4b0deSDaniel Lezcano 12*47c4b0deSDaniel Lezcano static struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { 13*47c4b0deSDaniel Lezcano /* Thermal zone */ 14*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED }, 15*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 }, 16*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 }, 17*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED }, 18*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 }, 19*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 }, 20*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 }, 21*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 }, 22*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 }, 23*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 }, 24*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING }, 25*47c4b0deSDaniel Lezcano 26*47c4b0deSDaniel Lezcano /* Governor(s) */ 27*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED }, 28*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING }, 29*47c4b0deSDaniel Lezcano 30*47c4b0deSDaniel Lezcano /* Cooling devices */ 31*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED }, 32*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 }, 33*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 }, 34*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 }, 35*47c4b0deSDaniel Lezcano [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING }, 36*47c4b0deSDaniel Lezcano }; 37*47c4b0deSDaniel Lezcano 38*47c4b0deSDaniel Lezcano static int parse_tz_get(struct genl_info *info, struct thermal_zone **tz) 39*47c4b0deSDaniel Lezcano { 40*47c4b0deSDaniel Lezcano struct nlattr *attr; 41*47c4b0deSDaniel Lezcano struct thermal_zone *__tz = NULL; 42*47c4b0deSDaniel Lezcano size_t size = 0; 43*47c4b0deSDaniel Lezcano int rem; 44*47c4b0deSDaniel Lezcano 45*47c4b0deSDaniel Lezcano nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_TZ], rem) { 46*47c4b0deSDaniel Lezcano 47*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_ID) { 48*47c4b0deSDaniel Lezcano 49*47c4b0deSDaniel Lezcano size++; 50*47c4b0deSDaniel Lezcano 51*47c4b0deSDaniel Lezcano __tz = realloc(__tz, sizeof(*__tz) * (size + 2)); 52*47c4b0deSDaniel Lezcano if (!__tz) 53*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 54*47c4b0deSDaniel Lezcano 55*47c4b0deSDaniel Lezcano __tz[size - 1].id = nla_get_u32(attr); 56*47c4b0deSDaniel Lezcano } 57*47c4b0deSDaniel Lezcano 58*47c4b0deSDaniel Lezcano 59*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_NAME) 60*47c4b0deSDaniel Lezcano nla_strlcpy(__tz[size - 1].name, attr, 61*47c4b0deSDaniel Lezcano THERMAL_NAME_LENGTH); 62*47c4b0deSDaniel Lezcano } 63*47c4b0deSDaniel Lezcano 64*47c4b0deSDaniel Lezcano if (__tz) 65*47c4b0deSDaniel Lezcano __tz[size].id = -1; 66*47c4b0deSDaniel Lezcano 67*47c4b0deSDaniel Lezcano *tz = __tz; 68*47c4b0deSDaniel Lezcano 69*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 70*47c4b0deSDaniel Lezcano } 71*47c4b0deSDaniel Lezcano 72*47c4b0deSDaniel Lezcano static int parse_cdev_get(struct genl_info *info, struct thermal_cdev **cdev) 73*47c4b0deSDaniel Lezcano { 74*47c4b0deSDaniel Lezcano struct nlattr *attr; 75*47c4b0deSDaniel Lezcano struct thermal_cdev *__cdev = NULL; 76*47c4b0deSDaniel Lezcano size_t size = 0; 77*47c4b0deSDaniel Lezcano int rem; 78*47c4b0deSDaniel Lezcano 79*47c4b0deSDaniel Lezcano nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_CDEV], rem) { 80*47c4b0deSDaniel Lezcano 81*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_ID) { 82*47c4b0deSDaniel Lezcano 83*47c4b0deSDaniel Lezcano size++; 84*47c4b0deSDaniel Lezcano 85*47c4b0deSDaniel Lezcano __cdev = realloc(__cdev, sizeof(*__cdev) * (size + 2)); 86*47c4b0deSDaniel Lezcano if (!__cdev) 87*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 88*47c4b0deSDaniel Lezcano 89*47c4b0deSDaniel Lezcano __cdev[size - 1].id = nla_get_u32(attr); 90*47c4b0deSDaniel Lezcano } 91*47c4b0deSDaniel Lezcano 92*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_NAME) { 93*47c4b0deSDaniel Lezcano nla_strlcpy(__cdev[size - 1].name, attr, 94*47c4b0deSDaniel Lezcano THERMAL_NAME_LENGTH); 95*47c4b0deSDaniel Lezcano } 96*47c4b0deSDaniel Lezcano 97*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_CUR_STATE) 98*47c4b0deSDaniel Lezcano __cdev[size - 1].cur_state = nla_get_u32(attr); 99*47c4b0deSDaniel Lezcano 100*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_CDEV_MAX_STATE) 101*47c4b0deSDaniel Lezcano __cdev[size - 1].max_state = nla_get_u32(attr); 102*47c4b0deSDaniel Lezcano } 103*47c4b0deSDaniel Lezcano 104*47c4b0deSDaniel Lezcano if (__cdev) 105*47c4b0deSDaniel Lezcano __cdev[size].id = -1; 106*47c4b0deSDaniel Lezcano 107*47c4b0deSDaniel Lezcano *cdev = __cdev; 108*47c4b0deSDaniel Lezcano 109*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 110*47c4b0deSDaniel Lezcano } 111*47c4b0deSDaniel Lezcano 112*47c4b0deSDaniel Lezcano static int parse_tz_get_trip(struct genl_info *info, struct thermal_zone *tz) 113*47c4b0deSDaniel Lezcano { 114*47c4b0deSDaniel Lezcano struct nlattr *attr; 115*47c4b0deSDaniel Lezcano struct thermal_trip *__tt = NULL; 116*47c4b0deSDaniel Lezcano size_t size = 0; 117*47c4b0deSDaniel Lezcano int rem; 118*47c4b0deSDaniel Lezcano 119*47c4b0deSDaniel Lezcano nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_TZ_TRIP], rem) { 120*47c4b0deSDaniel Lezcano 121*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_ID) { 122*47c4b0deSDaniel Lezcano 123*47c4b0deSDaniel Lezcano size++; 124*47c4b0deSDaniel Lezcano 125*47c4b0deSDaniel Lezcano __tt = realloc(__tt, sizeof(*__tt) * (size + 2)); 126*47c4b0deSDaniel Lezcano if (!__tt) 127*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 128*47c4b0deSDaniel Lezcano 129*47c4b0deSDaniel Lezcano __tt[size - 1].id = nla_get_u32(attr); 130*47c4b0deSDaniel Lezcano } 131*47c4b0deSDaniel Lezcano 132*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_TYPE) 133*47c4b0deSDaniel Lezcano __tt[size - 1].type = nla_get_u32(attr); 134*47c4b0deSDaniel Lezcano 135*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_TEMP) 136*47c4b0deSDaniel Lezcano __tt[size - 1].temp = nla_get_u32(attr); 137*47c4b0deSDaniel Lezcano 138*47c4b0deSDaniel Lezcano if (nla_type(attr) == THERMAL_GENL_ATTR_TZ_TRIP_HYST) 139*47c4b0deSDaniel Lezcano __tt[size - 1].hyst = nla_get_u32(attr); 140*47c4b0deSDaniel Lezcano } 141*47c4b0deSDaniel Lezcano 142*47c4b0deSDaniel Lezcano if (__tt) 143*47c4b0deSDaniel Lezcano __tt[size].id = -1; 144*47c4b0deSDaniel Lezcano 145*47c4b0deSDaniel Lezcano tz->trip = __tt; 146*47c4b0deSDaniel Lezcano 147*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 148*47c4b0deSDaniel Lezcano } 149*47c4b0deSDaniel Lezcano 150*47c4b0deSDaniel Lezcano static int parse_tz_get_temp(struct genl_info *info, struct thermal_zone *tz) 151*47c4b0deSDaniel Lezcano { 152*47c4b0deSDaniel Lezcano int id = -1; 153*47c4b0deSDaniel Lezcano 154*47c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_ID]) 155*47c4b0deSDaniel Lezcano id = nla_get_u32(info->attrs[THERMAL_GENL_ATTR_TZ_ID]); 156*47c4b0deSDaniel Lezcano 157*47c4b0deSDaniel Lezcano if (tz->id != id) 158*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 159*47c4b0deSDaniel Lezcano 160*47c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_TEMP]) 161*47c4b0deSDaniel Lezcano tz->temp = nla_get_u32(info->attrs[THERMAL_GENL_ATTR_TZ_TEMP]); 162*47c4b0deSDaniel Lezcano 163*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 164*47c4b0deSDaniel Lezcano } 165*47c4b0deSDaniel Lezcano 166*47c4b0deSDaniel Lezcano static int parse_tz_get_gov(struct genl_info *info, struct thermal_zone *tz) 167*47c4b0deSDaniel Lezcano { 168*47c4b0deSDaniel Lezcano int id = -1; 169*47c4b0deSDaniel Lezcano 170*47c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_ID]) 171*47c4b0deSDaniel Lezcano id = nla_get_u32(info->attrs[THERMAL_GENL_ATTR_TZ_ID]); 172*47c4b0deSDaniel Lezcano 173*47c4b0deSDaniel Lezcano if (tz->id != id) 174*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 175*47c4b0deSDaniel Lezcano 176*47c4b0deSDaniel Lezcano if (info->attrs[THERMAL_GENL_ATTR_TZ_GOV_NAME]) { 177*47c4b0deSDaniel Lezcano nla_strlcpy(tz->governor, 178*47c4b0deSDaniel Lezcano info->attrs[THERMAL_GENL_ATTR_TZ_GOV_NAME], 179*47c4b0deSDaniel Lezcano THERMAL_NAME_LENGTH); 180*47c4b0deSDaniel Lezcano } 181*47c4b0deSDaniel Lezcano 182*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 183*47c4b0deSDaniel Lezcano } 184*47c4b0deSDaniel Lezcano 185*47c4b0deSDaniel Lezcano static int handle_netlink(struct nl_cache_ops *unused, 186*47c4b0deSDaniel Lezcano struct genl_cmd *cmd, 187*47c4b0deSDaniel Lezcano struct genl_info *info, void *arg) 188*47c4b0deSDaniel Lezcano { 189*47c4b0deSDaniel Lezcano int ret; 190*47c4b0deSDaniel Lezcano 191*47c4b0deSDaniel Lezcano switch (cmd->c_id) { 192*47c4b0deSDaniel Lezcano 193*47c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_ID: 194*47c4b0deSDaniel Lezcano ret = parse_tz_get(info, arg); 195*47c4b0deSDaniel Lezcano break; 196*47c4b0deSDaniel Lezcano 197*47c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_CDEV_GET: 198*47c4b0deSDaniel Lezcano ret = parse_cdev_get(info, arg); 199*47c4b0deSDaniel Lezcano break; 200*47c4b0deSDaniel Lezcano 201*47c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_TEMP: 202*47c4b0deSDaniel Lezcano ret = parse_tz_get_temp(info, arg); 203*47c4b0deSDaniel Lezcano break; 204*47c4b0deSDaniel Lezcano 205*47c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_TRIP: 206*47c4b0deSDaniel Lezcano ret = parse_tz_get_trip(info, arg); 207*47c4b0deSDaniel Lezcano break; 208*47c4b0deSDaniel Lezcano 209*47c4b0deSDaniel Lezcano case THERMAL_GENL_CMD_TZ_GET_GOV: 210*47c4b0deSDaniel Lezcano ret = parse_tz_get_gov(info, arg); 211*47c4b0deSDaniel Lezcano break; 212*47c4b0deSDaniel Lezcano 213*47c4b0deSDaniel Lezcano default: 214*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 215*47c4b0deSDaniel Lezcano }; 216*47c4b0deSDaniel Lezcano 217*47c4b0deSDaniel Lezcano return ret; 218*47c4b0deSDaniel Lezcano } 219*47c4b0deSDaniel Lezcano 220*47c4b0deSDaniel Lezcano static struct genl_cmd thermal_cmds[] = { 221*47c4b0deSDaniel Lezcano { 222*47c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_ID, 223*47c4b0deSDaniel Lezcano .c_name = (char *)"List thermal zones", 224*47c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 225*47c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 226*47c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 227*47c4b0deSDaniel Lezcano }, 228*47c4b0deSDaniel Lezcano { 229*47c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_GOV, 230*47c4b0deSDaniel Lezcano .c_name = (char *)"Get governor", 231*47c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 232*47c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 233*47c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 234*47c4b0deSDaniel Lezcano }, 235*47c4b0deSDaniel Lezcano { 236*47c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_TEMP, 237*47c4b0deSDaniel Lezcano .c_name = (char *)"Get thermal zone temperature", 238*47c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 239*47c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 240*47c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 241*47c4b0deSDaniel Lezcano }, 242*47c4b0deSDaniel Lezcano { 243*47c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_TZ_GET_TRIP, 244*47c4b0deSDaniel Lezcano .c_name = (char *)"Get thermal zone trip points", 245*47c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 246*47c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 247*47c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 248*47c4b0deSDaniel Lezcano }, 249*47c4b0deSDaniel Lezcano { 250*47c4b0deSDaniel Lezcano .c_id = THERMAL_GENL_CMD_CDEV_GET, 251*47c4b0deSDaniel Lezcano .c_name = (char *)"Get cooling devices", 252*47c4b0deSDaniel Lezcano .c_msg_parser = handle_netlink, 253*47c4b0deSDaniel Lezcano .c_maxattr = THERMAL_GENL_ATTR_MAX, 254*47c4b0deSDaniel Lezcano .c_attr_policy = thermal_genl_policy, 255*47c4b0deSDaniel Lezcano }, 256*47c4b0deSDaniel Lezcano }; 257*47c4b0deSDaniel Lezcano 258*47c4b0deSDaniel Lezcano static struct genl_ops thermal_cmd_ops = { 259*47c4b0deSDaniel Lezcano .o_name = (char *)"thermal", 260*47c4b0deSDaniel Lezcano .o_cmds = thermal_cmds, 261*47c4b0deSDaniel Lezcano .o_ncmds = ARRAY_SIZE(thermal_cmds), 262*47c4b0deSDaniel Lezcano }; 263*47c4b0deSDaniel Lezcano 264*47c4b0deSDaniel Lezcano static thermal_error_t thermal_genl_auto(struct thermal_handler *th, int id, int cmd, 265*47c4b0deSDaniel Lezcano int flags, void *arg) 266*47c4b0deSDaniel Lezcano { 267*47c4b0deSDaniel Lezcano struct nl_msg *msg; 268*47c4b0deSDaniel Lezcano void *hdr; 269*47c4b0deSDaniel Lezcano 270*47c4b0deSDaniel Lezcano msg = nlmsg_alloc(); 271*47c4b0deSDaniel Lezcano if (!msg) 272*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 273*47c4b0deSDaniel Lezcano 274*47c4b0deSDaniel Lezcano hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, thermal_cmd_ops.o_id, 275*47c4b0deSDaniel Lezcano 0, flags, cmd, THERMAL_GENL_VERSION); 276*47c4b0deSDaniel Lezcano if (!hdr) 277*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 278*47c4b0deSDaniel Lezcano 279*47c4b0deSDaniel Lezcano if (id >= 0 && nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id)) 280*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 281*47c4b0deSDaniel Lezcano 282*47c4b0deSDaniel Lezcano if (nl_send_msg(th->sk_cmd, th->cb_cmd, msg, genl_handle_msg, arg)) 283*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 284*47c4b0deSDaniel Lezcano 285*47c4b0deSDaniel Lezcano nlmsg_free(msg); 286*47c4b0deSDaniel Lezcano 287*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 288*47c4b0deSDaniel Lezcano } 289*47c4b0deSDaniel Lezcano 290*47c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_tz(struct thermal_handler *th, struct thermal_zone **tz) 291*47c4b0deSDaniel Lezcano { 292*47c4b0deSDaniel Lezcano return thermal_genl_auto(th, -1, THERMAL_GENL_CMD_TZ_GET_ID, 293*47c4b0deSDaniel Lezcano NLM_F_DUMP | NLM_F_ACK, tz); 294*47c4b0deSDaniel Lezcano } 295*47c4b0deSDaniel Lezcano 296*47c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_cdev(struct thermal_handler *th, struct thermal_cdev **tc) 297*47c4b0deSDaniel Lezcano { 298*47c4b0deSDaniel Lezcano return thermal_genl_auto(th, -1, THERMAL_GENL_CMD_CDEV_GET, 299*47c4b0deSDaniel Lezcano NLM_F_DUMP | NLM_F_ACK, tc); 300*47c4b0deSDaniel Lezcano } 301*47c4b0deSDaniel Lezcano 302*47c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_trip(struct thermal_handler *th, struct thermal_zone *tz) 303*47c4b0deSDaniel Lezcano { 304*47c4b0deSDaniel Lezcano return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_TRIP, 305*47c4b0deSDaniel Lezcano 0, tz); 306*47c4b0deSDaniel Lezcano } 307*47c4b0deSDaniel Lezcano 308*47c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_governor(struct thermal_handler *th, struct thermal_zone *tz) 309*47c4b0deSDaniel Lezcano { 310*47c4b0deSDaniel Lezcano return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_GOV, 0, tz); 311*47c4b0deSDaniel Lezcano } 312*47c4b0deSDaniel Lezcano 313*47c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th, struct thermal_zone *tz) 314*47c4b0deSDaniel Lezcano { 315*47c4b0deSDaniel Lezcano return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_TEMP, 0, tz); 316*47c4b0deSDaniel Lezcano } 317*47c4b0deSDaniel Lezcano 318*47c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_exit(struct thermal_handler *th) 319*47c4b0deSDaniel Lezcano { 320*47c4b0deSDaniel Lezcano if (genl_unregister_family(&thermal_cmd_ops)) 321*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 322*47c4b0deSDaniel Lezcano 323*47c4b0deSDaniel Lezcano nl_thermal_disconnect(th->sk_cmd, th->cb_cmd); 324*47c4b0deSDaniel Lezcano 325*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 326*47c4b0deSDaniel Lezcano } 327*47c4b0deSDaniel Lezcano 328*47c4b0deSDaniel Lezcano thermal_error_t thermal_cmd_init(struct thermal_handler *th) 329*47c4b0deSDaniel Lezcano { 330*47c4b0deSDaniel Lezcano int ret; 331*47c4b0deSDaniel Lezcano int family; 332*47c4b0deSDaniel Lezcano 333*47c4b0deSDaniel Lezcano if (nl_thermal_connect(&th->sk_cmd, &th->cb_cmd)) 334*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 335*47c4b0deSDaniel Lezcano 336*47c4b0deSDaniel Lezcano ret = genl_register_family(&thermal_cmd_ops); 337*47c4b0deSDaniel Lezcano if (ret) 338*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 339*47c4b0deSDaniel Lezcano 340*47c4b0deSDaniel Lezcano ret = genl_ops_resolve(th->sk_cmd, &thermal_cmd_ops); 341*47c4b0deSDaniel Lezcano if (ret) 342*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 343*47c4b0deSDaniel Lezcano 344*47c4b0deSDaniel Lezcano family = genl_ctrl_resolve(th->sk_cmd, "nlctrl"); 345*47c4b0deSDaniel Lezcano if (family != GENL_ID_CTRL) 346*47c4b0deSDaniel Lezcano return THERMAL_ERROR; 347*47c4b0deSDaniel Lezcano 348*47c4b0deSDaniel Lezcano return THERMAL_SUCCESS; 349*47c4b0deSDaniel Lezcano } 350