xref: /openbmc/linux/arch/sparc/kernel/led.c (revision ee1858d3)
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/init.h>
4 #include <linux/proc_fs.h>
5 #include <linux/string.h>
6 
7 #include <asm/auxio.h>
8 
9 #define LED_MAX_LENGTH 8 /* maximum chars written to proc file */
10 
11 static inline void led_toggle(void)
12 {
13 	unsigned char val = get_auxio();
14 	unsigned char on, off;
15 
16 	if (val & AUXIO_LED) {
17 		on = 0;
18 		off = AUXIO_LED;
19 	} else {
20 		on = AUXIO_LED;
21 		off = 0;
22 	}
23 
24 	set_auxio(on, off);
25 }
26 
27 static struct timer_list led_blink_timer;
28 
29 static void led_blink(unsigned long timeout)
30 {
31 	led_toggle();
32 
33 	/* reschedule */
34 	if (!timeout) { /* blink according to load */
35 		led_blink_timer.expires = jiffies +
36 			((1 + (avenrun[0] >> FSHIFT)) * HZ);
37 		led_blink_timer.data = 0;
38 	} else { /* blink at user specified interval */
39 		led_blink_timer.expires = jiffies + (timeout * HZ);
40 		led_blink_timer.data = timeout;
41 	}
42 	add_timer(&led_blink_timer);
43 }
44 
45 static int led_read_proc(char *buf, char **start, off_t offset, int count,
46 			 int *eof, void *data)
47 {
48 	int len = 0;
49 
50 	if (get_auxio() & AUXIO_LED)
51 		len = sprintf(buf, "on\n");
52 	else
53 		len = sprintf(buf, "off\n");
54 
55 	return len;
56 }
57 
58 static int led_write_proc(struct file *file, const char *buffer,
59 			  unsigned long count, void *data)
60 {
61 	char *buf = NULL;
62 
63 	if (count > LED_MAX_LENGTH)
64 		count = LED_MAX_LENGTH;
65 
66 	buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL);
67 	if (!buf)
68 		return -ENOMEM;
69 
70 	if (copy_from_user(buf, buffer, count)) {
71 		kfree(buf);
72 		return -EFAULT;
73 	}
74 
75 	buf[count] = '\0';
76 
77 	/* work around \n when echo'ing into proc */
78 	if (buf[count - 1] == '\n')
79 		buf[count - 1] = '\0';
80 
81 	/* before we change anything we want to stop any running timers,
82 	 * otherwise calls such as on will have no persistent effect
83 	 */
84 	del_timer_sync(&led_blink_timer);
85 
86 	if (!strcmp(buf, "on")) {
87 		auxio_set_led(AUXIO_LED_ON);
88 	} else if (!strcmp(buf, "toggle")) {
89 		led_toggle();
90 	} else if ((*buf > '0') && (*buf <= '9')) {
91 		led_blink(simple_strtoul(buf, NULL, 10));
92 	} else if (!strcmp(buf, "load")) {
93 		led_blink(0);
94 	} else {
95 		auxio_set_led(AUXIO_LED_OFF);
96 	}
97 
98 	kfree(buf);
99 
100 	return count;
101 }
102 
103 static struct proc_dir_entry *led;
104 
105 #define LED_VERSION	"0.1"
106 
107 static int __init led_init(void)
108 {
109 	init_timer(&led_blink_timer);
110 	led_blink_timer.function = led_blink;
111 
112 	led = create_proc_entry("led", 0, NULL);
113 	if (!led)
114 		return -ENOMEM;
115 
116 	led->read_proc = led_read_proc; /* reader function */
117 	led->write_proc = led_write_proc; /* writer function */
118 	led->owner = THIS_MODULE;
119 
120 	printk(KERN_INFO
121 	       "led: version %s, Lars Kotthoff <metalhead@metalhead.ws>\n",
122 	       LED_VERSION);
123 
124 	return 0;
125 }
126 
127 static void __exit led_exit(void)
128 {
129 	remove_proc_entry("led", NULL);
130 	del_timer_sync(&led_blink_timer);
131 }
132 
133 module_init(led_init);
134 module_exit(led_exit);
135 
136 MODULE_AUTHOR("Lars Kotthoff <metalhead@metalhead.ws>");
137 MODULE_DESCRIPTION("Provides control of the front LED on SPARC systems.");
138 MODULE_LICENSE("GPL");
139 MODULE_VERSION(LED_VERSION);
140