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