Merge branch 'misc' into release
[firefly-linux-kernel-4.4.55.git] / drivers / thermal / thermal_sys.c
index bde3477c1c6b75293f2181ba93ae3dc1677bea85..7d0e63c79280c37c6a88e9be1e8834eea11eba31 100644 (file)
@@ -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;
@@ -1207,6 +1225,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;
@@ -1218,9 +1312,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);
@@ -1228,7 +1328,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);