input/device: Send UHID_DESTROY upon disconnection
authorArchie Pusaka <apusaka@chromium.org>
Mon, 3 Aug 2020 06:52:24 +0000 (14:52 +0800)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 12 Apr 2021 09:00:50 +0000 (14:30 +0530)
According to the uhid documentation: "If your device disconnects,
you should send an UHID_DESTROY event"

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
profiles/input/device.c

index 94dba27..dd57b76 100644 (file)
@@ -119,6 +119,7 @@ bool input_get_classic_bonded_only(void)
 
 static void input_device_enter_reconnect_mode(struct input_device *idev);
 static int connection_disconnect(struct input_device *idev, uint32_t flags);
+static int uhid_disconnect(struct input_device *idev);
 
 static bool input_device_bonded(struct input_device *idev)
 {
@@ -400,6 +401,10 @@ static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data
        if (!idev->ctrl_io && idev->virtual_cable_unplug)
                virtual_cable_unplug(idev);
 
+       /* If connection abruptly ended, uhid might be not yet disconnected */
+       if (idev->uhid_created)
+               uhid_disconnect(idev);
+
        return FALSE;
 }
 
@@ -976,6 +981,28 @@ static int uhid_connadd(struct input_device *idev, struct hidp_connadd_req *req)
        return err;
 }
 
+static int uhid_disconnect(struct input_device *idev)
+{
+       int err;
+       struct uhid_event ev;
+
+       if (!idev->uhid_created)
+               return 0;
+
+       memset(&ev, 0, sizeof(ev));
+       ev.type = UHID_DESTROY;
+
+       err = bt_uhid_send(idev->uhid, &ev);
+       if (err < 0) {
+               error("bt_uhid_send: %s", strerror(-err));
+               return err;
+       }
+
+       idev->uhid_created = false;
+
+       return err;
+}
+
 static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition,
                                                                gpointer data)
 {
@@ -1150,7 +1177,7 @@ static int connection_disconnect(struct input_device *idev, uint32_t flags)
                idev->virtual_cable_unplug = true;
 
        if (idev->uhid)
-               return 0;
+               return uhid_disconnect(idev);
        else
                return ioctl_disconnect(idev, flags);
 }