Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.18 237 lines 6.6 kB view raw
1/* 2 * LED Kernel Transient Trigger 3 * 4 * Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com> 5 * 6 * Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's 7 * ledtrig-heartbeat.c 8 * Design and use-case input from Jonas Bonn <jonas@southpole.se> and 9 * Neil Brown <neilb@suse.de> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 */ 16/* 17 * Transient trigger allows one shot timer activation. Please refer to 18 * Documentation/leds/ledtrig-transient.txt for details 19*/ 20 21#include <linux/module.h> 22#include <linux/kernel.h> 23#include <linux/init.h> 24#include <linux/device.h> 25#include <linux/slab.h> 26#include <linux/timer.h> 27#include <linux/leds.h> 28#include "../leds.h" 29 30struct transient_trig_data { 31 int activate; 32 int state; 33 int restore_state; 34 unsigned long duration; 35 struct timer_list timer; 36}; 37 38static void transient_timer_function(unsigned long data) 39{ 40 struct led_classdev *led_cdev = (struct led_classdev *) data; 41 struct transient_trig_data *transient_data = led_cdev->trigger_data; 42 43 transient_data->activate = 0; 44 __led_set_brightness(led_cdev, transient_data->restore_state); 45} 46 47static ssize_t transient_activate_show(struct device *dev, 48 struct device_attribute *attr, char *buf) 49{ 50 struct led_classdev *led_cdev = dev_get_drvdata(dev); 51 struct transient_trig_data *transient_data = led_cdev->trigger_data; 52 53 return sprintf(buf, "%d\n", transient_data->activate); 54} 55 56static ssize_t transient_activate_store(struct device *dev, 57 struct device_attribute *attr, const char *buf, size_t size) 58{ 59 struct led_classdev *led_cdev = dev_get_drvdata(dev); 60 struct transient_trig_data *transient_data = led_cdev->trigger_data; 61 unsigned long state; 62 ssize_t ret; 63 64 ret = kstrtoul(buf, 10, &state); 65 if (ret) 66 return ret; 67 68 if (state != 1 && state != 0) 69 return -EINVAL; 70 71 /* cancel the running timer */ 72 if (state == 0 && transient_data->activate == 1) { 73 del_timer(&transient_data->timer); 74 transient_data->activate = state; 75 __led_set_brightness(led_cdev, transient_data->restore_state); 76 return size; 77 } 78 79 /* start timer if there is no active timer */ 80 if (state == 1 && transient_data->activate == 0 && 81 transient_data->duration != 0) { 82 transient_data->activate = state; 83 __led_set_brightness(led_cdev, transient_data->state); 84 transient_data->restore_state = 85 (transient_data->state == LED_FULL) ? LED_OFF : LED_FULL; 86 mod_timer(&transient_data->timer, 87 jiffies + transient_data->duration); 88 } 89 90 /* state == 0 && transient_data->activate == 0 91 timer is not active - just return */ 92 /* state == 1 && transient_data->activate == 1 93 timer is already active - just return */ 94 95 return size; 96} 97 98static ssize_t transient_duration_show(struct device *dev, 99 struct device_attribute *attr, char *buf) 100{ 101 struct led_classdev *led_cdev = dev_get_drvdata(dev); 102 struct transient_trig_data *transient_data = led_cdev->trigger_data; 103 104 return sprintf(buf, "%lu\n", transient_data->duration); 105} 106 107static ssize_t transient_duration_store(struct device *dev, 108 struct device_attribute *attr, const char *buf, size_t size) 109{ 110 struct led_classdev *led_cdev = dev_get_drvdata(dev); 111 struct transient_trig_data *transient_data = led_cdev->trigger_data; 112 unsigned long state; 113 ssize_t ret; 114 115 ret = kstrtoul(buf, 10, &state); 116 if (ret) 117 return ret; 118 119 transient_data->duration = state; 120 return size; 121} 122 123static ssize_t transient_state_show(struct device *dev, 124 struct device_attribute *attr, char *buf) 125{ 126 struct led_classdev *led_cdev = dev_get_drvdata(dev); 127 struct transient_trig_data *transient_data = led_cdev->trigger_data; 128 int state; 129 130 state = (transient_data->state == LED_FULL) ? 1 : 0; 131 return sprintf(buf, "%d\n", state); 132} 133 134static ssize_t transient_state_store(struct device *dev, 135 struct device_attribute *attr, const char *buf, size_t size) 136{ 137 struct led_classdev *led_cdev = dev_get_drvdata(dev); 138 struct transient_trig_data *transient_data = led_cdev->trigger_data; 139 unsigned long state; 140 ssize_t ret; 141 142 ret = kstrtoul(buf, 10, &state); 143 if (ret) 144 return ret; 145 146 if (state != 1 && state != 0) 147 return -EINVAL; 148 149 transient_data->state = (state == 1) ? LED_FULL : LED_OFF; 150 return size; 151} 152 153static DEVICE_ATTR(activate, 0644, transient_activate_show, 154 transient_activate_store); 155static DEVICE_ATTR(duration, 0644, transient_duration_show, 156 transient_duration_store); 157static DEVICE_ATTR(state, 0644, transient_state_show, transient_state_store); 158 159static void transient_trig_activate(struct led_classdev *led_cdev) 160{ 161 int rc; 162 struct transient_trig_data *tdata; 163 164 tdata = kzalloc(sizeof(struct transient_trig_data), GFP_KERNEL); 165 if (!tdata) { 166 dev_err(led_cdev->dev, 167 "unable to allocate transient trigger\n"); 168 return; 169 } 170 led_cdev->trigger_data = tdata; 171 172 rc = device_create_file(led_cdev->dev, &dev_attr_activate); 173 if (rc) 174 goto err_out; 175 176 rc = device_create_file(led_cdev->dev, &dev_attr_duration); 177 if (rc) 178 goto err_out_duration; 179 180 rc = device_create_file(led_cdev->dev, &dev_attr_state); 181 if (rc) 182 goto err_out_state; 183 184 setup_timer(&tdata->timer, transient_timer_function, 185 (unsigned long) led_cdev); 186 led_cdev->activated = true; 187 188 return; 189 190err_out_state: 191 device_remove_file(led_cdev->dev, &dev_attr_duration); 192err_out_duration: 193 device_remove_file(led_cdev->dev, &dev_attr_activate); 194err_out: 195 dev_err(led_cdev->dev, "unable to register transient trigger\n"); 196 led_cdev->trigger_data = NULL; 197 kfree(tdata); 198} 199 200static void transient_trig_deactivate(struct led_classdev *led_cdev) 201{ 202 struct transient_trig_data *transient_data = led_cdev->trigger_data; 203 204 if (led_cdev->activated) { 205 del_timer_sync(&transient_data->timer); 206 __led_set_brightness(led_cdev, transient_data->restore_state); 207 device_remove_file(led_cdev->dev, &dev_attr_activate); 208 device_remove_file(led_cdev->dev, &dev_attr_duration); 209 device_remove_file(led_cdev->dev, &dev_attr_state); 210 led_cdev->trigger_data = NULL; 211 led_cdev->activated = false; 212 kfree(transient_data); 213 } 214} 215 216static struct led_trigger transient_trigger = { 217 .name = "transient", 218 .activate = transient_trig_activate, 219 .deactivate = transient_trig_deactivate, 220}; 221 222static int __init transient_trig_init(void) 223{ 224 return led_trigger_register(&transient_trigger); 225} 226 227static void __exit transient_trig_exit(void) 228{ 229 led_trigger_unregister(&transient_trigger); 230} 231 232module_init(transient_trig_init); 233module_exit(transient_trig_exit); 234 235MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>"); 236MODULE_DESCRIPTION("Transient LED trigger"); 237MODULE_LICENSE("GPL");