[gnome-settings-daemon/benzea/rfkill-gudev: 61/61] rfkill: Use GUdev to monitor rfkill device presence



commit 0ea06c8ea96d79e6adf7ffd4720f2b055fc8f479
Author: Benjamin Berg <bberg redhat com>
Date:   Tue Aug 28 13:05:59 2018 +0200

    rfkill: Use GUdev to monitor rfkill device presence
    
    This adds the required code to use GUdev to monitor for the existence of
    the rfkill device. This is relevant as the rfkill device might not exist
    initially if the rfkill module is not loaded during login.
    
    Fixes issue #52

 meson.build                  |  1 +
 plugins/rfkill/meson.build   |  7 +++-
 plugins/rfkill/rfkill-glib.c | 99 ++++++++++++++++++++++++++++++++++++++------
 3 files changed, 94 insertions(+), 13 deletions(-)
---
diff --git a/meson.build b/meson.build
index c94c4f85..7510f816 100644
--- a/meson.build
+++ b/meson.build
@@ -182,6 +182,7 @@ enable_rfkill = get_option('rfkill')
 assert(enable_rfkill or not host_is_linux, 'rfkill is not optional on Linux platforms')
 if enable_rfkill
   assert(cc.has_header('linux/rfkill.h'), 'rfkill support requested but RFKill headers not found')
+  assert(enable_gudev, 'GUdev is required for rfkill support')
 
   udev_dir = get_option('udev_dir')
   if udev_dir == ''
diff --git a/plugins/rfkill/meson.build b/plugins/rfkill/meson.build
index b85620b4..4d70352a 100644
--- a/plugins/rfkill/meson.build
+++ b/plugins/rfkill/meson.build
@@ -9,7 +9,12 @@ sources = files(
   'main.c'
 )
 
-deps = plugins_deps + [gio_unix_dep]
+deps = plugins_deps
+deps += [
+  gio_unix_dep,
+  gudev_dep,
+  m_dep
+]
 
 executable(
   'gsd-' + plugin_name,
diff --git a/plugins/rfkill/rfkill-glib.c b/plugins/rfkill/rfkill-glib.c
index 9862105e..38500ae9 100644
--- a/plugins/rfkill/rfkill-glib.c
+++ b/plugins/rfkill/rfkill-glib.c
@@ -38,6 +38,7 @@
 #include <gio/gunixoutputstream.h>
 
 #include "rfkill-glib.h"
+#include <gudev/gudev.h>
 
 enum {
        CHANGED,
@@ -53,11 +54,15 @@ static int signals[LAST_SIGNAL] = { 0 };
 struct _CcRfkillGlib {
        GObject parent;
 
+       GUdevClient *udev;
+       gchar *device_file;
+
        GOutputStream *stream;
        GIOChannel *channel;
        guint watch_id;
 
        /* rfkill-input inhibitor */
+       gboolean noinput;
        int noinput_fd;
 
        /* Pending Bluetooth enablement.
@@ -374,12 +379,13 @@ event_cb (GIOChannel   *source,
 static void
 cc_rfkill_glib_init (CcRfkillGlib *rfkill)
 {
+       rfkill->device_file = NULL;
        rfkill->noinput_fd = -1;
 }
 
-gboolean
-cc_rfkill_glib_open (CcRfkillGlib  *rfkill,
-                     GError       **error)
+static gboolean
+_cc_rfkill_glib_open (CcRfkillGlib  *rfkill,
+                      GError       **error)
 {
        int fd;
        int ret;
@@ -387,8 +393,10 @@ cc_rfkill_glib_open (CcRfkillGlib  *rfkill,
 
        g_return_val_if_fail (CC_RFKILL_IS_GLIB (rfkill), FALSE);
        g_return_val_if_fail (rfkill->stream == NULL, FALSE);
+       g_assert (rfkill->device_file);
+
+       fd = open(rfkill->device_file, O_RDWR);
 
-       fd = open("/dev/rfkill", O_RDWR);
        if (fd < 0) {
                g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
                                     "Could not open RFKILL control device, please verify your installation");
@@ -455,6 +463,60 @@ cc_rfkill_glib_open (CcRfkillGlib  *rfkill,
        return TRUE;
 }
 
+static void
+uevent_cb (GUdevClient *client,
+           gchar       *action,
+           GUdevDevice *device,
+           gpointer     user_data)
+{
+       CcRfkillGlib  *rfkill = CC_RFKILL_GLIB (user_data);
+
+       if (g_strcmp0 (action, "add") != 0)
+               return;
+
+       if (g_strcmp0 (g_udev_device_get_name (device), "rfkill") == 0) {
+               g_autoptr(GError) error = NULL;
+
+               g_debug ("Rfkill device has been created");
+
+               if (g_udev_device_get_device_file (device)) {
+                       g_clear_pointer (&rfkill->device_file, g_free);
+                       rfkill->device_file = g_strdup (g_udev_device_get_device_file (device));
+               } else {
+                       g_warning ("rfkill udev device does not have a device file!");
+               }
+
+               if (!_cc_rfkill_glib_open (rfkill, &error))
+                       g_warning ("Could not open rfkill device: %s", error->message);
+               else
+                       g_debug ("Opened rfkill device after uevent");
+
+               g_clear_object (&rfkill->udev);
+
+               /* Sync rfkill input inhibition state*/
+               cc_rfkill_glib_set_rfkill_input_inhibited (rfkill, rfkill->noinput);
+       }
+}
+
+gboolean
+cc_rfkill_glib_open (CcRfkillGlib  *rfkill,
+                     GError       **error)
+{
+       const char * const subsystems[] = { "misc", NULL };
+       GUdevDevice *device;
+
+       rfkill->udev = g_udev_client_new (subsystems);
+       g_debug ("Setting up uevent listener");
+       g_signal_connect (rfkill->udev, "uevent", G_CALLBACK (uevent_cb), rfkill);
+
+       /* Simulate uevent if device already exists. */
+       device = g_udev_client_query_by_subsystem_and_name (rfkill->udev, "misc", "rfkill");
+       if (device)
+               uevent_cb (rfkill->udev, "add", device, rfkill);
+
+       return TRUE;
+}
+
 #define RFKILL_INPUT_INHIBITED(rfkill) (rfkill->noinput_fd >= 0)
 
 gboolean
@@ -462,7 +524,7 @@ cc_rfkill_glib_get_rfkill_input_inhibited (CcRfkillGlib        *rfkill)
 {
        g_return_val_if_fail (CC_RFKILL_IS_GLIB (rfkill), FALSE);
 
-       return RFKILL_INPUT_INHIBITED(rfkill);
+       return rfkill->noinput;
 }
 
 void
@@ -471,21 +533,28 @@ cc_rfkill_glib_set_rfkill_input_inhibited (CcRfkillGlib *rfkill,
 {
        g_return_if_fail (CC_RFKILL_IS_GLIB (rfkill));
 
-       /* Nothing to do if the states already match. */
-       if (RFKILL_INPUT_INHIBITED(rfkill) == inhibit)
+       /* Shortcut in case we don't have an rfkill device */
+       if (!rfkill->stream) {
+               if (rfkill->noinput == inhibit)
+                       return;
+
+               rfkill->noinput = inhibit;
+               g_object_notify (G_OBJECT (rfkill), "rfkill-input-inhibited");
+
                return;
+       }
 
        if (!inhibit && RFKILL_INPUT_INHIBITED(rfkill)) {
                close (rfkill->noinput_fd);
-               rfkill->noinput_fd = -1;
-
                g_debug ("Closed rfkill noinput FD.");
+
+               rfkill->noinput_fd = -1;
        }
 
        if (inhibit && !RFKILL_INPUT_INHIBITED(rfkill)) {
                int fd, res;
                /* Open write only as we don't want to do any IO to it ever. */
-               fd = open ("/dev/rfkill", O_WRONLY);
+               fd = open (rfkill->device_file, O_WRONLY);
                if (fd < 0) {
                        if (errno == EACCES)
                                g_warning ("Could not open RFKILL control device, please verify your 
installation");
@@ -506,7 +575,10 @@ cc_rfkill_glib_set_rfkill_input_inhibited (CcRfkillGlib *rfkill,
                rfkill->noinput_fd = fd;
        }
 
-       g_object_notify (G_OBJECT (rfkill), "rfkill-input-inhibited");
+       if (rfkill->noinput != RFKILL_INPUT_INHIBITED(rfkill)) {
+               rfkill->noinput = RFKILL_INPUT_INHIBITED(rfkill);
+               g_object_notify (G_OBJECT (rfkill), "rfkill-input-inhibited");
+       }
 }
 
 static void
@@ -537,7 +609,7 @@ cc_rfkill_glib_get_property (GObject    *object,
 
        switch (prop_id) {
        case PROP_RFKILL_INPUT_INHIBITED:
-               g_value_set_boolean (value, RFKILL_INPUT_INHIBITED(rfkill));
+               g_value_set_boolean (value, rfkill->noinput);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -566,6 +638,9 @@ cc_rfkill_glib_finalize (GObject *object)
                rfkill->noinput_fd = -1;
        }
 
+       g_clear_pointer (&rfkill->device_file, g_free);
+       g_clear_object (&rfkill->udev);
+
        G_OBJECT_CLASS(cc_rfkill_glib_parent_class)->finalize(object);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]