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_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; 205 led_trigger_set(led_cdev, trig); 206 break; 207 } 208 } 209 up_write(&led_cdev->trigger_lock); 210 up_read(&triggers_list_lock); 211 } 212 EXPORT_SYMBOL_GPL(led_trigger_set_default); 213 214 void led_trigger_rename_static(const char *name, struct led_trigger *trig) 215 { 216 /* new name must be on a temporary string to prevent races */ 217 BUG_ON(name == trig->name); 218 219 down_write(&triggers_list_lock); 220 /* this assumes that trig->name was originaly allocated to 221 * non constant storage */ 222 strcpy((char *)trig->name, name); 223 up_write(&triggers_list_lock); 224 } 225 EXPORT_SYMBOL_GPL(led_trigger_rename_static); 226 227 /* LED Trigger Interface */ 228 229 int led_trigger_register(struct led_trigger *trig) 230 { 231 struct led_classdev *led_cdev; 232 struct led_trigger *_trig; 233 234 rwlock_init(&trig->leddev_list_lock); 235 INIT_LIST_HEAD(&trig->led_cdevs); 236 237 down_write(&triggers_list_lock); 238 /* Make sure the trigger's name isn't already in use */ 239 list_for_each_entry(_trig, &trigger_list, next_trig) { 240 if (!strcmp(_trig->name, trig->name)) { 241 up_write(&triggers_list_lock); 242 return -EEXIST; 243 } 244 } 245 /* Add to the list of led triggers */ 246 list_add_tail(&trig->next_trig, &trigger_list); 247 up_write(&triggers_list_lock); 248 249 /* Register with any LEDs that have this as a default trigger */ 250 down_read(&leds_list_lock); 251 list_for_each_entry(led_cdev, &leds_list, node) { 252 down_write(&led_cdev->trigger_lock); 253 if (!led_cdev->trigger && led_cdev->default_trigger && 254 !strcmp(led_cdev->default_trigger, trig->name)) { 255 led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; 256 led_trigger_set(led_cdev, trig); 257 } 258 up_write(&led_cdev->trigger_lock); 259 } 260 up_read(&leds_list_lock); 261 262 return 0; 263 } 264 EXPORT_SYMBOL_GPL(led_trigger_register); 265 266 void led_trigger_unregister(struct led_trigger *trig) 267 { 268 struct led_classdev *led_cdev; 269 270 if (list_empty_careful(&trig->next_trig)) 271 return; 272 273 /* Remove from the list of led triggers */ 274 down_write(&triggers_list_lock); 275 list_del_init(&trig->next_trig); 276 up_write(&triggers_list_lock); 277 278 /* Remove anyone actively using this trigger */ 279 down_read(&leds_list_lock); 280 list_for_each_entry(led_cdev, &leds_list, node) { 281 down_write(&led_cdev->trigger_lock); 282 if (led_cdev->trigger == trig) 283 led_trigger_set(led_cdev, NULL); 284 up_write(&led_cdev->trigger_lock); 285 } 286 up_read(&leds_list_lock); 287 } 288 EXPORT_SYMBOL_GPL(led_trigger_unregister); 289 290 static void devm_led_trigger_release(struct device *dev, void *res) 291 { 292 led_trigger_unregister(*(struct led_trigger **)res); 293 } 294 295 int devm_led_trigger_register(struct device *dev, 296 struct led_trigger *trig) 297 { 298 struct led_trigger **dr; 299 int rc; 300 301 dr = devres_alloc(devm_led_trigger_release, sizeof(*dr), 302 GFP_KERNEL); 303 if (!dr) 304 return -ENOMEM; 305 306 *dr = trig; 307 308 rc = led_trigger_register(trig); 309 if (rc) 310 devres_free(dr); 311 else 312 devres_add(dev, dr); 313 314 return rc; 315 } 316 EXPORT_SYMBOL_GPL(devm_led_trigger_register); 317 318 /* Simple LED Tigger Interface */ 319 320 void led_trigger_event(struct led_trigger *trig, 321 enum led_brightness brightness) 322 { 323 struct led_classdev *led_cdev; 324 325 if (!trig) 326 return; 327 328 read_lock(&trig->leddev_list_lock); 329 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) 330 led_set_brightness(led_cdev, brightness); 331 read_unlock(&trig->leddev_list_lock); 332 } 333 EXPORT_SYMBOL_GPL(led_trigger_event); 334 335 static void led_trigger_blink_setup(struct led_trigger *trig, 336 unsigned long *delay_on, 337 unsigned long *delay_off, 338 int oneshot, 339 int invert) 340 { 341 struct led_classdev *led_cdev; 342 343 if (!trig) 344 return; 345 346 read_lock(&trig->leddev_list_lock); 347 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) { 348 if (oneshot) 349 led_blink_set_oneshot(led_cdev, delay_on, delay_off, 350 invert); 351 else 352 led_blink_set(led_cdev, delay_on, delay_off); 353 } 354 read_unlock(&trig->leddev_list_lock); 355 } 356 357 void led_trigger_blink(struct led_trigger *trig, 358 unsigned long *delay_on, 359 unsigned long *delay_off) 360 { 361 led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0); 362 } 363 EXPORT_SYMBOL_GPL(led_trigger_blink); 364 365 void led_trigger_blink_oneshot(struct led_trigger *trig, 366 unsigned long *delay_on, 367 unsigned long *delay_off, 368 int invert) 369 { 370 led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert); 371 } 372 EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot); 373 374 void led_trigger_register_simple(const char *name, struct led_trigger **tp) 375 { 376 struct led_trigger *trig; 377 int err; 378 379 trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); 380 381 if (trig) { 382 trig->name = name; 383 err = led_trigger_register(trig); 384 if (err < 0) { 385 kfree(trig); 386 trig = NULL; 387 pr_warn("LED trigger %s failed to register (%d)\n", 388 name, err); 389 } 390 } else { 391 pr_warn("LED trigger %s failed to register (no memory)\n", 392 name); 393 } 394 *tp = trig; 395 } 396 EXPORT_SYMBOL_GPL(led_trigger_register_simple); 397 398 void led_trigger_unregister_simple(struct led_trigger *trig) 399 { 400 if (trig) 401 led_trigger_unregister(trig); 402 kfree(trig); 403 } 404 EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); 405