Home | History | Annotate | Download | only in plugins
      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