210-reset_button.patch 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. --- a/arch/mips/ar231x/Makefile
  2. +++ b/arch/mips/ar231x/Makefile
  3. @@ -8,7 +8,7 @@
  4. # Copyright (C) 2006-2009 Felix Fietkau <[email protected]>
  5. #
  6. -obj-y += board.o prom.o devices.o
  7. +obj-y += board.o prom.o devices.o reset.o
  8. obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o
  9. obj-$(CONFIG_ATHEROS_AR2315) += ar2315.o
  10. obj-$(CONFIG_ATHEROS_AR2315_PCI) += pci.o
  11. --- /dev/null
  12. +++ b/arch/mips/ar231x/reset.c
  13. @@ -0,0 +1,157 @@
  14. +#include <linux/init.h>
  15. +#include <linux/module.h>
  16. +#include <linux/timer.h>
  17. +#include <linux/interrupt.h>
  18. +#include <linux/kobject.h>
  19. +#include <linux/workqueue.h>
  20. +#include <linux/skbuff.h>
  21. +#include <linux/netlink.h>
  22. +#include <net/sock.h>
  23. +#include <asm/uaccess.h>
  24. +#include <ar231x_platform.h>
  25. +#include <ar231x.h>
  26. +#include <gpio.h>
  27. +#include "devices.h"
  28. +
  29. +#define AR531X_RESET_GPIO_IRQ (AR531X_GPIO_IRQ(ar231x_board.config->resetConfigGpio))
  30. +
  31. +struct event_t {
  32. + struct work_struct wq;
  33. + int set;
  34. + unsigned long jiffies;
  35. +};
  36. +
  37. +static struct timer_list rst_button_timer;
  38. +static unsigned long seen;
  39. +
  40. +extern struct sock *uevent_sock;
  41. +extern u64 uevent_next_seqnum(void);
  42. +
  43. +static int no_release_workaround = 1;
  44. +module_param(no_release_workaround, int, 0);
  45. +
  46. +static inline void
  47. +add_msg(struct sk_buff *skb, char *msg)
  48. +{
  49. + char *scratch;
  50. + scratch = skb_put(skb, strlen(msg) + 1);
  51. + sprintf(scratch, msg);
  52. +}
  53. +
  54. +static void
  55. +hotplug_button(struct work_struct *wq)
  56. +{
  57. + struct sk_buff *skb;
  58. + struct event_t *event;
  59. + size_t len;
  60. + char *scratch, *s;
  61. + char buf[128];
  62. +
  63. + event = container_of(wq, struct event_t, wq);
  64. + if (!uevent_sock)
  65. + goto done;
  66. +
  67. + /* allocate message with the maximum possible size */
  68. + s = event->set ? "pressed" : "released";
  69. + len = strlen(s) + 2;
  70. + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
  71. + if (!skb)
  72. + goto done;
  73. +
  74. + /* add header */
  75. + scratch = skb_put(skb, len);
  76. + sprintf(scratch, "%s@",s);
  77. +
  78. + /* copy keys to our continuous event payload buffer */
  79. + add_msg(skb, "HOME=/");
  80. + add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
  81. + add_msg(skb, "SUBSYSTEM=button");
  82. + add_msg(skb, "BUTTON=reset");
  83. + add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
  84. + sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
  85. + add_msg(skb, buf);
  86. + snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
  87. + add_msg(skb, buf);
  88. +
  89. + NETLINK_CB(skb).dst_group = 1;
  90. + netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
  91. +
  92. +done:
  93. + kfree(event);
  94. +}
  95. +
  96. +static void
  97. +reset_button_poll(unsigned long unused)
  98. +{
  99. + struct event_t *event;
  100. + int gpio = ~0;
  101. +
  102. + if(!no_release_workaround)
  103. + return;
  104. +
  105. + gpio = ar231x_gpiodev->get();
  106. + gpio &= (1 << (AR531X_RESET_GPIO_IRQ - AR531X_GPIO_IRQ_BASE));
  107. + if(gpio) {
  108. + rst_button_timer.expires = jiffies + (HZ / 4);
  109. + add_timer(&rst_button_timer);
  110. + return;
  111. + }
  112. +
  113. + event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
  114. + if (!event)
  115. + return;
  116. +
  117. + event->set = 0;
  118. + event->jiffies = jiffies;
  119. + INIT_WORK(&event->wq, hotplug_button);
  120. + schedule_work(&event->wq);
  121. +}
  122. +
  123. +static irqreturn_t
  124. +button_handler(int irq, void *dev_id)
  125. +{
  126. + static int pressed = 0;
  127. + struct event_t *event;
  128. + u32 gpio = ~0;
  129. +
  130. + event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
  131. + if (!event)
  132. + return IRQ_NONE;
  133. +
  134. + pressed = !pressed;
  135. +
  136. + gpio = ar231x_gpiodev->get() & (1 << (irq - AR531X_GPIO_IRQ_BASE));
  137. +
  138. + event->set = gpio;
  139. + if(!event->set)
  140. + no_release_workaround = 0;
  141. +
  142. + event->jiffies = jiffies;
  143. +
  144. + INIT_WORK(&event->wq, hotplug_button);
  145. + schedule_work(&event->wq);
  146. +
  147. + seen = jiffies;
  148. + if(event->set && no_release_workaround)
  149. + mod_timer(&rst_button_timer, jiffies + (HZ / 4));
  150. +
  151. + return IRQ_HANDLED;
  152. +}
  153. +
  154. +
  155. +static int __init
  156. +ar231x_init_reset(void)
  157. +{
  158. + seen = jiffies;
  159. +
  160. + init_timer(&rst_button_timer);
  161. + rst_button_timer.function = reset_button_poll;
  162. + rst_button_timer.expires = jiffies + HZ / 50;
  163. + add_timer(&rst_button_timer);
  164. +
  165. + request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar231x_reset", NULL);
  166. +
  167. + return 0;
  168. +}
  169. +
  170. +module_init(ar231x_init_reset);