From 799757ccf1d03c33c75bc597cd5ef77741dcb6a7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 3 Jun 2011 09:17:04 +0000 Subject: Imported upstream 4.91 --- plugins/maemo6.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 plugins/maemo6.c (limited to 'plugins/maemo6.c') diff --git a/plugins/maemo6.c b/plugins/maemo6.c new file mode 100644 index 0000000..56f2664 --- /dev/null +++ b/plugins/maemo6.c @@ -0,0 +1,252 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2006-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * + * + * 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 +#endif + +#include +#include + +#include "adapter.h" +#include "plugin.h" +#include "log.h" +#include "gdbus.h" + +/* from mce/mode-names.h */ +#define MCE_RADIO_STATE_BLUETOOTH (1 << 3) + +/* from mce/dbus-names.h */ +#define MCE_SERVICE "com.nokia.mce" +#define MCE_REQUEST_IF "com.nokia.mce.request" +#define MCE_SIGNAL_IF "com.nokia.mce.signal" +#define MCE_REQUEST_PATH "/com/nokia/mce/request" +#define MCE_SIGNAL_PATH "/com/nokia/mce/signal" +#define MCE_RADIO_STATES_CHANGE_REQ "req_radio_states_change" +#define MCE_RADIO_STATES_GET "get_radio_states" +#define MCE_RADIO_STATES_SIG "radio_states_ind" + +static guint watch_id; +static DBusConnection *conn = NULL; +static gboolean mce_bt_set = FALSE; +static gboolean collision = FALSE; + +static gboolean mce_signal_callback(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter args; + uint32_t sigvalue; + struct btd_adapter *adapter = user_data; + + DBG("received mce signal"); + + if (!dbus_message_iter_init(message, &args)) + error("message has no arguments"); + else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)) + error("argument is not uint32"); + else { + dbus_message_iter_get_basic(&args, &sigvalue); + DBG("got signal with value %u", sigvalue); + + /* set the adapter according to the mce signal + and remember the value */ + mce_bt_set = sigvalue & MCE_RADIO_STATE_BLUETOOTH ? + TRUE : FALSE; + + if (mce_bt_set) + btd_adapter_switch_online(adapter); + else + btd_adapter_switch_offline(adapter); + } + + return TRUE; +} + +static void read_radio_states_cb(DBusPendingCall *call, void *user_data) +{ + DBusError err; + DBusMessage *reply; + dbus_uint32_t radio_states; + struct btd_adapter *adapter = user_data; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&err); + if (dbus_set_error_from_message(&err, reply)) { + error("mce replied with an error: %s, %s", + err.name, err.message); + dbus_error_free(&err); + goto done; + } + + dbus_error_init(&err); + if (dbus_message_get_args(reply, &err, + DBUS_TYPE_UINT32, &radio_states, + DBUS_TYPE_INVALID) == FALSE) { + error("unable to parse get_radio_states reply: %s, %s", + err.name, err.message); + dbus_error_free(&err); + goto done; + } + + DBG("radio_states: %d", radio_states); + + mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE; + + /* check if the adapter has not completed the initial power + * cycle, if so delay action to mce_notify_powered */ + collision = mce_bt_set && adapter_powering_down(adapter); + + if (collision) + goto done; + + if (mce_bt_set) + btd_adapter_switch_online(adapter); + else + btd_adapter_switch_offline(adapter); + +done: + dbus_message_unref(reply); +} + +static void adapter_powered(struct btd_adapter *adapter, gboolean powered) +{ + DBusMessage *msg; + dbus_uint32_t radio_states = 0; + dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH; + static gboolean startup = TRUE; + + DBG("adapter_powered called with %d", powered); + + if (startup) { + startup = FALSE; + return; + } + + /* check if the plugin got the get_radio_states reply from the + * mce when the adapter was not yet down during the power + * cycling when bluetoothd is started */ + if (collision) { + error("maemo6: powered state collision"); + collision = FALSE; + + if (mce_bt_set) + btd_adapter_switch_online(adapter); + + return; + } + + /* nothing to do if the states match */ + if (mce_bt_set == powered) + return; + + /* set the mce value according to the state of the adapter */ + msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH, + MCE_REQUEST_IF, MCE_RADIO_STATES_CHANGE_REQ); + + if (powered) + radio_states = MCE_RADIO_STATE_BLUETOOTH; + + dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states, + DBUS_TYPE_UINT32, &radio_mask, + DBUS_TYPE_INVALID); + + if (dbus_connection_send(conn, msg, NULL)) + mce_bt_set = powered; + else + error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ); + + dbus_message_unref(msg); +} + +static int mce_probe(struct btd_adapter *adapter) +{ + DBusMessage *msg; + DBusPendingCall *call; + + DBG("path %s", adapter_get_path(adapter)); + + msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH, + MCE_REQUEST_IF, MCE_RADIO_STATES_GET); + + if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) { + error("calling %s failed", MCE_RADIO_STATES_GET); + dbus_message_unref(msg); + return -1; + } + + dbus_pending_call_set_notify(call, read_radio_states_cb, adapter, NULL); + dbus_pending_call_unref(call); + dbus_message_unref(msg); + + watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH, + MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG, + mce_signal_callback, adapter, NULL); + + btd_adapter_register_powered_callback(adapter, adapter_powered); + + return 0; +} + +static void mce_remove(struct btd_adapter *adapter) +{ + DBG("path %s", adapter_get_path(adapter)); + + if (watch_id > 0) + g_dbus_remove_watch(conn, watch_id); + + btd_adapter_unregister_powered_callback(adapter, adapter_powered); +} + +static struct btd_adapter_driver mce_driver = { + .name = "mce", + .probe = mce_probe, + .remove = mce_remove, +}; + +static int maemo6_init(void) +{ + DBG("init maemo6 plugin"); + + conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (conn == NULL) { + error("Unable to connect to D-Bus"); + return -1; + } + + return btd_register_adapter_driver(&mce_driver); +} + +static void maemo6_exit(void) +{ + DBG("exit maemo6 plugin"); + + if (conn != NULL) + dbus_connection_unref(conn); + + btd_unregister_adapter_driver(&mce_driver); +} + +BLUETOOTH_PLUGIN_DEFINE(maemo6, VERSION, + BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, maemo6_init, maemo6_exit) -- cgit v1.2.3