Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.24-rc2 188 lines 4.7 kB view raw
1/* 2 * LED Kernel Timer Trigger 3 * 4 * Copyright 2005-2006 Openedhand Ltd. 5 * 6 * Author: Richard Purdie <rpurdie@openedhand.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 */ 13 14#include <linux/module.h> 15#include <linux/jiffies.h> 16#include <linux/kernel.h> 17#include <linux/init.h> 18#include <linux/list.h> 19#include <linux/spinlock.h> 20#include <linux/device.h> 21#include <linux/sysdev.h> 22#include <linux/timer.h> 23#include <linux/ctype.h> 24#include <linux/leds.h> 25#include "leds.h" 26 27struct timer_trig_data { 28 unsigned long delay_on; /* milliseconds on */ 29 unsigned long delay_off; /* milliseconds off */ 30 struct timer_list timer; 31}; 32 33static void led_timer_function(unsigned long data) 34{ 35 struct led_classdev *led_cdev = (struct led_classdev *) data; 36 struct timer_trig_data *timer_data = led_cdev->trigger_data; 37 unsigned long brightness = LED_OFF; 38 unsigned long delay = timer_data->delay_off; 39 40 if (!timer_data->delay_on || !timer_data->delay_off) { 41 led_set_brightness(led_cdev, LED_OFF); 42 return; 43 } 44 45 if (!led_cdev->brightness) { 46 brightness = LED_FULL; 47 delay = timer_data->delay_on; 48 } 49 50 led_set_brightness(led_cdev, brightness); 51 52 mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay)); 53} 54 55static ssize_t led_delay_on_show(struct device *dev, 56 struct device_attribute *attr, char *buf) 57{ 58 struct led_classdev *led_cdev = dev_get_drvdata(dev); 59 struct timer_trig_data *timer_data = led_cdev->trigger_data; 60 61 sprintf(buf, "%lu\n", timer_data->delay_on); 62 63 return strlen(buf) + 1; 64} 65 66static ssize_t led_delay_on_store(struct device *dev, 67 struct device_attribute *attr, const char *buf, size_t size) 68{ 69 struct led_classdev *led_cdev = dev_get_drvdata(dev); 70 struct timer_trig_data *timer_data = led_cdev->trigger_data; 71 int ret = -EINVAL; 72 char *after; 73 unsigned long state = simple_strtoul(buf, &after, 10); 74 size_t count = after - buf; 75 76 if (*after && isspace(*after)) 77 count++; 78 79 if (count == size) { 80 timer_data->delay_on = state; 81 mod_timer(&timer_data->timer, jiffies + 1); 82 ret = count; 83 } 84 85 return ret; 86} 87 88static ssize_t led_delay_off_show(struct device *dev, 89 struct device_attribute *attr, char *buf) 90{ 91 struct led_classdev *led_cdev = dev_get_drvdata(dev); 92 struct timer_trig_data *timer_data = led_cdev->trigger_data; 93 94 sprintf(buf, "%lu\n", timer_data->delay_off); 95 96 return strlen(buf) + 1; 97} 98 99static ssize_t led_delay_off_store(struct device *dev, 100 struct device_attribute *attr, const char *buf, size_t size) 101{ 102 struct led_classdev *led_cdev = dev_get_drvdata(dev); 103 struct timer_trig_data *timer_data = led_cdev->trigger_data; 104 int ret = -EINVAL; 105 char *after; 106 unsigned long state = simple_strtoul(buf, &after, 10); 107 size_t count = after - buf; 108 109 if (*after && isspace(*after)) 110 count++; 111 112 if (count == size) { 113 timer_data->delay_off = state; 114 mod_timer(&timer_data->timer, jiffies + 1); 115 ret = count; 116 } 117 118 return ret; 119} 120 121static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); 122static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); 123 124static void timer_trig_activate(struct led_classdev *led_cdev) 125{ 126 struct timer_trig_data *timer_data; 127 int rc; 128 129 timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); 130 if (!timer_data) 131 return; 132 133 led_cdev->trigger_data = timer_data; 134 135 init_timer(&timer_data->timer); 136 timer_data->timer.function = led_timer_function; 137 timer_data->timer.data = (unsigned long) led_cdev; 138 139 rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); 140 if (rc) 141 goto err_out; 142 rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); 143 if (rc) 144 goto err_out_delayon; 145 146 return; 147 148err_out_delayon: 149 device_remove_file(led_cdev->dev, &dev_attr_delay_on); 150err_out: 151 led_cdev->trigger_data = NULL; 152 kfree(timer_data); 153} 154 155static void timer_trig_deactivate(struct led_classdev *led_cdev) 156{ 157 struct timer_trig_data *timer_data = led_cdev->trigger_data; 158 159 if (timer_data) { 160 device_remove_file(led_cdev->dev, &dev_attr_delay_on); 161 device_remove_file(led_cdev->dev, &dev_attr_delay_off); 162 del_timer_sync(&timer_data->timer); 163 kfree(timer_data); 164 } 165} 166 167static struct led_trigger timer_led_trigger = { 168 .name = "timer", 169 .activate = timer_trig_activate, 170 .deactivate = timer_trig_deactivate, 171}; 172 173static int __init timer_trig_init(void) 174{ 175 return led_trigger_register(&timer_led_trigger); 176} 177 178static void __exit timer_trig_exit(void) 179{ 180 led_trigger_unregister(&timer_led_trigger); 181} 182 183module_init(timer_trig_init); 184module_exit(timer_trig_exit); 185 186MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); 187MODULE_DESCRIPTION("Timer LED trigger"); 188MODULE_LICENSE("GPL");