• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/notifier.h>
14 #include <linux/cpu.h>
15 #include <linux/syscore_ops.h>
16 #include <linux/string.h>
17 
18 #include <asm/leds.h>
19 
dummy_leds_event(led_event_t evt)20 static void dummy_leds_event(led_event_t evt)
21 {
22 }
23 
24 void (*leds_event)(led_event_t) = dummy_leds_event;
25 
26 struct leds_evt_name {
27 	const char	name[8];
28 	int		on;
29 	int		off;
30 };
31 
32 static const struct leds_evt_name evt_names[] = {
33 	{ "amber", led_amber_on, led_amber_off },
34 	{ "blue",  led_blue_on,  led_blue_off  },
35 	{ "green", led_green_on, led_green_off },
36 	{ "red",   led_red_on,   led_red_off   },
37 };
38 
leds_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)39 static ssize_t leds_store(struct device *dev,
40 			struct device_attribute *attr,
41 			const char *buf, size_t size)
42 {
43 	int ret = -EINVAL, len = strcspn(buf, " ");
44 
45 	if (len > 0 && buf[len] == '\0')
46 		len--;
47 
48 	if (strncmp(buf, "claim", len) == 0) {
49 		leds_event(led_claim);
50 		ret = size;
51 	} else if (strncmp(buf, "release", len) == 0) {
52 		leds_event(led_release);
53 		ret = size;
54 	} else {
55 		int i;
56 
57 		for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
58 			if (strlen(evt_names[i].name) != len ||
59 			    strncmp(buf, evt_names[i].name, len) != 0)
60 				continue;
61 			if (strncmp(buf+len, " on", 3) == 0) {
62 				leds_event(evt_names[i].on);
63 				ret = size;
64 			} else if (strncmp(buf+len, " off", 4) == 0) {
65 				leds_event(evt_names[i].off);
66 				ret = size;
67 			}
68 			break;
69 		}
70 	}
71 	return ret;
72 }
73 
74 static DEVICE_ATTR(event, 0200, NULL, leds_store);
75 
76 static struct bus_type leds_subsys = {
77 	.name		= "leds",
78 	.dev_name	= "leds",
79 };
80 
81 static struct device leds_device = {
82 	.id		= 0,
83 	.bus		= &leds_subsys,
84 };
85 
leds_suspend(void)86 static int leds_suspend(void)
87 {
88 	leds_event(led_stop);
89 	return 0;
90 }
91 
leds_resume(void)92 static void leds_resume(void)
93 {
94 	leds_event(led_start);
95 }
96 
leds_shutdown(void)97 static void leds_shutdown(void)
98 {
99 	leds_event(led_halted);
100 }
101 
102 static struct syscore_ops leds_syscore_ops = {
103 	.shutdown	= leds_shutdown,
104 	.suspend	= leds_suspend,
105 	.resume		= leds_resume,
106 };
107 
leds_idle_notifier(struct notifier_block * nb,unsigned long val,void * data)108 static int leds_idle_notifier(struct notifier_block *nb, unsigned long val,
109                                 void *data)
110 {
111 	switch (val) {
112 	case IDLE_START:
113 		leds_event(led_idle_start);
114 		break;
115 	case IDLE_END:
116 		leds_event(led_idle_end);
117 		break;
118 	}
119 
120 	return 0;
121 }
122 
123 static struct notifier_block leds_idle_nb = {
124 	.notifier_call = leds_idle_notifier,
125 };
126 
leds_init(void)127 static int __init leds_init(void)
128 {
129 	int ret;
130 	ret = subsys_system_register(&leds_subsys, NULL);
131 	if (ret == 0)
132 		ret = device_register(&leds_device);
133 	if (ret == 0)
134 		ret = device_create_file(&leds_device, &dev_attr_event);
135 	if (ret == 0) {
136 		register_syscore_ops(&leds_syscore_ops);
137 		idle_notifier_register(&leds_idle_nb);
138 	}
139 
140 	return ret;
141 }
142 
143 device_initcall(leds_init);
144 
145 EXPORT_SYMBOL(leds_event);
146