1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2010 Nokia Corporation 6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include <config.h> 27 #endif 28 29 #include <glib.h> 30 #include <dbus/dbus.h> 31 32 #include "adapter.h" 33 #include "plugin.h" 34 #include "log.h" 35 #include "gdbus.h" 36 37 /* from mce/mode-names.h */ 38 #define MCE_RADIO_STATE_BLUETOOTH (1 << 3) 39 40 /* from mce/dbus-names.h */ 41 #define MCE_SERVICE "com.nokia.mce" 42 #define MCE_REQUEST_IF "com.nokia.mce.request" 43 #define MCE_SIGNAL_IF "com.nokia.mce.signal" 44 #define MCE_REQUEST_PATH "/com/nokia/mce/request" 45 #define MCE_SIGNAL_PATH "/com/nokia/mce/signal" 46 #define MCE_RADIO_STATES_GET "get_radio_states" 47 #define MCE_RADIO_STATES_SIG "radio_states_ind" 48 49 static guint watch_id; 50 static DBusConnection *conn = NULL; 51 52 static gboolean mce_signal_callback(DBusConnection *connection, 53 DBusMessage *message, void *user_data) 54 { 55 DBusMessageIter args; 56 uint32_t sigvalue; 57 struct btd_adapter *adapter = user_data; 58 59 DBG("received mce signal"); 60 61 if (!dbus_message_iter_init(message, &args)) 62 error("message has no arguments"); 63 else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)) 64 error("argument is not uint32"); 65 else { 66 dbus_message_iter_get_basic(&args, &sigvalue); 67 DBG("got signal with value %u", sigvalue); 68 69 if (sigvalue & MCE_RADIO_STATE_BLUETOOTH) 70 btd_adapter_switch_online(adapter); 71 else 72 btd_adapter_switch_offline(adapter); 73 } 74 75 return TRUE; 76 } 77 78 static void read_radio_states_cb(DBusPendingCall *call, void *user_data) 79 { 80 DBusError err; 81 DBusMessage *reply; 82 dbus_uint32_t radio_states; 83 struct btd_adapter *adapter = user_data; 84 85 reply = dbus_pending_call_steal_reply(call); 86 87 dbus_error_init(&err); 88 if (dbus_set_error_from_message(&err, reply)) { 89 error("mce replied with an error: %s, %s", 90 err.name, err.message); 91 dbus_error_free(&err); 92 goto done; 93 } 94 95 dbus_error_init(&err); 96 if (dbus_message_get_args(reply, &err, 97 DBUS_TYPE_UINT32, &radio_states, 98 DBUS_TYPE_INVALID) == FALSE) { 99 error("unable to parse get_radio_states reply: %s, %s", 100 err.name, err.message); 101 dbus_error_free(&err); 102 goto done; 103 } 104 105 if (radio_states & MCE_RADIO_STATE_BLUETOOTH) 106 btd_adapter_switch_online(adapter); 107 108 done: 109 dbus_message_unref(reply); 110 } 111 112 static int mce_probe(struct btd_adapter *adapter) 113 { 114 DBusMessage *msg; 115 DBusPendingCall *call; 116 117 DBG("path %s", adapter_get_path(adapter)); 118 119 msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH, 120 MCE_REQUEST_IF, MCE_RADIO_STATES_GET); 121 122 if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) { 123 error("calling %s failed", MCE_RADIO_STATES_GET); 124 dbus_message_unref(msg); 125 return -1; 126 } 127 128 dbus_pending_call_set_notify(call, read_radio_states_cb, adapter, NULL); 129 dbus_pending_call_unref(call); 130 dbus_message_unref(msg); 131 132 watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH, 133 MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG, 134 mce_signal_callback, adapter, NULL); 135 return 0; 136 } 137 138 static void mce_remove(struct btd_adapter *adapter) 139 { 140 DBG("path %s", adapter_get_path(adapter)); 141 142 if (watch_id > 0) 143 g_dbus_remove_watch(conn, watch_id); 144 } 145 146 static struct btd_adapter_driver mce_driver = { 147 .name = "mce", 148 .probe = mce_probe, 149 .remove = mce_remove, 150 }; 151 152 static int maemo6_init(void) 153 { 154 DBG("init maemo6 plugin"); 155 156 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); 157 if (conn == NULL) { 158 error("Unable to connect to D-Bus"); 159 return -1; 160 } 161 162 return btd_register_adapter_driver(&mce_driver); 163 } 164 165 static void maemo6_exit(void) 166 { 167 DBG("exit maemo6 plugin"); 168 169 if (conn != NULL) 170 dbus_connection_unref(conn); 171 172 btd_unregister_adapter_driver(&mce_driver); 173 } 174 175 BLUETOOTH_PLUGIN_DEFINE(maemo6, VERSION, 176 BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, maemo6_init, maemo6_exit) 177