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_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
mce_signal_callback(DBusConnection * connection,DBusMessage * message,void * user_data)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
read_radio_states_cb(DBusPendingCall * call,void * user_data)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
mce_probe(struct btd_adapter * adapter)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
mce_remove(struct btd_adapter * adapter)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
maemo6_init(void)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
maemo6_exit(void)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