3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2006-2010 Nokia Corporation
6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
30 #include <dbus/dbus.h>
37 /* from mce/mode-names.h */
38 #define MCE_RADIO_STATE_BLUETOOTH (1 << 3)
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_CHANGE_REQ "req_radio_states_change"
47 #define MCE_RADIO_STATES_GET "get_radio_states"
48 #define MCE_RADIO_STATES_SIG "radio_states_ind"
49 #define MCE_TKLOCK_MODE_SIG "tklock_mode_ind"
51 static guint watch_id;
52 static guint tklock_watch_id;
53 static DBusConnection *conn = NULL;
54 static gboolean mce_bt_set = FALSE;
55 static gboolean mce_bt_on = FALSE;
57 static gboolean mce_tklock_mode_cb(DBusConnection *connection,
58 DBusMessage *message, void *user_data)
60 struct btd_adapter *adapter = user_data;
64 if (!dbus_message_iter_init(message, &args)) {
65 error("message has no arguments");
66 } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
67 error("argument is not string");
70 dbus_message_iter_get_basic(&args, &sigvalue);
71 DBG("got signal with value %s", sigvalue);
73 if (g_strcmp0("unlocked", sigvalue) == 0 && mce_bt_on)
74 btd_adapter_enable_auto_connect(adapter);
80 static gboolean mce_signal_callback(DBusConnection *connection,
81 DBusMessage *message, void *user_data)
85 struct btd_adapter *adapter = user_data;
88 DBG("received mce signal");
90 if (!dbus_message_iter_init(message, &args))
91 error("message has no arguments");
92 else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
93 error("argument is not uint32");
95 dbus_message_iter_get_basic(&args, &sigvalue);
96 DBG("got signal with value %u", sigvalue);
98 /* set the adapter according to the mce signal
99 and remember the value */
100 mce_bt_on = sigvalue & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
103 err = btd_adapter_switch_online(adapter);
105 err = btd_adapter_switch_offline(adapter);
115 static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
119 dbus_uint32_t radio_states;
120 struct btd_adapter *adapter = user_data;
123 reply = dbus_pending_call_steal_reply(call);
125 dbus_error_init(&derr);
126 if (dbus_set_error_from_message(&derr, reply)) {
127 error("mce replied with an error: %s, %s",
128 derr.name, derr.message);
129 dbus_error_free(&derr);
133 if (dbus_message_get_args(reply, &derr,
134 DBUS_TYPE_UINT32, &radio_states,
135 DBUS_TYPE_INVALID) == FALSE) {
136 error("unable to parse get_radio_states reply: %s, %s",
137 derr.name, derr.message);
138 dbus_error_free(&derr);
142 DBG("radio_states: %d", radio_states);
144 mce_bt_on = radio_states & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
147 err = btd_adapter_switch_online(adapter);
149 err = btd_adapter_switch_offline(adapter);
155 dbus_message_unref(reply);
158 static void adapter_powered(struct btd_adapter *adapter, gboolean powered)
161 static gboolean startup = TRUE;
163 DBG("adapter_powered called with %d", powered);
166 DBusPendingCall *call;
168 /* Initialization: sync adapter state and MCE radio state */
170 DBG("Startup: reading MCE Bluetooth radio state...");
173 msg = dbus_message_new_method_call(MCE_SERVICE,
174 MCE_REQUEST_PATH, MCE_REQUEST_IF,
175 MCE_RADIO_STATES_GET);
177 if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) {
178 error("calling %s failed", MCE_RADIO_STATES_GET);
179 dbus_message_unref(msg);
183 dbus_pending_call_set_notify(call, read_radio_states_cb,
185 dbus_pending_call_unref(call);
186 dbus_message_unref(msg);
190 /* MCE initiated operation */
191 if (mce_bt_set == TRUE) {
196 /* Non MCE operation: set MCE according to adapter state */
197 if (mce_bt_on != powered) {
198 dbus_uint32_t radio_states;
199 dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH;
201 msg = dbus_message_new_method_call(MCE_SERVICE,
202 MCE_REQUEST_PATH, MCE_REQUEST_IF,
203 MCE_RADIO_STATES_CHANGE_REQ);
205 radio_states = (powered ? MCE_RADIO_STATE_BLUETOOTH : 0);
207 DBG("Changing MCE Bluetooth radio state to: %d", radio_states);
209 dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states,
210 DBUS_TYPE_UINT32, &radio_mask,
213 if (dbus_connection_send(conn, msg, NULL))
216 error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ);
218 dbus_message_unref(msg);
222 static int mce_probe(struct btd_adapter *adapter)
225 DBG("path %s", adapter_get_path(adapter));
227 watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
228 MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG,
229 mce_signal_callback, adapter, NULL);
231 tklock_watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
232 MCE_SIGNAL_IF, MCE_TKLOCK_MODE_SIG,
233 mce_tklock_mode_cb, adapter, NULL);
235 btd_adapter_register_powered_callback(adapter, adapter_powered);
240 static void mce_remove(struct btd_adapter *adapter)
242 DBG("path %s", adapter_get_path(adapter));
245 g_dbus_remove_watch(conn, watch_id);
247 if (tklock_watch_id > 0)
248 g_dbus_remove_watch(conn, tklock_watch_id);
250 btd_adapter_unregister_powered_callback(adapter, adapter_powered);
253 static struct btd_adapter_driver mce_driver = {
256 .remove = mce_remove,
259 static int maemo6_init(void)
261 DBG("init maemo6 plugin");
263 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
265 error("Unable to connect to D-Bus");
269 return btd_register_adapter_driver(&mce_driver);
272 static void maemo6_exit(void)
274 DBG("exit maemo6 plugin");
277 dbus_connection_unref(conn);
279 btd_unregister_adapter_driver(&mce_driver);
282 BLUETOOTH_PLUGIN_DEFINE(maemo6, VERSION,
283 BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, maemo6_init, maemo6_exit)