diff --git a/modem/ofono/0001-doc-ofonod.8-escape-minus-sign.patch b/modem/ofono/0001-doc-ofonod.8-escape-minus-sign.patch new file mode 100644 index 000000000..e36711291 --- /dev/null +++ b/modem/ofono/0001-doc-ofonod.8-escape-minus-sign.patch @@ -0,0 +1,25 @@ +From 20653ec096bd0e15c09926f8dfc7771bf2036b9a Mon Sep 17 00:00:00 2001 +From: Jonny Lamb +Date: Mon, 29 Nov 2010 18:04:01 +0000 +Subject: [PATCH] doc/ofonod.8: escape minus sign + +I'm a sucker for lintian-cleanliness! + +Signed-off-by: Jonny Lamb +--- + doc/ofonod.8 | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: ofono-1.21/doc/ofonod.8 +=================================================================== +--- ofono-1.21.orig/doc/ofonod.8 ++++ ofono-1.21/doc/ofonod.8 +@@ -18,7 +18,7 @@ is used to manage \fID-Bus\fP permission + .SH OPTIONS + .TP + .B --debug, -d +-Enable debug information output. Note multiple arguments to -d can be ++Enable debug information output. Note multiple arguments to \-d can be + specified, colon, comma or space separated. The arguments are relative + source code filenames for which debugging output should be enabled; + output shell-style globs are accepted (e.g.: "plugins/*:src/main.c"). diff --git a/modem/ofono/0002-common-create-GList-helper-ofono_call_compare.patch b/modem/ofono/0002-common-create-GList-helper-ofono_call_compare.patch new file mode 100644 index 000000000..4d615c93f --- /dev/null +++ b/modem/ofono/0002-common-create-GList-helper-ofono_call_compare.patch @@ -0,0 +1,205 @@ +From c97a48fd4b94d4e6785dd713abe2a06da5e0d623 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Wed, 12 Jul 2017 21:00:00 +0200 +Subject: [PATCH 02/17] common: create GList helper ofono_call_compare + +replaces at_util_call_compare (atmodem) and +call_compare (rild). +--- + drivers/atmodem/atutil.c | 17 ++--------------- + drivers/atmodem/atutil.h | 1 - + drivers/atmodem/voicecall.c | 2 +- + drivers/hfpmodem/voicecall.c | 2 +- + drivers/huaweimodem/voicecall.c | 2 +- + drivers/ifxmodem/voicecall.c | 2 +- + drivers/rilmodem/voicecall.c | 16 +--------------- + drivers/stemodem/voicecall.c | 2 +- + src/common.c | 14 ++++++++++++++ + src/common.h | 2 ++ + 10 files changed, 24 insertions(+), 36 deletions(-) + +Index: ofono-1.21/drivers/atmodem/atutil.c +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/atutil.c ++++ ofono-1.21/drivers/atmodem/atutil.c +@@ -32,6 +32,7 @@ + #define OFONO_API_SUBJECT_TO_CHANGE + #include + #include ++#include "../src/common.h" + + #include "atutil.h" + #include "vendor.h" +@@ -102,20 +103,6 @@ gint at_util_call_compare_by_id(gconstpo + return 0; + } + +-gint at_util_call_compare(gconstpointer a, gconstpointer b) +-{ +- const struct ofono_call *ca = a; +- const struct ofono_call *cb = b; +- +- if (ca->id < cb->id) +- return -1; +- +- if (ca->id > cb->id) +- return 1; +- +- return 0; +-} +- + GSList *at_util_parse_clcc(GAtResult *result, unsigned int *ret_mpty_ids) + { + GAtResultIter iter; +@@ -174,7 +161,7 @@ GSList *at_util_parse_clcc(GAtResult *re + else + call->clip_validity = 2; + +- l = g_slist_insert_sorted(l, call, at_util_call_compare); ++ l = g_slist_insert_sorted(l, call, ofono_call_compare); + + if (mpty) + mpty_ids |= 1 << id; +Index: ofono-1.21/drivers/atmodem/atutil.h +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/atutil.h ++++ ofono-1.21/drivers/atmodem/atutil.h +@@ -54,7 +54,6 @@ void decode_at_error(struct ofono_error + gint at_util_call_compare_by_status(gconstpointer a, gconstpointer b); + gint at_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b); + gint at_util_call_compare_by_id(gconstpointer a, gconstpointer b); +-gint at_util_call_compare(gconstpointer a, gconstpointer b); + GSList *at_util_parse_clcc(GAtResult *result, unsigned int *mpty_ids); + gboolean at_util_parse_reg(GAtResult *result, const char *prefix, + int *mode, int *status, +Index: ofono-1.21/drivers/atmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/voicecall.c ++++ ofono-1.21/drivers/atmodem/voicecall.c +@@ -132,7 +132,7 @@ static struct ofono_call *create_call(st + call->clip_validity = clip; + call->cnap_validity = CNAP_VALIDITY_NOT_AVAILABLE; + +- d->calls = g_slist_insert_sorted(d->calls, call, at_util_call_compare); ++ d->calls = g_slist_insert_sorted(d->calls, call, ofono_call_compare); + + return call; + } +Index: ofono-1.21/drivers/hfpmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/hfpmodem/voicecall.c ++++ ofono-1.21/drivers/hfpmodem/voicecall.c +@@ -128,7 +128,7 @@ static struct ofono_call *create_call(st + call->phone_number.type = num_type; + } + +- d->calls = g_slist_insert_sorted(d->calls, call, at_util_call_compare); ++ d->calls = g_slist_insert_sorted(d->calls, call, ofono_call_compare); + + call->clip_validity = clip; + +Index: ofono-1.21/drivers/huaweimodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/huaweimodem/voicecall.c ++++ ofono-1.21/drivers/huaweimodem/voicecall.c +@@ -76,7 +76,7 @@ static struct ofono_call *create_call(st + + call->clip_validity = clip; + +- d->calls = g_slist_insert_sorted(d->calls, call, at_util_call_compare); ++ d->calls = g_slist_insert_sorted(d->calls, call, ofono_call_compare); + + return call; + } +Index: ofono-1.21/drivers/ifxmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/ifxmodem/voicecall.c ++++ ofono-1.21/drivers/ifxmodem/voicecall.c +@@ -107,7 +107,7 @@ static struct ofono_call *create_call(st + + call->clip_validity = clip; + +- d->calls = g_slist_insert_sorted(d->calls, call, at_util_call_compare); ++ d->calls = g_slist_insert_sorted(d->calls, call, ofono_call_compare); + + return call; + } +Index: ofono-1.21/drivers/rilmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/rilmodem/voicecall.c ++++ ofono-1.21/drivers/rilmodem/voicecall.c +@@ -117,20 +117,6 @@ done: + ofono_voicecall_disconnected(vc, reqdata->id, reason, NULL); + } + +-static int call_compare(gconstpointer a, gconstpointer b) +-{ +- const struct ofono_call *ca = a; +- const struct ofono_call *cb = b; +- +- if (ca->id < cb->id) +- return -1; +- +- if (ca->id > cb->id) +- return 1; +- +- return 0; +-} +- + static void clcc_poll_cb(struct ril_msg *message, gpointer user_data) + { + struct ofono_voicecall *vc = user_data; +@@ -209,7 +195,7 @@ static void clcc_poll_cb(struct ril_msg + call->id, call->status, call->type, + call->phone_number.number, call->name); + +- calls = g_slist_insert_sorted(calls, call, call_compare); ++ calls = g_slist_insert_sorted(calls, call, ofono_call_compare); + } + + no_calls: +Index: ofono-1.21/drivers/stemodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/stemodem/voicecall.c ++++ ofono-1.21/drivers/stemodem/voicecall.c +@@ -128,7 +128,7 @@ static struct ofono_call *create_call(st + + call->clip_validity = clip; + +- d->calls = g_slist_insert_sorted(d->calls, call, at_util_call_compare); ++ d->calls = g_slist_insert_sorted(d->calls, call, ofono_call_compare); + + return call; + } +Index: ofono-1.21/src/common.c +=================================================================== +--- ofono-1.21.orig/src/common.c ++++ ofono-1.21/src/common.c +@@ -765,3 +765,17 @@ const char *call_status_to_string(enum c + + return "unknown"; + } ++ ++gint ofono_call_compare(gconstpointer a, gconstpointer b) ++{ ++ const struct ofono_call *ca = a; ++ const struct ofono_call *cb = b; ++ ++ if (ca->id < cb->id) ++ return -1; ++ ++ if (ca->id > cb->id) ++ return 1; ++ ++ return 0; ++} +Index: ofono-1.21/src/common.h +=================================================================== +--- ofono-1.21.orig/src/common.h ++++ ofono-1.21/src/common.h +@@ -184,4 +184,5 @@ const char *registration_tech_to_string( + const char *packet_bearer_to_string(int bearer); + + gboolean is_valid_apn(const char *apn); ++gint ofono_call_compare(gconstpointer a, gconstpointer b); + const char *call_status_to_string(enum call_status status); diff --git a/modem/ofono/0003-voicecall-common-promote-call_status_to_string-publi.patch b/modem/ofono/0003-voicecall-common-promote-call_status_to_string-publi.patch new file mode 100644 index 000000000..f942f3078 --- /dev/null +++ b/modem/ofono/0003-voicecall-common-promote-call_status_to_string-publi.patch @@ -0,0 +1,54 @@ +From 99767e9da1b956afdd08c359785721a293931295 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Tue, 25 Jul 2017 11:34:36 +0200 +Subject: [PATCH 03/17] voicecall,common: promote call_status_to_string() + public + +call_status_to_string() is useful for debug output. +Change signature to contain enum call_status +Replace default case to get compiler warning when new enums added +--- + src/common.c | 21 +++++++++++++++++++++ + src/common.h | 1 + + src/voicecall.c | 24 ++---------------------- + 3 files changed, 24 insertions(+), 22 deletions(-) + +Index: ofono-1.21/src/common.c +=================================================================== +--- ofono-1.21.orig/src/common.c ++++ ofono-1.21/src/common.c +@@ -779,3 +779,24 @@ gint ofono_call_compare(gconstpointer a, + + return 0; + } ++ ++const char *ofono_call_status_to_string(enum call_status status) ++{ ++ switch (status) { ++ case CALL_STATUS_ACTIVE: ++ return "active"; ++ case CALL_STATUS_HELD: ++ return "held"; ++ case CALL_STATUS_DIALING: ++ return "dialing"; ++ case CALL_STATUS_ALERTING: ++ return "alerting"; ++ case CALL_STATUS_INCOMING: ++ return "incoming"; ++ case CALL_STATUS_WAITING: ++ return "waiting"; ++ case CALL_STATUS_DISCONNECTED: ++ return "disconnected"; ++ } ++ return "unknown"; ++} +Index: ofono-1.21/src/common.h +=================================================================== +--- ofono-1.21.orig/src/common.h ++++ ofono-1.21/src/common.h +@@ -185,4 +185,4 @@ const char *packet_bearer_to_string(int + + gboolean is_valid_apn(const char *apn); + gint ofono_call_compare(gconstpointer a, gconstpointer b); +-const char *call_status_to_string(enum call_status status); ++const char *ofono_call_status_to_string(enum call_status status); diff --git a/modem/ofono/0006-add-call-list-helper-to-manage-voice-call-lists.patch b/modem/ofono/0006-add-call-list-helper-to-manage-voice-call-lists.patch new file mode 100644 index 000000000..736dc3572 --- /dev/null +++ b/modem/ofono/0006-add-call-list-helper-to-manage-voice-call-lists.patch @@ -0,0 +1,467 @@ +From 2ae2366c262a15e4f3269afd9c80ddf06c1b9b46 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Tue, 25 Jul 2017 12:42:29 +0200 +Subject: [PATCH 06/17] add call-list helper to manage voice call lists + +Many drivers asks the modem for a complete call list of current calls. +These list of calls can be feeded into call-list which parse the +list and notify ofono for new calls. +--- + Makefile.am | 13 ++- + include/call-list.h | 38 ++++++++ + src/call-list.c | 114 ++++++++++++++++++++++++ + unit/test-call-list.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 399 insertions(+), 3 deletions(-) + create mode 100644 include/call-list.h + create mode 100644 src/call-list.c + create mode 100644 unit/test-call-list.c + +Index: ofono-1.21/Makefile.am +=================================================================== +--- ofono-1.21.orig/Makefile.am ++++ ofono-1.21/Makefile.am +@@ -22,7 +22,7 @@ pkginclude_HEADERS = include/log.h inclu + include/private-network.h include/cdma-netreg.h \ + include/cdma-provision.h include/handsfree.h \ + include/handsfree-audio.h include/siri.h \ +- include/netmon.h include/lte.h ++ include/netmon.h include/lte.h include/call-list.h + + nodist_pkginclude_HEADERS = include/version.h + +@@ -630,7 +630,7 @@ src_ofonod_SOURCES = $(builtin_sources) + src/cdma-provision.c src/handsfree.c \ + src/handsfree-audio.c src/bluetooth.h \ + src/hfp.h src/siri.c \ +- src/netmon.c src/lte.c \ ++ src/netmon.c src/lte.c src/call-list.c \ + src/netmonagent.c src/netmonagent.h + + src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \ +@@ -807,7 +807,8 @@ unit_tests = unit/test-common unit/test- + unit/test-rilmodem-cs \ + unit/test-rilmodem-sms \ + unit/test-rilmodem-cb \ +- unit/test-rilmodem-gprs ++ unit/test-rilmodem-gprs \ ++ unit/test-call-list + + noinst_PROGRAMS = $(unit_tests) \ + unit/test-sms-root unit/test-mux unit/test-caif +@@ -849,6 +850,12 @@ unit_test_sms_root_SOURCES = unit/test-s + unit_test_sms_root_LDADD = @GLIB_LIBS@ + unit_objects += $(unit_test_sms_root_OBJECTS) + ++unit_test_call_list_SOURCES = \ ++ src/common.c src/util.c src/log.c \ ++ src/call-list.c unit/test-call-list.c ++unit_test_call_list_LDADD = @GLIB_LIBS@ -ldl ++unit_objects += $(unit_test_call_list_OBJECTS) ++ + unit_test_mux_SOURCES = unit/test-mux.c $(gatchat_sources) + unit_test_mux_LDADD = @GLIB_LIBS@ + unit_objects += $(unit_test_mux_OBJECTS) +Index: ofono-1.21/include/call-list.h +=================================================================== +--- /dev/null ++++ ofono-1.21/include/call-list.h +@@ -0,0 +1,38 @@ ++/* ++ * ++ * oFono - Open Source Telephony ++ * ++ * Copyright (C) 2017 Alexander Couzens ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++ ++struct ofono_voicecall; ++struct ofono_phone_number; ++ ++/* ++ * Can be called by the driver in the dialing callback, ++ * when the new call id already known ++ */ ++void ofono_call_list_dial_callback(struct ofono_voicecall *vc, ++ GSList **call_list, ++ const struct ofono_phone_number *ph, ++ int call_id); ++ ++/* ++ * Called with a list of known calls e.g. clcc. ++ * Call list will take ownership of all ofono call within the calls. ++ */ ++void ofono_call_list_notify(struct ofono_voicecall *vc, ++ GSList **call_list, ++ GSList *calls); +Index: ofono-1.21/src/call-list.c +=================================================================== +--- /dev/null ++++ ofono-1.21/src/call-list.c +@@ -0,0 +1,114 @@ ++/* ++ * ++ * oFono - Open Source Telephony ++ * ++ * Copyright (C) 2017 Alexander Couzens ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++ ++#include "common.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++void ofono_call_list_dial_callback(struct ofono_voicecall *vc, ++ GSList **call_list, ++ const struct ofono_phone_number *ph, ++ int call_id) ++{ ++ GSList *list; ++ struct ofono_call *call; ++ ++ /* list_notify could be triggered before this call back is handled */ ++ list = g_slist_find_custom(*call_list, ++ GINT_TO_POINTER(call_id), ++ ofono_call_compare_by_id); ++ ++ if (list && list->data) { ++ call = list->data; ++ DBG("Call id %d already known. In state %s(%d)", ++ call_id, ofono_call_status_to_string(call->status), ++ call->status); ++ return; ++ } ++ ++ call = g_new0(struct ofono_call, 1); ++ call->id = call_id; ++ ++ memcpy(&call->called_number, ph, sizeof(*ph)); ++ call->direction = CALL_DIRECTION_MOBILE_ORIGINATED; ++ call->status = CALL_STATUS_DIALING; ++ call->type = 0; /* voice */ ++ ++ *call_list = g_slist_insert_sorted(*call_list, ++ call, ++ ofono_call_compare); ++ ofono_voicecall_notify(vc, call); ++} ++ ++void ofono_call_list_notify(struct ofono_voicecall *vc, ++ GSList **call_list, ++ GSList *calls) ++{ ++ GSList *old_calls = *call_list; ++ GSList *new_calls = calls; ++ struct ofono_call *new_call, *old_call; ++ ++ while (old_calls || new_calls) { ++ old_call = old_calls ? old_calls->data : NULL; ++ new_call = new_calls ? new_calls->data : NULL; ++ ++ /* we drop disconnected calls and treat them as not existent */ ++ if (new_call && new_call->status == CALL_STATUS_DISCONNECTED) { ++ new_calls = new_calls->next; ++ calls = g_slist_remove(calls, new_call); ++ g_free(new_call); ++ continue; ++ } ++ ++ if (old_call && ++ (new_call == NULL || ++ (new_call->id > old_call->id))) { ++ ofono_voicecall_disconnected( ++ vc, ++ old_call->id, ++ OFONO_DISCONNECT_REASON_UNKNOWN, ++ NULL); ++ old_calls = old_calls->next; ++ } else if (new_call && ++ (old_call == NULL || ++ (new_call->id < old_call->id))) { ++ ++ /* new call, signal it */ ++ if (new_call->type == 0) ++ ofono_voicecall_notify(vc, new_call); ++ ++ new_calls = new_calls->next; ++ } else { ++ if (memcmp(new_call, old_call, sizeof(*new_call)) ++ && new_call->type == 0) ++ ofono_voicecall_notify(vc, new_call); ++ ++ new_calls = new_calls->next; ++ old_calls = old_calls->next; ++ } ++ } ++ ++ g_slist_free_full(*call_list, g_free); ++ *call_list = calls; ++} +Index: ofono-1.21/unit/test-call-list.c +=================================================================== +--- /dev/null ++++ ofono-1.21/unit/test-call-list.c +@@ -0,0 +1,237 @@ ++/* ++ * ++ * oFono - Open Source Telephony ++ * ++ * Copyright (C) 2017 Alexander Couzens ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++ ++#include ++#include ++ ++ ++#include "../src/common.h" ++#include ++#include ++ ++struct voicecall { ++}; ++ ++struct notified { ++ unsigned int id; ++ enum call_status status; ++}; ++ ++static struct notified notified_list[32]; ++static int notified_idx; ++static int notified_check; ++ ++void reset_notified(void) ++{ ++ notified_idx = 0; ++ notified_check = 0; ++ memset(¬ified_list, 0, sizeof(notified_list)); ++} ++ ++void ofono_voicecall_notify(struct ofono_voicecall *vc, ++ struct ofono_call *call) ++{ ++ notified_list[notified_idx].id = call->id; ++ notified_list[notified_idx].status = call->status; ++ notified_idx++; ++} ++ ++void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id, ++ enum ofono_disconnect_reason reason, ++ const struct ofono_error *error) ++{ ++ notified_list[notified_idx].id = id; ++ notified_list[notified_idx].status = CALL_STATUS_DISCONNECTED; ++ notified_idx++; ++} ++ ++static GSList *create_call( ++ GSList *calls, ++ unsigned int id, ++ enum call_status status, ++ enum call_direction direction) ++{ ++ struct ofono_call *call = g_new0(struct ofono_call, 1); ++ ++ call->id = id; ++ call->status = status; ++ call->direction = direction; ++ ++ calls = g_slist_insert_sorted(calls, call, ofono_call_compare); ++ ++ return calls; ++} ++ ++static void assert_notified(unsigned int call_id, int call_status) ++{ ++ g_assert(notified_idx >= notified_check); ++ g_assert(notified_list[notified_check].id == call_id); ++ g_assert(notified_list[notified_check].status == call_status); ++ ++ notified_check++; ++} ++ ++static void test_notify_disconnected(void) ++{ ++ struct ofono_voicecall *vc = NULL; ++ struct ofono_phone_number ph; ++ GSList *call_list; ++ GSList *calls; ++ ++ strcpy(ph.number, "004888123456"); ++ ph.type = 0; ++ ++ /* reset test */ ++ reset_notified(); ++ call_list = NULL; ++ ++ /* fill disconnected call*/ ++ calls = create_call(NULL, 1, CALL_STATUS_DISCONNECTED, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ++ /* incoming call */ ++ calls = create_call(NULL, 1, CALL_STATUS_DISCONNECTED, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ calls = create_call(calls, 1, CALL_STATUS_ALERTING, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ++ /* answer call */ ++ calls = create_call(NULL, 1, CALL_STATUS_ACTIVE, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ calls = create_call(calls, 1, CALL_STATUS_DISCONNECTED, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ++ /* another call waiting */ ++ calls = create_call(NULL, 1, CALL_STATUS_DISCONNECTED, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ calls = create_call(calls, 1, CALL_STATUS_ACTIVE, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ calls = create_call(calls, 2, CALL_STATUS_DISCONNECTED, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ calls = create_call(calls, 2, CALL_STATUS_WAITING, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ calls = create_call(calls, 2, CALL_STATUS_DISCONNECTED, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ++ /* end all calls */ ++ ofono_call_list_notify(vc, &call_list, NULL); ++ ++ /* verify call history */ ++ assert_notified(1, CALL_STATUS_ALERTING); ++ assert_notified(1, CALL_STATUS_ACTIVE); ++ assert_notified(2, CALL_STATUS_WAITING); ++ assert_notified(1, CALL_STATUS_DISCONNECTED); ++ assert_notified(2, CALL_STATUS_DISCONNECTED); ++ ++ g_assert(notified_check == notified_idx); ++ g_slist_free_full(call_list, g_free); ++} ++ ++static void test_notify(void) ++{ ++ struct ofono_voicecall *vc = NULL; ++ struct ofono_phone_number ph; ++ GSList *call_list; ++ GSList *calls; ++ ++ strcpy(ph.number, "004888123456"); ++ ph.type = 0; ++ ++ /* reset test */ ++ reset_notified(); ++ call_list = NULL; ++ ++ /* incoming call */ ++ calls = create_call(NULL, 1, CALL_STATUS_ALERTING, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ++ /* answer call */ ++ calls = create_call(NULL, 1, CALL_STATUS_ACTIVE, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ++ /* another call waiting */ ++ calls = create_call(NULL, 1, CALL_STATUS_ACTIVE, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ calls = create_call(calls, 2, CALL_STATUS_WAITING, ++ CALL_DIRECTION_MOBILE_TERMINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ++ /* end all calls */ ++ ofono_call_list_notify(vc, &call_list, NULL); ++ ++ /* verify call history */ ++ assert_notified(1, CALL_STATUS_ALERTING); ++ assert_notified(1, CALL_STATUS_ACTIVE); ++ assert_notified(2, CALL_STATUS_WAITING); ++ assert_notified(1, CALL_STATUS_DISCONNECTED); ++ assert_notified(2, CALL_STATUS_DISCONNECTED); ++ ++ g_assert(notified_check == notified_idx); ++ g_slist_free_full(call_list, g_free); ++} ++ ++static void test_dial_callback(void) ++{ ++ struct ofono_voicecall *vc = NULL; ++ struct ofono_phone_number ph; ++ struct ofono_call *call; ++ GSList *call_list, *calls; ++ ++ /* reset test */ ++ reset_notified(); ++ call_list = NULL; ++ ++ strcpy(ph.number, "0099301234567890"); ++ ph.type = 0; ++ ++ /* check if a call gets added to the call_list */ ++ ofono_call_list_dial_callback(vc, &call_list, &ph, 33); ++ ++ call = call_list->data; ++ g_assert(strcmp(call->called_number.number, ph.number) == 0); ++ g_slist_free_full(call_list, g_free); ++ ++ /* check when notify is faster than dial_callback */ ++ call_list = NULL; ++ calls = create_call(NULL, 1, CALL_STATUS_DIALING, ++ CALL_DIRECTION_MOBILE_ORIGINATED); ++ ofono_call_list_notify(vc, &call_list, calls); ++ ofono_call_list_dial_callback(vc, &call_list, &ph, 1); ++ call = call_list->data; ++ g_assert(call_list->next == NULL); ++ g_slist_free_full(call_list, g_free); ++ ++ call_list = NULL; ++} ++ ++int main(int argc, char **argv) ++{ ++ g_test_init(&argc, &argv, NULL); ++ ++ g_test_add_func("/test-call-list/test_notify", test_notify); ++ g_test_add_func("/test-call-list/test_notify_disconnected", ++ test_notify_disconnected); ++ g_test_add_func("/test-call-list/dial_callback", test_dial_callback); ++ return g_test_run(); ++} diff --git a/modem/ofono/0007-common-atmodem-rename-move-at_util_call_compare_by_s.patch b/modem/ofono/0007-common-atmodem-rename-move-at_util_call_compare_by_s.patch new file mode 100644 index 000000000..3454162a4 --- /dev/null +++ b/modem/ofono/0007-common-atmodem-rename-move-at_util_call_compare_by_s.patch @@ -0,0 +1,313 @@ +From 4c71f0ca71c74987523c68764df28840ccd3882e Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Tue, 25 Jul 2017 15:35:51 +0200 +Subject: [PATCH 07/17] common,atmodem: rename & move + at_util_call_compare_by_status to common.c + +at_util_call_compare_by_status is used by several modem drivers. +--- + drivers/atmodem/atutil.c | 11 ----------- + drivers/atmodem/atutil.h | 2 +- + drivers/atmodem/voicecall.c | 16 ++++++++-------- + drivers/hfpmodem/voicecall.c | 20 ++++++++++---------- + drivers/huaweimodem/voicecall.c | 4 ++-- + drivers/ifxmodem/voicecall.c | 10 +++++----- + src/common.c | 11 +++++++++++ + src/common.h | 1 + + 8 files changed, 38 insertions(+), 37 deletions(-) + +Index: ofono-1.21/drivers/atmodem/atutil.c +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/atutil.c ++++ ofono-1.21/drivers/atmodem/atutil.c +@@ -69,17 +69,6 @@ void decode_at_error(struct ofono_error + } + } + +-gint at_util_call_compare_by_status(gconstpointer a, gconstpointer b) +-{ +- const struct ofono_call *call = a; +- int status = GPOINTER_TO_INT(b); +- +- if (status != call->status) +- return 1; +- +- return 0; +-} +- + gint at_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b) + { + const struct ofono_call *call = a; +Index: ofono-1.21/drivers/atmodem/atutil.h +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/atutil.h ++++ ofono-1.21/drivers/atmodem/atutil.h +@@ -51,7 +51,7 @@ enum at_util_charset { + typedef void (*at_util_sim_inserted_cb_t)(gboolean present, void *userdata); + + void decode_at_error(struct ofono_error *error, const char *final); +-gint at_util_call_compare_by_status(gconstpointer a, gconstpointer b); ++gint ofono_call_compare_by_status(gconstpointer a, gconstpointer b); + gint at_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b); + gint at_util_call_compare_by_id(gconstpointer a, gconstpointer b); + GSList *at_util_parse_clcc(GAtResult *result, unsigned int *mpty_ids); +Index: ofono-1.21/drivers/atmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/voicecall.c ++++ ofono-1.21/drivers/atmodem/voicecall.c +@@ -660,13 +660,13 @@ static void ring_notify(GAtResult *resul + /* See comment in CRING */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + /* RING can repeat, ignore if we already have an incoming call */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + /* Generate an incoming call of unknown type */ +@@ -698,13 +698,13 @@ static void cring_notify(GAtResult *resu + */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + /* CRING can repeat, ignore if we already have an incoming call */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + g_at_result_iter_init(&iter, result); +@@ -748,7 +748,7 @@ static void clip_notify(GAtResult *resul + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CLIP for unknown call"); + return; +@@ -810,7 +810,7 @@ static void cdip_notify(GAtResult *resul + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CDIP for unknown call"); + return; +@@ -859,7 +859,7 @@ static void cnap_notify(GAtResult *resul + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CNAP for unknown call"); + return; +@@ -913,7 +913,7 @@ static void ccwa_notify(GAtResult *resul + /* Some modems resend CCWA, ignore it the second time around */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + g_at_result_iter_init(&iter, result); +Index: ofono-1.21/drivers/hfpmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/hfpmodem/voicecall.c ++++ ofono-1.21/drivers/hfpmodem/voicecall.c +@@ -85,12 +85,12 @@ static GSList *find_dialing(GSList *call + GSList *c; + + c = g_slist_find_custom(calls, GINT_TO_POINTER(CALL_STATUS_DIALING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + + if (c == NULL) + c = g_slist_find_custom(calls, + GINT_TO_POINTER(CALL_STATUS_ALERTING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + + return c; + } +@@ -720,7 +720,7 @@ static void ccwa_notify(GAtResult *resul + /* CCWA can repeat, ignore if we already have an waiting call */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + /* some phones may send extra CCWA after active call is ended +@@ -729,7 +729,7 @@ static void ccwa_notify(GAtResult *resul + */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + +@@ -772,7 +772,7 @@ static gboolean clip_timeout(gpointer us + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + + if (l == NULL) + return FALSE; +@@ -801,12 +801,12 @@ static void ring_notify(GAtResult *resul + /* RING can repeat, ignore if we already have an incoming call */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + waiting = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + + /* If we started receiving RINGS but have a waiting call, most + * likely all other calls were dropped and we just didn't get +@@ -851,7 +851,7 @@ static void clip_notify(GAtResult *resul + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + + if (l == NULL) { + ofono_error("CLIP for unknown call"); +@@ -967,7 +967,7 @@ static void ciev_callsetup_notify(struct + + waiting = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + + /* This is a truly bizarre case not covered at all by the specification + * (yes, they are complete idiots). Here we assume the other side is +@@ -1046,7 +1046,7 @@ static void ciev_callsetup_notify(struct + { + GSList *o = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_DIALING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + + if (o) { + struct ofono_call *call = o->data; +Index: ofono-1.21/drivers/huaweimodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/huaweimodem/voicecall.c ++++ ofono-1.21/drivers/huaweimodem/voicecall.c +@@ -179,7 +179,7 @@ static void cring_notify(GAtResult *resu + /* CRING can repeat, ignore if we already have an incoming call */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + g_at_result_iter_init(&iter, result); +@@ -218,7 +218,7 @@ static void clip_notify(GAtResult *resul + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CLIP for unknown call"); + return; +Index: ofono-1.21/drivers/ifxmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/ifxmodem/voicecall.c ++++ ofono-1.21/drivers/ifxmodem/voicecall.c +@@ -545,12 +545,12 @@ static void cring_notify(GAtResult *resu + */ + if (g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status)) ++ ofono_call_compare_by_status)) + return; + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CRING received before XCALLSTAT!!!"); + return; +@@ -589,7 +589,7 @@ static void clip_notify(GAtResult *resul + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CLIP for unknown call"); + return; +@@ -649,7 +649,7 @@ static void cnap_notify(GAtResult *resul + */ + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_INCOMING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CNAP for unknown call"); + return; +@@ -695,7 +695,7 @@ static void ccwa_notify(GAtResult *resul + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(CALL_STATUS_WAITING), +- at_util_call_compare_by_status); ++ ofono_call_compare_by_status); + if (l == NULL) { + ofono_error("CCWA received before XCALLSTAT!!!"); + return; +Index: ofono-1.21/src/common.c +=================================================================== +--- ofono-1.21.orig/src/common.c ++++ ofono-1.21/src/common.c +@@ -780,6 +780,17 @@ gint ofono_call_compare(gconstpointer a, + return 0; + } + ++gint ofono_call_compare_by_status(gconstpointer a, gconstpointer b) ++{ ++ const struct ofono_call *call = a; ++ int status = GPOINTER_TO_INT(b); ++ ++ if (status != call->status) ++ return 1; ++ ++ return 0; ++} ++ + const char *ofono_call_status_to_string(enum call_status status) + { + switch (status) { +Index: ofono-1.21/src/common.h +=================================================================== +--- ofono-1.21.orig/src/common.h ++++ ofono-1.21/src/common.h +@@ -185,4 +185,5 @@ const char *packet_bearer_to_string(int + + gboolean is_valid_apn(const char *apn); + gint ofono_call_compare(gconstpointer a, gconstpointer b); ++gint ofono_call_compare_by_status(gconstpointer a, gconstpointer b); + const char *ofono_call_status_to_string(enum call_status status); diff --git a/modem/ofono/0008-common-atmodem-rename-move-at_util_call_compare_by_i.patch b/modem/ofono/0008-common-atmodem-rename-move-at_util_call_compare_by_i.patch new file mode 100644 index 000000000..2abbe0023 --- /dev/null +++ b/modem/ofono/0008-common-atmodem-rename-move-at_util_call_compare_by_i.patch @@ -0,0 +1,156 @@ +From 3bba30fd23705dc8817b2eb0f28c9be03b8f7892 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Tue, 25 Jul 2017 15:39:36 +0200 +Subject: [PATCH 08/17] common,atmodem: rename & move + at_util_call_compare_by_id to common.c + +at_util_call_compare_by_id is used by several modem drivers. +--- + drivers/atmodem/atutil.c | 14 -------------- + drivers/atmodem/atutil.h | 2 +- + drivers/huaweimodem/voicecall.c | 6 +++--- + drivers/ifxmodem/voicecall.c | 4 ++-- + drivers/stemodem/voicecall.c | 2 +- + src/common.c | 14 ++++++++++++++ + src/common.h | 1 + + 7 files changed, 22 insertions(+), 21 deletions(-) + +Index: ofono-1.21/drivers/atmodem/atutil.c +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/atutil.c ++++ ofono-1.21/drivers/atmodem/atutil.c +@@ -78,20 +78,6 @@ gint at_util_call_compare_by_phone_numbe + sizeof(struct ofono_phone_number)); + } + +-gint at_util_call_compare_by_id(gconstpointer a, gconstpointer b) +-{ +- const struct ofono_call *call = a; +- unsigned int id = GPOINTER_TO_UINT(b); +- +- if (id < call->id) +- return -1; +- +- if (id > call->id) +- return 1; +- +- return 0; +-} +- + GSList *at_util_parse_clcc(GAtResult *result, unsigned int *ret_mpty_ids) + { + GAtResultIter iter; +Index: ofono-1.21/drivers/atmodem/atutil.h +=================================================================== +--- ofono-1.21.orig/drivers/atmodem/atutil.h ++++ ofono-1.21/drivers/atmodem/atutil.h +@@ -53,7 +53,7 @@ typedef void (*at_util_sim_inserted_cb_t + void decode_at_error(struct ofono_error *error, const char *final); + gint ofono_call_compare_by_status(gconstpointer a, gconstpointer b); + gint at_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b); +-gint at_util_call_compare_by_id(gconstpointer a, gconstpointer b); ++gint ofono_call_compare_by_id(gconstpointer a, gconstpointer b); + GSList *at_util_parse_clcc(GAtResult *result, unsigned int *mpty_ids); + gboolean at_util_parse_reg(GAtResult *result, const char *prefix, + int *mode, int *status, +Index: ofono-1.21/drivers/huaweimodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/huaweimodem/voicecall.c ++++ ofono-1.21/drivers/huaweimodem/voicecall.c +@@ -347,7 +347,7 @@ static void conf_notify(GAtResult *resul + ofono_info("Call setup: id %d", call_id); + + l = g_slist_find_custom(vd->calls, GINT_TO_POINTER(call_id), +- at_util_call_compare_by_id); ++ ofono_call_compare_by_id); + if (l == NULL) { + ofono_error("Received CONF for untracked call"); + return; +@@ -384,7 +384,7 @@ static void conn_notify(GAtResult *resul + ofono_info("Call connect: id %d type %d", call_id, call_type); + + l = g_slist_find_custom(vd->calls, GINT_TO_POINTER(call_id), +- at_util_call_compare_by_id); ++ ofono_call_compare_by_id); + if (l == NULL) { + ofono_error("Received CONN for untracked call"); + return; +@@ -428,7 +428,7 @@ static void cend_notify(GAtResult *resul + call_id, duration, end_status); + + l = g_slist_find_custom(vd->calls, GINT_TO_POINTER(call_id), +- at_util_call_compare_by_id); ++ ofono_call_compare_by_id); + if (l == NULL) { + ofono_error("Received CEND for untracked call"); + return; +Index: ofono-1.21/drivers/ifxmodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/ifxmodem/voicecall.c ++++ ofono-1.21/drivers/ifxmodem/voicecall.c +@@ -135,7 +135,7 @@ static void xcallstat_notify(GAtResult * + return; + + l = g_slist_find_custom(vd->calls, GINT_TO_POINTER(id), +- at_util_call_compare_by_id); ++ ofono_call_compare_by_id); + + if (l == NULL && status != CALL_STATUS_DIALING && + status != CALL_STATUS_INCOMING && +@@ -773,7 +773,7 @@ static void xcolp_notify(GAtResult *resu + + l = g_slist_find_custom(vd->calls, + GINT_TO_POINTER(call_id), +- at_util_call_compare_by_id); ++ ofono_call_compare_by_id); + if (l == NULL) { + ofono_error("XCOLP for unknown call"); + return; +Index: ofono-1.21/drivers/stemodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/stemodem/voicecall.c ++++ ofono-1.21/drivers/stemodem/voicecall.c +@@ -462,7 +462,7 @@ static void ecav_notify(GAtResult *resul + * If it doesn't exists we make a new one + */ + l = g_slist_find_custom(vd->calls, GUINT_TO_POINTER(id), +- at_util_call_compare_by_id); ++ ofono_call_compare_by_id); + + if (l) + existing_call = l->data; +Index: ofono-1.21/src/common.c +=================================================================== +--- ofono-1.21.orig/src/common.c ++++ ofono-1.21/src/common.c +@@ -791,6 +791,20 @@ gint ofono_call_compare_by_status(gconst + return 0; + } + ++gint ofono_call_compare_by_id(gconstpointer a, gconstpointer b) ++{ ++ const struct ofono_call *call = a; ++ unsigned int id = GPOINTER_TO_UINT(b); ++ ++ if (id < call->id) ++ return -1; ++ ++ if (id > call->id) ++ return 1; ++ ++ return 0; ++} ++ + const char *ofono_call_status_to_string(enum call_status status) + { + switch (status) { +Index: ofono-1.21/src/common.h +=================================================================== +--- ofono-1.21.orig/src/common.h ++++ ofono-1.21/src/common.h +@@ -186,4 +186,5 @@ const char *packet_bearer_to_string(int + gboolean is_valid_apn(const char *apn); + gint ofono_call_compare(gconstpointer a, gconstpointer b); + gint ofono_call_compare_by_status(gconstpointer a, gconstpointer b); ++gint ofono_call_compare_by_id(gconstpointer a, gconstpointer b); + const char *ofono_call_status_to_string(enum call_status status); diff --git a/modem/ofono/0011-qmimodem-sync-the-modem-on-enable.patch b/modem/ofono/0011-qmimodem-sync-the-modem-on-enable.patch new file mode 100644 index 000000000..353318a22 --- /dev/null +++ b/modem/ofono/0011-qmimodem-sync-the-modem-on-enable.patch @@ -0,0 +1,123 @@ +From 32dac2f67735efa1bbfcd7c5563d5cbc980c6770 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Tue, 25 Jul 2017 20:36:00 +0200 +Subject: [PATCH 11/17] qmimodem: sync the modem on enable + +The qmi sync call release all previous resources. +--- + drivers/qmimodem/qmi.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + drivers/qmimodem/qmi.h | 5 ++++- + plugins/gobi.c | 12 +++++++++++- + 3 files changed, 62 insertions(+), 2 deletions(-) + +Index: ofono-1.21/drivers/qmimodem/qmi.c +=================================================================== +--- ofono-1.21.orig/drivers/qmimodem/qmi.c ++++ ofono-1.21/drivers/qmimodem/qmi.c +@@ -1323,6 +1323,53 @@ bool qmi_device_shutdown(struct qmi_devi + return true; + } + ++struct sync_data { ++ qmi_sync_func_t func; ++ void *user_data; ++}; ++ ++static void qmi_device_sync_callback(uint16_t message, uint16_t length, ++ const void *buffer, void *user_data) ++{ ++ struct sync_data *data = user_data; ++ ++ if(data->func) ++ data->func(data->user_data); ++ ++ g_free(data); ++} ++ ++/* sync will release all previous clients */ ++bool qmi_device_sync(struct qmi_device *device, ++ qmi_sync_func_t func, void *user_data) ++{ ++ struct qmi_request *req; ++ struct qmi_control_hdr *hdr; ++ struct sync_data *func_data; ++ ++ if (!device) ++ return false; ++ ++ func_data = g_new0(struct sync_data, 1); ++ func_data->func = func; ++ func_data->user_data = user_data; ++ ++ req = __request_alloc(QMI_SERVICE_CONTROL, 0x00, ++ QMI_CTL_SYNC, QMI_CONTROL_HDR_SIZE, ++ NULL, 0, ++ qmi_device_sync_callback, func_data, (void **) &hdr); ++ ++ if (device->next_control_tid < 1) ++ device->next_control_tid = 1; ++ ++ hdr->type = 0x00; ++ hdr->transaction = device->next_control_tid++; ++ ++ __request_submit(device, req, hdr->transaction); ++ ++ return true; ++} ++ + static bool get_device_file_name(struct qmi_device *device, + char *file_name, int size) + { +Index: ofono-1.21/drivers/qmimodem/qmi.h +=================================================================== +--- ofono-1.21.orig/drivers/qmimodem/qmi.h ++++ ofono-1.21/drivers/qmimodem/qmi.h +@@ -76,7 +76,7 @@ typedef void (*qmi_destroy_func_t)(void + struct qmi_device; + + typedef void (*qmi_debug_func_t)(const char *str, void *user_data); +- ++typedef void (*qmi_sync_func_t)(void *user_data); + typedef void (*qmi_shutdown_func_t)(void *user_data); + typedef void (*qmi_discover_func_t)(uint8_t count, + const struct qmi_version *list, void *user_data); +@@ -96,6 +96,9 @@ bool qmi_device_discover(struct qmi_devi + bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func, + void *user_data, qmi_destroy_func_t destroy); + ++bool qmi_device_sync(struct qmi_device *device, ++ qmi_sync_func_t func, void *user_data); ++ + enum qmi_device_expected_data_format qmi_device_get_expected_data_format( + struct qmi_device *device); + bool qmi_device_set_expected_data_format(struct qmi_device *device, +Index: ofono-1.21/plugins/gobi.c +=================================================================== +--- ofono-1.21.orig/plugins/gobi.c ++++ ofono-1.21/plugins/gobi.c +@@ -320,6 +320,16 @@ static void discover_cb(uint8_t count, c + create_dms_cb, modem, NULL); + } + ++static void sync_cb(void *user_data) ++{ ++ struct ofono_modem *modem = user_data; ++ struct gobi_data *data = ofono_modem_get_data(modem); ++ ++ DBG("modem in sync"); ++ ++ qmi_device_discover(data->device, discover_cb, modem, NULL); ++} ++ + static int gobi_enable(struct ofono_modem *modem) + { + struct gobi_data *data = ofono_modem_get_data(modem); +@@ -347,7 +357,7 @@ static int gobi_enable(struct ofono_mode + + qmi_device_set_close_on_unref(data->device, true); + +- qmi_device_discover(data->device, discover_cb, modem, NULL); ++ qmi_device_sync(data->device, sync_cb, modem); + + return -EINPROGRESS; + } diff --git a/modem/ofono/0014-network-ofono_netreg_status_notify-debug-output-lac-.patch b/modem/ofono/0014-network-ofono_netreg_status_notify-debug-output-lac-.patch new file mode 100644 index 000000000..514651d07 --- /dev/null +++ b/modem/ofono/0014-network-ofono_netreg_status_notify-debug-output-lac-.patch @@ -0,0 +1,26 @@ +From e3d6b09ab785af7e0eab4628592a8bb8239ef7a3 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Wed, 26 Jul 2017 02:11:23 +0200 +Subject: [PATCH 14/17] network/ofono_netreg_status_notify: debug output lac + and ci + +The location are code and cell id is updated at the same time. +--- + src/network.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: ofono-1.21/src/network.c +=================================================================== +--- ofono-1.21.orig/src/network.c ++++ ofono-1.21/src/network.c +@@ -1351,8 +1351,8 @@ void ofono_netreg_status_notify(struct o + if (netreg == NULL) + return; + +- DBG("%s status %d tech %d", __ofono_atom_get_path(netreg->atom), +- status, tech); ++ DBG("%s status %d tech %d lac %d ci %d", ++ __ofono_atom_get_path(netreg->atom), status, tech, lac, ci); + + if (netreg->status != status) { + struct ofono_modem *modem; diff --git a/modem/ofono/0015-network-debug-output-the-network-time-if-updated.patch b/modem/ofono/0015-network-debug-output-the-network-time-if-updated.patch new file mode 100644 index 000000000..cf9e33d84 --- /dev/null +++ b/modem/ofono/0015-network-debug-output-the-network-time-if-updated.patch @@ -0,0 +1,25 @@ +From 8f00ef8b3b9be29ad6f58769234a30c6c5ae0d27 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Wed, 26 Jul 2017 02:12:16 +0200 +Subject: [PATCH 15/17] network: debug output the network time if updated + +--- + src/network.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: ofono-1.21/src/network.c +=================================================================== +--- ofono-1.21.orig/src/network.c ++++ ofono-1.21/src/network.c +@@ -1407,6 +1407,11 @@ void ofono_netreg_time_notify(struct ofo + if (info == NULL) + return; + ++ DBG("net time %d-%02d-%02d %02d:%02d:%02d utcoff %d dst %d", ++ info->year, info->mon, info->mday, ++ info->hour, info->min, info->sec, ++ info->utcoff, info->dst); ++ + __ofono_nettime_info_received(modem, info); + } + diff --git a/modem/ofono/0016-voicecall-prefer-release_specific-over-hang_up_activ.patch b/modem/ofono/0016-voicecall-prefer-release_specific-over-hang_up_activ.patch new file mode 100644 index 000000000..f5f1d6fd1 --- /dev/null +++ b/modem/ofono/0016-voicecall-prefer-release_specific-over-hang_up_activ.patch @@ -0,0 +1,53 @@ +From d43fde3c5e6165b8a977c8917c11e4d1a55eac3f Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Tue, 25 Jul 2017 16:43:03 +0200 +Subject: [PATCH 16/17] voicecall: prefer release_specific() over + hang_up_active/hangup_all + +release_specific() has the call_id as parameter in difference to the more unspecific +calls hangup_all and hangup_active. +--- + src/voicecall.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +Index: ofono-1.21/src/voicecall.c +=================================================================== +--- ofono-1.21.orig/src/voicecall.c ++++ ofono-1.21/src/voicecall.c +@@ -542,10 +542,18 @@ static DBusMessage *voicecall_hangup(DBu + if (vc->dial_req && vc->dial_req->call != v) + return __ofono_error_busy(msg); + +- switch (call->status) { +- case CALL_STATUS_DISCONNECTED: ++ if (call->status == CALL_STATUS_DISCONNECTED) + return __ofono_error_failed(msg); + ++ if (vc->driver->release_specific) { ++ vc->pending = dbus_message_ref(msg); ++ vc->driver->release_specific(vc, call->id, ++ generic_callback, vc); ++ ++ return NULL; ++ } ++ ++ switch (call->status) { + case CALL_STATUS_INCOMING: + if (vc->driver->hangup_all == NULL && + vc->driver->hangup_active == NULL) +@@ -615,14 +623,7 @@ static DBusMessage *voicecall_hangup(DBu + break; + } + +- if (vc->driver->release_specific == NULL) +- return __ofono_error_not_implemented(msg); +- +- vc->pending = dbus_message_ref(msg); +- vc->driver->release_specific(vc, call->id, +- generic_callback, vc); +- +- return NULL; ++ return __ofono_error_not_implemented(msg); + } + + static DBusMessage *voicecall_answer(DBusConnection *conn, diff --git a/modem/ofono/0017-RFC-qmimodem-implement-voice-calls.patch b/modem/ofono/0017-RFC-qmimodem-implement-voice-calls.patch new file mode 100644 index 000000000..2f8eee062 --- /dev/null +++ b/modem/ofono/0017-RFC-qmimodem-implement-voice-calls.patch @@ -0,0 +1,976 @@ +From df3b0c1cd8be029ff2c98c2ba7ba1110385a17f6 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Tue, 25 Jul 2017 15:31:48 +0200 +Subject: [PATCH 17/17] [RFC] qmimodem: implement voice calls + +The voice_generated.* files is an RFC how files should look like. +They aren't yet generated. +--- + Makefile.am | 5 +- + drivers/qmimodem/qmi.h | 13 ++ + drivers/qmimodem/voice.c | 86 ++++++++++ + drivers/qmimodem/voice.h | 84 ++++++++++ + drivers/qmimodem/voice_generated.c | 210 +++++++++++++++++++++++ + drivers/qmimodem/voice_generated.h | 113 +++++++++++++ + drivers/qmimodem/voicecall.c | 332 ++++++++++++++++++++++++++++++++++++- + 7 files changed, 840 insertions(+), 3 deletions(-) + create mode 100644 drivers/qmimodem/voice.c + create mode 100644 drivers/qmimodem/voice.h + create mode 100644 drivers/qmimodem/voice_generated.c + create mode 100644 drivers/qmimodem/voice_generated.h + +Index: ofono-1.21/Makefile.am +=================================================================== +--- ofono-1.21.orig/Makefile.am ++++ ofono-1.21/Makefile.am +@@ -216,7 +216,9 @@ qmi_sources = drivers/qmimodem/qmi.h dri + drivers/qmimodem/wds.h \ + drivers/qmimodem/pds.h \ + drivers/qmimodem/common.h \ +- drivers/qmimodem/wda.h ++ drivers/qmimodem/wda.h \ ++ drivers/qmimodem/voice.h \ ++ drivers/qmimodem/voice.c + + builtin_modules += qmimodem + builtin_sources += $(qmi_sources) \ +@@ -225,6 +227,7 @@ builtin_sources += $(qmi_sources) \ + drivers/qmimodem/qmimodem.c \ + drivers/qmimodem/devinfo.c \ + drivers/qmimodem/voicecall.c \ ++ drivers/qmimodem/voice_generated.c \ + drivers/qmimodem/network-registration.c \ + drivers/qmimodem/sim-legacy.c \ + drivers/qmimodem/sim.c \ +Index: ofono-1.21/drivers/qmimodem/qmi.h +=================================================================== +--- ofono-1.21.orig/drivers/qmimodem/qmi.h ++++ ofono-1.21/drivers/qmimodem/qmi.h +@@ -19,6 +19,9 @@ + * + */ + ++#ifndef __OFONO_QMI_QMI_H ++#define __OFONO_QMI_QMI_H ++ + #include + #include + +@@ -175,3 +178,13 @@ uint16_t qmi_service_register(struct qmi + void *user_data, qmi_destroy_func_t destroy); + bool qmi_service_unregister(struct qmi_service *service, uint16_t id); + bool qmi_service_unregister_all(struct qmi_service *service); ++ ++ ++/* FIXME: find a place for parse_error */ ++enum parse_error { ++ NONE = 0, ++ MISSING_MANDATORY = 1, ++ INVALID_LENGTH = 2, ++}; ++ ++#endif /* __OFONO_QMI_QMI_H */ +Index: ofono-1.21/drivers/qmimodem/voice.c +=================================================================== +--- /dev/null ++++ ofono-1.21/drivers/qmimodem/voice.c +@@ -0,0 +1,86 @@ ++/* ++ * ++ * oFono - Open Source Telephony ++ * ++ * Copyright (C) 2017 Alexander Couzens ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++ ++#include "voice.h" ++#include "../../src/common.h" ++ ++#define _(X) case X: return #X ++ ++const char *qmi_voice_call_state_name(enum qmi_voice_call_state value) ++{ ++ switch (value) { ++ _(QMI_CALL_STATE_IDLE); ++ _(QMI_CALL_STATE_ORIG); ++ _(QMI_CALL_STATE_INCOMING); ++ _(QMI_CALL_STATE_CONV); ++ _(QMI_CALL_STATE_CC_IN_PROG); ++ _(QMI_CALL_STATE_ALERTING); ++ _(QMI_CALL_STATE_HOLD); ++ _(QMI_CALL_STATE_WAITING); ++ _(QMI_CALL_STATE_DISCONNECTING); ++ _(QMI_CALL_STATE_END); ++ _(QMI_CALL_STATE_SETUP); ++ } ++ return "QMI_CALL_STATE_"; ++} ++ ++int qmi_to_ofono_status(uint8_t status, int *ret) { ++ int err = 0; ++ switch (status) { ++ case QMI_CALL_STATE_IDLE: ++ case QMI_CALL_STATE_END: ++ case QMI_CALL_STATE_DISCONNECTING: ++ *ret = CALL_STATUS_DISCONNECTED; ++ break; ++ case QMI_CALL_STATE_HOLD: ++ *ret = CALL_STATUS_HELD; ++ break; ++ case QMI_CALL_STATE_WAITING: ++ *ret = CALL_STATUS_WAITING; ++ break; ++ case QMI_CALL_STATE_ORIG: ++ *ret = CALL_STATUS_DIALING; ++ break; ++ case QMI_CALL_STATE_INCOMING: ++ *ret = CALL_STATUS_INCOMING; ++ break; ++ case QMI_CALL_STATE_CONV: ++ *ret = CALL_STATUS_ACTIVE; ++ break; ++ case QMI_CALL_STATE_CC_IN_PROG: ++ case QMI_CALL_STATE_SETUP: ++ /* FIXME: unsure if _SETUP is dialing or not */ ++ *ret = CALL_STATUS_DIALING; ++ break; ++ case QMI_CALL_STATE_ALERTING: ++ *ret = CALL_STATUS_ALERTING; ++ break; ++ default: ++ err = 1; ++ } ++ return err; ++} ++ ++uint8_t ofono_to_qmi_direction(enum call_direction ofono_direction) { ++ return ofono_direction + 1; ++} ++enum call_direction qmi_to_ofono_direction(uint8_t qmi_direction) { ++ return qmi_direction - 1; ++} ++ +Index: ofono-1.21/drivers/qmimodem/voice.h +=================================================================== +--- /dev/null ++++ ofono-1.21/drivers/qmimodem/voice.h +@@ -0,0 +1,84 @@ ++/* ++ * ++ * oFono - Open Source Telephony ++ * ++ * Copyright (C) 2017 Alexander Couzens ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++enum call_direction; ++ ++enum ussd_dcs { ++ USS_DCS_ASCII = 0x1, ++ USS_DCS_8BIT, ++ USS_DCS_UCS2, ++}; ++ ++enum ussd_user_required { ++ NO_USER_ACTION_REQUIRED = 0x1, ++ USER_ACTION_REQUIRED = 0x2, ++}; ++ ++struct qmi_ussd_data { ++ uint8_t dcs; ++ uint8_t length; ++ uint8_t data[0]; ++} __attribute__((__packed__)); ++ ++enum voice_commands { ++ QMI_VOICE_CANCEL_USSD = 0x3c, ++ QMI_VOICE_USSD_RELEASE_IND = 0x3d, ++ QMI_VOICE_USSD_IND = 0x3e, ++ QMI_VOICE_SUPS_IND = 0x42, ++ QMI_VOICE_ASYNC_ORIG_USSD = 0x43, ++}; ++ ++enum qmi_voice_call_state { ++ QMI_CALL_STATE_IDLE = 0x0, ++ QMI_CALL_STATE_ORIG, ++ QMI_CALL_STATE_INCOMING, ++ QMI_CALL_STATE_CONV, ++ QMI_CALL_STATE_CC_IN_PROG, ++ QMI_CALL_STATE_ALERTING, ++ QMI_CALL_STATE_HOLD, ++ QMI_CALL_STATE_WAITING, ++ QMI_CALL_STATE_DISCONNECTING, ++ QMI_CALL_STATE_END, ++ QMI_CALL_STATE_SETUP ++}; ++ ++enum qmi_voice_call_type { ++ QMI_CALL_TYPE_VOICE = 0x0, ++ QMI_CALL_TYPE_VOICE_FORCE, ++}; ++ ++const char *qmi_voice_call_state_name(enum qmi_voice_call_state value); ++uint8_t ofono_to_qmi_direction(enum call_direction ofono_direction); ++enum call_direction qmi_to_ofono_direction(uint8_t qmi_direction); ++int qmi_to_ofono_status(uint8_t status, int *ret); ++ ++#define QMI_VOICE_IND_ALL_STATUS 0x2e ++ ++#define QMI_VOICE_PARAM_USS_DATA 0x01 ++ ++#define QMI_VOICE_PARAM_ASYNC_USSD_ERROR 0x10 ++#define QMI_VOICE_PARAM_ASYNC_USSD_FAILURE_CASE 0x11 ++#define QMI_VOICE_PARAM_ASYNC_USSD_DATA 0x12 ++ ++#define QMI_VOICE_PARAM_USSD_IND_USER_ACTION 0x01 ++#define QMI_VOICE_PARAM_USSD_IND_DATA 0x10 ++#define QMI_VOICE_PARAM_USSD_IND_UCS2 0x11 ++ ++/* according to GSM TS 23.038 */ ++#define USSD_DCS_8BIT 0xf4 ++#define USSD_DCS_UCS2 0x48 ++#define USSD_DCS_UNSPECIFIC 0x0f +Index: ofono-1.21/drivers/qmimodem/voice_generated.c +=================================================================== +--- /dev/null ++++ ofono-1.21/drivers/qmimodem/voice_generated.c +@@ -0,0 +1,210 @@ ++ ++#include ++#include ++#include ++ ++#include "voice_generated.h" ++ ++int qmi_voice_dial_call( ++ struct qmi_voice_dial_call_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy) ++{ ++ struct qmi_param *param = NULL; ++ ++ param = qmi_param_new(); ++ if (!param) ++ goto error; ++ ++ if (arg->calling_number_set) { ++ if (!qmi_param_append(param, ++ 0x1, ++ strlen(arg->calling_number), ++ arg->calling_number)) ++ goto error; ++ } ++ ++ if (arg->call_type_set) ++ qmi_param_append_uint8(param, 0x10, arg->call_type); ++ ++ if (qmi_service_send(service, ++ 0x20, ++ param, ++ func, ++ user_data, ++ destroy) > 0) ++ return 0; ++error: ++ g_free(param); ++ return 1; ++} ++ ++enum parse_error qmi_voice_dial_call_parse( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_dial_call_result *result) ++{ ++ int err = NONE; ++ ++ /* mandatory */ ++ if (qmi_result_get_uint8(qmi_result, 0x10, &result->call_id)) ++ result->call_id_set = 1; ++ else ++ err = MISSING_MANDATORY; ++ ++ return err; ++} ++ ++int qmi_voice_end_call( ++ struct qmi_voice_end_call_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy) ++{ ++ struct qmi_param *param = NULL; ++ ++ param = qmi_param_new(); ++ if (!param) ++ goto error; ++ ++ if (arg->call_id_set) { ++ if (!qmi_param_append_uint8( ++ param, ++ 0x1, ++ arg->call_id)) ++ goto error; ++ } ++ ++ if (qmi_service_send(service, ++ 0x21, ++ param, ++ func, ++ user_data, ++ destroy) > 0) ++ return 0; ++error: ++ g_free(param); ++ return 1; ++} ++ ++enum parse_error qmi_voice_end_call_parse( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_end_call_result *result) ++{ ++ int err = NONE; ++ ++ /* optional */ ++ if (qmi_result_get_uint8(qmi_result, 0x10, &result->call_id)) ++ result->call_id_set = 1; ++ ++ return err; ++} ++ ++ ++int qmi_voice_answer_call( ++ struct qmi_voice_answer_call_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy) ++{ ++ struct qmi_param *param = NULL; ++ ++ param = qmi_param_new(); ++ if (!param) ++ goto error; ++ ++ if (arg->call_id_set) { ++ if (!qmi_param_append_uint8( ++ param, ++ 0x1, ++ arg->call_id)) ++ goto error; ++ } ++ ++ if (qmi_service_send(service, ++ 0x22, ++ param, ++ func, ++ user_data, ++ destroy) > 0) ++ return 0; ++error: ++ g_free(param); ++ return 1; ++} ++ ++ ++enum parse_error qmi_voice_answer_call_parse( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_answer_call_result *result) ++{ ++ int err = NONE; ++ ++ /* optional */ ++ if (qmi_result_get_uint8(qmi_result, 0x10, &result->call_id)) ++ result->call_id_set = 1; ++ ++ return err; ++} ++ ++enum parse_error qmi_voice_ind_call_status( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_all_call_status_ind *result) ++{ ++ int err = NONE; ++ int offset; ++ uint16_t len; ++ const struct qmi_voice_remote_party_number *remote_party_number; ++ const struct qmi_voice_call_information *call_information; ++ ++ /* mandatory */ ++ call_information = qmi_result_get(qmi_result, 0x01, &len); ++ if (call_information) ++ { ++ int instance_size = sizeof(struct qmi_voice_call_information_instance); ++ /* verify the length */ ++ if (len < sizeof(call_information->size)) ++ return INVALID_LENGTH; ++ ++ if (len != call_information->size * sizeof(struct qmi_voice_call_information_instance) ++ + sizeof(call_information->size)) ++ return INVALID_LENGTH; ++ result->call_information_set = 1; ++ result->call_information = call_information; ++ } else ++ return MISSING_MANDATORY; ++ ++ /* mandatory */ ++ remote_party_number = qmi_result_get(qmi_result, 0x10, &len); ++ if (remote_party_number) { ++ const struct qmi_voice_remote_party_number_instance *instance; ++ int instance_size = sizeof(struct qmi_voice_remote_party_number_instance); ++ int i; ++ ++ /* verify the length */ ++ if (len < sizeof(remote_party_number->size)) ++ return INVALID_LENGTH; ++ ++ for (i = 0, offset = sizeof(remote_party_number->size); ++ offset <= len && i < 16 && i < remote_party_number->size; i++) ++ { ++ if (offset == len) { ++ break; ++ } else if (offset + instance_size > len) { ++ return INVALID_LENGTH; ++ } ++ ++ instance = (void *)remote_party_number + offset; ++ result->remote_party_number[i] = instance; ++ offset += sizeof(struct qmi_voice_remote_party_number_instance) + instance->number_size; ++ } ++ result->remote_party_number_set = 1; ++ result->remote_party_number_size = remote_party_number->size; ++ } else ++ return MISSING_MANDATORY; ++ ++ return err; ++} +Index: ofono-1.21/drivers/qmimodem/voice_generated.h +=================================================================== +--- /dev/null ++++ ofono-1.21/drivers/qmimodem/voice_generated.h +@@ -0,0 +1,113 @@ ++ ++#ifndef __OFONO_QMI_VOICE_GENERATED_H ++#define __OFONO_QMI_VOICE_GENERATED_H ++ ++#include "qmi.h" ++ ++struct qmi_voice_remote_party_number_instance { ++ uint8_t call_id; ++ uint8_t presentation_indicator; ++ uint8_t number_size; ++ char number[0]; ++} __attribute__((__packed__)); ++ ++struct qmi_voice_remote_party_number { ++ uint8_t size; ++ struct qmi_voice_remote_party_number_instance instance[0]; ++} __attribute__((__packed__)); ++ ++/* generator / parser */ ++ ++struct qmi_voice_dial_call_arg { ++ bool calling_number_set; ++ const char *calling_number; ++ bool call_type_set; ++ uint8_t call_type; ++}; ++ ++int qmi_voice_dial_call( ++ struct qmi_voice_dial_call_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy); ++ ++struct qmi_voice_dial_call_result { ++ bool call_id_set; ++ uint8_t call_id; ++}; ++ ++enum parse_error qmi_voice_dial_call_parse( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_dial_call_result *result); ++ ++struct qmi_voice_end_call_arg { ++ bool call_id_set; ++ uint8_t call_id; ++}; ++ ++int qmi_voice_end_call( ++ struct qmi_voice_end_call_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy); ++ ++struct qmi_voice_end_call_result { ++ bool call_id_set; ++ uint8_t call_id; ++}; ++ ++enum parse_error qmi_voice_end_call_parse( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_end_call_result *result); ++ ++struct qmi_voice_answer_call_arg { ++ bool call_id_set; ++ uint8_t call_id; ++}; ++ ++int qmi_voice_answer_call( ++ struct qmi_voice_answer_call_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy); ++ ++struct qmi_voice_answer_call_result { ++ bool call_id_set; ++ uint8_t call_id; ++}; ++ ++enum parse_error qmi_voice_answer_call_parse( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_answer_call_result *result); ++ ++struct qmi_voice_call_information_instance { ++ uint8_t id; ++ uint8_t state; ++ uint8_t type; ++ uint8_t direction; ++ uint8_t mode; ++ uint8_t multipart_indicator; ++ uint8_t als; ++} __attribute__((__packed__)); ++ ++struct qmi_voice_call_information { ++ uint8_t size; ++ struct qmi_voice_call_information_instance instance[0]; ++} __attribute__((__packed__)) ; ++ ++struct qmi_voice_all_call_status_ind { ++ bool call_information_set; ++ const struct qmi_voice_call_information *call_information; ++ bool remote_party_number_set; ++ uint8_t remote_party_number_size; ++ const struct qmi_voice_remote_party_number_instance *remote_party_number[16]; ++}; ++ ++enum parse_error qmi_voice_ind_call_status( ++ struct qmi_result *qmi_result, ++ struct qmi_voice_all_call_status_ind *result); ++ ++#endif /* __OFONO_QMI_VOICE_GENERATED_H */ +Index: ofono-1.21/drivers/qmimodem/voicecall.c +=================================================================== +--- ofono-1.21.orig/drivers/qmimodem/voicecall.c ++++ ofono-1.21/drivers/qmimodem/voicecall.c +@@ -3,6 +3,7 @@ + * oFono - Open Source Telephony + * + * Copyright (C) 2011-2012 Intel Corporation. All rights reserved. ++ * Copyright (C) 2017 Alexander Couzens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -23,20 +24,113 @@ + #include + #endif + ++#include ++ + #include + #include + #include ++#include + +-#include "qmi.h" ++#include "../src/common.h" + ++#include "qmi.h" + #include "qmimodem.h" ++#include "voice.h" ++#include "voice_generated.h" ++ ++#ifndef ARRAY_SIZE ++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) ++#endif ++ ++ ++/* qmi protocol */ ++ ++ ++/* end of qmi */ + + struct voicecall_data { + struct qmi_service *voice; + uint16_t major; + uint16_t minor; ++ GSList *call_list; ++ struct voicecall_static *vs; ++ struct ofono_phone_number dialed; + }; + ++static void all_call_status_ind(struct qmi_result *result, void *user_data) ++{ ++ struct ofono_voicecall *vc = user_data; ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ GSList *calls = NULL; ++ int i; ++ int size = 0; ++ struct qmi_voice_all_call_status_ind status_ind; ++ GSList *n, *o; ++ struct ofono_call *nc, *oc; ++ ++ ++ if (qmi_voice_ind_call_status(result, &status_ind) != NONE) { ++ DBG("Parsing of all call status indication failed"); ++ return; ++ } ++ ++ if (!status_ind.remote_party_number_set || !status_ind.call_information_set) { ++ DBG("Some required fields are not set"); ++ return; ++ } ++ ++ size = status_ind.call_information->size; ++ if (!size) { ++ DBG("No call informations received!"); ++ return; ++ } ++ ++ /* expect we have valid fields for every call */ ++ if (size != status_ind.remote_party_number_size) { ++ DBG("Not all fields have the same size"); ++ return; ++ } ++ ++ for (i = 0; i < size; i++) { ++ struct qmi_voice_call_information_instance call_info; ++ struct ofono_call *call; ++ const struct qmi_voice_remote_party_number_instance *remote_party = status_ind.remote_party_number[i]; ++ int number_size; ++ ++ call_info = status_ind.call_information->instance[i]; ++ call = g_new0(struct ofono_call, 1); ++ call->id = call_info.id; ++ call->direction = qmi_to_ofono_direction(call_info.direction); ++ ++ if (qmi_to_ofono_status(call_info.state, &call->status)) { ++ DBG("Ignore call id %d, because can not convert QMI state 0x%x to ofono.", ++ call_info.id, call_info.state); ++ continue; ++ } ++ DBG("Call %d in state %s(%d)", ++ call_info.id, ++ qmi_voice_call_state_name(call_info.state), ++ call_info.state); ++ ++ call->type = 0; /* always voice */ ++ number_size = remote_party->number_size; ++ if (number_size > OFONO_MAX_PHONE_NUMBER_LENGTH) ++ OFONO_MAX_PHONE_NUMBER_LENGTH; ++ strncpy(call->phone_number.number, remote_party->number, ++ number_size); ++ /* FIXME: set phone_number_type */ ++ ++ if (strlen(call->phone_number.number) > 0) ++ call->clip_validity = 0; ++ else ++ call->clip_validity = 2; ++ ++ calls = g_slist_insert_sorted(calls, call, ofono_call_compare); ++ } ++ ++ ofono_call_list_notify(vc, &vd->call_list, calls); ++} ++ + static void create_voice_cb(struct qmi_service *service, void *user_data) + { + struct ofono_voicecall *vc = user_data; +@@ -58,6 +152,12 @@ static void create_voice_cb(struct qmi_s + + data->voice = qmi_service_ref(service); + ++ /* FIXME: we should call indication_register to ensure we get notified on call events. ++ * We rely at the moment on the default value of notifications ++ */ ++ qmi_service_register(data->voice, QMI_VOICE_IND_ALL_STATUS, ++ all_call_status_ind, vc, NULL); ++ + ofono_voicecall_register(vc); + } + +@@ -77,7 +177,6 @@ static int qmi_voicecall_probe(struct of + create_voice_cb, vc, NULL); + + return 0; +- + } + + static void qmi_voicecall_remove(struct ofono_voicecall *vc) +@@ -92,13 +191,242 @@ static void qmi_voicecall_remove(struct + + qmi_service_unref(data->voice); + ++ g_slist_free_full(data->call_list, g_free); ++ + g_free(data); + } + ++ ++static struct ofono_call *create_call(struct ofono_voicecall *vc, ++ enum call_direction direction, ++ enum call_status status, ++ const char *num, ++ int num_type, ++ int clip) ++{ ++ return NULL; ++} ++ ++static void dial_cb(struct qmi_result *result, void *user_data) ++{ ++ struct cb_data *cbd = user_data; ++ struct ofono_voicecall *vc = cbd->user; ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ ofono_voicecall_cb_t cb = cbd->cb; ++ uint16_t error; ++ struct qmi_voice_dial_call_result dial_result; ++ struct ofono_call *call; ++ ++ if (qmi_result_set_error(result, &error)) { ++ DBG("QMI Error %d", error); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ if (NONE != qmi_voice_dial_call_parse(result, &dial_result)) { ++ DBG("Received invalid Result"); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ if (!dial_result.call_id_set) { ++ DBG("Didn't receive a call id"); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ DBG("New call QMI id %d", dial_result.call_id); ++ ofono_call_list_dial_callback(vc, ++ &vd->call_list, ++ &vd->dialed, ++ dial_result.call_id); ++ ++ ++ /* FIXME: create a timeout on this call_id */ ++ CALLBACK_WITH_SUCCESS(cb, cbd->data); ++} ++ ++static void dial(struct ofono_voicecall *vc, const struct ofono_phone_number *ph, ++ enum ofono_clir_option clir, ofono_voicecall_cb_t cb, ++ void *data) ++{ ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ struct cb_data *cbd = cb_data_new(cb, data); ++ struct qmi_voice_dial_call_arg arg; ++ ++ cbd->user = vc; ++ arg.calling_number_set = true; ++ arg.calling_number = ph->number; ++ memcpy(&vd->dialed, ph, sizeof(*ph)); ++ ++ arg.call_type_set = true; ++ arg.call_type = QMI_CALL_TYPE_VOICE_FORCE; ++ ++ if (!qmi_voice_dial_call( ++ &arg, ++ vd->voice, ++ dial_cb, ++ cbd, ++ g_free)) ++ return; ++ ++ CALLBACK_WITH_FAILURE(cb, data); ++ g_free(cbd); ++} ++ ++static void answer_cb(struct qmi_result *result, void *user_data) ++{ ++ struct cb_data *cbd = user_data; ++ struct ofono_voicecall *vc = cbd->user; ++ ofono_voicecall_cb_t cb = cbd->cb; ++ uint16_t error; ++ struct qmi_voice_answer_call_result answer_result; ++ struct ofono_call *call; ++ ++ if (qmi_result_set_error(result, &error)) { ++ DBG("QMI Error %d", error); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ /* TODO: what happens when calling it with no active call or wrong caller id? */ ++ if (NONE != qmi_voice_answer_call_parse(result, &answer_result)) { ++ DBG("Received invalid Result"); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ CALLBACK_WITH_SUCCESS(cb, cbd->data); ++} ++ ++static void answer(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data) ++{ ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ struct cb_data *cbd = cb_data_new(cb, data); ++ struct qmi_voice_answer_call_arg arg; ++ struct ofono_call *call; ++ GSList *list; ++ ++ DBG(""); ++ cbd->user = vc; ++ ++ list = g_slist_find_custom(vd->call_list, ++ GINT_TO_POINTER(CALL_STATUS_INCOMING), ++ ofono_call_compare_by_status); ++ ++ if (list == NULL) { ++ DBG("Can not find a call to answer"); ++ goto err; ++ } ++ ++ call = list->data; ++ ++ arg.call_id_set = true; ++ arg.call_id = call->id; ++ ++ if (!qmi_voice_answer_call( ++ &arg, ++ vd->voice, ++ answer_cb, ++ cbd, ++ g_free)) ++ return; ++err: ++ CALLBACK_WITH_FAILURE(cb, data); ++ g_free(cbd); ++} ++ ++static void end_cb(struct qmi_result *result, void *user_data) ++{ ++ struct cb_data *cbd = user_data; ++ struct ofono_voicecall *vc = cbd->user; ++ ofono_voicecall_cb_t cb = cbd->cb; ++ uint16_t error; ++ struct qmi_voice_end_call_result end_result; ++ struct ofono_call *call; ++ ++ if (qmi_result_set_error(result, &error)) { ++ DBG("QMI Error %d", error); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ if (NONE != qmi_voice_end_call_parse(result, &end_result)) { ++ DBG("Received invalid Result"); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ CALLBACK_WITH_SUCCESS(cb, cbd->data); ++} ++ ++static void release_specific(struct ofono_voicecall *vc, int id, ++ ofono_voicecall_cb_t cb, void *data) ++{ ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ struct cb_data *cbd = cb_data_new(cb, data); ++ struct qmi_voice_end_call_arg arg; ++ int i; ++ ++ DBG(""); ++ cbd->user = vc; ++ ++ arg.call_id_set = true; ++ arg.call_id = id; ++ ++ if (!qmi_voice_end_call(&arg, ++ vd->voice, ++ end_cb, ++ cbd, ++ g_free)) ++ return; ++ ++ CALLBACK_WITH_FAILURE(cb, data); ++ g_free(cbd); ++} ++ ++static void hangup_active(struct ofono_voicecall *vc, ++ ofono_voicecall_cb_t cb, void *data) ++{ ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ struct qmi_voice_end_call_arg arg; ++ struct ofono_call *call; ++ GSList *list = NULL; ++ enum call_status active[] = { ++ CALL_STATUS_ACTIVE, ++ CALL_STATUS_DIALING, ++ CALL_STATUS_ALERTING ++ }; ++ int i; ++ ++ DBG(""); ++ for (i = 0; i < ARRAY_SIZE(active); i++) { ++ list = g_slist_find_custom(vd->call_list, ++ GINT_TO_POINTER(CALL_STATUS_ACTIVE), ++ ofono_call_compare_by_status); ++ ++ if (list) ++ break; ++ } ++ ++ if (list == NULL) { ++ DBG("Can not find a call to hang up"); ++ CALLBACK_WITH_FAILURE(cb, data); ++ return; ++ } ++ ++ call = list->data; ++ release_specific(vc, call->id, cb, data); ++} ++ + static struct ofono_voicecall_driver driver = { + .name = "qmimodem", + .probe = qmi_voicecall_probe, + .remove = qmi_voicecall_remove, ++ .dial = dial, ++ .answer = answer, ++ .hangup_active = hangup_active, ++ .release_specific = release_specific, + }; + + void qmi_voicecall_init(void) diff --git a/modem/ofono/APKBUILD b/modem/ofono/APKBUILD index cc2103b5d..8981c0e45 100644 --- a/modem/ofono/APKBUILD +++ b/modem/ofono/APKBUILD @@ -2,13 +2,13 @@ pkgname=ofono _upstreamver=1.21 pkgver=1.21_p20180307 -pkgrel=2 +pkgrel=3 pkgdesc="Infrastructure for building mobile telephony (GSM/UMTS) applications" url="https://01.org/ofono" arch="all" license="GPL2" depends="bluez mobile-broadband-provider-info" -makedepends="glib-dev dbus-dev eudev-dev +makedepends="autoconf automake libtool glib-dev dbus-dev eudev-dev linux-headers bsd-compat-headers libexecinfo-dev mobile-broadband-provider-info" options="!check" @@ -18,12 +18,24 @@ source="https://www.kernel.org/pub/linux/network/$pkgname/$pkgname-$_upstreamver 0001-nokia-gpio-do-not-create-links-to-gpios-in-dev-cmt.patch::https://git.alpinelinux.org/cgit/aports/plain/testing/ofono/0001-nokia-gpio-do-not-create-links-to-gpios-in-dev-cmt.patch?id=014ae282b4a9152a5b64451f2815f34fcb53507c support-smdpkt.patch udev.rules + 0001-doc-ofonod.8-escape-minus-sign.patch + 0002-common-create-GList-helper-ofono_call_compare.patch + 0003-voicecall-common-promote-call_status_to_string-publi.patch + 0006-add-call-list-helper-to-manage-voice-call-lists.patch + 0007-common-atmodem-rename-move-at_util_call_compare_by_s.patch + 0008-common-atmodem-rename-move-at_util_call_compare_by_i.patch + 0011-qmimodem-sync-the-modem-on-enable.patch + 0014-network-ofono_netreg_status_notify-debug-output-lac-.patch + 0015-network-debug-output-the-network-time-if-updated.patch + 0016-voicecall-prefer-release_specific-over-hang_up_activ.patch + 0017-RFC-qmimodem-implement-voice-calls.patch " builddir="$srcdir"/$pkgname-$_upstreamver build() { cd "$builddir" + autoreconf --install ./configure \ --prefix=/usr \ --sysconfdir=/etc \ @@ -45,4 +57,15 @@ sha512sums="bbc7fdb1d05294839eee5f31ec345866315a80feac8ccc2a67e0ca2c1030c55e0fb4 fd0d303ca71df6953155aac0624c847f273030ebc5fb12efe2fa2ae7b8d75380e2885ab08d9c65c80cf756ef952569832ffdc25317e86a99552b4caac322b3ed ofono.initd a1f66f3f40c1aa4af5f5b66436414408b46f3c90f2a2c88fa12e09ca6a1732334d2f47687478d652a3a176ee93c1905752635246fd01412834565626c021ca64 0001-nokia-gpio-do-not-create-links-to-gpios-in-dev-cmt.patch b946ac618aa2ab864876f7a81b689a0c3b776ad66657aaac508a52ea803d7031378dab0d7292ee41caba3e35b6e15d7309910c754a5762de7754be813c257b82 support-smdpkt.patch -8f2893dfc291fc210ef217c4bc74d79436a0997001dd2773809625d52dd19d092cc75d3f9aa5ed2f3d4a6248d4a4e17013a7655323f7dad951f744c55b572417 udev.rules" +8f2893dfc291fc210ef217c4bc74d79436a0997001dd2773809625d52dd19d092cc75d3f9aa5ed2f3d4a6248d4a4e17013a7655323f7dad951f744c55b572417 udev.rules +e602504d41a0c28f99db138255eb9f0f020e59c26fcabc99f2bbe9f4e3d3c99b33ffb247a362569c841f55111b7fd8db0b18e98c3497ef04aa9bde467b86475d 0001-doc-ofonod.8-escape-minus-sign.patch +1ffa1c7c0a99aabf5e064f7c99db43727942365c8b76b2d3e6278e4995570a067e73755e1111f8bcf3f1574b4d24d427c48fe2dc474ad89099d5d818b597fcb5 0002-common-create-GList-helper-ofono_call_compare.patch +4658e7dfdb9167f97c279a55fb2b53d5c33eda87c54cd7fcaaaf489e2b6d2d6b2b487b415ee616827d4388e379a842833860809103010d8b1be75b76505cf8c8 0003-voicecall-common-promote-call_status_to_string-publi.patch +0de8030dad134851cacc9564186aef07db94ab72c914c03326a0e8070e764a3fd47cc921a49bbf6c0828692599005e0dd412b808abb9adfd6b7bc49fcd176b93 0006-add-call-list-helper-to-manage-voice-call-lists.patch +1ecf593363e25b51cff36d692afd12886877c82b75fce853d137dd0c5fa2910ece4a3a18744b563e898be7df254826c80861f2bb0a113d9c2d9cde686b2297ac 0007-common-atmodem-rename-move-at_util_call_compare_by_s.patch +a1b04a014e7643105529b6060577555747c1094c0fc770c99e5fc5b8b97843ba3a23577e33ffa7a77379ef02669ebe96dbf1c25271cf2fd5ab11dabb21aeb588 0008-common-atmodem-rename-move-at_util_call_compare_by_i.patch +1664244d301267537423f47d57b67374659c81fc073435507be6845c0a8fec776cc3dd18e3781040e173a92610b6f0cf78a59378414948eb881e8c7cdf9b7322 0011-qmimodem-sync-the-modem-on-enable.patch +1e6bce11888ce11080a6dd07c487836104abc52be3e908c96eac412ce17941aadfd19bab386706cb9491e6ecf9666efac7cb85db98ca50dd920928a3c502157a 0014-network-ofono_netreg_status_notify-debug-output-lac-.patch +61728285a5247e964d71d2f93d6aa62967ba9be978d41f99928829e3a753124830aede022b86eb5b39b04485afba1a1f2bb7595b0cec5a04899b74297f9297ab 0015-network-debug-output-the-network-time-if-updated.patch +6d85d384261af82314d11310150dc37b01bbf89b6cb3c3b5576724a97cdbf96f67a02bf3828560d773a6ff1271202cf290606070f41d52af16bbea320e48f660 0016-voicecall-prefer-release_specific-over-hang_up_activ.patch +25279f9570b4312100c87bb7d17c39bdeea04acce19414503a9274befc3ff07383488433d9900540933e8e409eed3b47996196d50c9a40f9d01e921066701b64 0017-RFC-qmimodem-implement-voice-calls.patch"