3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
6
* Copyright (C) 2006-2009 Bastien Nocera <hadess@hadess.net>
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
29
#include <dbus/dbus-glib-lowlevel.h>
30
#include <hal/libhal.h>
32
#include "bluetooth-killswitch.h"
39
static int signals[LAST_SIGNAL] = { 0 };
41
#define BLUETOOTH_KILLSWITCH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
42
BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitchPrivate))
44
typedef struct _BluetoothIndKillswitch BluetoothIndKillswitch;
45
struct _BluetoothIndKillswitch {
47
DBusPendingCall *call;
48
KillswitchState state, target_state;
51
typedef struct _BluetoothKillswitchPrivate BluetoothKillswitchPrivate;
52
struct _BluetoothKillswitchPrivate {
53
LibHalContext *halctx;
54
DBusConnection *connection;
55
guint num_remaining_answers;
56
GList *killswitches; /* a GList of BluetoothIndKillswitch */
59
G_DEFINE_TYPE(BluetoothKillswitch, bluetooth_killswitch, G_TYPE_OBJECT)
62
power_to_state (int power)
65
case 1: /* RFKILL_STATE_UNBLOCKED */
66
return KILLSWITCH_STATE_UNBLOCKED;
67
case 0: /* RFKILL_STATE_SOFT_BLOCKED */
68
case 2: /* RFKILL_STATE_HARD_BLOCKED */
69
return KILLSWITCH_STATE_SOFT_BLOCKED;
71
g_warning ("Unknown power state %d, please file a bug at "PACKAGE_BUGREPORT, power);
72
return KILLSWITCH_STATE_UNKNOWN;
77
setpower_reply (DBusPendingCall *call, void *user_data)
79
BluetoothKillswitch *killswitch = BLUETOOTH_KILLSWITCH (user_data);
80
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
85
priv->num_remaining_answers--;
87
reply = dbus_pending_call_steal_reply(call);
89
if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &retval,
90
DBUS_TYPE_INVALID) == FALSE) {
91
dbus_message_unref(reply);
95
/* Look for the killswitch */
96
for (l = priv->killswitches; l ; l = l->next) {
97
BluetoothIndKillswitch *ind = l->data;
98
if (call != ind->call)
102
ind->state = ind->target_state;
106
dbus_message_unref(reply);
107
dbus_pending_call_unref (call);
110
if (priv->num_remaining_answers == 0)
111
g_signal_emit (G_OBJECT (killswitch),
112
signals[STATE_CHANGED],
113
0, bluetooth_killswitch_get_state (killswitch));
117
getpower_reply (DBusPendingCall *call, void *user_data)
119
BluetoothKillswitch *killswitch = BLUETOOTH_KILLSWITCH (user_data);
120
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
125
priv->num_remaining_answers--;
127
reply = dbus_pending_call_steal_reply (call);
129
if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &power,
130
DBUS_TYPE_INVALID) == FALSE) {
131
dbus_message_unref(reply);
135
/* Look for the killswitch */
136
for (l = priv->killswitches; l ; l = l->next) {
137
BluetoothIndKillswitch *ind = l->data;
138
if (call != ind->call)
140
ind->state = power_to_state (power);
145
dbus_message_unref(reply);
146
dbus_pending_call_unref (call);
149
if (priv->num_remaining_answers == 0)
150
g_signal_emit (G_OBJECT (killswitch),
151
signals[STATE_CHANGED],
152
0, bluetooth_killswitch_get_state (killswitch));
156
bluetooth_killswitch_update_state (BluetoothKillswitch *killswitch)
158
BluetoothKillswitchPrivate *priv;
161
g_return_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch));
163
priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
165
if (priv->num_remaining_answers > 0)
168
for (l = priv->killswitches ; l ; l = l->next) {
169
BluetoothIndKillswitch *ind = l->data;
170
DBusPendingCall *call;
171
DBusMessage *message;
173
/* Already checking status */
174
if (ind->call != NULL)
177
message = dbus_message_new_method_call ("org.freedesktop.Hal",
179
"org.freedesktop.Hal.Device.KillSwitch",
185
if (dbus_connection_send_with_reply (priv->connection, message, &call, -1) == FALSE) {
186
dbus_message_unref(message);
190
priv->num_remaining_answers++;
191
dbus_pending_call_set_notify (call, getpower_reply, killswitch, NULL);
193
dbus_message_unref (message);
198
bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch, KillswitchState state)
200
BluetoothKillswitchPrivate *priv;
204
g_return_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch));
205
g_return_if_fail (state == KILLSWITCH_STATE_SOFT_BLOCKED || state == KILLSWITCH_STATE_UNBLOCKED);
207
priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
209
if (priv->num_remaining_answers > 0)
212
value = (state == KILLSWITCH_STATE_UNBLOCKED);
214
for (l = priv->killswitches ; l ; l = l->next) {
215
BluetoothIndKillswitch *ind = l->data;
216
DBusPendingCall *call;
217
DBusMessage *message;
219
message = dbus_message_new_method_call("org.freedesktop.Hal",
221
"org.freedesktop.Hal.Device.KillSwitch",
226
dbus_message_append_args(message,
227
DBUS_TYPE_BOOLEAN, &value,
230
if (dbus_connection_send_with_reply(priv->connection, message,
231
&call, -1) == FALSE) {
232
dbus_message_unref(message);
237
ind->target_state = state;
238
priv->num_remaining_answers++;
240
dbus_pending_call_set_notify(call, setpower_reply, killswitch, NULL);
242
dbus_message_unref(message);
247
bluetooth_killswitch_get_state (BluetoothKillswitch *killswitch)
249
BluetoothKillswitchPrivate *priv;
250
int state = KILLSWITCH_STATE_UNKNOWN;
253
g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), KILLSWITCH_STATE_UNKNOWN);
255
priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
256
if (priv->connection == NULL)
257
return KILLSWITCH_STATE_UNKNOWN;
259
for (l = priv->killswitches ; l ; l = l->next) {
260
BluetoothIndKillswitch *ind = l->data;
262
if (ind->state == KILLSWITCH_STATE_SOFT_BLOCKED) {
263
if (state == KILLSWITCH_STATE_UNKNOWN)
264
state = KILLSWITCH_STATE_SOFT_BLOCKED;
265
if (state != KILLSWITCH_STATE_SOFT_BLOCKED)
266
state = KILLSWITCH_STATE_MIXED;
268
if (state == KILLSWITCH_STATE_UNKNOWN)
269
state = KILLSWITCH_STATE_UNBLOCKED;
270
if (state != KILLSWITCH_STATE_UNBLOCKED)
271
state = KILLSWITCH_STATE_MIXED;
275
if (state == KILLSWITCH_STATE_UNKNOWN)
276
return KILLSWITCH_STATE_UNKNOWN;
282
bluetooth_killswitch_has_killswitches (BluetoothKillswitch *killswitch)
284
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
286
g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), FALSE);
288
return (priv->killswitches != NULL);
292
add_killswitch (BluetoothKillswitch *killswitch, const char *udi)
294
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
295
DBusPendingCall *call;
296
DBusMessage *message;
297
BluetoothIndKillswitch *ind;
300
type = libhal_device_get_property_string (priv->halctx,
304
if (type == NULL || g_str_equal(type, "bluetooth") == FALSE) {
310
message = dbus_message_new_method_call ("org.freedesktop.Hal",
312
"org.freedesktop.Hal.Device.KillSwitch",
318
if (dbus_connection_send_with_reply (priv->connection, message, &call, -1) == FALSE) {
319
dbus_message_unref(message);
323
ind = g_new0 (BluetoothIndKillswitch, 1);
324
ind->udi = g_strdup (udi);
326
priv->killswitches = g_list_append (priv->killswitches, ind);
327
priv->num_remaining_answers++;
329
dbus_pending_call_set_notify (call, getpower_reply, killswitch, NULL);
331
dbus_message_unref (message);
335
bluetooth_killswitch_init (BluetoothKillswitch *killswitch)
337
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
341
priv->connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
342
if (priv->connection == NULL)
345
priv->halctx = libhal_ctx_new();
346
if (priv->halctx == NULL) {
347
dbus_connection_unref (priv->connection);
351
if (libhal_ctx_set_dbus_connection(priv->halctx, priv->connection) == FALSE) {
352
libhal_ctx_free(priv->halctx);
353
dbus_connection_unref (priv->connection);
358
if (libhal_ctx_init(priv->halctx, NULL) == FALSE) {
359
g_printerr("Couldn't init HAL context\n");
360
dbus_connection_unref (priv->connection);
361
libhal_ctx_free(priv->halctx);
366
list = libhal_find_device_by_capability(priv->halctx, "killswitch", &num, NULL);
371
add_killswitch (killswitch, *tmp);
375
libhal_free_string_array (list);
380
free_ind_killswitch (BluetoothIndKillswitch *ind)
386
bluetooth_killswitch_finalize (GObject *object)
388
BluetoothKillswitchPrivate *priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (object);
390
if (priv->halctx != NULL) {
391
libhal_ctx_shutdown(priv->halctx, NULL);
392
libhal_ctx_free(priv->halctx);
396
if (priv->connection != NULL) {
397
dbus_connection_unref(priv->connection);
398
priv->connection = NULL;
401
g_list_foreach (priv->killswitches, (GFunc) free_ind_killswitch, NULL);
402
g_list_free (priv->killswitches);
403
priv->killswitches = NULL;
405
G_OBJECT_CLASS(bluetooth_killswitch_parent_class)->finalize(object);
409
bluetooth_killswitch_class_init(BluetoothKillswitchClass *klass)
411
GObjectClass *object_class = (GObjectClass *) klass;
413
g_type_class_add_private(klass, sizeof(BluetoothKillswitchPrivate));
414
object_class->finalize = bluetooth_killswitch_finalize;
416
signals[STATE_CHANGED] =
417
g_signal_new ("state-changed",
418
G_TYPE_FROM_CLASS (klass),
420
G_STRUCT_OFFSET (BluetoothKillswitchClass, state_changed),
422
g_cclosure_marshal_VOID__INT,
423
G_TYPE_NONE, 1, G_TYPE_INT);
427
BluetoothKillswitch *
428
bluetooth_killswitch_new (void)
430
return BLUETOOTH_KILLSWITCH(g_object_new (BLUETOOTH_TYPE_KILLSWITCH, NULL));