Hi Arjan,

I m submitting the medfield thermal driver patch series.

This one, the first one in the series, adds event notification
support to the generic thermal sysfs framework in the kernel.

I have also added a documentation for the same in
Documentation/thermal/sysfs-api.txt


------------------------------------------------------------
Signed-off-by:  <[email protected]>

Index: ac_kernel/kernel/Documentation/ABI/stable/thermal-notification
===================================================================
--- /dev/null
+++ ac_kernel/kernel/Documentation/ABI/stable/thermal-notification
@@ -0,0 +1,4 @@
+What:          A notification mechanism for thermal related events
+Description:
+       This interface enables notification for thermal related events.
+       The notification is in the form of a netlink event.
Index: ac_kernel/kernel/Documentation/thermal/sysfs-api.txt
===================================================================
--- ac_kernel.orig/kernel/Documentation/thermal/sysfs-api.txt
+++ ac_kernel/kernel/Documentation/thermal/sysfs-api.txt
@@ -278,3 +278,15 @@ method, the sys I/F structure will be bu
     |---name:                  acpitz
     |---temp1_input:           37000
     |---temp1_crit:            100000
+
+4. Event Notification
+
+The framework includes a simple notification mechanism, in the form of a
+netlink event. Netlink socket initialization is done during the _init_
+of the framework. Drivers which intend to use the notification mechanism
+just need to call generate_netlink_event() with two arguments viz
+(originator, event). Typically the originator will be an integer assigned
+to a thermal_zone_device when it registers itself with the framework. The
+event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
+THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
+crosses any of the configured thresholds.
Index: ac_kernel/kernel/drivers/thermal/thermal_sys.c
===================================================================
--- ac_kernel.orig/kernel/drivers/thermal/thermal_sys.c
+++ ac_kernel/kernel/drivers/thermal/thermal_sys.c
@@ -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,23 @@ static LIST_HEAD(thermal_tz_list);
 static LIST_HEAD(thermal_cdev_list);
 static DEFINE_MUTEX(thermal_list_lock);

+static DEFINE_MUTEX(thermal_trip_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;
@@ -216,6 +235,30 @@ trip_point_temp_show(struct device *dev,
 }

 static ssize_t
+trip_point_temp_store(struct device *dev, struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+       int trip, result;
+       long temperature;
+
+       if (!tz->ops->set_trip_temp)
+               return -EPERM;
+
+       if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
+               return -EINVAL;
+
+       if (strict_strtoul(buf, 10, &temperature))
+               return -EINVAL;
+
+       mutex_lock(&thermal_trip_lock);
+       result = tz->ops->set_trip_temp(tz, trip, temperature);
+       mutex_unlock(&thermal_trip_lock);
+
+       return (result == 0) ? count : -EINVAL;
+}
+
+static ssize_t
 passive_store(struct device *dev, struct device_attribute *attr,
                    const char *buf, size_t count)
 {
@@ -282,31 +325,55 @@ static DEVICE_ATTR(mode, 0644, mode_show
 static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \
                   passive_store);

+/* trip point temperatures may be configurable */
 static struct device_attribute trip_point_attrs[] = {
-       __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_10_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_10_temp, 0444, trip_point_temp_show, NULL),
-       __ATTR(trip_point_11_type, 0444, trip_point_type_show, NULL),
-       __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_0_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_0_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_1_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_1_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_2_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_2_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_3_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_3_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_4_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_4_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_5_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_5_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_6_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_6_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_7_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_7_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_8_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_8_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_9_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_9_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_10_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_10_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
+
+       __ATTR(trip_point_11_type, S_IRUGO, trip_point_type_show, NULL),
+       __ATTR(trip_point_11_temp, S_IRUGO | S_IWUSR, trip_point_temp_show,
+               trip_point_temp_store),
 };

 #define TRIP_POINT_ATTR_ADD(_dev, _index, result)     \
@@ -584,7 +651,7 @@ thermal_remove_hwmon_sysfs(struct therma
 }
 #endif

-static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
                                            int delay)
 {
        cancel_delayed_work(&(tz->poll_queue));
@@ -609,6 +676,13 @@ static void thermal_zone_device_passive(
        long state, max_state;

        /*
+        * For polling mechanisms, call the notify method.
+        * Interrupts will have their own handlers.
+        */
+       if (tz->ops->notify && tz->polling_delay)
+               tz->ops->notify(tz, trip, THERMAL_TRIP_PASSIVE);
+
+       /*
         * Above Trip?
         * -----------
         * Calculate the thermal trend (using the passive cooling equation)
@@ -1214,28 +1288,117 @@ void thermal_zone_device_unregister(stru

 EXPORT_SYMBOL(thermal_zone_device_unregister);

-static int __init thermal_init(void)
+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;
+       }
+
+       printk(KERN_INFO "netlink event: orig:%d event:%d", orig, event);
+
+       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 = 0;
+       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 void genetlink_exit(void)
+{
+       genl_unregister_family(&thermal_event_genl_family);
+}
+
+static int __init thermal_init(void)
+{
+       int result = 0;
        result = class_register(&thermal_class);
        if (result) {
                idr_destroy(&thermal_tz_idr);
                idr_destroy(&thermal_cdev_idr);
                mutex_destroy(&thermal_idr_lock);
                mutex_destroy(&thermal_list_lock);
+               mutex_destroy(&thermal_trip_lock);
        }
+       result = genetlink_init();
        return result;
 }

 static void __exit thermal_exit(void)
 {
+
        class_unregister(&thermal_class);
        idr_destroy(&thermal_tz_idr);
        idr_destroy(&thermal_cdev_idr);
        mutex_destroy(&thermal_idr_lock);
        mutex_destroy(&thermal_list_lock);
+       mutex_destroy(&thermal_trip_lock);
+       genetlink_exit();
 }

-subsys_initcall(thermal_init);
+fs_initcall(thermal_init);
 module_exit(thermal_exit);
Index: ac_kernel/kernel/include/linux/thermal.h
===================================================================
--- ac_kernel.orig/kernel/include/linux/thermal.h
+++ ac_kernel/kernel/include/linux/thermal.h
@@ -29,8 +29,45 @@
 #include <linux/device.h>
 #include <linux/workqueue.h>

-struct thermal_zone_device;
-struct thermal_cooling_device;
+#define THERMAL_GENL_FAMILY_NAME               "thermal_event"
+#define THERMAL_GENL_VERSION                   0x01
+#define THERMAL_GENL_MCAST_GROUP_NAME          "thermal_mc_group"
+
+#define THERMAL_TRIPS_NONE -1
+#define THERMAL_MAX_TRIPS 12
+#define THERMAL_NAME_LENGTH 20
+
+#define KELVIN_TO_CELSIUS(t)   (long)(((long)t-2732 >= 0) ?    \
+                               ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
+#define CELSIUS_TO_KELVIN(t)   ((t)*10+2732)
+
+enum events {
+       THERMAL_AUX0,
+       THERMAL_AUX1,
+       THERMAL_CRITICAL,
+       THERMAL_DEV_FAULT,
+};
+
+struct thermal_genl_event {
+       u32 orig;
+       enum events event;
+};
+
+/* attributes of thermal_genl_family */
+enum {
+       THERMAL_GENL_ATTR_UNSPEC,
+       THERMAL_GENL_ATTR_EVENT,
+       __THERMAL_GENL_ATTR_MAX,
+};
+#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
+
+/* commands supported by the thermal_genl_family */
+enum {
+       THERMAL_GENL_CMD_UNSPEC,
+       THERMAL_GENL_CMD_EVENT,
+       __THERMAL_GENL_CMD_MAX,
+};
+#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)

 enum thermal_device_mode {
        THERMAL_DEVICE_DISABLED = 0,
@@ -44,20 +81,23 @@ enum thermal_trip_type {
        THERMAL_TRIP_CRITICAL,
 };

+struct thermal_zone_device;
+struct thermal_cooling_device;
+
 struct thermal_zone_device_ops {
        int (*bind) (struct thermal_zone_device *,
                     struct thermal_cooling_device *);
        int (*unbind) (struct thermal_zone_device *,
                       struct thermal_cooling_device *);
-       int (*get_temp) (struct thermal_zone_device *, unsigned long *);
+       int (*get_temp) (struct thermal_zone_device *, long *);
        int (*get_mode) (struct thermal_zone_device *,
                         enum thermal_device_mode *);
        int (*set_mode) (struct thermal_zone_device *,
                enum thermal_device_mode);
        int (*get_trip_type) (struct thermal_zone_device *, int,
                enum thermal_trip_type *);
-       int (*get_trip_temp) (struct thermal_zone_device *, int,
-                             unsigned long *);
+       int (*get_trip_temp) (struct thermal_zone_device *, int, long *);
+       int (*set_trip_temp) (struct thermal_zone_device *, int, long);
        int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
        int (*notify) (struct thermal_zone_device *, int,
                       enum thermal_trip_type);
@@ -69,9 +109,6 @@ struct thermal_cooling_device_ops {
        int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
 };

-#define THERMAL_TRIPS_NONE -1
-#define THERMAL_MAX_TRIPS 12
-#define THERMAL_NAME_LENGTH 20
 struct thermal_cooling_device {
        int id;
        char type[THERMAL_NAME_LENGTH];
@@ -81,9 +118,6 @@ struct thermal_cooling_device {
        struct list_head node;
 };

-#define KELVIN_TO_CELSIUS(t)   (long)(((long)t-2732 >= 0) ?    \
-                               ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
-#define CELSIUS_TO_KELVIN(t)   ((t)*10+2732)

 #if defined(CONFIG_THERMAL_HWMON)
 /* thermal zone devices with the same type share one hwmon device */
@@ -129,11 +163,10 @@ struct thermal_zone_device {
 };

 struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
-                                                        struct
-                                                        thermal_zone_device_ops
-                                                        *, int tc1, int tc2,
-                                                        int passive_freq,
-                                                        int polling_freq);
+                                        struct  thermal_zone_device_ops *,
+                                                       int tc1, int tc2,
+                                                       int passive_freq,
+                                                       int polling_freq);
 void thermal_zone_device_unregister(struct thermal_zone_device *);

 int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
@@ -142,9 +175,9 @@ int thermal_zone_unbind_cooling_device(s
                                       struct thermal_cooling_device *);
 void thermal_zone_device_update(struct thermal_zone_device *);
 struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
-                                                              struct
-                                                              
thermal_cooling_device_ops
-                                                              *);
+                                       struct thermal_cooling_device_ops *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+void thermal_zone_device_set_polling(struct thermal_zone_device *, int);
+extern int generate_netlink_event(u32 orig, enum events event);

 #endif /* __THERMAL_H__ */

Attachment: Adding_notification_support_to_thermal_framework.patch
Description: Adding_notification_support_to_thermal_framework.patch

_______________________________________________
Meego-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to