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