events.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: LGPL-2.1+
  2. // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <[email protected]>
  3. #include <linux/netlink.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <thermal.h>
  8. #include "thermal_nl.h"
  9. /*
  10. * Optimization: fill this array to tell which event we do want to pay
  11. * attention to. That happens at init time with the ops
  12. * structure. Each ops will enable the event and the general handler
  13. * will be able to discard the event if there is not ops associated
  14. * with it.
  15. */
  16. static int enabled_ops[__THERMAL_GENL_EVENT_MAX];
  17. static int handle_thermal_event(struct nl_msg *n, void *arg)
  18. {
  19. struct nlmsghdr *nlh = nlmsg_hdr(n);
  20. struct genlmsghdr *genlhdr = genlmsg_hdr(nlh);
  21. struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
  22. struct thermal_handler_param *thp = arg;
  23. struct thermal_events_ops *ops = &thp->th->ops->events;
  24. genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
  25. arg = thp->arg;
  26. /*
  27. * This is an event we don't care of, bail out.
  28. */
  29. if (!enabled_ops[genlhdr->cmd])
  30. return THERMAL_SUCCESS;
  31. switch (genlhdr->cmd) {
  32. case THERMAL_GENL_EVENT_TZ_CREATE:
  33. return ops->tz_create(nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME]),
  34. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
  35. case THERMAL_GENL_EVENT_TZ_DELETE:
  36. return ops->tz_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
  37. case THERMAL_GENL_EVENT_TZ_ENABLE:
  38. return ops->tz_enable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
  39. case THERMAL_GENL_EVENT_TZ_DISABLE:
  40. return ops->tz_disable(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
  41. case THERMAL_GENL_EVENT_TZ_TRIP_CHANGE:
  42. return ops->trip_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
  43. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
  44. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]),
  45. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]),
  46. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]), arg);
  47. case THERMAL_GENL_EVENT_TZ_TRIP_ADD:
  48. return ops->trip_add(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
  49. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
  50. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]),
  51. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]),
  52. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]), arg);
  53. case THERMAL_GENL_EVENT_TZ_TRIP_DELETE:
  54. return ops->trip_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
  55. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]), arg);
  56. case THERMAL_GENL_EVENT_TZ_TRIP_UP:
  57. return ops->trip_high(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
  58. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
  59. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), arg);
  60. case THERMAL_GENL_EVENT_TZ_TRIP_DOWN:
  61. return ops->trip_low(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
  62. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]),
  63. nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), arg);
  64. case THERMAL_GENL_EVENT_CDEV_ADD:
  65. return ops->cdev_add(nla_get_string(attrs[THERMAL_GENL_ATTR_CDEV_NAME]),
  66. nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]),
  67. nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_MAX_STATE]), arg);
  68. case THERMAL_GENL_EVENT_CDEV_DELETE:
  69. return ops->cdev_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]), arg);
  70. case THERMAL_GENL_EVENT_CDEV_STATE_UPDATE:
  71. return ops->cdev_update(nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]),
  72. nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE]), arg);
  73. case THERMAL_GENL_EVENT_TZ_GOV_CHANGE:
  74. return ops->gov_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
  75. nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]), arg);
  76. default:
  77. return -1;
  78. }
  79. }
  80. static void thermal_events_ops_init(struct thermal_events_ops *ops)
  81. {
  82. enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create;
  83. enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete;
  84. enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable;
  85. enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable;
  86. enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high;
  87. enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low;
  88. enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change;
  89. enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add;
  90. enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete;
  91. enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add;
  92. enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete;
  93. enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update;
  94. enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change;
  95. }
  96. thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg)
  97. {
  98. struct thermal_handler_param thp = { .th = th, .arg = arg };
  99. if (!th)
  100. return THERMAL_ERROR;
  101. if (nl_cb_set(th->cb_event, NL_CB_VALID, NL_CB_CUSTOM,
  102. handle_thermal_event, &thp))
  103. return THERMAL_ERROR;
  104. return nl_recvmsgs(th->sk_event, th->cb_event);
  105. }
  106. int thermal_events_fd(struct thermal_handler *th)
  107. {
  108. if (!th)
  109. return -1;
  110. return nl_socket_get_fd(th->sk_event);
  111. }
  112. thermal_error_t thermal_events_exit(struct thermal_handler *th)
  113. {
  114. if (nl_unsubscribe_thermal(th->sk_event, th->cb_event,
  115. THERMAL_GENL_EVENT_GROUP_NAME))
  116. return THERMAL_ERROR;
  117. nl_thermal_disconnect(th->sk_event, th->cb_event);
  118. return THERMAL_SUCCESS;
  119. }
  120. thermal_error_t thermal_events_init(struct thermal_handler *th)
  121. {
  122. thermal_events_ops_init(&th->ops->events);
  123. if (nl_thermal_connect(&th->sk_event, &th->cb_event))
  124. return THERMAL_ERROR;
  125. if (nl_subscribe_thermal(th->sk_event, th->cb_event,
  126. THERMAL_GENL_EVENT_GROUP_NAME))
  127. return THERMAL_ERROR;
  128. return THERMAL_SUCCESS;
  129. }