root/drivers/leds/led-triggers.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. led_trigger_store
  2. led_trigger_show
  3. led_trigger_set
  4. led_trigger_remove
  5. led_trigger_set_default
  6. led_trigger_rename_static
  7. led_trigger_register
  8. led_trigger_unregister
  9. devm_led_trigger_release
  10. devm_led_trigger_register
  11. led_trigger_event
  12. led_trigger_blink_setup
  13. led_trigger_blink
  14. led_trigger_blink_oneshot
  15. led_trigger_register_simple
  16. led_trigger_unregister_simple

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * LED Triggers Core
   4  *
   5  * Copyright 2005-2007 Openedhand Ltd.
   6  *
   7  * Author: Richard Purdie <rpurdie@openedhand.com>
   8  */
   9 
  10 #include <linux/export.h>
  11 #include <linux/kernel.h>
  12 #include <linux/list.h>
  13 #include <linux/spinlock.h>
  14 #include <linux/device.h>
  15 #include <linux/timer.h>
  16 #include <linux/rwsem.h>
  17 #include <linux/leds.h>
  18 #include <linux/slab.h>
  19 #include "leds.h"
  20 
  21 /*
  22  * Nests outside led_cdev->trigger_lock
  23  */
  24 static DECLARE_RWSEM(triggers_list_lock);
  25 LIST_HEAD(trigger_list);
  26 
  27  /* Used by LED Class */
  28 
  29 ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
  30                 const char *buf, size_t count)
  31 {
  32         struct led_classdev *led_cdev = dev_get_drvdata(dev);
  33         struct led_trigger *trig;
  34         int ret = count;
  35 
  36         mutex_lock(&led_cdev->led_access);
  37 
  38         if (led_sysfs_is_disabled(led_cdev)) {
  39                 ret = -EBUSY;
  40                 goto unlock;
  41         }
  42 
  43         if (sysfs_streq(buf, "none")) {
  44                 led_trigger_remove(led_cdev);
  45                 goto unlock;
  46         }
  47 
  48         down_read(&triggers_list_lock);
  49         list_for_each_entry(trig, &trigger_list, next_trig) {
  50                 if (sysfs_streq(buf, trig->name)) {
  51                         down_write(&led_cdev->trigger_lock);
  52                         led_trigger_set(led_cdev, trig);
  53                         up_write(&led_cdev->trigger_lock);
  54 
  55                         up_read(&triggers_list_lock);
  56                         goto unlock;
  57                 }
  58         }
  59         /* we come here only if buf matches no trigger */
  60         ret = -EINVAL;
  61         up_read(&triggers_list_lock);
  62 
  63 unlock:
  64         mutex_unlock(&led_cdev->led_access);
  65         return ret;
  66 }
  67 EXPORT_SYMBOL_GPL(led_trigger_store);
  68 
  69 ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
  70                 char *buf)
  71 {
  72         struct led_classdev *led_cdev = dev_get_drvdata(dev);
  73         struct led_trigger *trig;
  74         int len = 0;
  75 
  76         down_read(&triggers_list_lock);
  77         down_read(&led_cdev->trigger_lock);
  78 
  79         if (!led_cdev->trigger)
  80                 len += scnprintf(buf+len, PAGE_SIZE - len, "[none] ");
  81         else
  82                 len += scnprintf(buf+len, PAGE_SIZE - len, "none ");
  83 
  84         list_for_each_entry(trig, &trigger_list, next_trig) {
  85                 if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
  86                                                         trig->name))
  87                         len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ",
  88                                          trig->name);
  89                 else
  90                         len += scnprintf(buf+len, PAGE_SIZE - len, "%s ",
  91                                          trig->name);
  92         }
  93         up_read(&led_cdev->trigger_lock);
  94         up_read(&triggers_list_lock);
  95 
  96         len += scnprintf(len+buf, PAGE_SIZE - len, "\n");
  97         return len;
  98 }
  99 EXPORT_SYMBOL_GPL(led_trigger_show);
 100 
 101 /* Caller must ensure led_cdev->trigger_lock held */
 102 int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
 103 {
 104         unsigned long flags;
 105         char *event = NULL;
 106         char *envp[2];
 107         const char *name;
 108         int ret;
 109 
 110         if (!led_cdev->trigger && !trig)
 111                 return 0;
 112 
 113         name = trig ? trig->name : "none";
 114         event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
 115 
 116         /* Remove any existing trigger */
 117         if (led_cdev->trigger) {
 118                 write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
 119                 list_del(&led_cdev->trig_list);
 120                 write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
 121                         flags);
 122                 cancel_work_sync(&led_cdev->set_brightness_work);
 123                 led_stop_software_blink(led_cdev);
 124                 if (led_cdev->trigger->deactivate)
 125                         led_cdev->trigger->deactivate(led_cdev);
 126                 device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
 127                 led_cdev->trigger = NULL;
 128                 led_cdev->trigger_data = NULL;
 129                 led_cdev->activated = false;
 130                 led_set_brightness(led_cdev, LED_OFF);
 131         }
 132         if (trig) {
 133                 write_lock_irqsave(&trig->leddev_list_lock, flags);
 134                 list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
 135                 write_unlock_irqrestore(&trig->leddev_list_lock, flags);
 136                 led_cdev->trigger = trig;
 137 
 138                 if (trig->activate)
 139                         ret = trig->activate(led_cdev);
 140                 else
 141                         ret = 0;
 142 
 143                 if (ret)
 144                         goto err_activate;
 145 
 146                 ret = device_add_groups(led_cdev->dev, trig->groups);
 147                 if (ret) {
 148                         dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
 149                         goto err_add_groups;
 150                 }
 151         }
 152 
 153         if (event) {
 154                 envp[0] = event;
 155                 envp[1] = NULL;
 156                 if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp))
 157                         dev_err(led_cdev->dev,
 158                                 "%s: Error sending uevent\n", __func__);
 159                 kfree(event);
 160         }
 161 
 162         return 0;
 163 
 164 err_add_groups:
 165 
 166         if (trig->deactivate)
 167                 trig->deactivate(led_cdev);
 168 err_activate:
 169 
 170         write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
 171         list_del(&led_cdev->trig_list);
 172         write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
 173         led_cdev->trigger = NULL;
 174         led_cdev->trigger_data = NULL;
 175         led_set_brightness(led_cdev, LED_OFF);
 176         kfree(event);
 177 
 178         return ret;
 179 }
 180 EXPORT_SYMBOL_GPL(led_trigger_set);
 181 
 182 void led_trigger_remove(struct led_classdev *led_cdev)
 183 {
 184         down_write(&led_cdev->trigger_lock);
 185         led_trigger_set(led_cdev, NULL);
 186         up_write(&led_cdev->trigger_lock);
 187 }
 188 EXPORT_SYMBOL_GPL(led_trigger_remove);
 189 
 190 void led_trigger_set_default(struct led_classdev *led_cdev)
 191 {
 192         struct led_trigger *trig;
 193 
 194         if (!led_cdev->default_trigger)
 195                 return;
 196 
 197         down_read(&triggers_list_lock);
 198         down_write(&led_cdev->trigger_lock);
 199         list_for_each_entry(trig, &trigger_list, next_trig) {
 200                 if (!strcmp(led_cdev->default_trigger, trig->name)) {
 201                         led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
 202                         led_trigger_set(led_cdev, trig);
 203                         break;
 204                 }
 205         }
 206         up_write(&led_cdev->trigger_lock);
 207         up_read(&triggers_list_lock);
 208 }
 209 EXPORT_SYMBOL_GPL(led_trigger_set_default);
 210 
 211 void led_trigger_rename_static(const char *name, struct led_trigger *trig)
 212 {
 213         /* new name must be on a temporary string to prevent races */
 214         BUG_ON(name == trig->name);
 215 
 216         down_write(&triggers_list_lock);
 217         /* this assumes that trig->name was originaly allocated to
 218          * non constant storage */
 219         strcpy((char *)trig->name, name);
 220         up_write(&triggers_list_lock);
 221 }
 222 EXPORT_SYMBOL_GPL(led_trigger_rename_static);
 223 
 224 /* LED Trigger Interface */
 225 
 226 int led_trigger_register(struct led_trigger *trig)
 227 {
 228         struct led_classdev *led_cdev;
 229         struct led_trigger *_trig;
 230 
 231         rwlock_init(&trig->leddev_list_lock);
 232         INIT_LIST_HEAD(&trig->led_cdevs);
 233 
 234         down_write(&triggers_list_lock);
 235         /* Make sure the trigger's name isn't already in use */
 236         list_for_each_entry(_trig, &trigger_list, next_trig) {
 237                 if (!strcmp(_trig->name, trig->name)) {
 238                         up_write(&triggers_list_lock);
 239                         return -EEXIST;
 240                 }
 241         }
 242         /* Add to the list of led triggers */
 243         list_add_tail(&trig->next_trig, &trigger_list);
 244         up_write(&triggers_list_lock);
 245 
 246         /* Register with any LEDs that have this as a default trigger */
 247         down_read(&leds_list_lock);
 248         list_for_each_entry(led_cdev, &leds_list, node) {
 249                 down_write(&led_cdev->trigger_lock);
 250                 if (!led_cdev->trigger && led_cdev->default_trigger &&
 251                             !strcmp(led_cdev->default_trigger, trig->name)) {
 252                         led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
 253                         led_trigger_set(led_cdev, trig);
 254                 }
 255                 up_write(&led_cdev->trigger_lock);
 256         }
 257         up_read(&leds_list_lock);
 258 
 259         return 0;
 260 }
 261 EXPORT_SYMBOL_GPL(led_trigger_register);
 262 
 263 void led_trigger_unregister(struct led_trigger *trig)
 264 {
 265         struct led_classdev *led_cdev;
 266 
 267         if (list_empty_careful(&trig->next_trig))
 268                 return;
 269 
 270         /* Remove from the list of led triggers */
 271         down_write(&triggers_list_lock);
 272         list_del_init(&trig->next_trig);
 273         up_write(&triggers_list_lock);
 274 
 275         /* Remove anyone actively using this trigger */
 276         down_read(&leds_list_lock);
 277         list_for_each_entry(led_cdev, &leds_list, node) {
 278                 down_write(&led_cdev->trigger_lock);
 279                 if (led_cdev->trigger == trig)
 280                         led_trigger_set(led_cdev, NULL);
 281                 up_write(&led_cdev->trigger_lock);
 282         }
 283         up_read(&leds_list_lock);
 284 }
 285 EXPORT_SYMBOL_GPL(led_trigger_unregister);
 286 
 287 static void devm_led_trigger_release(struct device *dev, void *res)
 288 {
 289         led_trigger_unregister(*(struct led_trigger **)res);
 290 }
 291 
 292 int devm_led_trigger_register(struct device *dev,
 293                               struct led_trigger *trig)
 294 {
 295         struct led_trigger **dr;
 296         int rc;
 297 
 298         dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
 299                           GFP_KERNEL);
 300         if (!dr)
 301                 return -ENOMEM;
 302 
 303         *dr = trig;
 304 
 305         rc = led_trigger_register(trig);
 306         if (rc)
 307                 devres_free(dr);
 308         else
 309                 devres_add(dev, dr);
 310 
 311         return rc;
 312 }
 313 EXPORT_SYMBOL_GPL(devm_led_trigger_register);
 314 
 315 /* Simple LED Tigger Interface */
 316 
 317 void led_trigger_event(struct led_trigger *trig,
 318                         enum led_brightness brightness)
 319 {
 320         struct led_classdev *led_cdev;
 321 
 322         if (!trig)
 323                 return;
 324 
 325         read_lock(&trig->leddev_list_lock);
 326         list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
 327                 led_set_brightness(led_cdev, brightness);
 328         read_unlock(&trig->leddev_list_lock);
 329 }
 330 EXPORT_SYMBOL_GPL(led_trigger_event);
 331 
 332 static void led_trigger_blink_setup(struct led_trigger *trig,
 333                              unsigned long *delay_on,
 334                              unsigned long *delay_off,
 335                              int oneshot,
 336                              int invert)
 337 {
 338         struct led_classdev *led_cdev;
 339 
 340         if (!trig)
 341                 return;
 342 
 343         read_lock(&trig->leddev_list_lock);
 344         list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
 345                 if (oneshot)
 346                         led_blink_set_oneshot(led_cdev, delay_on, delay_off,
 347                                               invert);
 348                 else
 349                         led_blink_set(led_cdev, delay_on, delay_off);
 350         }
 351         read_unlock(&trig->leddev_list_lock);
 352 }
 353 
 354 void led_trigger_blink(struct led_trigger *trig,
 355                        unsigned long *delay_on,
 356                        unsigned long *delay_off)
 357 {
 358         led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
 359 }
 360 EXPORT_SYMBOL_GPL(led_trigger_blink);
 361 
 362 void led_trigger_blink_oneshot(struct led_trigger *trig,
 363                                unsigned long *delay_on,
 364                                unsigned long *delay_off,
 365                                int invert)
 366 {
 367         led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
 368 }
 369 EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
 370 
 371 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
 372 {
 373         struct led_trigger *trig;
 374         int err;
 375 
 376         trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
 377 
 378         if (trig) {
 379                 trig->name = name;
 380                 err = led_trigger_register(trig);
 381                 if (err < 0) {
 382                         kfree(trig);
 383                         trig = NULL;
 384                         pr_warn("LED trigger %s failed to register (%d)\n",
 385                                 name, err);
 386                 }
 387         } else {
 388                 pr_warn("LED trigger %s failed to register (no memory)\n",
 389                         name);
 390         }
 391         *tp = trig;
 392 }
 393 EXPORT_SYMBOL_GPL(led_trigger_register_simple);
 394 
 395 void led_trigger_unregister_simple(struct led_trigger *trig)
 396 {
 397         if (trig)
 398                 led_trigger_unregister(trig);
 399         kfree(trig);
 400 }
 401 EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);

/* [<][>][^][v][top][bottom][index][help] */