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 : 207 : 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");
|