/*
* Button Hotplug driver
*
- * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
*
* Based on the diag.c - GPIO interface driver for Broadcom boards
* Copyright (C) 2006 Mike Baker <mbm@openwrt.org>,
#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
-#include <net/sock.h>
+#include <linux/kobject.h>
#define DRV_NAME "button-hotplug"
-#define DRV_VERSION "0.3.0"
+#define DRV_VERSION "0.4.1"
#define DRV_DESC "Button Hotplug driver"
#define BH_SKB_SIZE 2048
-#define BH_BTN_MIN BTN_0
-#define BH_BTN_MAX BTN_9
-
-#define BH_BTN_COUNT (BH_BTN_MAX - BH_BTN_MIN + 1)
-
#define PFX DRV_NAME ": "
-/*#define BH_DEBUG*/
+#undef BH_DEBUG
#ifdef BH_DEBUG
-#define BH_DBG(fmt, args...) printk(KERN_DEBUG "%s" fmt, ##args )
+#define BH_DBG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, DRV_NAME, ##args )
#else
#define BH_DBG(fmt, args...) do {} while (0)
#endif
-#define BH_ERR(fmt, args...) printk(KERN_ERR "%s" fmt, ##args )
+#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, DRV_NAME, ##args )
+
+#ifndef BIT_MASK
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#endif
struct bh_priv {
- unsigned long seen[BH_BTN_COUNT];
+ unsigned long *seen;
struct input_handle handle;
};
struct bh_event {
- char *name;
+ const char *name;
char *action;
unsigned long seen;
struct work_struct work;
};
-extern struct sock *uevent_sock;
+struct bh_map {
+ unsigned int code;
+ const char *name;
+};
+
extern u64 uevent_next_seqnum(void);
-static char *button_names[BH_BTN_COUNT] = {
- "BTN_0", "BTN_1", "BTN_2", "BTN_3", "BTN_4",
- "BTN_5", "BTN_6", "BTN_7", "BTN_8", "BTN_9"
+#define BH_MAP(_code, _name) \
+ { \
+ .code = (_code), \
+ .name = (_name), \
+ }
+
+static struct bh_map button_map[] = {
+ BH_MAP(BTN_0, "BTN_0"),
+ BH_MAP(BTN_1, "BTN_1"),
+ BH_MAP(BTN_2, "BTN_2"),
+ BH_MAP(BTN_3, "BTN_3"),
+ BH_MAP(BTN_4, "BTN_4"),
+ BH_MAP(BTN_5, "BTN_5"),
+ BH_MAP(BTN_6, "BTN_6"),
+ BH_MAP(BTN_7, "BTN_7"),
+ BH_MAP(BTN_8, "BTN_8"),
+ BH_MAP(BTN_9, "BTN_9"),
+ BH_MAP(KEY_RESTART, "reset"),
+#ifdef KEY_WPS_BUTTON
+ BH_MAP(KEY_WPS_BUTTON, "wps"),
+#endif /* KEY_WPS_BUTTON */
};
/* -------------------------------------------------------------------------*/
struct bh_event *event = container_of(work, struct bh_event, work);
int ret = 0;
- if (!uevent_sock)
- goto out_free_event;
-
event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
if (!event->skb)
goto out_free_event;
goto out_free_skb;
NETLINK_CB(event->skb).dst_group = 1;
- netlink_broadcast(uevent_sock, event->skb, 0, 1, GFP_KERNEL);
+ broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
out_free_skb:
if (ret) {
kfree(event);
}
-static int button_hotplug_create_event(char *name, unsigned long seen,
+static int button_hotplug_create_event(const char *name, unsigned long seen,
int pressed)
{
struct bh_event *event;
/* -------------------------------------------------------------------------*/
#ifdef CONFIG_HOTPLUG
+static int button_get_index(unsigned int code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(button_map); i++)
+ if (button_map[i].code == code)
+ return i;
+
+ return -1;
+}
static void button_hotplug_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct bh_priv *priv = handle->private;
unsigned long seen = jiffies;
- unsigned int btn;
+ int btn;
BH_DBG("event type=%u, code=%u, value=%d\n", type, code, value);
if (type != EV_KEY)
return;
- if (code < BH_BTN_MIN || code > BH_BTN_MAX)
+ btn = button_get_index(code);
+ if (btn < 0)
return;
- btn = code - BH_BTN_MIN;
- button_hotplug_create_event(button_names[btn],
+ button_hotplug_create_event(button_map[btn].name,
(seen - priv->seen[btn]) / HZ, value);
priv->seen[btn] = seen;
}
int ret;
int i;
- for (i = BH_BTN_MIN; i <= BH_BTN_MAX; i++)
- if (test_bit(i, dev->keybit))
+ for (i = 0; i < ARRAY_SIZE(button_map); i++)
+ if (test_bit(button_map[i].code, dev->keybit))
break;
- if (i > BH_BTN_MAX)
+ if (i == ARRAY_SIZE(button_map))
return -ENODEV;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv) +
+ (sizeof(unsigned long) * ARRAY_SIZE(button_map)),
+ GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->seen = (unsigned long *) &priv[1];
priv->handle.private = priv;
priv->handle.dev = dev;
priv->handle.handler = handler;