[gnome-bluetooth] Bug 585765 – Move killswitch code to /dev/rfkill
- From: Bastien Nocera <hadess src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-bluetooth] Bug 585765 – Move killswitch code to /dev/rfkill
- Date: Thu, 30 Jul 2009 19:54:00 +0000 (UTC)
commit 822c0ba3d02183cbac571dcc01f1b234d355c851
Author: Bastien Nocera <hadess hadess net>
Date: Thu Jul 30 20:47:15 2009 +0100
Bug 585765 â?? Move killswitch code to /dev/rfkill
Port the killswitch code to using rfkill sub-system in newer
kernels.
Note that your distribution will need to ship udev rules
to allow normal users to change the killswitch state.
applet/main.c | 14 +-
configure.ac | 3 +-
lib/bluetooth-killswitch.c | 443 ++++++++++++++++++--------------------------
lib/bluetooth-killswitch.h | 7 +-
4 files changed, 197 insertions(+), 270 deletions(-)
---
diff --git a/applet/main.c b/applet/main.c
index e9b077d..c3875af 100644
--- a/applet/main.c
+++ b/applet/main.c
@@ -274,11 +274,7 @@ killswitch_state_changed (BluetoothKillswitch *killswitch, KillswitchState state
gboolean bstate = FALSE;
const char *label, *status_label;
- if (state == KILLSWITCH_STATE_UNKNOWN || state == KILLSWITCH_STATE_MIXED) {
- sensitive = FALSE;
- label = NULL;
- status_label = N_("Bluetooth: Unknown");
- } else if (state == KILLSWITCH_STATE_SOFT_BLOCKED) {
+ if (state == KILLSWITCH_STATE_SOFT_BLOCKED) {
label = N_("Turn On Bluetooth");
status_label = N_("Bluetooth: Off");
bstate = FALSE;
@@ -286,6 +282,10 @@ killswitch_state_changed (BluetoothKillswitch *killswitch, KillswitchState state
label = N_("Turn Off Bluetooth");
status_label = N_("Bluetooth: On");
bstate = TRUE;
+ } else if (state == KILLSWITCH_STATE_HARD_BLOCKED) {
+ sensitive = FALSE;
+ label = NULL;
+ status_label = N_("Bluetooth: Disabled");
} else {
g_assert_not_reached ();
}
@@ -1011,6 +1011,10 @@ int main(int argc, char *argv[])
G_CALLBACK (device_changed), NULL);
/* Set the default */
device_changed (devices_model, NULL, NULL, NULL);
+ if (killswitch != NULL) {
+ killswitch_state_changed (killswitch,
+ bluetooth_killswitch_get_state (killswitch));
+ }
gconf = gconf_client_get_default();
diff --git a/configure.ac b/configure.ac
index f3c42b9..bf8b52b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -107,8 +107,7 @@ dnl Requires for the private library
PKG_CHECK_MODULES(COMMON,
dbus-glib-1 >= $DBUS_GLIB_REQUIRED
gmodule-2.0
- gtk+-2.0
- hal >= $HAL_REQUIRED)
+ gtk+-2.0)
dnl Requires for the geoclue plugin
PKG_CHECK_MODULES(GEOCLUE,
diff --git a/lib/bluetooth-killswitch.c b/lib/bluetooth-killswitch.c
index aca3aa5..a4beeae 100644
--- a/lib/bluetooth-killswitch.c
+++ b/lib/bluetooth-killswitch.c
@@ -26,8 +26,20 @@
#include <config.h>
#endif
-#include <dbus/dbus-glib-lowlevel.h>
-#include <hal/libhal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "rfkill.h"
+
+#ifndef RFKILL_EVENT_SIZE_V1
+#define RFKILL_EVENT_SIZE_V1 8
+#endif
#include "bluetooth-killswitch.h"
@@ -43,237 +55,116 @@ static int signals[LAST_SIGNAL] = { 0 };
typedef struct _BluetoothIndKillswitch BluetoothIndKillswitch;
struct _BluetoothIndKillswitch {
- char *udi;
- DBusPendingCall *call;
- KillswitchState state, target_state;
+ guint index;
+ KillswitchState state;
};
-typedef struct _BluetoothKillswitchPrivate BluetoothKillswitchPrivate;
struct _BluetoothKillswitchPrivate {
- LibHalContext *halctx;
- DBusConnection *connection;
- guint num_remaining_answers;
+ int fd;
+ GIOChannel *channel;
GList *killswitches; /* a GList of BluetoothIndKillswitch */
+ BluetoothKillswitchPrivate *priv;
};
G_DEFINE_TYPE(BluetoothKillswitch, bluetooth_killswitch, G_TYPE_OBJECT)
-static int
-power_to_state (int power)
+static KillswitchState
+event_to_state (guint soft, guint hard)
{
- switch (power) {
- case 1: /* RFKILL_STATE_UNBLOCKED */
- return KILLSWITCH_STATE_UNBLOCKED;
- case 0: /* RFKILL_STATE_SOFT_BLOCKED */
- case 2: /* RFKILL_STATE_HARD_BLOCKED */
+ if (hard)
+ return KILLSWITCH_STATE_HARD_BLOCKED;
+ else if (soft)
return KILLSWITCH_STATE_SOFT_BLOCKED;
- default:
- g_warning ("Unknown power state %d, please file a bug at "PACKAGE_BUGREPORT, power);
- return KILLSWITCH_STATE_UNKNOWN;
- }
+ else
+ return KILLSWITCH_STATE_UNBLOCKED;
}
static void
-setpower_reply (DBusPendingCall *call, void *user_data)
+update_killswitch (BluetoothKillswitch *killswitch,
+ guint index, guint soft, guint hard)
{
- BluetoothKillswitch *killswitch = BLUETOOTH_KILLSWITCH (user_data);
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
- DBusMessage *reply;
- gint32 retval;
GList *l;
+ gboolean changed = FALSE;
- priv->num_remaining_answers--;
-
- reply = dbus_pending_call_steal_reply(call);
-
- if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &retval,
- DBUS_TYPE_INVALID) == FALSE) {
- dbus_message_unref(reply);
- goto done;
- }
-
- /* Look for the killswitch */
- for (l = priv->killswitches; l ; l = l->next) {
+ for (l = priv->killswitches; l != NULL; l = l->next) {
BluetoothIndKillswitch *ind = l->data;
- if (call != ind->call)
- continue;
- ind->call = NULL;
- if (retval == 0)
- ind->state = ind->target_state;
- break;
- }
-
- dbus_message_unref(reply);
- dbus_pending_call_unref (call);
-done:
- if (priv->num_remaining_answers == 0)
- g_signal_emit (G_OBJECT (killswitch),
- signals[STATE_CHANGED],
- 0, bluetooth_killswitch_get_state (killswitch));
-}
-
-static void
-getpower_reply (DBusPendingCall *call, void *user_data)
-{
- BluetoothKillswitch *killswitch = BLUETOOTH_KILLSWITCH (user_data);
- BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
- DBusMessage *reply;
- GList *l;
- gint32 power;
-
- priv->num_remaining_answers--;
-
- reply = dbus_pending_call_steal_reply (call);
-
- if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &power,
- DBUS_TYPE_INVALID) == FALSE) {
- dbus_message_unref(reply);
- goto done;
- }
-
- /* Look for the killswitch */
- for (l = priv->killswitches; l ; l = l->next) {
- BluetoothIndKillswitch *ind = l->data;
- if (call != ind->call)
- continue;
- ind->state = power_to_state (power);
- ind->call = NULL;
- break;
+ if (ind->index == index) {
+ KillswitchState state = event_to_state (soft, hard);
+ if (state != ind->state) {
+ ind->state = state;
+ changed = TRUE;
+ }
+ break;
+ }
}
- dbus_message_unref(reply);
- dbus_pending_call_unref (call);
-
-done:
- if (priv->num_remaining_answers == 0)
+ if (changed != FALSE) {
+ g_message ("updating killswitch status %d", index);
g_signal_emit (G_OBJECT (killswitch),
signals[STATE_CHANGED],
0, bluetooth_killswitch_get_state (killswitch));
-}
-
-void
-bluetooth_killswitch_update_state (BluetoothKillswitch *killswitch)
-{
- BluetoothKillswitchPrivate *priv;
- GList *l;
-
- g_return_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch));
-
- priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
-
- if (priv->num_remaining_answers > 0)
- return;
-
- for (l = priv->killswitches ; l ; l = l->next) {
- BluetoothIndKillswitch *ind = l->data;
- DBusPendingCall *call;
- DBusMessage *message;
-
- /* Already checking status */
- if (ind->call != NULL)
- continue;
-
- message = dbus_message_new_method_call ("org.freedesktop.Hal",
- ind->udi,
- "org.freedesktop.Hal.Device.KillSwitch",
- "GetPower");
-
- if (message == NULL)
- continue;
-
- if (dbus_connection_send_with_reply (priv->connection, message, &call, -1) == FALSE) {
- dbus_message_unref(message);
- continue;
- }
-
- priv->num_remaining_answers++;
- dbus_pending_call_set_notify (call, getpower_reply, killswitch, NULL);
-
- dbus_message_unref (message);
}
}
void
-bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch, KillswitchState state)
+bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch,
+ KillswitchState state)
{
- BluetoothKillswitchPrivate *priv;
- gboolean value;
- GList *l;
-
- g_return_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch));
- g_return_if_fail (state == KILLSWITCH_STATE_SOFT_BLOCKED || state == KILLSWITCH_STATE_UNBLOCKED);
-
- priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
-
- if (priv->num_remaining_answers > 0)
- return;
-
- value = (state == KILLSWITCH_STATE_UNBLOCKED);
-
- for (l = priv->killswitches ; l ; l = l->next) {
- BluetoothIndKillswitch *ind = l->data;
- DBusPendingCall *call;
- DBusMessage *message;
-
- message = dbus_message_new_method_call("org.freedesktop.Hal",
- ind->udi,
- "org.freedesktop.Hal.Device.KillSwitch",
- "SetPower");
- if (message == NULL)
- return;
-
- dbus_message_append_args(message,
- DBUS_TYPE_BOOLEAN, &value,
- DBUS_TYPE_INVALID);
-
- if (dbus_connection_send_with_reply(priv->connection, message,
- &call, -1) == FALSE) {
- dbus_message_unref(message);
- return;
- }
-
- ind->call = call;
- ind->target_state = state;
- priv->num_remaining_answers++;
-
- dbus_pending_call_set_notify(call, setpower_reply, killswitch, NULL);
-
- dbus_message_unref(message);
- }
+ BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
+ struct rfkill_event event;
+ ssize_t len;
+
+ g_return_if_fail (state != KILLSWITCH_STATE_HARD_BLOCKED);
+
+ memset (&event, 0, sizeof(event));
+ event.op = RFKILL_OP_CHANGE_ALL;
+ event.type = RFKILL_TYPE_BLUETOOTH;
+ if (state == KILLSWITCH_STATE_SOFT_BLOCKED)
+ event.soft = 1;
+ else if (state == KILLSWITCH_STATE_UNBLOCKED)
+ event.soft = 0;
+ else
+ g_assert_not_reached ();
+
+ len = write (priv->fd, &event, sizeof(event));
+ if (len < 0)
+ g_warning ("Failed to change RFKILL state: %s",
+ g_strerror (errno));
}
KillswitchState
bluetooth_killswitch_get_state (BluetoothKillswitch *killswitch)
{
BluetoothKillswitchPrivate *priv;
- int state = KILLSWITCH_STATE_UNKNOWN;
+ int state = KILLSWITCH_STATE_UNBLOCKED;
GList *l;
- g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), KILLSWITCH_STATE_UNKNOWN);
+ g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), state);
priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
- if (priv->connection == NULL)
- return KILLSWITCH_STATE_UNKNOWN;
for (l = priv->killswitches ; l ; l = l->next) {
BluetoothIndKillswitch *ind = l->data;
+ g_message ("killswitch %d is %d",
+ ind->index, ind->state);
+
+ if (ind->state == KILLSWITCH_STATE_HARD_BLOCKED) {
+ state = KILLSWITCH_STATE_HARD_BLOCKED;
+ break;
+ }
+
if (ind->state == KILLSWITCH_STATE_SOFT_BLOCKED) {
- if (state == KILLSWITCH_STATE_UNKNOWN)
- state = KILLSWITCH_STATE_SOFT_BLOCKED;
- if (state != KILLSWITCH_STATE_SOFT_BLOCKED)
- state = KILLSWITCH_STATE_MIXED;
- } else {
- if (state == KILLSWITCH_STATE_UNKNOWN)
- state = KILLSWITCH_STATE_UNBLOCKED;
- if (state != KILLSWITCH_STATE_UNBLOCKED)
- state = KILLSWITCH_STATE_MIXED;
+ state = KILLSWITCH_STATE_SOFT_BLOCKED;
+ continue;
}
+
+ state = ind->state;
}
- if (state == KILLSWITCH_STATE_UNKNOWN)
- return KILLSWITCH_STATE_UNKNOWN;
+ g_message ("killswitches state %d", state);
return state;
}
@@ -289,97 +180,142 @@ bluetooth_killswitch_has_killswitches (BluetoothKillswitch *killswitch)
}
static void
-add_killswitch (BluetoothKillswitch *killswitch, const char *udi)
+remove_killswitch (BluetoothKillswitch *killswitch,
+ guint index)
{
- BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
- DBusPendingCall *call;
- DBusMessage *message;
- BluetoothIndKillswitch *ind;
- char *type;
+ BluetoothKillswitchPrivate *priv = killswitch->priv;
+ GList *l;
- type = libhal_device_get_property_string (priv->halctx,
- udi,
- "killswitch.type",
- NULL);
- if (type == NULL || g_str_equal(type, "bluetooth") == FALSE) {
- g_free (type);
- return;
+ for (l = priv->killswitches; l != NULL; l = l->next) {
+ BluetoothIndKillswitch *ind = l->data;
+ if (ind->index == index) {
+ priv->killswitches = g_list_remove (priv->killswitches, ind);
+ g_message ("removing killswitch idx %d", index);
+ return;
+ }
}
- g_free (type);
-
- message = dbus_message_new_method_call ("org.freedesktop.Hal",
- udi,
- "org.freedesktop.Hal.Device.KillSwitch",
- "GetPower");
+}
- if (message == NULL)
- return;
+static void
+add_killswitch (BluetoothKillswitch *killswitch,
+ guint index,
+ KillswitchState state)
- if (dbus_connection_send_with_reply (priv->connection, message, &call, -1) == FALSE) {
- dbus_message_unref(message);
- return;
- }
+{
+ BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
+ BluetoothIndKillswitch *ind;
+ g_message ("adding killswitch idx %d state %d", index, state);
ind = g_new0 (BluetoothIndKillswitch, 1);
- ind->udi = g_strdup (udi);
- ind->call = call;
+ ind->index = index;
+ ind->state = state;
priv->killswitches = g_list_append (priv->killswitches, ind);
- priv->num_remaining_answers++;
+}
- dbus_pending_call_set_notify (call, getpower_reply, killswitch, NULL);
+static gboolean
+event_cb (GIOChannel *source,
+ GIOCondition condition,
+ BluetoothKillswitch *killswitch)
+{
+ if (condition & G_IO_IN) {
+ GIOStatus status;
+ struct rfkill_event event;
+
+ status = g_io_channel_read_chars (source,
+ (char *) &event,
+ sizeof(event),
+ NULL,
+ NULL);
+ if (status == G_IO_STATUS_NORMAL) {
+ g_message ("RFKILL event: idx %u type %u op %u soft %u hard %u\n",
+ event.idx, event.type, event.op,
+ event.soft, event.hard);
+
+ if (event.type != RFKILL_TYPE_BLUETOOTH &&
+ event.type != RFKILL_TYPE_ALL)
+ return TRUE;
+
+ if (event.op == RFKILL_OP_CHANGE) {
+ update_killswitch (killswitch, event.idx, event.soft, event.hard);
+ } else if (event.op == RFKILL_OP_DEL) {
+ remove_killswitch (killswitch, event.idx);
+ } else if (event.op == RFKILL_OP_ADD) {
+ KillswitchState state;
+ state = event_to_state (event.soft, event.hard);
+ add_killswitch (killswitch, event.idx, state);
+ }
+
+ g_signal_emit (G_OBJECT (killswitch),
+ signals[STATE_CHANGED],
+ 0, bluetooth_killswitch_get_state (killswitch));
+ }
+ } else {
+ g_message ("something else happened");
+ return FALSE;
+ }
- dbus_message_unref (message);
+ return TRUE;
}
static void
bluetooth_killswitch_init (BluetoothKillswitch *killswitch)
{
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
- char **list;
- int num;
+ struct rfkill_event event;
+ int fd;
- priv->connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
- if (priv->connection == NULL)
- return;
+ killswitch->priv = priv;
- priv->halctx = libhal_ctx_new();
- if (priv->halctx == NULL) {
- dbus_connection_unref (priv->connection);
+ fd = open("/dev/rfkill", O_RDWR);
+ if (fd < 0) {
+ if (errno == EACCES)
+ g_warning ("Could not open RFKILL control device, please verify your installation");
return;
}
- if (libhal_ctx_set_dbus_connection(priv->halctx, priv->connection) == FALSE) {
- libhal_ctx_free(priv->halctx);
- dbus_connection_unref (priv->connection);
- priv->halctx = NULL;
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ g_message ("Can't set RFKILL control device to non-blocking");
+ close(fd);
return;
}
- if (libhal_ctx_init(priv->halctx, NULL) == FALSE) {
- g_printerr("Couldn't init HAL context\n");
- dbus_connection_unref (priv->connection);
- libhal_ctx_free(priv->halctx);
- priv->halctx = NULL;
- return;
- }
+ while (1) {
+ KillswitchState state;
+ ssize_t len;
- list = libhal_find_device_by_capability(priv->halctx, "killswitch", &num, NULL);
- if (list) {
- char **tmp = list;
+ len = read(fd, &event, sizeof(event));
+ if (len < 0) {
+ if (errno == -G_IO_ERROR_AGAIN)
+ break;
+ g_message ("Reading of RFKILL events failed");
+ break;
+ }
- while (*tmp) {
- add_killswitch (killswitch, *tmp);
- tmp++;
+ if (len != RFKILL_EVENT_SIZE_V1) {
+ g_warning("Wrong size of RFKILL event\n");
+ continue;
}
- libhal_free_string_array (list);
+ if (event.op != RFKILL_OP_ADD)
+ continue;
+ if (event.type != RFKILL_TYPE_BLUETOOTH)
+ continue;
+ state = event_to_state (event.soft, event.hard);
+
+ add_killswitch (killswitch, event.idx, state);
}
-}
-static void
-free_ind_killswitch (BluetoothIndKillswitch *ind)
-{
- g_free (ind->udi);
+ /* Setup monitoring */
+ priv->fd = fd;
+ priv->channel = g_io_channel_unix_new (priv->fd);
+ g_io_add_watch (priv->channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR,
+ (GIOFunc) event_cb,
+ killswitch);
+
+ g_signal_emit (G_OBJECT (killswitch),
+ signals[STATE_CHANGED],
+ 0, bluetooth_killswitch_get_state (killswitch));
}
static void
@@ -387,18 +323,7 @@ bluetooth_killswitch_finalize (GObject *object)
{
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (object);
- if (priv->halctx != NULL) {
- libhal_ctx_shutdown(priv->halctx, NULL);
- libhal_ctx_free(priv->halctx);
- priv->halctx = NULL;
- }
-
- if (priv->connection != NULL) {
- dbus_connection_unref(priv->connection);
- priv->connection = NULL;
- }
-
- g_list_foreach (priv->killswitches, (GFunc) free_ind_killswitch, NULL);
+ g_list_foreach (priv->killswitches, (GFunc) g_free, NULL);
g_list_free (priv->killswitches);
priv->killswitches = NULL;
diff --git a/lib/bluetooth-killswitch.h b/lib/bluetooth-killswitch.h
index 75f791a..a8927c9 100644
--- a/lib/bluetooth-killswitch.h
+++ b/lib/bluetooth-killswitch.h
@@ -30,10 +30,9 @@
G_BEGIN_DECLS
typedef enum {
- KILLSWITCH_STATE_UNKNOWN = -1,
KILLSWITCH_STATE_SOFT_BLOCKED = 0,
KILLSWITCH_STATE_UNBLOCKED,
- KILLSWITCH_STATE_MIXED,
+ KILLSWITCH_STATE_HARD_BLOCKED
} KillswitchState;
#define BLUETOOTH_TYPE_KILLSWITCH (bluetooth_killswitch_get_type())
@@ -50,9 +49,11 @@ typedef enum {
typedef struct _BluetoothKillswitch BluetoothKillswitch;
typedef struct _BluetoothKillswitchClass BluetoothKillswitchClass;
+typedef struct _BluetoothKillswitchPrivate BluetoothKillswitchPrivate;
struct _BluetoothKillswitch {
GObject parent;
+ BluetoothKillswitchPrivate *priv;
};
struct _BluetoothKillswitchClass {
@@ -66,8 +67,6 @@ GType bluetooth_killswitch_get_type(void);
BluetoothKillswitch * bluetooth_killswitch_new (void);
gboolean bluetooth_killswitch_has_killswitches (BluetoothKillswitch *killswitch);
-
-void bluetooth_killswitch_update_state (BluetoothKillswitch *killswitch);
void bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch, KillswitchState state);
KillswitchState bluetooth_killswitch_get_state (BluetoothKillswitch *killswitch);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]