led.c 2.9 KB

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