Buffalo NAS-Central Forums

Welcome to the Linkstation Wiki community
It is currently Fri Oct 31, 2014 12:35 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 2 posts ] 
Author Message
PostPosted: Mon Jul 30, 2012 7:27 am 
Offline
Newbie

Joined: Fri Mar 21, 2008 3:04 am
Posts: 52
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=25941

or be similar, otherwise you need to modify button-hotplug.c accordingly.


Top
 Profile  
 
PostPosted: Mon Jul 30, 2012 2:08 pm 
Offline
Newbie

Joined: Fri Mar 21, 2008 3:04 am
Posts: 52
Next we need to create the udev rule for the power switch:
under /etc/udev/rules.d, add a file named "99-gpio-buttons.rules", the content should look like this:

Code:
SUBSYSTEM=="button", ENV{BUTTON}=="BTN_1", ENV{BACTION}=="released", RUN+="/sbin/poweroff"


That's all. When you move the switch from on to off or to auto, the machine will try to power off. But if the power switch is moved to auto, the machine will actually restart. Distinguish auto from off is possible, but I didn't bother to try that since this is already enough for me. And to implement that I'll need to search again since I don't have too much shell script skill. (Basically you define another rule for AUTO switch (BTN_2), when it is on, create a file. Then for power switch "BTN_1", when it is released, delay a few time, then check that file's existence, you know the switch's exact position).


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:

Protected by Anti-Spam ACP
Protected by Anti-Spam ACP Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group