• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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