Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * One-shot LED Trigger
0004  *
0005  * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
0006  *
0007  * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/kernel.h>
0012 #include <linux/init.h>
0013 #include <linux/device.h>
0014 #include <linux/ctype.h>
0015 #include <linux/slab.h>
0016 #include <linux/leds.h>
0017 #include "../leds.h"
0018 
0019 #define DEFAULT_DELAY 100
0020 
0021 struct oneshot_trig_data {
0022     unsigned int invert;
0023 };
0024 
0025 static ssize_t led_shot(struct device *dev,
0026         struct device_attribute *attr, const char *buf, size_t size)
0027 {
0028     struct led_classdev *led_cdev = led_trigger_get_led(dev);
0029     struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);
0030 
0031     led_blink_set_oneshot(led_cdev,
0032             &led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
0033             oneshot_data->invert);
0034 
0035     /* content is ignored */
0036     return size;
0037 }
0038 static ssize_t led_invert_show(struct device *dev,
0039         struct device_attribute *attr, char *buf)
0040 {
0041     struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);
0042 
0043     return sprintf(buf, "%u\n", oneshot_data->invert);
0044 }
0045 
0046 static ssize_t led_invert_store(struct device *dev,
0047         struct device_attribute *attr, const char *buf, size_t size)
0048 {
0049     struct led_classdev *led_cdev = led_trigger_get_led(dev);
0050     struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);
0051     unsigned long state;
0052     int ret;
0053 
0054     ret = kstrtoul(buf, 0, &state);
0055     if (ret)
0056         return ret;
0057 
0058     oneshot_data->invert = !!state;
0059 
0060     if (oneshot_data->invert)
0061         led_set_brightness_nosleep(led_cdev, LED_FULL);
0062     else
0063         led_set_brightness_nosleep(led_cdev, LED_OFF);
0064 
0065     return size;
0066 }
0067 
0068 static ssize_t led_delay_on_show(struct device *dev,
0069         struct device_attribute *attr, char *buf)
0070 {
0071     struct led_classdev *led_cdev = led_trigger_get_led(dev);
0072 
0073     return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
0074 }
0075 
0076 static ssize_t led_delay_on_store(struct device *dev,
0077         struct device_attribute *attr, const char *buf, size_t size)
0078 {
0079     struct led_classdev *led_cdev = led_trigger_get_led(dev);
0080     unsigned long state;
0081     int ret;
0082 
0083     ret = kstrtoul(buf, 0, &state);
0084     if (ret)
0085         return ret;
0086 
0087     led_cdev->blink_delay_on = state;
0088 
0089     return size;
0090 }
0091 
0092 static ssize_t led_delay_off_show(struct device *dev,
0093         struct device_attribute *attr, char *buf)
0094 {
0095     struct led_classdev *led_cdev = led_trigger_get_led(dev);
0096 
0097     return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
0098 }
0099 
0100 static ssize_t led_delay_off_store(struct device *dev,
0101         struct device_attribute *attr, const char *buf, size_t size)
0102 {
0103     struct led_classdev *led_cdev = led_trigger_get_led(dev);
0104     unsigned long state;
0105     int ret;
0106 
0107     ret = kstrtoul(buf, 0, &state);
0108     if (ret)
0109         return ret;
0110 
0111     led_cdev->blink_delay_off = state;
0112 
0113     return size;
0114 }
0115 
0116 static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
0117 static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
0118 static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
0119 static DEVICE_ATTR(shot, 0200, NULL, led_shot);
0120 
0121 static struct attribute *oneshot_trig_attrs[] = {
0122     &dev_attr_delay_on.attr,
0123     &dev_attr_delay_off.attr,
0124     &dev_attr_invert.attr,
0125     &dev_attr_shot.attr,
0126     NULL
0127 };
0128 ATTRIBUTE_GROUPS(oneshot_trig);
0129 
0130 static void pattern_init(struct led_classdev *led_cdev)
0131 {
0132     u32 *pattern;
0133     unsigned int size = 0;
0134 
0135     pattern = led_get_default_pattern(led_cdev, &size);
0136     if (!pattern)
0137         goto out_default;
0138 
0139     if (size != 2) {
0140         dev_warn(led_cdev->dev,
0141              "Expected 2 but got %u values for delays pattern\n",
0142              size);
0143         goto out_default;
0144     }
0145 
0146     led_cdev->blink_delay_on = pattern[0];
0147     led_cdev->blink_delay_off = pattern[1];
0148     kfree(pattern);
0149 
0150     return;
0151 
0152 out_default:
0153     kfree(pattern);
0154     led_cdev->blink_delay_on = DEFAULT_DELAY;
0155     led_cdev->blink_delay_off = DEFAULT_DELAY;
0156 }
0157 
0158 static int oneshot_trig_activate(struct led_classdev *led_cdev)
0159 {
0160     struct oneshot_trig_data *oneshot_data;
0161 
0162     oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
0163     if (!oneshot_data)
0164         return -ENOMEM;
0165 
0166     led_set_trigger_data(led_cdev, oneshot_data);
0167 
0168     if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) {
0169         pattern_init(led_cdev);
0170         /*
0171          * Mark as initialized even on pattern_init() error because
0172          * any consecutive call to it would produce the same error.
0173          */
0174         led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER;
0175     }
0176 
0177     return 0;
0178 }
0179 
0180 static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
0181 {
0182     struct oneshot_trig_data *oneshot_data = led_get_trigger_data(led_cdev);
0183 
0184     kfree(oneshot_data);
0185 
0186     /* Stop blinking */
0187     led_set_brightness(led_cdev, LED_OFF);
0188 }
0189 
0190 static struct led_trigger oneshot_led_trigger = {
0191     .name     = "oneshot",
0192     .activate = oneshot_trig_activate,
0193     .deactivate = oneshot_trig_deactivate,
0194     .groups = oneshot_trig_groups,
0195 };
0196 module_led_trigger(oneshot_led_trigger);
0197 
0198 MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
0199 MODULE_DESCRIPTION("One-shot LED trigger");
0200 MODULE_LICENSE("GPL v2");