|
@@ -32,6 +32,8 @@
|
|
|
#include <linux/thermal.h>
|
|
|
#include <linux/spinlock.h>
|
|
|
#include <linux/reboot.h>
|
|
|
+#include <net/netlink.h>
|
|
|
+#include <net/genetlink.h>
|
|
|
|
|
|
MODULE_AUTHOR("Zhang Rui");
|
|
|
MODULE_DESCRIPTION("Generic thermal management sysfs support");
|
|
@@ -58,6 +60,22 @@ static LIST_HEAD(thermal_tz_list);
|
|
|
static LIST_HEAD(thermal_cdev_list);
|
|
|
static DEFINE_MUTEX(thermal_list_lock);
|
|
|
|
|
|
+static unsigned int thermal_event_seqnum;
|
|
|
+
|
|
|
+static struct genl_family thermal_event_genl_family = {
|
|
|
+ .id = GENL_ID_GENERATE,
|
|
|
+ .name = THERMAL_GENL_FAMILY_NAME,
|
|
|
+ .version = THERMAL_GENL_VERSION,
|
|
|
+ .maxattr = THERMAL_GENL_ATTR_MAX,
|
|
|
+};
|
|
|
+
|
|
|
+static struct genl_multicast_group thermal_event_mcgrp = {
|
|
|
+ .name = THERMAL_GENL_MCAST_GROUP_NAME,
|
|
|
+};
|
|
|
+
|
|
|
+static int genetlink_init(void);
|
|
|
+static void genetlink_exit(void);
|
|
|
+
|
|
|
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
|
|
|
{
|
|
|
int err;
|
|
@@ -1214,6 +1232,82 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
|
|
|
|
|
EXPORT_SYMBOL(thermal_zone_device_unregister);
|
|
|
|
|
|
+int generate_netlink_event(u32 orig, enum events event)
|
|
|
+{
|
|
|
+ struct sk_buff *skb;
|
|
|
+ struct nlattr *attr;
|
|
|
+ struct thermal_genl_event *thermal_event;
|
|
|
+ void *msg_header;
|
|
|
+ int size;
|
|
|
+ int result;
|
|
|
+
|
|
|
+ /* allocate memory */
|
|
|
+ size = nla_total_size(sizeof(struct thermal_genl_event)) + \
|
|
|
+ nla_total_size(0);
|
|
|
+
|
|
|
+ skb = genlmsg_new(size, GFP_ATOMIC);
|
|
|
+ if (!skb)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ /* add the genetlink message header */
|
|
|
+ msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
|
|
|
+ &thermal_event_genl_family, 0,
|
|
|
+ THERMAL_GENL_CMD_EVENT);
|
|
|
+ if (!msg_header) {
|
|
|
+ nlmsg_free(skb);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* fill the data */
|
|
|
+ attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \
|
|
|
+ sizeof(struct thermal_genl_event));
|
|
|
+
|
|
|
+ if (!attr) {
|
|
|
+ nlmsg_free(skb);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ thermal_event = nla_data(attr);
|
|
|
+ if (!thermal_event) {
|
|
|
+ nlmsg_free(skb);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(thermal_event, 0, sizeof(struct thermal_genl_event));
|
|
|
+
|
|
|
+ thermal_event->orig = orig;
|
|
|
+ thermal_event->event = event;
|
|
|
+
|
|
|
+ /* send multicast genetlink message */
|
|
|
+ result = genlmsg_end(skb, msg_header);
|
|
|
+ if (result < 0) {
|
|
|
+ nlmsg_free(skb);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
|
|
|
+ if (result)
|
|
|
+ printk(KERN_INFO "failed to send netlink event:%d", result);
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(generate_netlink_event);
|
|
|
+
|
|
|
+static int genetlink_init(void)
|
|
|
+{
|
|
|
+ int result;
|
|
|
+
|
|
|
+ result = genl_register_family(&thermal_event_genl_family);
|
|
|
+ if (result)
|
|
|
+ return result;
|
|
|
+
|
|
|
+ result = genl_register_mc_group(&thermal_event_genl_family,
|
|
|
+ &thermal_event_mcgrp);
|
|
|
+ if (result)
|
|
|
+ genl_unregister_family(&thermal_event_genl_family);
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
static int __init thermal_init(void)
|
|
|
{
|
|
|
int result = 0;
|
|
@@ -1225,9 +1319,15 @@ static int __init thermal_init(void)
|
|
|
mutex_destroy(&thermal_idr_lock);
|
|
|
mutex_destroy(&thermal_list_lock);
|
|
|
}
|
|
|
+ result = genetlink_init();
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+static void genetlink_exit(void)
|
|
|
+{
|
|
|
+ genl_unregister_family(&thermal_event_genl_family);
|
|
|
+}
|
|
|
+
|
|
|
static void __exit thermal_exit(void)
|
|
|
{
|
|
|
class_unregister(&thermal_class);
|
|
@@ -1235,7 +1335,8 @@ static void __exit thermal_exit(void)
|
|
|
idr_destroy(&thermal_cdev_idr);
|
|
|
mutex_destroy(&thermal_idr_lock);
|
|
|
mutex_destroy(&thermal_list_lock);
|
|
|
+ genetlink_exit();
|
|
|
}
|
|
|
|
|
|
-subsys_initcall(thermal_init);
|
|
|
+fs_initcall(thermal_init);
|
|
|
module_exit(thermal_exit);
|