~morphis/ofono/ota9-suspend-fix

« back to all changes in this revision

Viewing changes to plugins/hfp_hf_bluez4.c

  • Committer: CI Train Bot
  • Author(s): Tony Espy
  • Date: 2015-09-11 13:56:28 UTC
  • mfrom: (6901.1.2 ofono-bzr)
  • Revision ID: ci-train-bot@canonical.com-20150911135628-edl4g206im8oeoph
New upstream release 1.16 ( built w/enable_bluez4 )

Approved by: Alfonso Sanchez-Beato, PS Jenkins bot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *  oFono - Open Source Telephony
 
4
 *
 
5
 *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
 
6
 *  Copyright (C) 2010  ProFUSION embedded systems
 
7
 *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
 
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 version 2 as
 
11
 *  published by the Free Software Foundation.
 
12
 *
 
13
 *  This program is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with this program; if not, write to the Free Software
 
20
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
21
 *
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif
 
27
#include <string.h>
 
28
#include <stdlib.h>
 
29
#include <stdio.h>
 
30
#include <errno.h>
 
31
#include <unistd.h>
 
32
#include <glib.h>
 
33
#include <gatchat.h>
 
34
#include <gattty.h>
 
35
#include <gdbus.h>
 
36
#include <ofono.h>
 
37
 
 
38
#define OFONO_API_SUBJECT_TO_CHANGE
 
39
#include <ofono/plugin.h>
 
40
#include <ofono/log.h>
 
41
#include <ofono/modem.h>
 
42
#include <ofono/devinfo.h>
 
43
#include <ofono/netreg.h>
 
44
#include <ofono/voicecall.h>
 
45
#include <ofono/call-volume.h>
 
46
#include <ofono/handsfree.h>
 
47
#include <ofono/siri.h>
 
48
 
 
49
#include <drivers/hfpmodem/slc.h>
 
50
 
 
51
#include "bluez4.h"
 
52
 
 
53
#define BLUEZ_GATEWAY_INTERFACE         BLUEZ_SERVICE ".HandsfreeGateway"
 
54
 
 
55
#define HFP_AGENT_INTERFACE "org.bluez.HandsfreeAgent"
 
56
#define HFP_AGENT_ERROR_INTERFACE "org.bluez.Error"
 
57
 
 
58
#ifndef DBUS_TYPE_UNIX_FD
 
59
#define DBUS_TYPE_UNIX_FD -1
 
60
#endif
 
61
 
 
62
static DBusConnection *connection;
 
63
static GHashTable *modem_hash = NULL;
 
64
 
 
65
struct hfp_data {
 
66
        struct hfp_slc_info info;
 
67
        char *handsfree_path;
 
68
        char *handsfree_address;
 
69
        DBusMessage *slc_msg;
 
70
        gboolean agent_registered;
 
71
        DBusPendingCall *call;
 
72
};
 
73
 
 
74
static void hfp_debug(const char *str, void *user_data)
 
75
{
 
76
        const char *prefix = user_data;
 
77
 
 
78
        ofono_info("%s%s", prefix, str);
 
79
}
 
80
 
 
81
static void slc_established(gpointer userdata)
 
82
{
 
83
        struct ofono_modem *modem = userdata;
 
84
        struct hfp_data *data = ofono_modem_get_data(modem);
 
85
        DBusMessage *msg;
 
86
 
 
87
        ofono_modem_set_powered(modem, TRUE);
 
88
 
 
89
        msg = dbus_message_new_method_return(data->slc_msg);
 
90
        g_dbus_send_message(connection, msg);
 
91
        dbus_message_unref(data->slc_msg);
 
92
        data->slc_msg = NULL;
 
93
 
 
94
        ofono_info("Service level connection established");
 
95
}
 
96
 
 
97
static void slc_failed(gpointer userdata)
 
98
{
 
99
        struct ofono_modem *modem = userdata;
 
100
        struct hfp_data *data = ofono_modem_get_data(modem);
 
101
        DBusMessage *msg;
 
102
 
 
103
        msg = g_dbus_create_error(data->slc_msg, HFP_AGENT_ERROR_INTERFACE
 
104
                                        ".Failed",
 
105
                                        "HFP Handshake failed");
 
106
        g_dbus_send_message(connection, msg);
 
107
        dbus_message_unref(data->slc_msg);
 
108
        data->slc_msg = NULL;
 
109
 
 
110
        ofono_error("Service level connection failed");
 
111
        ofono_modem_set_powered(modem, FALSE);
 
112
 
 
113
        g_at_chat_unref(data->info.chat);
 
114
        data->info.chat = NULL;
 
115
}
 
116
 
 
117
static void hfp_disconnected_cb(gpointer user_data)
 
118
{
 
119
        struct ofono_modem *modem = user_data;
 
120
        struct hfp_data *data = ofono_modem_get_data(modem);
 
121
 
 
122
        ofono_modem_set_powered(modem, FALSE);
 
123
 
 
124
        g_at_chat_unref(data->info.chat);
 
125
        data->info.chat = NULL;
 
126
}
 
127
 
 
128
/* either oFono or Phone could request SLC connection */
 
129
static int service_level_connection(struct ofono_modem *modem, int fd)
 
130
{
 
131
        struct hfp_data *data = ofono_modem_get_data(modem);
 
132
        GIOChannel *io;
 
133
        GAtSyntax *syntax;
 
134
        GAtChat *chat;
 
135
 
 
136
        io = g_io_channel_unix_new(fd);
 
137
        if (io == NULL) {
 
138
                ofono_error("Service level connection failed: %s (%d)",
 
139
                        strerror(errno), errno);
 
140
                return -EIO;
 
141
        }
 
142
 
 
143
        syntax = g_at_syntax_new_gsm_permissive();
 
144
        chat = g_at_chat_new(io, syntax);
 
145
        g_at_syntax_unref(syntax);
 
146
        g_io_channel_unref(io);
 
147
 
 
148
        if (chat == NULL)
 
149
                return -ENOMEM;
 
150
 
 
151
        g_at_chat_set_disconnect_function(chat, hfp_disconnected_cb, modem);
 
152
 
 
153
        if (getenv("OFONO_AT_DEBUG"))
 
154
                g_at_chat_set_debug(chat, hfp_debug, "");
 
155
 
 
156
        data->info.chat = chat;
 
157
        hfp_slc_establish(&data->info, slc_established, slc_failed, modem);
 
158
 
 
159
        return -EINPROGRESS;
 
160
}
 
161
 
 
162
static DBusMessage *hfp_agent_new_connection(DBusConnection *conn,
 
163
                                                DBusMessage *msg, void *data)
 
164
{
 
165
        int fd, err;
 
166
        struct ofono_modem *modem = data;
 
167
        struct hfp_data *hfp_data = ofono_modem_get_data(modem);
 
168
        guint16 version;
 
169
 
 
170
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UNIX_FD, &fd,
 
171
                                DBUS_TYPE_UINT16, &version, DBUS_TYPE_INVALID))
 
172
                return __ofono_error_invalid_args(msg);
 
173
 
 
174
        hfp_slc_info_init(&hfp_data->info, version);
 
175
 
 
176
        err = service_level_connection(modem, fd);
 
177
        if (err < 0 && err != -EINPROGRESS)
 
178
                return __ofono_error_failed(msg);
 
179
 
 
180
        hfp_data->slc_msg = msg;
 
181
        dbus_message_ref(msg);
 
182
 
 
183
        return NULL;
 
184
}
 
185
 
 
186
static DBusMessage *hfp_agent_release(DBusConnection *conn,
 
187
                                        DBusMessage *msg, void *data)
 
188
{
 
189
        struct ofono_modem *modem = data;
 
190
        struct hfp_data *hfp_data = ofono_modem_get_data(modem);
 
191
        const char *obj_path = ofono_modem_get_path(modem);
 
192
 
 
193
        g_dbus_unregister_interface(connection, obj_path, HFP_AGENT_INTERFACE);
 
194
        hfp_data->agent_registered = FALSE;
 
195
 
 
196
        g_hash_table_remove(modem_hash, hfp_data->handsfree_path);
 
197
        ofono_modem_remove(modem);
 
198
 
 
199
        return dbus_message_new_method_return(msg);
 
200
}
 
201
 
 
202
static const GDBusMethodTable agent_methods[] = {
 
203
        { GDBUS_ASYNC_METHOD("NewConnection",
 
204
                                GDBUS_ARGS({ "fd", "h" }, { "version", "q" }),
 
205
                                NULL, hfp_agent_new_connection) },
 
206
        { GDBUS_METHOD("Release", NULL, NULL, hfp_agent_release) },
 
207
        { }
 
208
};
 
209
 
 
210
static int hfp_hf_probe(const char *device, const char *dev_addr,
 
211
                                const char *adapter_addr, const char *alias)
 
212
{
 
213
        struct ofono_modem *modem;
 
214
        struct hfp_data *data;
 
215
        char buf[256];
 
216
 
 
217
        /* We already have this device in our hash, ignore */
 
218
        if (g_hash_table_lookup(modem_hash, device) != NULL)
 
219
                return -EALREADY;
 
220
 
 
221
        ofono_info("Using device: %s, devaddr: %s, adapter: %s",
 
222
                        device, dev_addr, adapter_addr);
 
223
 
 
224
        strcpy(buf, "hfp/");
 
225
        bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4);
 
226
 
 
227
        modem = ofono_modem_create(buf, "hfp");
 
228
        if (modem == NULL)
 
229
                return -ENOMEM;
 
230
 
 
231
        data = g_try_new0(struct hfp_data, 1);
 
232
        if (data == NULL)
 
233
                goto free;
 
234
 
 
235
        data->handsfree_path = g_strdup(device);
 
236
        if (data->handsfree_path == NULL)
 
237
                goto free;
 
238
 
 
239
        data->handsfree_address = g_strdup(dev_addr);
 
240
        if (data->handsfree_address == NULL)
 
241
                goto free;
 
242
 
 
243
        ofono_modem_set_data(modem, data);
 
244
        ofono_modem_set_name(modem, alias);
 
245
        ofono_modem_register(modem);
 
246
 
 
247
        g_hash_table_insert(modem_hash, g_strdup(device), modem);
 
248
 
 
249
        return 0;
 
250
 
 
251
free:
 
252
        if (data != NULL)
 
253
                g_free(data->handsfree_path);
 
254
 
 
255
        g_free(data);
 
256
        ofono_modem_remove(modem);
 
257
 
 
258
        return -ENOMEM;
 
259
}
 
260
 
 
261
static gboolean hfp_remove_modem(gpointer key, gpointer value,
 
262
                                        gpointer user_data)
 
263
{
 
264
        struct ofono_modem *modem = value;
 
265
        const char *device = key;
 
266
        const char *prefix = user_data;
 
267
 
 
268
        if (prefix && g_str_has_prefix(device, prefix) == FALSE)
 
269
                return FALSE;
 
270
 
 
271
        ofono_modem_remove(modem);
 
272
 
 
273
        return TRUE;
 
274
}
 
275
 
 
276
static void hfp_hf_remove(const char *prefix)
 
277
{
 
278
        DBG("%s", prefix);
 
279
 
 
280
        if (modem_hash == NULL)
 
281
                return;
 
282
 
 
283
        g_hash_table_foreach_remove(modem_hash, hfp_remove_modem,
 
284
                                                        (gpointer) prefix);
 
285
}
 
286
 
 
287
static void hfp_hf_set_alias(const char *device, const char *alias)
 
288
{
 
289
        struct ofono_modem *modem;
 
290
 
 
291
        if (device == NULL || alias == NULL)
 
292
                return;
 
293
 
 
294
        modem = g_hash_table_lookup(modem_hash, device);
 
295
        if (modem == NULL)
 
296
                return;
 
297
 
 
298
        ofono_modem_set_name(modem, alias);
 
299
}
 
300
 
 
301
static int hfp_register_ofono_handsfree(struct ofono_modem *modem)
 
302
{
 
303
        const char *obj_path = ofono_modem_get_path(modem);
 
304
        struct hfp_data *data = ofono_modem_get_data(modem);
 
305
        DBusMessage *msg;
 
306
 
 
307
        DBG("Registering oFono Agent to bluetooth daemon");
 
308
 
 
309
        msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path,
 
310
                                BLUEZ_GATEWAY_INTERFACE, "RegisterAgent");
 
311
        if (msg == NULL)
 
312
                return -ENOMEM;
 
313
 
 
314
        dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path,
 
315
                                DBUS_TYPE_INVALID);
 
316
 
 
317
        g_dbus_send_message(connection, msg);
 
318
        return 0;
 
319
}
 
320
 
 
321
static int hfp_unregister_ofono_handsfree(struct ofono_modem *modem)
 
322
{
 
323
        const char *obj_path = ofono_modem_get_path(modem);
 
324
        struct hfp_data *data = ofono_modem_get_data(modem);
 
325
        DBusMessage *msg;
 
326
 
 
327
        DBG("Unregistering oFono Agent from bluetooth daemon");
 
328
 
 
329
        msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path,
 
330
                                BLUEZ_GATEWAY_INTERFACE, "UnregisterAgent");
 
331
        if (msg == NULL)
 
332
                return -ENOMEM;
 
333
 
 
334
        dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path,
 
335
                                DBUS_TYPE_INVALID);
 
336
 
 
337
        g_dbus_send_message(connection, msg);
 
338
        return 0;
 
339
}
 
340
 
 
341
static int hfp_probe(struct ofono_modem *modem)
 
342
{
 
343
        const char *obj_path = ofono_modem_get_path(modem);
 
344
        struct hfp_data *data = ofono_modem_get_data(modem);
 
345
 
 
346
        if (data == NULL)
 
347
                return -EINVAL;
 
348
 
 
349
        g_dbus_register_interface(connection, obj_path, HFP_AGENT_INTERFACE,
 
350
                        agent_methods, NULL, NULL, modem, NULL);
 
351
 
 
352
        data->agent_registered = TRUE;
 
353
 
 
354
        if (hfp_register_ofono_handsfree(modem) != 0)
 
355
                return -EINVAL;
 
356
 
 
357
        return 0;
 
358
}
 
359
 
 
360
static void hfp_remove(struct ofono_modem *modem)
 
361
{
 
362
        struct hfp_data *data = ofono_modem_get_data(modem);
 
363
        const char *obj_path = ofono_modem_get_path(modem);
 
364
 
 
365
        if (data->call != NULL)
 
366
                dbus_pending_call_cancel(data->call);
 
367
 
 
368
        if (g_dbus_unregister_interface(connection, obj_path,
 
369
                                        HFP_AGENT_INTERFACE))
 
370
                hfp_unregister_ofono_handsfree(modem);
 
371
 
 
372
        g_free(data->handsfree_address);
 
373
        g_free(data->handsfree_path);
 
374
        g_free(data);
 
375
 
 
376
        ofono_modem_set_data(modem, NULL);
 
377
}
 
378
 
 
379
static void hfp_connect_reply(DBusPendingCall *call, gpointer user_data)
 
380
{
 
381
        struct ofono_modem *modem = user_data;
 
382
        struct hfp_data *data = ofono_modem_get_data(modem);
 
383
        DBusError derr;
 
384
        DBusMessage *reply, *msg;
 
385
 
 
386
        reply = dbus_pending_call_steal_reply(call);
 
387
 
 
388
        if (ofono_modem_get_powered(modem))
 
389
                goto done;
 
390
 
 
391
        dbus_error_init(&derr);
 
392
        if (!dbus_set_error_from_message(&derr, reply))
 
393
                goto done;
 
394
 
 
395
        DBG("Connect reply: %s", derr.message);
 
396
 
 
397
        if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) {
 
398
                msg = dbus_message_new_method_call(BLUEZ_SERVICE,
 
399
                                data->handsfree_path,
 
400
                                BLUEZ_GATEWAY_INTERFACE, "Disconnect");
 
401
                if (msg == NULL)
 
402
                        ofono_error("Disconnect failed");
 
403
                else
 
404
                        g_dbus_send_message(connection, msg);
 
405
        }
 
406
 
 
407
        ofono_modem_set_powered(modem, FALSE);
 
408
 
 
409
        dbus_error_free(&derr);
 
410
 
 
411
done:
 
412
        dbus_message_unref(reply);
 
413
        data->call = NULL;
 
414
}
 
415
 
 
416
/* power up hardware */
 
417
static int hfp_enable(struct ofono_modem *modem)
 
418
{
 
419
        struct hfp_data *data = ofono_modem_get_data(modem);
 
420
        int status;
 
421
 
 
422
        DBG("%p", modem);
 
423
 
 
424
        status = bluetooth_send_with_reply(data->handsfree_path,
 
425
                                        BLUEZ_GATEWAY_INTERFACE, "Connect",
 
426
                                        &data->call, hfp_connect_reply,
 
427
                                        modem, NULL,
 
428
                                        DBUS_TIMEOUT, DBUS_TYPE_INVALID);
 
429
 
 
430
        if (status < 0)
 
431
                return -EINVAL;
 
432
 
 
433
        return -EINPROGRESS;
 
434
}
 
435
 
 
436
static void hfp_power_down(DBusPendingCall *call, gpointer user_data)
 
437
{
 
438
        struct ofono_modem *modem = user_data;
 
439
        struct hfp_data *data = ofono_modem_get_data(modem);
 
440
        DBusMessage *reply;
 
441
        DBusError derr;
 
442
 
 
443
        reply = dbus_pending_call_steal_reply(call);
 
444
 
 
445
        dbus_error_init(&derr);
 
446
        if (dbus_set_error_from_message(&derr, reply)) {
 
447
                DBG("Disconnect reply: %s", derr.message);
 
448
                dbus_error_free(&derr);
 
449
                goto done;
 
450
        }
 
451
 
 
452
        ofono_modem_set_powered(modem, FALSE);
 
453
 
 
454
done:
 
455
        dbus_message_unref(reply);
 
456
        data->call = NULL;
 
457
}
 
458
 
 
459
static int hfp_disable(struct ofono_modem *modem)
 
460
{
 
461
        struct hfp_data *data = ofono_modem_get_data(modem);
 
462
        int status;
 
463
 
 
464
        DBG("%p", modem);
 
465
 
 
466
        g_at_chat_unref(data->info.chat);
 
467
        data->info.chat = NULL;
 
468
 
 
469
        if (data->agent_registered) {
 
470
                status = bluetooth_send_with_reply(data->handsfree_path,
 
471
                                        BLUEZ_GATEWAY_INTERFACE, "Disconnect",
 
472
                                        &data->call, hfp_power_down,
 
473
                                        modem, NULL,
 
474
                                        DBUS_TIMEOUT, DBUS_TYPE_INVALID);
 
475
 
 
476
                if (status < 0)
 
477
                        return -EINVAL;
 
478
        }
 
479
 
 
480
        return -EINPROGRESS;
 
481
}
 
482
 
 
483
static void hfp_pre_sim(struct ofono_modem *modem)
 
484
{
 
485
        struct hfp_data *data = ofono_modem_get_data(modem);
 
486
 
 
487
        DBG("%p", modem);
 
488
 
 
489
        ofono_devinfo_create(modem, 0, "hfpmodem", data->handsfree_address);
 
490
        ofono_voicecall_create(modem, 0, "hfpmodem", &data->info);
 
491
        ofono_netreg_create(modem, 0, "hfpmodem", &data->info);
 
492
        ofono_call_volume_create(modem, 0, "hfpmodem", &data->info);
 
493
        ofono_handsfree_create(modem, 0, "hfpmodem", &data->info);
 
494
        ofono_siri_create(modem, 0, "hfpmodem", &data->info);
 
495
}
 
496
 
 
497
static void hfp_post_sim(struct ofono_modem *modem)
 
498
{
 
499
        DBG("%p", modem);
 
500
}
 
501
 
 
502
static struct ofono_modem_driver hfp_driver = {
 
503
        .name           = "hfp",
 
504
        .modem_type     = OFONO_MODEM_TYPE_HFP,
 
505
        .probe          = hfp_probe,
 
506
        .remove         = hfp_remove,
 
507
        .enable         = hfp_enable,
 
508
        .disable        = hfp_disable,
 
509
        .pre_sim        = hfp_pre_sim,
 
510
        .post_sim       = hfp_post_sim,
 
511
};
 
512
 
 
513
static struct bluetooth_profile hfp_hf = {
 
514
        .name           = "hfp_hf",
 
515
        .probe          = hfp_hf_probe,
 
516
        .remove         = hfp_hf_remove,
 
517
        .set_alias      = hfp_hf_set_alias,
 
518
};
 
519
 
 
520
static int hfp_init(void)
 
521
{
 
522
        int err;
 
523
 
 
524
        if (DBUS_TYPE_UNIX_FD < 0)
 
525
                return -EBADF;
 
526
 
 
527
        connection = ofono_dbus_get_connection();
 
528
 
 
529
        err = ofono_modem_driver_register(&hfp_driver);
 
530
        if (err < 0)
 
531
                return err;
 
532
 
 
533
        err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_hf);
 
534
        if (err < 0) {
 
535
                ofono_modem_driver_unregister(&hfp_driver);
 
536
                return err;
 
537
        }
 
538
 
 
539
        modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
 
540
                                                g_free, NULL);
 
541
 
 
542
        return 0;
 
543
}
 
544
 
 
545
static void hfp_exit(void)
 
546
{
 
547
        bluetooth_unregister_uuid(HFP_AG_UUID);
 
548
        ofono_modem_driver_unregister(&hfp_driver);
 
549
 
 
550
        g_hash_table_destroy(modem_hash);
 
551
}
 
552
 
 
553
OFONO_PLUGIN_DEFINE(hfp_bluez4, "Hands-Free Profile Plugins", VERSION,
 
554
                        OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit)