3
* oFono - Open Source Telephony
5
* Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License version 2 as
9
* published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33
#include <ofono/log.h>
34
#include <ofono/modem.h>
38
#include "gatresult.h"
42
/* Amount of ms we wait between CLCC calls */
43
#define POLL_CLCC_INTERVAL 500
45
/* Amount of time we give for CLIP to arrive before we commence CLCC poll */
46
#define CLIP_INTERVAL 200
48
static const char *clcc_prefix[] = { "+CLCC:", NULL };
49
static const char *none_prefix[] = { NULL };
51
/* According to 27.007 COLP is an intermediate status for ATD */
52
static const char *atd_prefix[] = { "+COLP:", NULL };
54
struct voicecall_data {
58
unsigned int local_release;
59
unsigned int clcc_source;
62
static gboolean poll_clcc(gpointer user_data);
64
static int class_to_call_type(int cls)
78
static unsigned int alloc_next_id(struct voicecall_data *d)
82
for (i = 1; i < sizeof(d->id_list) * 8; i++) {
83
if (d->id_list & (0x1 << i))
86
d->id_list |= (0x1 << i);
94
static gboolean alloc_specific_id(struct voicecall_data *d, unsigned int id)
96
if (id < 1 || id > sizeof(d->id_list))
99
if (d->id_list & (0x1 << id))
102
d->id_list |= (0x1 << id);
108
static void release_id(struct voicecall_data *d, unsigned int id)
110
d->id_list &= ~(0x1 << id);
114
static gint call_compare_by_id(gconstpointer a, gconstpointer b)
116
const struct ofono_call *call = a;
117
unsigned int id = GPOINTER_TO_UINT(b);
129
static gint call_compare_by_status(gconstpointer a, gconstpointer b)
131
const struct ofono_call *call = a;
132
int status = GPOINTER_TO_INT(b);
134
if (status != call->status)
140
static gint call_compare(gconstpointer a, gconstpointer b)
142
const struct ofono_call *ca = a;
143
const struct ofono_call *cb = b;
154
static struct ofono_call *create_call(struct voicecall_data *d, int type,
155
int direction, int status,
156
const char *num, int num_type, int clip)
158
struct ofono_call *call;
160
/* Generate a call structure for the waiting call */
161
call = g_try_new0(struct ofono_call, 1);
166
call->id = alloc_next_id(d);
168
call->direction = direction;
169
call->status = status;
172
strncpy(call->phone_number.number, num,
173
OFONO_MAX_PHONE_NUMBER_LENGTH);
174
call->phone_number.type = num_type;
177
call->clip_validity = clip;
179
d->calls = g_slist_insert_sorted(d->calls, call, call_compare);
184
static GSList *parse_clcc(GAtResult *result)
188
int id, dir, status, type;
189
struct ofono_call *call;
191
g_at_result_iter_init(&iter, result);
193
while (g_at_result_iter_next(&iter, "+CLCC:")) {
194
const char *str = "";
195
int number_type = 129;
197
if (!g_at_result_iter_next_number(&iter, &id))
200
if (!g_at_result_iter_next_number(&iter, &dir))
203
if (!g_at_result_iter_next_number(&iter, &status))
206
if (!g_at_result_iter_next_number(&iter, &type))
209
if (!g_at_result_iter_skip_next(&iter))
212
if (g_at_result_iter_next_string(&iter, &str))
213
g_at_result_iter_next_number(&iter, &number_type);
215
call = g_try_new0(struct ofono_call, 1);
221
call->direction = dir;
222
call->status = status;
224
strncpy(call->phone_number.number, str,
225
OFONO_MAX_PHONE_NUMBER_LENGTH);
226
call->phone_number.type = number_type;
228
if (strlen(call->phone_number.number) > 0)
229
call->clip_validity = 0;
231
call->clip_validity = 2;
233
l = g_slist_insert_sorted(l, call, call_compare);
239
static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
241
struct ofono_modem *modem = user_data;
242
struct at_data *at = ofono_modem_get_userdata(modem);
245
struct ofono_call *nc, *oc;
246
gboolean poll_again = FALSE;
248
dump_response("clcc_poll_cb", ok, result);
251
ofono_error("We are polling CLCC and CLCC resulted in an error");
252
ofono_error("All bets are off for call management");
256
calls = parse_clcc(result);
259
o = at->voicecall->calls;
262
nc = n ? n->data : NULL;
263
oc = o ? o->data : NULL;
265
if (nc && nc->status >= 2 && nc->status <= 5)
268
if (oc && (!nc || (nc->id > oc->id))) {
269
enum ofono_disconnect_reason reason;
271
if (at->voicecall->local_release & (0x1 << oc->id))
272
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
274
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
277
ofono_voicecall_disconnected(modem, oc->id,
280
release_id(at->voicecall, oc->id);
283
} else if (nc && (!oc || (nc->id < oc->id))) {
284
/* new call, signal it */
286
ofono_voicecall_notify(modem, nc);
290
/* Always use the clip_validity from old call
291
* the only place this is truly told to us is
292
* in the CLIP notify, the rest are fudged
293
* anyway. Useful when RING, CLIP is used,
294
* and we're forced to use CLCC and clip_validity
297
nc->clip_validity = oc->clip_validity;
299
if (memcmp(nc, oc, sizeof(struct ofono_call)) && !nc->type)
300
ofono_voicecall_notify(modem, nc);
307
g_slist_foreach(at->voicecall->calls, (GFunc) g_free, NULL);
308
g_slist_free(at->voicecall->calls);
310
at->voicecall->calls = calls;
312
at->voicecall->local_release = 0;
314
if (poll_again && at->voicecall->poll_clcc &&
315
!at->voicecall->clcc_source)
316
at->voicecall->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL,
321
static gboolean poll_clcc(gpointer user_data)
323
struct ofono_modem *modem = user_data;
324
struct at_data *at = ofono_modem_get_userdata(modem);
326
g_at_chat_send(at->parser, "AT+CLCC", clcc_prefix,
327
clcc_poll_cb, modem, NULL);
329
at->voicecall->clcc_source = 0;
334
static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
336
struct cb_data *cbd = user_data;
337
struct at_data *at = ofono_modem_get_userdata(cbd->modem);
338
ofono_generic_cb_t cb = cbd->cb;
339
unsigned int released_status = GPOINTER_TO_UINT(cbd->user);
340
struct ofono_error error;
342
dump_response("generic_cb", ok, result);
343
decode_at_error(&error, g_at_result_final_response(result));
345
if (ok && released_status) {
347
struct ofono_call *call;
349
for (l = at->voicecall->calls; l; l = l->next) {
352
if (released_status & (0x1 << call->status))
353
at->voicecall->local_release |=
358
if (at->voicecall->poll_clcc)
359
g_at_chat_send(at->parser, "AT+CLCC", clcc_prefix,
360
clcc_poll_cb, cbd->modem, NULL);
362
/* We have to callback after we schedule a poll if required */
363
cb(&error, cbd->data);
366
static void release_id_cb(gboolean ok, GAtResult *result,
369
struct cb_data *cbd = user_data;
370
struct at_data *at = ofono_modem_get_userdata(cbd->modem);
371
ofono_generic_cb_t cb = cbd->cb;
372
struct ofono_error error;
374
dump_response("release_id_cb", ok, result);
375
decode_at_error(&error, g_at_result_final_response(result));
378
at->voicecall->local_release = GPOINTER_TO_UINT(cbd->user);
380
if (at->voicecall->poll_clcc)
381
g_at_chat_send(at->parser, "AT+CLCC", clcc_prefix,
382
clcc_poll_cb, cbd->modem, NULL);
384
/* We have to callback after we schedule a poll if required */
385
cb(&error, cbd->data);
387
static void atd_cb(gboolean ok, GAtResult *result, gpointer user_data)
389
struct cb_data *cbd = user_data;
390
struct at_data *at = ofono_modem_get_userdata(cbd->modem);
391
ofono_generic_cb_t cb = cbd->cb;
396
struct ofono_error error;
397
struct ofono_call *call;
399
dump_response("atd_cb", ok, result);
401
decode_at_error(&error, g_at_result_final_response(result));
406
g_at_result_iter_init(&iter, result);
408
if (g_at_result_iter_next(&iter, "+COLP:")) {
409
g_at_result_iter_next_string(&iter, &num);
410
g_at_result_iter_next_number(&iter, &type);
417
ofono_debug("colp_notify: %s %d %d", num, type, validity);
420
/* Generate a voice call that was just dialed, we guess the ID */
421
call = create_call(at->voicecall, 0, 0, 2, num, type, validity);
424
ofono_error("Unable to allocate call, call tracking will fail!");
428
/* Telephonyd will generate a call with the dialed number
429
* inside its dial callback. Unless we got COLP information
430
* we do not need to communicate that a call is being
434
ofono_voicecall_notify(cbd->modem, call);
436
if (at->voicecall->poll_clcc && !at->voicecall->clcc_source)
437
at->voicecall->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL,
442
cb(&error, cbd->data);
445
static void at_dial(struct ofono_modem *modem,
446
const struct ofono_phone_number *ph,
447
enum ofono_clir_option clir, enum ofono_cug_option cug,
448
ofono_generic_cb_t cb, void *data)
450
struct at_data *at = ofono_modem_get_userdata(modem);
451
struct cb_data *cbd = cb_data_new(modem, cb, data);
458
sprintf(buf, "ATD+%s", ph->number);
460
sprintf(buf, "ATD%s", ph->number);
463
case OFONO_CLIR_OPTION_INVOCATION:
466
case OFONO_CLIR_OPTION_SUPPRESSION:
474
case OFONO_CUG_OPTION_INVOCATION:
483
if (g_at_chat_send(at->parser, buf, atd_prefix,
484
atd_cb, cbd, g_free) > 0)
492
DECLARE_FAILURE(error);
497
static void at_template(const char *cmd, struct ofono_modem *modem,
498
GAtResultFunc result_cb, unsigned int released_status,
499
ofono_generic_cb_t cb, void *data)
501
struct at_data *at = ofono_modem_get_userdata(modem);
502
struct cb_data *cbd = cb_data_new(modem, cb, data);
507
cbd->user = GUINT_TO_POINTER(released_status);
509
if (g_at_chat_send(at->parser, cmd, none_prefix,
510
result_cb, cbd, g_free) > 0)
518
DECLARE_FAILURE(error);
523
static void at_answer(struct ofono_modem *modem, ofono_generic_cb_t cb, void *data)
525
at_template("ATA", modem, generic_cb, 0, cb, data);
528
static void at_hangup(struct ofono_modem *modem, ofono_generic_cb_t cb, void *data)
530
/* Hangup all calls */
531
at_template("AT+CHUP", modem, generic_cb, 0x3f, cb, data);
534
static void clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
536
struct cb_data *cbd = user_data;
537
ofono_call_list_cb_t cb = cbd->cb;
538
struct ofono_error error;
539
GSList *calls = NULL;
541
struct ofono_call *list;
544
dump_response("clcc_cb", ok, result);
545
decode_at_error(&error, g_at_result_final_response(result));
548
cb(&error, 0, NULL, cbd->data);
552
calls = parse_clcc(result);
556
cb(&e, 0, NULL, cbd->data);
560
list = g_try_new0(struct ofono_call, g_slist_length(calls));
564
cb(&e, 0, NULL, cbd->data);
568
for (num = 0, l = calls; l; l = l->next, num++)
569
memcpy(&list[num], l->data, sizeof(struct ofono_call));
571
cb(&error, num, list, cbd->data);
576
g_slist_foreach(calls, (GFunc) g_free, NULL);
580
static void at_list_calls(struct ofono_modem *modem, ofono_call_list_cb_t cb,
583
struct at_data *at = ofono_modem_get_userdata(modem);
584
struct cb_data *cbd = cb_data_new(modem, cb, data);
589
if (g_at_chat_send(at->parser, "AT+CLCC", clcc_prefix,
590
clcc_cb, cbd, g_free) > 0)
598
DECLARE_FAILURE(error);
599
cb(&error, 0, NULL, data);
604
static void at_hold_all_active(struct ofono_modem *modem, ofono_generic_cb_t cb,
607
at_template("AT+CHLD=2", modem, generic_cb, 0, cb, data);
610
static void at_release_all_held(struct ofono_modem *modem, ofono_generic_cb_t cb,
613
unsigned int held_status = 0x1 << 1;
614
at_template("AT+CHLD=0", modem, generic_cb, held_status, cb, data);
617
static void at_set_udub(struct ofono_modem *modem, ofono_generic_cb_t cb, void *data)
619
unsigned int incoming_or_waiting = (0x1 << 4) | (0x1 << 5);
620
at_template("AT+CHLD=0", modem, generic_cb, incoming_or_waiting,
624
static void at_release_all_active(struct ofono_modem *modem, ofono_generic_cb_t cb,
627
at_template("AT+CHLD=1", modem, generic_cb, 0x1, cb, data);
630
static void at_release_specific(struct ofono_modem *modem, int id,
631
ofono_generic_cb_t cb, void *data)
633
struct at_data *at = ofono_modem_get_userdata(modem);
634
struct cb_data *cbd = cb_data_new(modem, cb, data);
640
sprintf(buf, "AT+CHLD=1%d", id);
641
cbd->user = GINT_TO_POINTER(id);
643
if (g_at_chat_send(at->parser, buf, none_prefix,
644
release_id_cb, cbd, g_free) > 0)
652
DECLARE_FAILURE(error);
657
static void at_private_chat(struct ofono_modem *modem, int id,
658
ofono_generic_cb_t cb, void *data)
662
sprintf(buf, "AT+CHLD=2%d", id);
663
at_template(buf, modem, generic_cb, 0, cb, data);
666
static void at_create_multiparty(struct ofono_modem *modem, ofono_generic_cb_t cb,
669
at_template("AT+CHLD=3", modem, generic_cb, 0, cb, data);
672
static void at_transfer(struct ofono_modem *modem, ofono_generic_cb_t cb,
676
unsigned int transfer = 0x1 | 0x2;
678
/* Transfer can puts held & active calls together and disconnects
679
* from both. However, some networks support transfering of
680
* dialing/ringing calls as well.
682
transfer |= 0x4 | 0x8;
684
at_template("AT+CHLD=4", modem, generic_cb, transfer, cb, data);
687
static void at_deflect(struct ofono_modem *modem,
688
const struct ofono_phone_number *ph,
689
ofono_generic_cb_t cb, void *data)
692
unsigned int incoming_or_waiting = (0x1 << 4) | (0x1 << 5);
694
sprintf(buf, "AT+CTFR=%s,%d", ph->number, ph->type);
695
at_template(buf, modem, generic_cb, incoming_or_waiting, cb, data);
698
static void vts_cb(gboolean ok, GAtResult *result, gpointer user_data)
700
struct cb_data *cbd = user_data;
701
ofono_generic_cb_t cb = cbd->cb;
702
struct ofono_error error;
704
dump_response("vts_cb", ok, result);
705
decode_at_error(&error, g_at_result_final_response(result));
706
cb(&error, cbd->data);
709
static void at_send_dtmf(struct ofono_modem *modem, const char *dtmf,
710
ofono_generic_cb_t cb, void *data)
712
struct at_data *at = ofono_modem_get_userdata(modem);
713
struct cb_data *cbd = cb_data_new(modem, cb, data);
714
int len = strlen(dtmf);
722
/* strlen("+VTS=\"T\";") = 9 + initial AT + null */
723
buf = g_try_new(char, len * 9 + 3);
728
s = sprintf(buf, "AT+VTS=\"%c\"", dtmf[0]);
730
for (i = 1; i < len; i++)
731
s += sprintf(buf + s, ";+VTS=\"%c\"", dtmf[i]);
733
s = g_at_chat_send(at->parser, buf, none_prefix,
734
vts_cb, cbd, g_free);
746
DECLARE_FAILURE(error);
751
static void ring_notify(GAtResult *result, gpointer user_data)
753
struct ofono_modem *modem = user_data;
754
struct at_data *at = ofono_modem_get_userdata(modem);
755
struct ofono_call *call;
757
dump_response("ring_notify", TRUE, result);
759
/* RING can repeat, ignore if we already have an incoming call */
760
if (g_slist_find_custom(at->voicecall->calls, GINT_TO_POINTER(4),
761
call_compare_by_status))
764
/* Generate an incoming call of unknown type */
765
call = create_call(at->voicecall, 9, 1, 4, NULL, 128, 2);
768
ofono_error("Couldn't create call, call management is fubar!");
772
/* We don't know the call type, we must run clcc */
773
at->voicecall->clcc_source = g_timeout_add(CLIP_INTERVAL,
777
static void cring_notify(GAtResult *result, gpointer user_data)
779
struct ofono_modem *modem = user_data;
780
struct at_data *at = ofono_modem_get_userdata(modem);
784
struct ofono_call *call;
786
dump_response("cring_notify", TRUE, result);
788
/* CRING can repeat, ignore if we already have an incoming call */
789
if (g_slist_find_custom(at->voicecall->calls, GINT_TO_POINTER(4),
790
call_compare_by_status))
793
g_at_result_iter_init(&iter, result);
795
if (!g_at_result_iter_next(&iter, "+CRING:"))
798
line = g_at_result_iter_raw_line(&iter);
803
/* Ignore everything that is not voice for now */
804
if (!strcasecmp(line, "VOICE"))
809
/* Generate an incoming call */
810
call = create_call(at->voicecall, type, 1, 4, NULL, 128, 2);
812
/* We have a call, and call type but don't know the number and
813
* must wait for the CLIP to arrive before announcing the call.
814
* So we wait, and schedule the clcc call. If the CLIP arrives
815
* earlier, we announce the call there
817
at->voicecall->clcc_source =
818
g_timeout_add(CLIP_INTERVAL, poll_clcc, modem);
820
ofono_debug("cring_notify");
823
static void clip_notify(GAtResult *result, gpointer user_data)
825
struct ofono_modem *modem = user_data;
826
struct at_data *at = ofono_modem_get_userdata(modem);
831
struct ofono_call *call;
833
dump_response("clip_notify", TRUE, result);
835
l = g_slist_find_custom(at->voicecall->calls, GINT_TO_POINTER(4),
836
call_compare_by_status);
839
ofono_error("CLIP for unknown call");
843
g_at_result_iter_init(&iter, result);
845
if (!g_at_result_iter_next(&iter, "+CLIP:"))
848
if (!g_at_result_iter_next_string(&iter, &num))
851
if (!g_at_result_iter_next_number(&iter, &type))
859
/* Skip subaddr, satype and alpha */
860
g_at_result_iter_skip_next(&iter);
861
g_at_result_iter_skip_next(&iter);
862
g_at_result_iter_skip_next(&iter);
864
/* If we have CLI validity field, override our guessed value */
865
g_at_result_iter_next_number(&iter, &validity);
867
ofono_debug("clip_notify: %s %d %d", num, type, validity);
871
strncpy(call->phone_number.number, num,
872
OFONO_MAX_PHONE_NUMBER_LENGTH);
873
call->phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
874
call->phone_number.type = type;
875
call->clip_validity = validity;
878
ofono_voicecall_notify(modem, call);
880
/* We started a CLCC, but the CLIP arrived and the call type
881
* is known. If we don't need to poll, cancel the GSource
883
if (call->type != 9 && !at->voicecall->poll_clcc &&
884
at->voicecall->clcc_source &&
885
g_source_remove(at->voicecall->clcc_source))
886
at->voicecall->clcc_source = 0;
889
static void ccwa_notify(GAtResult *result, gpointer user_data)
891
struct ofono_modem *modem = user_data;
892
struct at_data *at = ofono_modem_get_userdata(modem);
895
int num_type, validity, cls;
896
struct ofono_call *call;
898
dump_response("ccwa_notify", TRUE, result);
900
g_at_result_iter_init(&iter, result);
902
if (!g_at_result_iter_next(&iter, "+CCWA:"))
905
if (!g_at_result_iter_next_string(&iter, &num))
908
if (!g_at_result_iter_next_number(&iter, &num_type))
911
if (!g_at_result_iter_next_number(&iter, &cls))
914
/* Skip alpha field */
915
g_at_result_iter_skip_next(&iter);
922
/* If we have CLI validity field, override our guessed value */
923
g_at_result_iter_next_number(&iter, &validity);
925
ofono_debug("ccwa_notify: %s %d %d %d", num, num_type, cls, validity);
927
call = create_call(at->voicecall, class_to_call_type(cls), 1, 5,
928
num, num_type, validity);
931
ofono_error("malloc call structfailed. Call management is fubar");
935
if (call->type == 0) /* Only notify voice calls */
936
ofono_voicecall_notify(modem, call);
938
if (at->voicecall->poll_clcc && !at->voicecall->clcc_source)
939
at->voicecall->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL,
944
static void no_carrier_notify(GAtResult *result, gpointer user_data)
946
struct ofono_modem *modem = user_data;
947
struct at_data *at = ofono_modem_get_userdata(modem);
949
if (at->voicecall->poll_clcc)
950
g_at_chat_send(at->parser, "AT+CLCC", clcc_prefix,
951
clcc_poll_cb, modem, NULL);
954
static void no_answer_notify(GAtResult *result, gpointer user_data)
956
struct ofono_modem *modem = user_data;
957
struct at_data *at = ofono_modem_get_userdata(modem);
959
if (at->voicecall->poll_clcc)
960
g_at_chat_send(at->parser, "AT+CLCC", clcc_prefix,
961
clcc_poll_cb, modem, NULL);
964
static void busy_notify(GAtResult *result, gpointer user_data)
966
struct ofono_modem *modem = user_data;
967
struct at_data *at = ofono_modem_get_userdata(modem);
969
/* Call was rejected, most likely due to network congestion
970
* or UDUB on the other side
971
* TODO: Handle UDUB or other conditions somehow
973
if (at->voicecall->poll_clcc)
974
g_at_chat_send(at->parser, "AT+CLCC", clcc_prefix,
975
clcc_poll_cb, modem, NULL);
978
static void cssi_notify(GAtResult *result, gpointer user_data)
980
struct ofono_modem *modem = user_data;
984
dump_response("cssi_notify", TRUE, result);
986
g_at_result_iter_init(&iter, result);
988
if (!g_at_result_iter_next(&iter, "+CSSI:"))
991
if (!g_at_result_iter_next_number(&iter, &code1))
994
if (!g_at_result_iter_next_number(&iter, &index))
997
ofono_cssi_notify(modem, code1, index);
1000
static void cssu_notify(GAtResult *result, gpointer user_data)
1002
struct ofono_modem *modem = user_data;
1007
struct ofono_phone_number ph;
1009
ph.number[0] = '\0';
1012
dump_response("cssu_notify", TRUE, result);
1014
g_at_result_iter_init(&iter, result);
1016
if (!g_at_result_iter_next(&iter, "+CSSU:"))
1019
if (!g_at_result_iter_next_number(&iter, &code2))
1022
/* This field is optional, if we can't read it, try to skip it */
1023
if (!g_at_result_iter_next_number(&iter, &index) &&
1024
!g_at_result_iter_skip_next(&iter))
1027
if (!g_at_result_iter_next_string(&iter, &num))
1030
strncpy(ph.number, num, OFONO_MAX_PHONE_NUMBER_LENGTH);
1032
if (!g_at_result_iter_next_number(&iter, &ph.type))
1036
ofono_cssu_notify(modem, code2, index, &ph);
1039
static struct ofono_voicecall_ops ops = {
1041
.answer = at_answer,
1042
.hangup = at_hangup,
1043
.list_calls = at_list_calls,
1044
.hold_all_active = at_hold_all_active,
1045
.release_all_held = at_release_all_held,
1046
.set_udub = at_set_udub,
1047
.release_all_active = at_release_all_active,
1048
.release_specific = at_release_specific,
1049
.private_chat = at_private_chat,
1050
.create_multiparty = at_create_multiparty,
1051
.transfer = at_transfer,
1052
.deflect = at_deflect,
1053
.swap_without_accept = NULL,
1054
.send_tones = at_send_dtmf
1057
static void at_voicecall_initialized(gboolean ok, GAtResult *result,
1060
struct ofono_modem *modem = user_data;
1061
struct at_data *at = ofono_modem_get_userdata(modem);
1063
ofono_debug("voicecall_init: registering to notifications");
1065
g_at_chat_register(at->parser, "RING",
1066
ring_notify, FALSE, modem, NULL);
1067
g_at_chat_register(at->parser, "+CRING:",
1068
cring_notify, FALSE, modem, NULL);
1069
g_at_chat_register(at->parser, "+CLIP:",
1070
clip_notify, FALSE, modem, NULL);
1071
g_at_chat_register(at->parser, "+CCWA:",
1072
ccwa_notify, FALSE, modem, NULL);
1073
g_at_chat_register(at->parser, "+CSSI:",
1074
cssi_notify, FALSE, modem, NULL);
1075
g_at_chat_register(at->parser, "+CSSU:",
1076
cssu_notify, FALSE, modem, NULL);
1078
/* Modems with 'better' call progress indicators should
1079
* probably not even bother registering to these
1081
g_at_chat_register(at->parser, "NO CARRIER",
1082
no_carrier_notify, FALSE, modem, NULL);
1083
g_at_chat_register(at->parser, "NO ANSWER",
1084
no_answer_notify, FALSE, modem, NULL);
1085
g_at_chat_register(at->parser, "BUSY",
1086
busy_notify, FALSE, modem, NULL);
1088
ofono_voicecall_register(modem, &ops);
1091
void at_voicecall_init(struct ofono_modem *modem)
1093
struct at_data *at = ofono_modem_get_userdata(modem);
1095
at->voicecall = g_try_new0(struct voicecall_data, 1);
1100
at->voicecall->poll_clcc = TRUE;
1102
ofono_debug("Sending voice initialization commands");
1104
g_at_chat_send(at->parser, "AT+CRC=1", NULL, NULL, NULL, NULL);
1105
g_at_chat_send(at->parser, "AT+CLIP=1", NULL, NULL, NULL, NULL);
1106
g_at_chat_send(at->parser, "AT+COLP=1", NULL, NULL, NULL, NULL);
1107
g_at_chat_send(at->parser, "AT+CSSN=1,1", NULL, NULL, NULL, NULL);
1108
g_at_chat_send(at->parser, "AT+CCWA=1", NULL,
1109
at_voicecall_initialized, modem, NULL);
1112
void at_voicecall_exit(struct ofono_modem *modem)
1114
struct at_data *at = ofono_modem_get_userdata(modem);
1119
g_slist_foreach(at->voicecall->calls, (GFunc) g_free, NULL);
1120
g_slist_free(at->voicecall->calls);
1122
g_free(at->voicecall);
1123
at->voicecall = NULL;
1125
ofono_voicecall_unregister(modem);