1 /*
2  * LED support code, ripped out of arch/arm/kernel/time.c
3  *
4  *  Copyright (C) 1994-2001 Russell King
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #include <linux/export.h>
11 #include <linux/init.h>
12 #include <linux/device.h>
13 #include <linux/syscore_ops.h>
14 #include <linux/string.h>
15 
16 #include <asm/leds.h>
17 
dummy_leds_event(led_event_t evt)18 static void dummy_leds_event(led_event_t evt)
19 {
20 }
21 
22 void (*leds_event)(led_event_t) = dummy_leds_event;
23 
24 struct leds_evt_name {
25 	const char	name[8];
26 	int		on;
27 	int		off;
28 };
29 
30 static const struct leds_evt_name evt_names[] = {
31 	{ "amber", led_amber_on, led_amber_off },
32 	{ "blue",  led_blue_on,  led_blue_off  },
33 	{ "green", led_green_on, led_green_off },
34 	{ "red",   led_red_on,   led_red_off   },
35 };
36 
leds_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)37 static ssize_t leds_store(struct device *dev,
38 			struct device_attribute *attr,
39 			const char *buf, size_t size)
40 {
41 	int ret = -EINVAL, len = strcspn(buf, " ");
42 
43 	if (len > 0 && buf[len] == '\0')
44 		len--;
45 
46 	if (strncmp(buf, "claim", len) == 0) {
47 		leds_event(led_claim);
48 		ret = size;
49 	} else if (strncmp(buf, "release", len) == 0) {
50 		leds_event(led_release);
51 		ret = size;
52 	} else {
53 		int i;
54 
55 		for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
56 			if (strlen(evt_names[i].name) != len ||
57 			    strncmp(buf, evt_names[i].name, len) != 0)
58 				continue;
59 			if (strncmp(buf+len, " on", 3) == 0) {
60 				leds_event(evt_names[i].on);
61 				ret = size;
62 			} else if (strncmp(buf+len, " off", 4) == 0) {
63 				leds_event(evt_names[i].off);
64 				ret = size;
65 			}
66 			break;
67 		}
68 	}
69 	return ret;
70 }
71 
72 static DEVICE_ATTR(event, 0200, NULL, leds_store);
73 
74 static struct bus_type leds_subsys = {
75 	.name		= "leds",
76 	.dev_name	= "leds",
77 };
78 
79 static struct device leds_device = {
80 	.id		= 0,
81 	.bus		= &leds_subsys,
82 };
83 
leds_suspend(void)84 static int leds_suspend(void)
85 {
86 	leds_event(led_stop);
87 	return 0;
88 }
89 
leds_resume(void)90 static void leds_resume(void)
91 {
92 	leds_event(led_start);
93 }
94 
leds_shutdown(void)95 static void leds_shutdown(void)
96 {
97 	leds_event(led_halted);
98 }
99 
100 static struct syscore_ops leds_syscore_ops = {
101 	.shutdown	= leds_shutdown,
102 	.suspend	= leds_suspend,
103 	.resume		= leds_resume,
104 };
105 
leds_init(void)106 static int __init leds_init(void)
107 {
108 	int ret;
109 	ret = subsys_system_register(&leds_subsys, NULL);
110 	if (ret == 0)
111 		ret = device_register(&leds_device);
112 	if (ret == 0)
113 		ret = device_create_file(&leds_device, &dev_attr_event);
114 	if (ret == 0)
115 		register_syscore_ops(&leds_syscore_ops);
116 	return ret;
117 }
118 
119 device_initcall(leds_init);
120 
121 EXPORT_SYMBOL(leds_event);
122