Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * One-shot LED Trigger 4 : : * 5 : : * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> 6 : : * 7 : : * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com> 8 : : */ 9 : : 10 : : #include <linux/module.h> 11 : : #include <linux/kernel.h> 12 : : #include <linux/init.h> 13 : : #include <linux/device.h> 14 : : #include <linux/ctype.h> 15 : : #include <linux/slab.h> 16 : : #include <linux/leds.h> 17 : : #include "../leds.h" 18 : : 19 : : #define DEFAULT_DELAY 100 20 : : 21 : : struct oneshot_trig_data { 22 : : unsigned int invert; 23 : : }; 24 : : 25 : 0 : static ssize_t led_shot(struct device *dev, 26 : : struct device_attribute *attr, const char *buf, size_t size) 27 : : { 28 : : struct led_classdev *led_cdev = led_trigger_get_led(dev); 29 : : struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev); 30 : : 31 : 0 : led_blink_set_oneshot(led_cdev, 32 : : &led_cdev->blink_delay_on, &led_cdev->blink_delay_off, 33 : 0 : oneshot_data->invert); 34 : : 35 : : /* content is ignored */ 36 : 0 : return size; 37 : : } 38 : 0 : static ssize_t led_invert_show(struct device *dev, 39 : : struct device_attribute *attr, char *buf) 40 : : { 41 : : struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev); 42 : : 43 : 0 : return sprintf(buf, "%u\n", oneshot_data->invert); 44 : : } 45 : : 46 : 0 : static ssize_t led_invert_store(struct device *dev, 47 : : struct device_attribute *attr, const char *buf, size_t size) 48 : : { 49 : : struct led_classdev *led_cdev = led_trigger_get_led(dev); 50 : : struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev); 51 : : unsigned long state; 52 : : int ret; 53 : : 54 : : ret = kstrtoul(buf, 0, &state); 55 : 0 : if (ret) 56 : : return ret; 57 : : 58 : 0 : oneshot_data->invert = !!state; 59 : : 60 : 0 : if (oneshot_data->invert) 61 : 0 : led_set_brightness_nosleep(led_cdev, LED_FULL); 62 : : else 63 : 0 : led_set_brightness_nosleep(led_cdev, LED_OFF); 64 : : 65 : 0 : return size; 66 : : } 67 : : 68 : 0 : static ssize_t led_delay_on_show(struct device *dev, 69 : : struct device_attribute *attr, char *buf) 70 : : { 71 : : struct led_classdev *led_cdev = led_trigger_get_led(dev); 72 : : 73 : 0 : return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); 74 : : } 75 : : 76 : 0 : static ssize_t led_delay_on_store(struct device *dev, 77 : : struct device_attribute *attr, const char *buf, size_t size) 78 : : { 79 : : struct led_classdev *led_cdev = led_trigger_get_led(dev); 80 : : unsigned long state; 81 : : int ret; 82 : : 83 : : ret = kstrtoul(buf, 0, &state); 84 : 0 : if (ret) 85 : : return ret; 86 : : 87 : 0 : led_cdev->blink_delay_on = state; 88 : : 89 : 0 : return size; 90 : : } 91 : : 92 : 0 : static ssize_t led_delay_off_show(struct device *dev, 93 : : struct device_attribute *attr, char *buf) 94 : : { 95 : : struct led_classdev *led_cdev = led_trigger_get_led(dev); 96 : : 97 : 0 : return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); 98 : : } 99 : : 100 : 0 : static ssize_t led_delay_off_store(struct device *dev, 101 : : struct device_attribute *attr, const char *buf, size_t size) 102 : : { 103 : : struct led_classdev *led_cdev = led_trigger_get_led(dev); 104 : : unsigned long state; 105 : : int ret; 106 : : 107 : : ret = kstrtoul(buf, 0, &state); 108 : 0 : if (ret) 109 : : return ret; 110 : : 111 : 0 : led_cdev->blink_delay_off = state; 112 : : 113 : 0 : return size; 114 : : } 115 : : 116 : : static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); 117 : : static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); 118 : : static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store); 119 : : static DEVICE_ATTR(shot, 0200, NULL, led_shot); 120 : : 121 : : static struct attribute *oneshot_trig_attrs[] = { 122 : : &dev_attr_delay_on.attr, 123 : : &dev_attr_delay_off.attr, 124 : : &dev_attr_invert.attr, 125 : : &dev_attr_shot.attr, 126 : : NULL 127 : : }; 128 : : ATTRIBUTE_GROUPS(oneshot_trig); 129 : : 130 : 0 : static void pattern_init(struct led_classdev *led_cdev) 131 : : { 132 : : u32 *pattern; 133 : 0 : unsigned int size = 0; 134 : : 135 : 0 : pattern = led_get_default_pattern(led_cdev, &size); 136 : 0 : if (!pattern) 137 : : goto out_default; 138 : : 139 : 0 : if (size != 2) { 140 : 0 : dev_warn(led_cdev->dev, 141 : : "Expected 2 but got %u values for delays pattern\n", 142 : : size); 143 : 0 : goto out_default; 144 : : } 145 : : 146 : 0 : led_cdev->blink_delay_on = pattern[0]; 147 : 0 : led_cdev->blink_delay_off = pattern[1]; 148 : 0 : kfree(pattern); 149 : : 150 : 0 : return; 151 : : 152 : : out_default: 153 : 0 : kfree(pattern); 154 : 0 : led_cdev->blink_delay_on = DEFAULT_DELAY; 155 : 0 : led_cdev->blink_delay_off = DEFAULT_DELAY; 156 : : } 157 : : 158 : 0 : static int oneshot_trig_activate(struct led_classdev *led_cdev) 159 : : { 160 : : struct oneshot_trig_data *oneshot_data; 161 : : 162 : 0 : oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL); 163 : 0 : if (!oneshot_data) 164 : : return -ENOMEM; 165 : : 166 : : led_set_trigger_data(led_cdev, oneshot_data); 167 : : 168 : 0 : if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { 169 : 0 : pattern_init(led_cdev); 170 : : /* 171 : : * Mark as initialized even on pattern_init() error because 172 : : * any consecutive call to it would produce the same error. 173 : : */ 174 : 0 : led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; 175 : : } 176 : : 177 : : return 0; 178 : : } 179 : : 180 : 0 : static void oneshot_trig_deactivate(struct led_classdev *led_cdev) 181 : : { 182 : : struct oneshot_trig_data *oneshot_data = led_get_trigger_data(led_cdev); 183 : : 184 : 0 : kfree(oneshot_data); 185 : : 186 : : /* Stop blinking */ 187 : 0 : led_set_brightness(led_cdev, LED_OFF); 188 : 0 : } 189 : : 190 : : static struct led_trigger oneshot_led_trigger = { 191 : : .name = "oneshot", 192 : : .activate = oneshot_trig_activate, 193 : : .deactivate = oneshot_trig_deactivate, 194 : : .groups = oneshot_trig_groups, 195 : : }; 196 : 3 : module_led_trigger(oneshot_led_trigger); 197 : : 198 : : MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>"); 199 : : MODULE_DESCRIPTION("One-shot LED trigger"); 200 : : MODULE_LICENSE("GPL v2");