linux/drivers/leds/trigger/ledtrig-oneshot.c
<<
>>
Prefs
   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