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