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/export.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 += scnprintf(buf+len, PAGE_SIZE - len, "[none] "); 85 else 86 len += scnprintf(buf+len, PAGE_SIZE - 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 += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ", 92 trig->name); 93 else 94 len += scnprintf(buf+len, PAGE_SIZE - len, "%s ", 95 trig->name); 96 } 97 up_read(&led_cdev->trigger_lock); 98 up_read(&triggers_list_lock); 99 100 len += scnprintf(len+buf, PAGE_SIZE - len, "\n"); 101 return len; 102 } 103 EXPORT_SYMBOL_GPL(led_trigger_show); 104 105 /* Caller must ensure led_cdev->trigger_lock held */ 106 int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) 107 { 108 unsigned long flags; 109 char *event = NULL; 110 char *envp[2]; 111 const char *name; 112 int ret; 113 114 if (!led_cdev->trigger && !trig) 115 return 0; 116 117 name = trig ? trig->name : "none"; 118 event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name); 119 120 /* Remove any existing trigger */ 121 if (led_cdev->trigger) { 122 write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); 123 list_del(&led_cdev->trig_list); 124 write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, 125 flags); 126 cancel_work_sync(&led_cdev->set_brightness_work); 127 led_stop_software_blink(led_cdev); 128 if (led_cdev->trigger->deactivate) 129 led_cdev->trigger->deactivate(led_cdev); 130 device_remove_groups(led_cdev->dev, led_cdev->trigger->groups); 131 led_cdev->trigger = NULL; 132 led_cdev->trigger_data = NULL; 133 led_cdev->activated = false; 134 led_set_brightness(led_cdev, LED_OFF); 135 } 136 if (trig) { 137 write_lock_irqsave(&trig->leddev_list_lock, flags); 138 list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); 139 write_unlock_irqrestore(&trig->leddev_list_lock, flags); 140 led_cdev->trigger = trig; 141 142 if (trig->activate) 143 ret = trig->activate(led_cdev); 144 else 145 ret = 0; 146 147 if (ret) 148 goto err_activate; 149 150 ret = device_add_groups(led_cdev->dev, trig->groups); 151 if (ret) { 152 dev_err(led_cdev->dev, "Failed to add trigger attributes\n"); 153 goto err_add_groups; 154 } 155 } 156 157 if (event) { 158 envp[0] = event; 159 envp[1] = NULL; 160 if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp)) 161 dev_err(led_cdev->dev, 162 "%s: Error sending uevent\n", __func__); 163 kfree(event); 164 } 165 166 return 0; 167 168 err_add_groups: 169 170 if (trig->deactivate) 171 trig->deactivate(led_cdev); 172 err_activate: 173 174 led_cdev->trigger = NULL; 175 led_cdev->trigger_data = NULL; 176 write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); 177 list_del(&led_cdev->trig_list); 178 write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags); 179 led_set_brightness(led_cdev, LED_OFF); 180 181 return ret; 182 } 183 EXPORT_SYMBOL_GPL(led_trigger_set); 184 185 void led_trigger_remove(struct led_classdev *led_cdev) 186 { 187 down_write(&led_cdev->trigger_lock); 188 led_trigger_set(led_cdev, NULL); 189 up_write(&led_cdev->trigger_lock); 190 } 191 EXPORT_SYMBOL_GPL(led_trigger_remove); 192 193 void led_trigger_set_default(struct led_classdev *led_cdev) 194 { 195 struct led_trigger *trig; 196 197 if (!led_cdev->default_trigger) 198 return; 199 200 down_read(&triggers_list_lock); 201 down_write(&led_cdev->trigger_lock); 202 list_for_each_entry(trig, &trigger_list, next_trig) { 203 if (!strcmp(led_cdev->default_trigger, trig->name)) 204 led_trigger_set(led_cdev, trig); 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_trigger_set(led_cdev, trig); 253 up_write(&led_cdev->trigger_lock); 254 } 255 up_read(&leds_list_lock); 256 257 return 0; 258 } 259 EXPORT_SYMBOL_GPL(led_trigger_register); 260 261 void led_trigger_unregister(struct led_trigger *trig) 262 { 263 struct led_classdev *led_cdev; 264 265 if (list_empty_careful(&trig->next_trig)) 266 return; 267 268 /* Remove from the list of led triggers */ 269 down_write(&triggers_list_lock); 270 list_del_init(&trig->next_trig); 271 up_write(&triggers_list_lock); 272 273 /* Remove anyone actively using this trigger */ 274 down_read(&leds_list_lock); 275 list_for_each_entry(led_cdev, &leds_list, node) { 276 down_write(&led_cdev->trigger_lock); 277 if (led_cdev->trigger == trig) 278 led_trigger_set(led_cdev, NULL); 279 up_write(&led_cdev->trigger_lock); 280 } 281 up_read(&leds_list_lock); 282 } 283 EXPORT_SYMBOL_GPL(led_trigger_unregister); 284 285 static void devm_led_trigger_release(struct device *dev, void *res) 286 { 287 led_trigger_unregister(*(struct led_trigger **)res); 288 } 289 290 int devm_led_trigger_register(struct device *dev, 291 struct led_trigger *trig) 292 { 293 struct led_trigger **dr; 294 int rc; 295 296 dr = devres_alloc(devm_led_trigger_release, sizeof(*dr), 297 GFP_KERNEL); 298 if (!dr) 299 return -ENOMEM; 300 301 *dr = trig; 302 303 rc = led_trigger_register(trig); 304 if (rc) 305 devres_free(dr); 306 else 307 devres_add(dev, dr); 308 309 return rc; 310 } 311 EXPORT_SYMBOL_GPL(devm_led_trigger_register); 312 313 /* Simple LED Tigger Interface */ 314 315 void led_trigger_event(struct led_trigger *trig, 316 enum led_brightness brightness) 317 { 318 struct led_classdev *led_cdev; 319 320 if (!trig) 321 return; 322 323 read_lock(&trig->leddev_list_lock); 324 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) 325 led_set_brightness(led_cdev, brightness); 326 read_unlock(&trig->leddev_list_lock); 327 } 328 EXPORT_SYMBOL_GPL(led_trigger_event); 329 330 static void led_trigger_blink_setup(struct led_trigger *trig, 331 unsigned long *delay_on, 332 unsigned long *delay_off, 333 int oneshot, 334 int invert) 335 { 336 struct led_classdev *led_cdev; 337 338 if (!trig) 339 return; 340 341 read_lock(&trig->leddev_list_lock); 342 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) { 343 if (oneshot) 344 led_blink_set_oneshot(led_cdev, delay_on, delay_off, 345 invert); 346 else 347 led_blink_set(led_cdev, delay_on, delay_off); 348 } 349 read_unlock(&trig->leddev_list_lock); 350 } 351 352 void led_trigger_blink(struct led_trigger *trig, 353 unsigned long *delay_on, 354 unsigned long *delay_off) 355 { 356 led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0); 357 } 358 EXPORT_SYMBOL_GPL(led_trigger_blink); 359 360 void led_trigger_blink_oneshot(struct led_trigger *trig, 361 unsigned long *delay_on, 362 unsigned long *delay_off, 363 int invert) 364 { 365 led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert); 366 } 367 EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot); 368 369 void led_trigger_register_simple(const char *name, struct led_trigger **tp) 370 { 371 struct led_trigger *trig; 372 int err; 373 374 trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); 375 376 if (trig) { 377 trig->name = name; 378 err = led_trigger_register(trig); 379 if (err < 0) { 380 kfree(trig); 381 trig = NULL; 382 pr_warn("LED trigger %s failed to register (%d)\n", 383 name, err); 384 } 385 } else { 386 pr_warn("LED trigger %s failed to register (no memory)\n", 387 name); 388 } 389 *tp = trig; 390 } 391 EXPORT_SYMBOL_GPL(led_trigger_register_simple); 392 393 void led_trigger_unregister_simple(struct led_trigger *trig) 394 { 395 if (trig) 396 led_trigger_unregister(trig); 397 kfree(trig); 398 } 399 EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); 400