input: Add support for UserspaceHID=persist
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 25 Oct 2024 19:25:33 +0000 (15:25 -0400)
committerWootak Jung <wootak.jung@samsung.com>
Thu, 20 Feb 2025 07:43:24 +0000 (16:43 +0900)
This adds support for persist mode via input.conf:UserspaceHID but
don't default to it since this appears to create more problems than
it solves.

Fixes: https://github.com/bluez/bluez/issues/983
Fixes: https://github.com/bluez/bluez/issues/977
Fixes: https://github.com/bluez/bluez/issues/949
Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
profiles/input/device.c
profiles/input/device.h
profiles/input/hog.c
profiles/input/input.conf
profiles/input/manager.c

index 50dd0e6fa5df61b77b29ea6986bf83110fad54d1..6017c7ce5b3e9a40e1de165deeb68cc5c9b51293 100644 (file)
@@ -91,7 +91,7 @@ struct input_device {
 };
 
 static int idle_timeout = 0;
-static bool uhid_enabled = true;
+static uhid_state_t uhid_state = UHID_ENABLED;
 static bool classic_bonded_only = true;
 
 void input_set_idle_timeout(int timeout)
@@ -99,9 +99,23 @@ void input_set_idle_timeout(int timeout)
        idle_timeout = timeout;
 }
 
-void input_enable_userspace_hid(bool state)
+void input_set_userspace_hid(char *state)
 {
-       uhid_enabled = state;
+       if (!strcasecmp(state, "false") || !strcasecmp(state, "no") ||
+                       !strcasecmp(state, "off"))
+               uhid_state = UHID_DISABLED;
+       else if (!strcasecmp(state, "true") || !strcasecmp(state, "yes") ||
+                       !strcasecmp(state, "on"))
+               uhid_state = UHID_ENABLED;
+       else if (!strcasecmp(state, "persist"))
+               uhid_state = UHID_PERSIST;
+       else
+               error("Unknown value '%s'", state);
+}
+
+uint8_t input_get_userspace_hid(void)
+{
+       return uhid_state;
 }
 
 void input_set_classic_bonded_only(bool state)
@@ -181,6 +195,9 @@ static int uhid_disconnect(struct input_device *idev, bool force)
        if (idev->virtual_cable_unplug && !force)
                force = true;
 
+       if (!force && uhid_state != UHID_PERSIST)
+               force = true;
+
        err = bt_uhid_destroy(idev->uhid, force);
        if (err < 0) {
                error("bt_uhid_destroy: %s", strerror(-err));
@@ -1602,7 +1619,7 @@ int input_device_register(struct btd_service *service)
        if (!idev)
                return -EINVAL;
 
-       if (uhid_enabled) {
+       if (uhid_state) {
                idev->uhid = bt_uhid_new_default();
                if (!idev->uhid) {
                        error("bt_uhid_new_default: failed");
@@ -1776,7 +1793,7 @@ int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
        if (!idev)
                return -ENOENT;
 
-       if (uhid_enabled)
+       if (uhid_state)
                cond |= G_IO_IN;
 
        switch (psm) {
index 40409a28a0fb57919e3ff7772bdf4d150febab8b..ea9ee463be618eed1f8784575c7b9f5941f1bfcc 100755 (executable)
 #define L2CAP_PSM_HIDP_CTRL    0x11
 #define L2CAP_PSM_HIDP_INTR    0x13
 
+typedef enum {
+       UHID_DISABLED = 0,
+       UHID_ENABLED,
+       UHID_PERSIST
+} uhid_state_t;
+
 struct input_device;
 struct input_conn;
 
 void input_set_idle_timeout(int timeout);
-void input_enable_userspace_hid(bool state);
+void input_set_userspace_hid(char *state);
+uint8_t input_get_userspace_hid(void);
 void input_set_classic_bonded_only(bool state);
 bool input_get_classic_bonded_only(void);
 
index ed263761ed6184a0fc882bdd7965099621a40952..9b0dae2d1d53382b57818cc3aa388cd7bfc5dd4b 100755 (executable)
@@ -213,7 +213,10 @@ static int hog_disconnect(struct btd_service *service)
 {
        struct hog_device *dev = btd_service_get_user_data(service);
 
-       bt_hog_detach(dev->hog, false);
+       if (input_get_userspace_hid() == UHID_PERSIST)
+               bt_hog_detach(dev->hog, false);
+       else
+               bt_hog_detach(dev->hog, true);
 
        btd_service_disconnecting_complete(service, 0);
 
index 2d6ebcc0536aa76ce55827cd797b993257094d1f..57474c2c207df0f2c25effbae8bbc34a972f9abf 100755 (executable)
 #IdleTimeout=0
 
 # Enable HID protocol handling in userspace input profile
-# Defaults to true (Use UHID instead of kernel HIDP)
+# Possible values:
+#  - persist: Use UHID in persistent mode (keyboard only)
+#  - true: Use UHID instead
+#  - false: User kernel HIDP
+# Defaults to true
 #UserspaceHID=true
 
 # Limit HID connections to bonded devices
index 3f2937e63a1669d93b9ad37bf75c91aaab8a17c5..b703b377f12109b4703387b1569e8d1a606335f8 100755 (executable)
@@ -114,10 +114,10 @@ static int input_init(void)
        config = load_config_file(CONFIGDIR "/input.conf");
        if (config) {
                int idle_timeout;
-#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
-               gboolean uhid_enabled, classic_bonded_only;
-#else
-               gboolean uhid_enabled, classic_bonded_only, auto_sec;
+               char *uhid_enabled;
+               gboolean classic_bonded_only;
+#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
+               gboolean auto_sec;
 #endif
                idle_timeout = g_key_file_get_integer(config, "General",
                                                        "IdleTimeout", &err);
@@ -127,12 +127,12 @@ static int input_init(void)
                } else
                        g_clear_error(&err);
 
-               uhid_enabled = g_key_file_get_boolean(config, "General",
+               uhid_enabled = g_key_file_get_string(config, "General",
                                                        "UserspaceHID", &err);
                if (!err) {
-                       DBG("input.conf: UserspaceHID=%s", uhid_enabled ?
-                                                       "true" : "false");
-                       input_enable_userspace_hid(uhid_enabled);
+                       DBG("input.conf: UserspaceHID=%s", uhid_enabled);
+                       input_set_userspace_hid(uhid_enabled);
+                       free(uhid_enabled);
                } else
                        g_clear_error(&err);