Hi people,

First off, I'd note that button hotplug driver is a really great thing - lots of thanks to its creators!

As I sometimes use openwrt kernel with debian userspace, I've found that stock button_hotplug has no effect on debian. Even udevadm monitor shows nothing. Now, because researching debian's udev problems (if there are any) didn't seem quite attractive to me, I went another way around. I noticed that exactly zero in-tree drivers use uevent socket, but plenty of drivers use kobject_uevent_env() instead. So I modified button-hotplug to not use the socket but use kobject_uevent_env(). In the end, the driver even became somewhat smaller and simpler (imho). See the diff below. And, now it also works on debian! I've no idea if there are any serious downsides - I'm leaving judging up to the authors. The naming is a bit different, yes. (E.g. "ACTION" -> "BACTION", ...) For reference: my hardware is netgear wndr3800, openwrt is 10.03.1, debian is 6.0 Note: trunk version of button_hotplug is slightly different, I haven't tried it yet, but it still uses the socket AFAICS (via a wrapper, though)


Thank you.
Nikolai

--- button-hotplug.c.orig       2012-02-24 13:38:30.000000000 +0300
+++ button-hotplug.c    2012-02-24 14:04:39.000000000 +0300
@@ -25,7 +25,7 @@

 #define DRV_NAME       "button-hotplug"
 #define DRV_VERSION    "0.3.1"
-#define DRV_DESC       "Button Hotplug driver"
+#define DRV_DESC       "Button Hotplug driver (for Debian)"

 #define BH_SKB_SIZE    2048

@@ -53,6 +53,7 @@
 struct bh_priv {
        unsigned long           seen[BH_BTN_COUNT];
        struct input_handle     handle;
+       struct kobject          bh_kobj;
 };

 struct bh_event {
@@ -60,12 +61,24 @@
        char                    *action;
        unsigned long           seen;

-       struct sk_buff          *skb;
+       struct bh_priv          *priv;
        struct work_struct      work;
+
 };

-extern struct sock *uevent_sock;
-extern u64 uevent_next_seqnum(void);
+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,
+};

 static char *button_names[BH_BTN_COUNT] = {
        "BTN_0", "BTN_1", "BTN_2", "BTN_3", "BTN_4",
@@ -74,103 +87,25 @@

/* -------------------------------------------------------------------------*/

-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;
-
-       if (!uevent_sock)
-               goto out_free_event;
-
-       event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
-       if (!event->skb)
-               goto out_free_event;
-
-       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;
+       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 };

-       NETLINK_CB(event->skb).dst_group = 1;
-       netlink_broadcast(uevent_sock, event->skb, 0, 1, GFP_KERNEL);
+       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);

- 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(char *name, unsigned long seen,
-               int pressed)
+               int pressed, struct bh_priv *thispriv)
 {
        struct bh_event *event;

@@ -184,6 +119,7 @@
        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);
@@ -211,7 +147,7 @@

        btn = code - BH_BTN_MIN;
        button_hotplug_create_event(button_names[btn],
-                       (seen - priv->seen[btn]) / HZ, value);
+                       (seen - priv->seen[btn]) / HZ, value, priv);
        priv->seen[btn] = seen;
 }
 #else
@@ -244,6 +180,12 @@
        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)
                goto err_free_priv;
@@ -271,6 +213,8 @@
        input_close_device(handle);
        input_unregister_handle(handle);

+       kobject_put(&priv->bh_kobj);
+
        kfree(priv);
 }

@@ -301,6 +245,13 @@
        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");
@@ -312,6 +263,7 @@
 static void __exit button_hotplug_exit(void)
 {
        input_unregister_handler(&button_hotplug_handler);
+       kset_unregister(bh_kset);
 }
 module_exit(button_hotplug_exit);


_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to