summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-07-29 21:44:31 +0200
committerMarcel Holtmann <marcel@holtmann.org>2009-07-29 21:44:31 +0200
commit2163c034c59269f9a63b1f9ff2a17ce9a1f2ede6 (patch)
tree70b423d3572dc688cee3215513239cde0d0d0a3b /src
parent270b9869e7792fabd061b85345fc62140e01a11f (diff)
Add skeleton for RFKILL support
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/hcid.h3
-rw-r--r--src/main.c4
-rw-r--r--src/rfkill.c170
4 files changed, 178 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 9e72bf0f..569c060e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,7 +17,7 @@ sbin_PROGRAMS = bluetoothd
bluetoothd_SOURCES = main.c security.c hcid.h sdpd.h \
sdpd-server.c sdpd-request.c sdpd-service.c sdpd-database.c \
- plugin.h plugin.c storage.h storage.c agent.h agent.c \
+ plugin.h plugin.c storage.h storage.c agent.h agent.c rfkill.c \
error.h error.c manager.h manager.c adapter.h adapter.c \
device.h device.c dbus-common.c dbus-common.h dbus-hci.h dbus-hci.c
diff --git a/src/hcid.h b/src/hcid.h
index 605dc06a..2f072598 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -93,5 +93,8 @@ void set_pin_length(bdaddr_t *sba, int length);
gboolean plugin_init(GKeyFile *config);
void plugin_cleanup(void);
+void rfkill_init(void);
+void rfkill_exit(void);
+
void __probe_servers(const char *adapter);
void __remove_servers(const char *adapter);
diff --git a/src/main.c b/src/main.c
index e8b39a76..c76678cc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -431,6 +431,8 @@ int main(int argc, char *argv[])
exit(1);
}
+ rfkill_init();
+
manager_update_svc(BDADDR_ANY, 0);
debug("Entering main loop");
@@ -441,6 +443,8 @@ int main(int argc, char *argv[])
hcid_dbus_exit();
+ rfkill_exit();
+
plugin_cleanup();
stop_sdp_server();
diff --git a/src/rfkill.c b/src/rfkill.c
new file mode 100644
index 00000000..065c024c
--- /dev/null
+++ b/src/rfkill.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "manager.h"
+#include "adapter.h"
+#include "hcid.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 gboolean rfkill_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ unsigned char buf[32];
+ struct rfkill_event *event = (void *) buf;
+ struct btd_adapter *adapter;
+ char sysname[PATH_MAX];
+ gsize len;
+ GIOError err;
+ int fd, id;
+
+ 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("RFKILL event idx %u type %u op %u soft %u hard %u",
+ event->idx, event->type, event->op,
+ event->soft, event->hard);
+
+ if (event->soft || event->hard)
+ return TRUE;
+
+ if (event->op != RFKILL_OP_CHANGE)
+ return TRUE;
+
+ if (event->type != RFKILL_TYPE_BLUETOOTH &&
+ event->type != RFKILL_TYPE_ALL)
+ return TRUE;
+
+ snprintf(sysname, sizeof(sysname) - 1,
+ "/sys/class/rfkill/rfkill%u/name", event->idx);
+
+ fd = open(sysname, O_RDONLY);
+ if (fd < 0)
+ return TRUE;
+
+ memset(sysname, 0, sizeof(sysname));
+
+ if (read(fd, sysname, sizeof(sysname)) < 4) {
+ close(fd);
+ return TRUE;
+ }
+
+ close(fd);
+
+ if (g_str_has_prefix(sysname, "hci") == FALSE)
+ return TRUE;
+
+ id = atoi(sysname + 3);
+ if (id < 0)
+ return TRUE;
+
+ adapter = manager_find_adapter_by_id(id);
+ if (!adapter)
+ return TRUE;
+
+ debug("RFKILL unblock for hci%d", id);
+
+ return TRUE;
+}
+
+static GIOChannel *channel = NULL;
+
+void rfkill_init(void)
+{
+ int fd;
+
+ if (!main_opts.remember_powered)
+ return;
+
+ fd = open("/dev/rfkill", O_RDWR);
+ if (fd < 0) {
+ error("Failed to open RFKILL control device");
+ return;
+ }
+
+ 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);
+}
+
+void rfkill_exit(void)
+{
+ if (!channel)
+ return;
+
+ g_io_channel_shutdown(channel, TRUE, NULL);
+ g_io_channel_unref(channel);
+
+ channel = NULL;
+}