Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * LED Triggers Core
0004  *
0005  * Copyright 2005-2007 Openedhand Ltd.
0006  *
0007  * Author: Richard Purdie <rpurdie@openedhand.com>
0008  */
0009 
0010 #include <linux/export.h>
0011 #include <linux/kernel.h>
0012 #include <linux/list.h>
0013 #include <linux/spinlock.h>
0014 #include <linux/device.h>
0015 #include <linux/timer.h>
0016 #include <linux/rwsem.h>
0017 #include <linux/leds.h>
0018 #include <linux/slab.h>
0019 #include <linux/mm.h>
0020 #include "leds.h"
0021 
0022 /*
0023  * Nests outside led_cdev->trigger_lock
0024  */
0025 static DECLARE_RWSEM(triggers_list_lock);
0026 LIST_HEAD(trigger_list);
0027 
0028  /* Used by LED Class */
0029 
0030 static inline bool
0031 trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig)
0032 {
0033     return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type;
0034 }
0035 
0036 ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
0037               struct bin_attribute *bin_attr, char *buf,
0038               loff_t pos, size_t count)
0039 {
0040     struct device *dev = kobj_to_dev(kobj);
0041     struct led_classdev *led_cdev = dev_get_drvdata(dev);
0042     struct led_trigger *trig;
0043     int ret = count;
0044 
0045     mutex_lock(&led_cdev->led_access);
0046 
0047     if (led_sysfs_is_disabled(led_cdev)) {
0048         ret = -EBUSY;
0049         goto unlock;
0050     }
0051 
0052     if (sysfs_streq(buf, "none")) {
0053         led_trigger_remove(led_cdev);
0054         goto unlock;
0055     }
0056 
0057     down_read(&triggers_list_lock);
0058     list_for_each_entry(trig, &trigger_list, next_trig) {
0059         if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) {
0060             down_write(&led_cdev->trigger_lock);
0061             led_trigger_set(led_cdev, trig);
0062             up_write(&led_cdev->trigger_lock);
0063 
0064             up_read(&triggers_list_lock);
0065             goto unlock;
0066         }
0067     }
0068     /* we come here only if buf matches no trigger */
0069     ret = -EINVAL;
0070     up_read(&triggers_list_lock);
0071 
0072 unlock:
0073     mutex_unlock(&led_cdev->led_access);
0074     return ret;
0075 }
0076 EXPORT_SYMBOL_GPL(led_trigger_write);
0077 
0078 __printf(3, 4)
0079 static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, ...)
0080 {
0081     va_list args;
0082     int i;
0083 
0084     va_start(args, fmt);
0085     if (size <= 0)
0086         i = vsnprintf(NULL, 0, fmt, args);
0087     else
0088         i = vscnprintf(buf, size, fmt, args);
0089     va_end(args);
0090 
0091     return i;
0092 }
0093 
0094 static int led_trigger_format(char *buf, size_t size,
0095                   struct led_classdev *led_cdev)
0096 {
0097     struct led_trigger *trig;
0098     int len = led_trigger_snprintf(buf, size, "%s",
0099                        led_cdev->trigger ? "none" : "[none]");
0100 
0101     list_for_each_entry(trig, &trigger_list, next_trig) {
0102         bool hit;
0103 
0104         if (!trigger_relevant(led_cdev, trig))
0105             continue;
0106 
0107         hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name);
0108 
0109         len += led_trigger_snprintf(buf + len, size - len,
0110                         " %s%s%s", hit ? "[" : "",
0111                         trig->name, hit ? "]" : "");
0112     }
0113 
0114     len += led_trigger_snprintf(buf + len, size - len, "\n");
0115 
0116     return len;
0117 }
0118 
0119 /*
0120  * It was stupid to create 10000 cpu triggers, but we are stuck with it now.
0121  * Don't make that mistake again. We work around it here by creating binary
0122  * attribute, which is not limited by length. This is _not_ good design, do not
0123  * copy it.
0124  */
0125 ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
0126             struct bin_attribute *attr, char *buf,
0127             loff_t pos, size_t count)
0128 {
0129     struct device *dev = kobj_to_dev(kobj);
0130     struct led_classdev *led_cdev = dev_get_drvdata(dev);
0131     void *data;
0132     int len;
0133 
0134     down_read(&triggers_list_lock);
0135     down_read(&led_cdev->trigger_lock);
0136 
0137     len = led_trigger_format(NULL, 0, led_cdev);
0138     data = kvmalloc(len + 1, GFP_KERNEL);
0139     if (!data) {
0140         up_read(&led_cdev->trigger_lock);
0141         up_read(&triggers_list_lock);
0142         return -ENOMEM;
0143     }
0144     len = led_trigger_format(data, len + 1, led_cdev);
0145 
0146     up_read(&led_cdev->trigger_lock);
0147     up_read(&triggers_list_lock);
0148 
0149     len = memory_read_from_buffer(buf, count, &pos, data, len);
0150 
0151     kvfree(data);
0152 
0153     return len;
0154 }
0155 EXPORT_SYMBOL_GPL(led_trigger_read);
0156 
0157 /* Caller must ensure led_cdev->trigger_lock held */
0158 int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
0159 {
0160     char *event = NULL;
0161     char *envp[2];
0162     const char *name;
0163     int ret;
0164 
0165     if (!led_cdev->trigger && !trig)
0166         return 0;
0167 
0168     name = trig ? trig->name : "none";
0169     event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
0170 
0171     /* Remove any existing trigger */
0172     if (led_cdev->trigger) {
0173         spin_lock(&led_cdev->trigger->leddev_list_lock);
0174         list_del_rcu(&led_cdev->trig_list);
0175         spin_unlock(&led_cdev->trigger->leddev_list_lock);
0176 
0177         /* ensure it's no longer visible on the led_cdevs list */
0178         synchronize_rcu();
0179 
0180         cancel_work_sync(&led_cdev->set_brightness_work);
0181         led_stop_software_blink(led_cdev);
0182         if (led_cdev->trigger->deactivate)
0183             led_cdev->trigger->deactivate(led_cdev);
0184         device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
0185         led_cdev->trigger = NULL;
0186         led_cdev->trigger_data = NULL;
0187         led_cdev->activated = false;
0188         led_set_brightness(led_cdev, LED_OFF);
0189     }
0190     if (trig) {
0191         spin_lock(&trig->leddev_list_lock);
0192         list_add_tail_rcu(&led_cdev->trig_list, &trig->led_cdevs);
0193         spin_unlock(&trig->leddev_list_lock);
0194         led_cdev->trigger = trig;
0195 
0196         if (trig->activate)
0197             ret = trig->activate(led_cdev);
0198         else
0199             ret = 0;
0200 
0201         if (ret)
0202             goto err_activate;
0203 
0204         ret = device_add_groups(led_cdev->dev, trig->groups);
0205         if (ret) {
0206             dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
0207             goto err_add_groups;
0208         }
0209     }
0210 
0211     if (event) {
0212         envp[0] = event;
0213         envp[1] = NULL;
0214         if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp))
0215             dev_err(led_cdev->dev,
0216                 "%s: Error sending uevent\n", __func__);
0217         kfree(event);
0218     }
0219 
0220     return 0;
0221 
0222 err_add_groups:
0223 
0224     if (trig->deactivate)
0225         trig->deactivate(led_cdev);
0226 err_activate:
0227 
0228     spin_lock(&led_cdev->trigger->leddev_list_lock);
0229     list_del_rcu(&led_cdev->trig_list);
0230     spin_unlock(&led_cdev->trigger->leddev_list_lock);
0231     synchronize_rcu();
0232     led_cdev->trigger = NULL;
0233     led_cdev->trigger_data = NULL;
0234     led_set_brightness(led_cdev, LED_OFF);
0235     kfree(event);
0236 
0237     return ret;
0238 }
0239 EXPORT_SYMBOL_GPL(led_trigger_set);
0240 
0241 void led_trigger_remove(struct led_classdev *led_cdev)
0242 {
0243     down_write(&led_cdev->trigger_lock);
0244     led_trigger_set(led_cdev, NULL);
0245     up_write(&led_cdev->trigger_lock);
0246 }
0247 EXPORT_SYMBOL_GPL(led_trigger_remove);
0248 
0249 void led_trigger_set_default(struct led_classdev *led_cdev)
0250 {
0251     struct led_trigger *trig;
0252 
0253     if (!led_cdev->default_trigger)
0254         return;
0255 
0256     down_read(&triggers_list_lock);
0257     down_write(&led_cdev->trigger_lock);
0258     list_for_each_entry(trig, &trigger_list, next_trig) {
0259         if (!strcmp(led_cdev->default_trigger, trig->name) &&
0260             trigger_relevant(led_cdev, trig)) {
0261             led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
0262             led_trigger_set(led_cdev, trig);
0263             break;
0264         }
0265     }
0266     up_write(&led_cdev->trigger_lock);
0267     up_read(&triggers_list_lock);
0268 }
0269 EXPORT_SYMBOL_GPL(led_trigger_set_default);
0270 
0271 void led_trigger_rename_static(const char *name, struct led_trigger *trig)
0272 {
0273     /* new name must be on a temporary string to prevent races */
0274     BUG_ON(name == trig->name);
0275 
0276     down_write(&triggers_list_lock);
0277     /* this assumes that trig->name was originaly allocated to
0278      * non constant storage */
0279     strcpy((char *)trig->name, name);
0280     up_write(&triggers_list_lock);
0281 }
0282 EXPORT_SYMBOL_GPL(led_trigger_rename_static);
0283 
0284 /* LED Trigger Interface */
0285 
0286 int led_trigger_register(struct led_trigger *trig)
0287 {
0288     struct led_classdev *led_cdev;
0289     struct led_trigger *_trig;
0290 
0291     spin_lock_init(&trig->leddev_list_lock);
0292     INIT_LIST_HEAD(&trig->led_cdevs);
0293 
0294     down_write(&triggers_list_lock);
0295     /* Make sure the trigger's name isn't already in use */
0296     list_for_each_entry(_trig, &trigger_list, next_trig) {
0297         if (!strcmp(_trig->name, trig->name) &&
0298             (trig->trigger_type == _trig->trigger_type ||
0299              !trig->trigger_type || !_trig->trigger_type)) {
0300             up_write(&triggers_list_lock);
0301             return -EEXIST;
0302         }
0303     }
0304     /* Add to the list of led triggers */
0305     list_add_tail(&trig->next_trig, &trigger_list);
0306     up_write(&triggers_list_lock);
0307 
0308     /* Register with any LEDs that have this as a default trigger */
0309     down_read(&leds_list_lock);
0310     list_for_each_entry(led_cdev, &leds_list, node) {
0311         down_write(&led_cdev->trigger_lock);
0312         if (!led_cdev->trigger && led_cdev->default_trigger &&
0313             !strcmp(led_cdev->default_trigger, trig->name) &&
0314             trigger_relevant(led_cdev, trig)) {
0315             led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
0316             led_trigger_set(led_cdev, trig);
0317         }
0318         up_write(&led_cdev->trigger_lock);
0319     }
0320     up_read(&leds_list_lock);
0321 
0322     return 0;
0323 }
0324 EXPORT_SYMBOL_GPL(led_trigger_register);
0325 
0326 void led_trigger_unregister(struct led_trigger *trig)
0327 {
0328     struct led_classdev *led_cdev;
0329 
0330     if (list_empty_careful(&trig->next_trig))
0331         return;
0332 
0333     /* Remove from the list of led triggers */
0334     down_write(&triggers_list_lock);
0335     list_del_init(&trig->next_trig);
0336     up_write(&triggers_list_lock);
0337 
0338     /* Remove anyone actively using this trigger */
0339     down_read(&leds_list_lock);
0340     list_for_each_entry(led_cdev, &leds_list, node) {
0341         down_write(&led_cdev->trigger_lock);
0342         if (led_cdev->trigger == trig)
0343             led_trigger_set(led_cdev, NULL);
0344         up_write(&led_cdev->trigger_lock);
0345     }
0346     up_read(&leds_list_lock);
0347 }
0348 EXPORT_SYMBOL_GPL(led_trigger_unregister);
0349 
0350 static void devm_led_trigger_release(struct device *dev, void *res)
0351 {
0352     led_trigger_unregister(*(struct led_trigger **)res);
0353 }
0354 
0355 int devm_led_trigger_register(struct device *dev,
0356                   struct led_trigger *trig)
0357 {
0358     struct led_trigger **dr;
0359     int rc;
0360 
0361     dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
0362               GFP_KERNEL);
0363     if (!dr)
0364         return -ENOMEM;
0365 
0366     *dr = trig;
0367 
0368     rc = led_trigger_register(trig);
0369     if (rc)
0370         devres_free(dr);
0371     else
0372         devres_add(dev, dr);
0373 
0374     return rc;
0375 }
0376 EXPORT_SYMBOL_GPL(devm_led_trigger_register);
0377 
0378 /* Simple LED Trigger Interface */
0379 
0380 void led_trigger_event(struct led_trigger *trig,
0381             enum led_brightness brightness)
0382 {
0383     struct led_classdev *led_cdev;
0384 
0385     if (!trig)
0386         return;
0387 
0388     rcu_read_lock();
0389     list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list)
0390         led_set_brightness(led_cdev, brightness);
0391     rcu_read_unlock();
0392 }
0393 EXPORT_SYMBOL_GPL(led_trigger_event);
0394 
0395 static void led_trigger_blink_setup(struct led_trigger *trig,
0396                  unsigned long *delay_on,
0397                  unsigned long *delay_off,
0398                  int oneshot,
0399                  int invert)
0400 {
0401     struct led_classdev *led_cdev;
0402 
0403     if (!trig)
0404         return;
0405 
0406     rcu_read_lock();
0407     list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) {
0408         if (oneshot)
0409             led_blink_set_oneshot(led_cdev, delay_on, delay_off,
0410                           invert);
0411         else
0412             led_blink_set(led_cdev, delay_on, delay_off);
0413     }
0414     rcu_read_unlock();
0415 }
0416 
0417 void led_trigger_blink(struct led_trigger *trig,
0418                unsigned long *delay_on,
0419                unsigned long *delay_off)
0420 {
0421     led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
0422 }
0423 EXPORT_SYMBOL_GPL(led_trigger_blink);
0424 
0425 void led_trigger_blink_oneshot(struct led_trigger *trig,
0426                    unsigned long *delay_on,
0427                    unsigned long *delay_off,
0428                    int invert)
0429 {
0430     led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
0431 }
0432 EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
0433 
0434 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
0435 {
0436     struct led_trigger *trig;
0437     int err;
0438 
0439     trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
0440 
0441     if (trig) {
0442         trig->name = name;
0443         err = led_trigger_register(trig);
0444         if (err < 0) {
0445             kfree(trig);
0446             trig = NULL;
0447             pr_warn("LED trigger %s failed to register (%d)\n",
0448                 name, err);
0449         }
0450     } else {
0451         pr_warn("LED trigger %s failed to register (no memory)\n",
0452             name);
0453     }
0454     *tp = trig;
0455 }
0456 EXPORT_SYMBOL_GPL(led_trigger_register_simple);
0457 
0458 void led_trigger_unregister_simple(struct led_trigger *trig)
0459 {
0460     if (trig)
0461         led_trigger_unregister(trig);
0462     kfree(trig);
0463 }
0464 EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);