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