bluez/0001-Add-rfkill-plugin.patch
2009-07-29 13:57:54 +00:00

292 lines
7.0 KiB
Diff

From bf8b7c07542bd7acb4f9f98ba2165475f0ad9d65 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Tue, 28 Jul 2009 17:25:34 +0100
Subject: [PATCH] Add rfkill plugin
The plugin allows us to restore the previous power state on
adapters when the killswitch on them has been unblocked.
---
plugins/Makefile.am | 3 +
plugins/rfkill.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/adapter.c | 23 ++++--
src/adapter.h | 1 +
4 files changed, 219 insertions(+), 7 deletions(-)
create mode 100644 plugins/rfkill.c
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 9d9f970..9ba8180 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -15,6 +15,9 @@ endif
builtin_modules += hciops
builtin_sources += hciops.c
+builtin_modules += rfkill
+builtin_sources += rfkill.c
+
if NETLINK
plugin_LTLIBRARIES += netlink.la
netlink_la_LIBADD = @NETLINK_LIBS@
diff --git a/plugins/rfkill.c b/plugins/rfkill.c
new file mode 100644
index 0000000..fad8b47
--- /dev/null
+++ b/plugins/rfkill.c
@@ -0,0 +1,199 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * Author:
+ * Bastien Nocera <bnocera@redhat.com>, based on code by
+ * Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include "hcid.h"
+#include "plugin.h"
+#include "logging.h"
+
+#include "manager.h"
+#include "adapter.h"
+#include "device.h"
+
+enum rfkill_type {
+ RFKILL_TYPE_ALL = 0,
+ RFKILL_TYPE_WLAN,
+ RFKILL_TYPE_BLUETOOTH,
+ RFKILL_TYPE_UWB,
+ RFKILL_TYPE_WIMAX,
+ RFKILL_TYPE_WWAN,
+};
+
+enum rfkill_operation {
+ RFKILL_OP_ADD = 0,
+ RFKILL_OP_DEL,
+ RFKILL_OP_CHANGE,
+ RFKILL_OP_CHANGE_ALL,
+};
+
+struct rfkill_event {
+ uint32_t idx;
+ uint8_t type;
+ uint8_t op;
+ uint8_t soft;
+ uint8_t hard;
+};
+
+static char *get_name(__u32 idx)
+{
+ char *filename, *name, *pos;
+
+ filename = g_strdup_printf("/sys/class/rfkill/rfkill%u/name", idx);
+ if (g_file_get_contents(filename, &name, NULL, NULL) == FALSE) {
+ g_free(filename);
+ return NULL;
+ }
+
+ g_free(filename);
+
+ pos = strchr(name, '\n');
+ if (pos)
+ *pos = '\0';
+
+ return name;
+}
+
+static gboolean rfkill_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ unsigned char buf[32];
+ struct rfkill_event *event = (void *) buf;
+ char *sysname;
+ gboolean blocked;
+ gsize len;
+ GIOError err;
+
+ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ memset(buf, 0, sizeof(buf));
+
+ err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
+ if (err) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+ return FALSE;
+ }
+
+ if (len != sizeof(struct rfkill_event))
+ return TRUE;
+
+ debug("idx %u type %u op %u soft %u hard %u",
+ event->idx, event->type, event->op,
+ event->soft, event->hard);
+
+ blocked = (event->soft || event->hard) ? TRUE : FALSE;
+ /* We already disable devices correctly when rfkilled */
+ if (blocked)
+ return TRUE;
+
+ sysname = get_name(event->idx);
+ if (sysname == NULL)
+ return TRUE;
+ if (g_str_has_prefix(sysname, "hci") == FALSE) {
+ debug("Ignoring unblocked killswitch '%s'", sysname);
+ g_free(sysname);
+ return TRUE;
+ }
+
+ switch (event->type) {
+ case RFKILL_TYPE_ALL:
+ case RFKILL_TYPE_BLUETOOTH: {
+ struct btd_adapter *adapter;
+ int id;
+
+ id = atoi(sysname + strlen("hci"));
+ adapter = manager_find_adapter_by_id(id);
+ if (adapter)
+ adapter_set_powered(adapter, TRUE);
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_free(sysname);
+
+ return TRUE;
+}
+
+static GIOChannel *channel = NULL;
+
+static int rfkill_init(void)
+{
+ int fd;
+
+ debug("Init rfkill plugin");
+
+ if (main_opts.remember_powered == FALSE)
+ return 0;
+
+ fd = open("/dev/rfkill", O_RDWR);
+ if (fd < 0) {
+ debug("No rfkill support in the kernel");
+ return -EIO;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ rfkill_event, NULL);
+
+ return 0;
+}
+
+static void rfkill_exit(void)
+{
+ debug("Cleanup rfkill plugin");
+
+ if (channel == NULL)
+ return;
+
+ g_io_channel_shutdown(channel, TRUE, NULL);
+ g_io_channel_unref(channel);
+
+ channel = NULL;
+}
+
+BLUETOOTH_PLUGIN_DEFINE(rfkill, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, rfkill_init, rfkill_exit)
diff --git a/src/adapter.c b/src/adapter.c
index 06640e7..06c3018 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -483,21 +483,30 @@ done:
return 0;
}
-static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
- gboolean powered, void *data)
+int adapter_set_powered(struct btd_adapter *adapter, gboolean powered)
{
- struct btd_adapter *adapter = data;
uint8_t mode;
- int err;
mode = powered ? get_mode(&adapter->bdaddr, "on") : MODE_OFF;
if (mode == adapter->mode)
- return dbus_message_new_method_return(msg);
+ return -EALREADY;
- err = set_mode(adapter, mode);
- if (err < 0)
+ return set_mode(adapter, mode);
+}
+
+static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
+ gboolean powered, void *data)
+{
+ struct btd_adapter *adapter = data;
+ int err;
+
+ err = adapter_set_powered(adapter, powered);
+ if (err < 0) {
+ if (err == -EALREADY)
+ return dbus_message_new_method_return(msg);
return failed_strerror(msg, -err);
+ }
return dbus_message_new_method_return(msg);
}
diff --git a/src/adapter.h b/src/adapter.h
index d34fb80..fa02d5d 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -110,6 +110,7 @@ void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
void adapter_set_state(struct btd_adapter *adapter, int state);
int adapter_get_state(struct btd_adapter *adapter);
gboolean adapter_is_ready(struct btd_adapter *adapter);
+int adapter_set_powered(struct btd_adapter *adapter, gboolean powered);
struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
struct remote_dev_info *match);
void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
--
1.6.2.5