Root/drivers/leds/ledtrig-oneshot.c

1/*
2 * One-shot LED Trigger
3 *
4 * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
5 *
6 * Based on ledtrig-timer.c by 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/kernel.h>
16#include <linux/init.h>
17#include <linux/device.h>
18#include <linux/ctype.h>
19#include <linux/slab.h>
20#include <linux/leds.h>
21#include "leds.h"
22
23#define DEFAULT_DELAY 100
24
25struct oneshot_trig_data {
26    unsigned int invert;
27};
28
29static ssize_t led_shot(struct device *dev,
30        struct device_attribute *attr, const char *buf, size_t size)
31{
32    struct led_classdev *led_cdev = dev_get_drvdata(dev);
33    struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
34
35    led_blink_set_oneshot(led_cdev,
36            &led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
37            oneshot_data->invert);
38
39    /* content is ignored */
40    return size;
41}
42static ssize_t led_invert_show(struct device *dev,
43        struct device_attribute *attr, char *buf)
44{
45    struct led_classdev *led_cdev = dev_get_drvdata(dev);
46    struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
47
48    return sprintf(buf, "%u\n", oneshot_data->invert);
49}
50
51static ssize_t led_invert_store(struct device *dev,
52        struct device_attribute *attr, const char *buf, size_t size)
53{
54    struct led_classdev *led_cdev = dev_get_drvdata(dev);
55    struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
56    unsigned long state;
57    int ret;
58
59    ret = kstrtoul(buf, 0, &state);
60    if (ret)
61        return ret;
62
63    oneshot_data->invert = !!state;
64
65    if (oneshot_data->invert)
66        __led_set_brightness(led_cdev, LED_FULL);
67    else
68        __led_set_brightness(led_cdev, LED_OFF);
69
70    return size;
71}
72
73static ssize_t led_delay_on_show(struct device *dev,
74        struct device_attribute *attr, char *buf)
75{
76    struct led_classdev *led_cdev = dev_get_drvdata(dev);
77
78    return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
79}
80
81static ssize_t led_delay_on_store(struct device *dev,
82        struct device_attribute *attr, const char *buf, size_t size)
83{
84    struct led_classdev *led_cdev = dev_get_drvdata(dev);
85    unsigned long state;
86    int ret;
87
88    ret = kstrtoul(buf, 0, &state);
89    if (ret)
90        return ret;
91
92    led_cdev->blink_delay_on = state;
93
94    return size;
95}
96static ssize_t led_delay_off_show(struct device *dev,
97        struct device_attribute *attr, char *buf)
98{
99    struct led_classdev *led_cdev = dev_get_drvdata(dev);
100
101    return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
102}
103
104static ssize_t led_delay_off_store(struct device *dev,
105        struct device_attribute *attr, const char *buf, size_t size)
106{
107    struct led_classdev *led_cdev = dev_get_drvdata(dev);
108    unsigned long state;
109    int ret;
110
111    ret = kstrtoul(buf, 0, &state);
112    if (ret)
113        return ret;
114
115    led_cdev->blink_delay_off = state;
116
117    return size;
118}
119
120static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
121static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
122static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
123static DEVICE_ATTR(shot, 0200, NULL, led_shot);
124
125static void oneshot_trig_activate(struct led_classdev *led_cdev)
126{
127    struct oneshot_trig_data *oneshot_data;
128    int rc;
129
130    oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
131    if (!oneshot_data)
132        return;
133
134    led_cdev->trigger_data = oneshot_data;
135
136    rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
137    if (rc)
138        goto err_out_trig_data;
139    rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
140    if (rc)
141        goto err_out_delayon;
142    rc = device_create_file(led_cdev->dev, &dev_attr_invert);
143    if (rc)
144        goto err_out_delayoff;
145    rc = device_create_file(led_cdev->dev, &dev_attr_shot);
146    if (rc)
147        goto err_out_invert;
148
149    led_cdev->blink_delay_on = DEFAULT_DELAY;
150    led_cdev->blink_delay_off = DEFAULT_DELAY;
151
152    led_cdev->activated = true;
153
154    return;
155
156err_out_invert:
157    device_remove_file(led_cdev->dev, &dev_attr_invert);
158err_out_delayoff:
159    device_remove_file(led_cdev->dev, &dev_attr_delay_off);
160err_out_delayon:
161    device_remove_file(led_cdev->dev, &dev_attr_delay_on);
162err_out_trig_data:
163    kfree(led_cdev->trigger_data);
164}
165
166static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
167{
168    struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
169
170    if (led_cdev->activated) {
171        device_remove_file(led_cdev->dev, &dev_attr_delay_on);
172        device_remove_file(led_cdev->dev, &dev_attr_delay_off);
173        device_remove_file(led_cdev->dev, &dev_attr_invert);
174        device_remove_file(led_cdev->dev, &dev_attr_shot);
175        kfree(oneshot_data);
176        led_cdev->activated = false;
177    }
178
179    /* Stop blinking */
180    led_set_brightness(led_cdev, LED_OFF);
181}
182
183static struct led_trigger oneshot_led_trigger = {
184    .name = "oneshot",
185    .activate = oneshot_trig_activate,
186    .deactivate = oneshot_trig_deactivate,
187};
188
189static int __init oneshot_trig_init(void)
190{
191    return led_trigger_register(&oneshot_led_trigger);
192}
193
194static void __exit oneshot_trig_exit(void)
195{
196    led_trigger_unregister(&oneshot_led_trigger);
197}
198
199module_init(oneshot_trig_init);
200module_exit(oneshot_trig_exit);
201
202MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
203MODULE_DESCRIPTION("One-shot LED trigger");
204MODULE_LICENSE("GPL");
205

Archive Download this file



interactive