Fix the bug : TIVI-204 Fail to connect to bluetooth network
[profile/ivi/bluez.git] / plugins / maemo6.c
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@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_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"
50
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;
56
57 static gboolean mce_tklock_mode_cb(DBusConnection *connection,
58                                         DBusMessage *message, void *user_data)
59 {
60         struct btd_adapter *adapter = user_data;
61         DBusMessageIter args;
62         const char *sigvalue;
63
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");
68         } else {
69
70                 dbus_message_iter_get_basic(&args, &sigvalue);
71                 DBG("got signal with value %s", sigvalue);
72
73                 if (g_strcmp0("unlocked", sigvalue) == 0 && mce_bt_on)
74                         btd_adapter_enable_auto_connect(adapter);
75         }
76
77         return TRUE;
78 }
79
80 static gboolean mce_signal_callback(DBusConnection *connection,
81                                         DBusMessage *message, void *user_data)
82 {
83         DBusMessageIter args;
84         uint32_t sigvalue;
85         struct btd_adapter *adapter = user_data;
86         int err;
87
88         DBG("received mce signal");
89
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");
94         else {
95                 dbus_message_iter_get_basic(&args, &sigvalue);
96                 DBG("got signal with value %u", sigvalue);
97
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;
101
102                 if (mce_bt_on)
103                         err = btd_adapter_switch_online(adapter);
104                 else
105                         err = btd_adapter_switch_offline(adapter);
106
107                 if (err == 0)
108                         mce_bt_set = TRUE;
109
110         }
111
112         return TRUE;
113 }
114
115 static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
116 {
117         DBusError derr;
118         DBusMessage *reply;
119         dbus_uint32_t radio_states;
120         struct btd_adapter *adapter = user_data;
121         int err;
122
123         reply = dbus_pending_call_steal_reply(call);
124
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);
130                 goto done;
131         }
132
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);
139                 goto done;
140         }
141
142         DBG("radio_states: %d", radio_states);
143
144         mce_bt_on = radio_states & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
145
146         if (mce_bt_on)
147                 err = btd_adapter_switch_online(adapter);
148         else
149                 err = btd_adapter_switch_offline(adapter);
150
151         if (err == 0)
152                 mce_bt_set = TRUE;
153
154 done:
155         dbus_message_unref(reply);
156 }
157
158 static void adapter_powered(struct btd_adapter *adapter, gboolean powered)
159 {
160         DBusMessage *msg;
161         static gboolean startup = TRUE;
162
163         DBG("adapter_powered called with %d", powered);
164
165         if (startup) {
166                 DBusPendingCall *call;
167
168                 /* Initialization: sync adapter state and MCE radio state */
169
170                 DBG("Startup: reading MCE Bluetooth radio state...");
171                 startup = FALSE;
172
173                 msg = dbus_message_new_method_call(MCE_SERVICE,
174                                         MCE_REQUEST_PATH, MCE_REQUEST_IF,
175                                         MCE_RADIO_STATES_GET);
176
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);
180                         return;
181                 }
182
183                 dbus_pending_call_set_notify(call, read_radio_states_cb,
184                                                                 adapter, NULL);
185                 dbus_pending_call_unref(call);
186                 dbus_message_unref(msg);
187                 return;
188         }
189
190         /* MCE initiated operation */
191         if (mce_bt_set == TRUE) {
192                 mce_bt_set = FALSE;
193                 return;
194         }
195
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;
200
201                 msg = dbus_message_new_method_call(MCE_SERVICE,
202                                         MCE_REQUEST_PATH, MCE_REQUEST_IF,
203                                         MCE_RADIO_STATES_CHANGE_REQ);
204
205                 radio_states = (powered ? MCE_RADIO_STATE_BLUETOOTH : 0);
206
207                 DBG("Changing MCE Bluetooth radio state to: %d", radio_states);
208
209                 dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states,
210                                         DBUS_TYPE_UINT32, &radio_mask,
211                                         DBUS_TYPE_INVALID);
212
213                 if (dbus_connection_send(conn, msg, NULL))
214                         mce_bt_on = powered;
215                 else
216                         error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ);
217
218                 dbus_message_unref(msg);
219         }
220 }
221
222 static int mce_probe(struct btd_adapter *adapter)
223 {
224
225         DBG("path %s", adapter_get_path(adapter));
226
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);
230
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);
234
235         btd_adapter_register_powered_callback(adapter, adapter_powered);
236
237         return 0;
238 }
239
240 static void mce_remove(struct btd_adapter *adapter)
241 {
242         DBG("path %s", adapter_get_path(adapter));
243
244         if (watch_id > 0)
245                 g_dbus_remove_watch(conn, watch_id);
246
247         if (tklock_watch_id > 0)
248                 g_dbus_remove_watch(conn, tklock_watch_id);
249
250         btd_adapter_unregister_powered_callback(adapter, adapter_powered);
251 }
252
253 static struct btd_adapter_driver mce_driver = {
254         .name   = "mce",
255         .probe  = mce_probe,
256         .remove = mce_remove,
257 };
258
259 static int maemo6_init(void)
260 {
261         DBG("init maemo6 plugin");
262
263         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
264         if (conn == NULL) {
265                 error("Unable to connect to D-Bus");
266                 return -1;
267         }
268
269         return btd_register_adapter_driver(&mce_driver);
270 }
271
272 static void maemo6_exit(void)
273 {
274         DBG("exit maemo6 plugin");
275
276         if (conn != NULL)
277                 dbus_connection_unref(conn);
278
279         btd_unregister_adapter_driver(&mce_driver);
280 }
281
282 BLUETOOTH_PLUGIN_DEFINE(maemo6, VERSION,
283                 BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, maemo6_init, maemo6_exit)