As mentioned in another post, we need extra thing to support the switch at the back of the ls-wvl. But instead of poll the status of the switch continuously, I prefer to use hot plug event to do that. And to do that, I use the button hotplug kernel module found on openwrt.org. But again, a patch is needed to support udev.
First get the button hotplug sources from here (button-hotplug.c and Kconfig are needed):
h==ps://dev.openwrt.org/browser/trunk/package/button-hotplug/src
Apply this patch (got from h==ps://lists.openwrt.org/pipermail/openwrt-devel/2012-February/014205.html. I applied the patch manually, one line after another since it was mentioned that the source in trunk is different, but later found that the patch could be applied cleanly.)
Code:
--- bh-orig/button-hotplug.c 2010-09-01 04:06:30.000000000 +0800
+++ button-hotplug/button-hotplug.c 2012-07-30 14:20:13.311180106 +0800
@@ -19,7 +19,6 @@
#include <linux/input.h>
#include <linux/workqueue.h>
-#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/kobject.h>
@@ -48,6 +47,8 @@
struct bh_priv {
unsigned long *seen;
struct input_handle handle;
+
+ struct kobject bh_kobj;
};
struct bh_event {
@@ -55,17 +56,29 @@ struct bh_event {
char *action;
unsigned long seen;
- struct sk_buff *skb;
+ struct bh_priv *priv;
struct work_struct work;
};
+static struct kset *bh_kset;
+
+static struct attribute *bh_attrs[] = {
+ NULL,
+};
+
+static struct sysfs_ops bh_attr_ops = {
+};
+
+static struct kobj_type bh_ktype = {
+ .default_attrs = bh_attrs,
+ .sysfs_ops = &bh_attr_ops,
+};
+
struct bh_map {
unsigned int code;
const char *name;
};
-extern u64 uevent_next_seqnum(void);
-
#define BH_MAP(_code, _name) \
{ \
.code = (_code), \
@@ -89,102 +102,25 @@ static struct bh_map button_map[] = {
#endif /* KEY_WPS_BUTTON */
};
-/* -------------------------------------------------------------------------*/
-
-static int bh_event_add_var(struct bh_event *event, int argv,
- const char *format, ...)
-{
- static char buf[128];
- char *s;
- va_list args;
- int len;
-
- if (argv)
- return 0;
-
- va_start(args, format);
- len = vsnprintf(buf, sizeof(buf), format, args);
- va_end(args);
-
- if (len >= sizeof(buf)) {
- BH_ERR("buffer size too small\n");
- WARN_ON(1);
- return -ENOMEM;
- }
-
- s = skb_put(event->skb, len + 1);
- strcpy(s, buf);
-
- BH_DBG("added variable '%s'\n", s);
-
- return 0;
-}
-
-static int button_hotplug_fill_event(struct bh_event *event)
-{
- int ret;
-
- ret = bh_event_add_var(event, 0, "HOME=%s", "/");
- if (ret)
- return ret;
-
- ret = bh_event_add_var(event, 0, "PATH=%s",
- "/sbin:/bin:/usr/sbin:/usr/bin");
- if (ret)
- return ret;
-
- ret = bh_event_add_var(event, 0, "SUBSYSTEM=%s", "button");
- if (ret)
- return ret;
-
- ret = bh_event_add_var(event, 0, "ACTION=%s", event->action);
- if (ret)
- return ret;
-
- ret = bh_event_add_var(event, 0, "BUTTON=%s", event->name);
- if (ret)
- return ret;
-
- ret = bh_event_add_var(event, 0, "SEEN=%ld", event->seen);
- if (ret)
- return ret;
-
- ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
-
- return ret;
-}
-
static void button_hotplug_work(struct work_struct *work)
{
struct bh_event *event = container_of(work, struct bh_event, work);
- int ret = 0;
-
- event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
- if (!event->skb)
- goto out_free_event;
+ struct bh_priv *priv = event->priv;
+ char env_baction[20];
+ char env_button[20];
+ char env_seen[20];
+ char *envp[] = { env_baction, env_button, env_seen, NULL };
+
+ sprintf(env_baction, "BACTION=%s", event->action);
+ sprintf(env_button, "BUTTON=%s", event->name);
+ sprintf(env_seen, "SEEN=%ld", event->seen);
+ kobject_uevent_env(&priv->bh_kobj, KOBJ_CHANGE, envp);
- ret = bh_event_add_var(event, 0, "%s@", event->action);
- if (ret)
- goto out_free_skb;
-
- ret = button_hotplug_fill_event(event);
- if (ret)
- goto out_free_skb;
-
- NETLINK_CB(event->skb).dst_group = 1;
- broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
-
- out_free_skb:
- if (ret) {
- BH_ERR("work error %d\n", ret);
- kfree_skb(event->skb);
- }
- out_free_event:
kfree(event);
}
static int button_hotplug_create_event(const char *name, unsigned long seen,
- int pressed)
+ int pressed, struct bh_priv *thispriv)
{
struct bh_event *event;
@@ -198,6 +134,7 @@ static int button_hotplug_create_event(c
event->name = name;
event->seen = seen;
event->action = pressed ? "pressed" : "released";
+ event->priv = thispriv;
INIT_WORK(&event->work, (void *)(void *)button_hotplug_work);
schedule_work(&event->work);
@@ -235,7 +172,7 @@ static void button_hotplug_event(struct
return;
button_hotplug_create_event(button_map[btn].name,
- (seen - priv->seen[btn]) / HZ, value);
+ (seen - priv->seen[btn]) / HZ, value, priv);
priv->seen[btn] = seen;
}
#else
@@ -270,6 +207,11 @@ static int button_hotplug_connect(struct
priv->handle.dev = dev;
priv->handle.handler = handler;
priv->handle.name = DRV_NAME;
+
+ priv->bh_kobj.kset = bh_kset;
+ ret = kobject_init_and_add(&priv->bh_kobj, &bh_ktype, NULL, "bh-%s", dev->name);
+ if (ret)
+ goto err_free_priv;
ret = input_register_handle(&priv->handle);
if (ret)
@@ -298,6 +240,8 @@ static void button_hotplug_disconnect(st
input_close_device(handle);
input_unregister_handle(handle);
+ kobject_put(&priv->bh_kobj);
+
kfree(priv);
}
@@ -328,6 +272,13 @@ static int __init button_hotplug_init(vo
int ret;
printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+
+ bh_kset = kset_create_and_add("button", NULL, kernel_kobj);
+ if (!bh_kset) {
+ BH_ERR("unable to create kset\n");
+ return -ENOMEM;
+ }
+
ret = input_register_handler(&button_hotplug_handler);
if (ret)
BH_ERR("unable to register input handler\n");
@@ -339,6 +290,7 @@ module_init(button_hotplug_init);
static void __exit button_hotplug_exit(void)
{
input_unregister_handler(&button_hotplug_handler);
+ kset_unregister(bh_kset);
}
module_exit(button_hotplug_exit);
But use the make file shown below:
Code:
obj-m += button-hotplug.o
TOPDIR = /data/src/lswvl
KVERSION = 3.5.0-rc3
all:
make -C ${TOPDIR}/lib/modules/${KVERSION}/build M=`pwd` modules
install:
make -C ${TOPDIR}/lib/modules/${KVERSION}/build M=`pwd` INSTALL_MOD_PATH=${TOPDIR} modules_install
clean:
make -C ${TOPDIR}/lib/modules/${KVERSION}/build M=`pwd` clean
Modify the TOPDIR to point to your topdir that kernel modules are placed, and KVERSION to your kernel version. Then under the source directory, type
Code:
make && make install
to get the module compiled and installed.
Note that it was assumed that the sources were cross-compiled. And the kernel module is placed at $TOPDIR/lib/modules/$KVERSION, the kernel source should be pointed at by $TOPDIR/lib/modules/$KVERSION/build. So you still need to copy the kernel module sub-directory to the machine. And if it's not the case, modify the Makefile accordingly.
And to use button hotplug with ls-wvl, the buttons should be defined as in this thread:
viewtopic.php?f=73&t=25941or be similar, otherwise you need to modify button-hotplug.c accordingly.