---
drivers/ifxmodem/voicecall.c | 197 ++++++++++++++++++++----------------------
1 files changed, 95 insertions(+), 102 deletions(-)
diff --git a/drivers/ifxmodem/voicecall.c b/drivers/ifxmodem/voicecall.c
index d31fa70..209ab13 100644
--- a/drivers/ifxmodem/voicecall.c
+++ b/drivers/ifxmodem/voicecall.c
@@ -43,9 +43,6 @@
static const char *none_prefix[] = { NULL };
-/* According to 27.007 COLP is an intermediate status for ATD */
-static const char *atd_prefix[] = { "+COLP:", NULL };
-
struct voicecall_data {
GSList *calls;
unsigned int local_release;
@@ -120,7 +117,8 @@ static void xcallstat_notify(GAtResult *result, gpointer user_data)
int id;
int status;
GSList *l;
- struct ofono_call *call;
+ struct ofono_call *new_call;
+ struct ofono_call *existing_call = NULL;
g_at_result_iter_init(&iter, result);
@@ -136,53 +134,82 @@ static void xcallstat_notify(GAtResult *result, gpointer user_data)
l = g_slist_find_custom(vd->calls, GINT_TO_POINTER(id),
at_util_call_compare_by_id);
- if (l == NULL) {
- /*
- * We should only receive XCALLSTAT on waiting and incoming
- * In the case of waiting, we will get the rest of the info
- * from CCWA indication.
- * In the case of incoming, we will get the info from CLIP
- * indications.
- */
- if (status != CALL_STATUS_INCOMING &&
- status != CALL_STATUS_WAITING) {
- ofono_info("Received an XCALLSTAT for an untracked"
- " call, this indicates a bug!");
- return;
- }
-
+ if (l == NULL && status != CALL_STATUS_DIALING &&
+ status != CALL_STATUS_INCOMING &&
+ status != CALL_STATUS_WAITING) {
+ ofono_error("Received an XCALLSTAT for an untracked"
+ " call, this indicates a bug!");
return;
}
- call = l->data;
+ if (l)
+ existing_call = l->data;
- /* Check if call has been disconnected */
- if (status == CALL_STATUS_DISCONNECTED) {
- enum ofono_disconnect_reason r;
+ switch (status) {
+ case CALL_STATUS_DISCONNECTED:
+ {
+ enum ofono_disconnect_reason reason;
- if (vd->local_release & (1 << call->id))
- r = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
- else
- r = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
+ existing_call->status = status;
- if (call->type == 0)
- ofono_voicecall_disconnected(vc, call->id, r, NULL);
+ if (vd->local_release & (1 << existing_call->id))
+ reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
+ else
+ reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
- vd->local_release &= ~(1 << call->id);
- vd->calls = g_slist_remove(vd->calls, call);
- g_free(call);
+ ofono_voicecall_disconnected(vc, existing_call->id,
+ reason, NULL);
- return;
+ vd->local_release &= ~(1 << existing_call->id);
+ vd->calls = g_slist_remove(vd->calls, l->data);
+ g_free(existing_call);
+ break;
}
+ case CALL_STATUS_DIALING:
+ case CALL_STATUS_WAITING:
+ case CALL_STATUS_INCOMING:
+ {
+ int direction;
+
+ /* Handle the following situation:
+ * Active Call + Waiting Call. Active Call is Released.
+ * The Waiting call becomes Incoming. In this case, no
+ * need to create a new call. Call status change will be
+ * triggered from clip_notify.
+ */
+ if (existing_call) {
+ existing_call->status = status;
+ return;
+ }
- /* For connected status, simply reset back to active */
- if (status == 7)
- status = 0;
+ if (status == CALL_STATUS_DIALING)
+ direction = CALL_DIRECTION_MOBILE_ORIGINATED;
+ else
+ direction = CALL_DIRECTION_MOBILE_TERMINATED;
- call->status = status;
+ new_call = create_call(vc, 0, direction, status,
+ NULL, 128, CLIP_VALIDITY_NOT_AVAILABLE);
+ if (new_call == NULL) {
+ ofono_error("Unable to malloc. "
+ "Call management is fubar");
+ return;
+ }
- if (call->type == 0)
- ofono_voicecall_notify(vc, call);
+ new_call->id = id;
+ break;
+ }
+ case CALL_STATUS_ALERTING:
+ case CALL_STATUS_ACTIVE:
+ case CALL_STATUS_HELD:
+ default:
+ /* For connected status, simply reset back to active */
+ if (status == 7)
+ status = 0;
+
+ existing_call->status = status;
+ ofono_voicecall_notify(vc, existing_call);
+ break;
+ }
}
static void xem_notify(GAtResult *result, gpointer user_data)
@@ -253,51 +280,12 @@ static void release_id_cb(gboolean ok, GAtResult *result,
static void atd_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
- struct ofono_voicecall *vc = cbd->user;
ofono_voicecall_cb_t cb = cbd->cb;
- GAtResultIter iter;
- const char *num;
- int type = 128;
- int validity = 2;
struct ofono_error error;
- struct ofono_call *call;
decode_at_error(&error, g_at_result_final_response(result));
- if (!ok) {
- cb(&error, cbd->data);
- return;
- }
-
- g_at_result_iter_init(&iter, result);
-
- if (g_at_result_iter_next(&iter, "+COLP:")) {
- g_at_result_iter_next_string(&iter, &num);
- g_at_result_iter_next_number(&iter, &type);
-
- if (strlen(num) > 0)
- validity = 0;
- else
- validity = 2;
-
- DBG("colp_notify: %s %d %d", num, type, validity);
- }
-
- /* Generate a voice call that was just dialed, we guess the ID */
- call = create_call(vc, 0, 0, CALL_STATUS_DIALING, num, type, validity);
- if (call == NULL) {
- ofono_error("Unable to malloc, call tracking will fail!");
- return;
- }
-
- /* Let oFono core will generate a call with the dialed number
- * inside its dial callback.
- */
cb(&error, cbd->data);
-
- /* If we got COLP information, then notify the core */
- if (validity != 2)
- ofono_voicecall_notify(vc, call);
}
static void ifx_dial(struct ofono_voicecall *vc,
@@ -329,7 +317,7 @@ static void ifx_dial(struct ofono_voicecall *vc,
strcat(buf, ";");
- if (g_at_chat_send(vd->chat, buf, atd_prefix,
+ if (g_at_chat_send(vd->chat, buf, none_prefix,
atd_cb, cbd, g_free) > 0)
return;
@@ -537,25 +525,28 @@ static void cring_notify(GAtResult *result, gpointer user_data)
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
GAtResultIter iter;
const char *line;
- int type;
+ GSList *l;
+ struct ofono_call *call;
/* Handle the following situation:
* Active Call + Waiting Call. Active Call is Released. The Waiting
- * call becomes Incoming and RING/CRING indications are signaled.
- * Sometimes these arrive before we managed to poll CLCC to find about
- * the stage change. If this happens, simply ignore the RING/CRING
- * when a waiting call exists (cannot have waiting + incoming in GSM)
+ * call becomes Incoming and CRING indications are signaled.
+ * Sometimes these arrive before the actual state change notification.
+ * If this happens, simply ignore the CRING when a waiting call
+ * exists (cannot have waiting + incoming in GSM)
*/
if (g_slist_find_custom(vd->calls,
GINT_TO_POINTER(CALL_STATUS_WAITING),
at_util_call_compare_by_status))
return;
- /* CRING can repeat, ignore if we already have an incoming call */
- if (g_slist_find_custom(vd->calls,
+ l = g_slist_find_custom(vd->calls,
GINT_TO_POINTER(CALL_STATUS_INCOMING),
- at_util_call_compare_by_status))
+ at_util_call_compare_by_status);
+ if (l == NULL) {
+ ofono_error("CRING received before XCALLSTAT!!!");
return;
+ }
g_at_result_iter_init(&iter, result);
@@ -566,14 +557,13 @@ static void cring_notify(GAtResult *result, gpointer user_data)
if (line == NULL)
return;
+ call = l->data;
+
/* Ignore everything that is not voice for now */
if (!strcasecmp(line, "VOICE"))
- type = 0;
+ call->type = 0;
else
- type = 9;
-
- /* Generate an incoming call */
- create_call(vc, type, 1, CALL_STATUS_INCOMING, NULL, 128, 2);
+ call->type = 9;
/* Assume the CLIP always arrives, and we signal the call there */
DBG("cring_notify");
@@ -642,13 +632,16 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
GAtResultIter iter;
const char *num;
int num_type, validity, cls;
+ GSList *l;
struct ofono_call *call;
- /* Some modems resend CCWA, ignore it the second time around */
- if (g_slist_find_custom(vd->calls,
+ l = g_slist_find_custom(vd->calls,
GINT_TO_POINTER(CALL_STATUS_WAITING),
- at_util_call_compare_by_status))
+ at_util_call_compare_by_status);
+ if (l == NULL) {
+ ofono_error("CCWA received before XCALLSTAT!!!");
return;
+ }
g_at_result_iter_init(&iter, result);
@@ -677,12 +670,13 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
DBG("ccwa_notify: %s %d %d %d", num, num_type, cls, validity);
- call = create_call(vc, class_to_call_type(cls), 1, CALL_STATUS_WAITING,
- num, num_type, validity);
- if (call == NULL) {
- ofono_error("Unable to malloc. Call management is fubar");
- return;
- }
+ call = l->data;
+
+ call->type = class_to_call_type(cls);
+ strncpy(call->phone_number.number, num, OFONO_MAX_PHONE_NUMBER_LENGTH);
+ call->phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
+ call->phone_number.type = num_type;
+ call->clip_validity = validity;
if (call->type == 0) /* Only notify voice calls */
ofono_voicecall_notify(vc, call);
@@ -776,7 +770,6 @@ static int ifx_voicecall_probe(struct ofono_voicecall *vc, unsigned
int vendor,
g_at_chat_send(vd->chat, "AT+CRC=1", none_prefix, NULL, NULL, NULL);
g_at_chat_send(vd->chat, "AT+CLIP=1", none_prefix, NULL, NULL, NULL);
- g_at_chat_send(vd->chat, "AT+COLP=1", none_prefix, NULL, NULL, NULL);
g_at_chat_send(vd->chat, "AT+CNAP=1", none_prefix, NULL, NULL, NULL);
g_at_chat_send(vd->chat, "AT+CCWA=1", none_prefix,
ifx_voicecall_initialized, vc, NULL);
--
1.7.0.4