isimodem: fix problems in call state reporting
authorPekka Pessi <Pekka.Pessi@nokia.com>
Tue, 1 Feb 2011 22:22:09 +0000 (00:22 +0200)
committerAki Niemi <aki.niemi@nokia.com>
Thu, 3 Feb 2011 12:59:53 +0000 (14:59 +0200)
Do not report early incoming calls.

Report "disconnected" state separately.

Call ofono_voicecall_disconnected() only after call id is released.

drivers/isimodem/voicecall.c

index 8267f1c..0a32f27 100644 (file)
@@ -363,10 +363,13 @@ static int isi_call_status_to_clcc(const struct isi_call *call)
        case CALL_STATUS_WAITING:
                return 5;
 
-       case CALL_STATUS_ANSWERED:
-       case CALL_STATUS_ACTIVE:
        case CALL_STATUS_MO_RELEASE:
        case CALL_STATUS_MT_RELEASE:
+       case CALL_STATUS_TERMINATED:
+               return 6;
+
+       case CALL_STATUS_ANSWERED:
+       case CALL_STATUS_ACTIVE:
        case CALL_STATUS_HOLD_INITIATED:
                return 0;
 
@@ -375,11 +378,10 @@ static int isi_call_status_to_clcc(const struct isi_call *call)
                return 1;
 
        case CALL_STATUS_RECONNECT_PENDING:
-       case CALL_STATUS_TERMINATED:
        case CALL_STATUS_SWAP_INITIATED:
+       default:
                return 0;
        }
-       return 0;
 }
 
 static struct ofono_call isi_call_as_ofono_call(const struct isi_call *call)
@@ -433,13 +435,27 @@ static struct isi_call *isi_call_set_idle(struct isi_call *call)
        return call;
 }
 
-static void isi_call_release(struct ofono_voicecall *ovc, struct isi_call *call)
+static void isi_call_disconnected(struct ofono_voicecall *ovc,
+                                       struct isi_call *call)
 {
        struct ofono_error error = {
                OFONO_ERROR_TYPE_NO_ERROR, 0
        };
+
+       DBG("disconnected id=%u reason=%u", call->id, call->reason);
+
+       ofono_voicecall_disconnected(ovc, call->id, call->reason, &error);
+
+       isi_call_set_idle(call);
+}
+
+static void isi_call_set_disconnect_reason(struct isi_call *call)
+{
        enum ofono_disconnect_reason reason;
 
+       if (call->reason != OFONO_DISCONNECT_REASON_UNKNOWN)
+               return;
+
        switch (call->status) {
        case CALL_STATUS_IDLE:
                reason = OFONO_DISCONNECT_REASON_UNKNOWN;
@@ -456,17 +472,9 @@ static void isi_call_release(struct ofono_voicecall *ovc, struct isi_call *call)
        case CALL_STATUS_TERMINATED:
        default:
                reason = OFONO_DISCONNECT_REASON_ERROR;
-               break;
-       }
-
-       if (!call->reason) {
-               call->reason = reason;
-               DBG("disconnected id=%u reason=%u", call->id, reason);
-               ofono_voicecall_disconnected(ovc, call->id, reason, &error);
        }
 
-       if (!reason)
-               isi_call_set_idle(call);
+       call->reason = reason;
 }
 
 static void isi_call_notify(struct ofono_voicecall *ovc, struct isi_call *call)
@@ -487,11 +495,20 @@ static void isi_call_notify(struct ofono_voicecall *ovc, struct isi_call *call)
 
        switch (call->status) {
        case CALL_STATUS_IDLE:
+               isi_call_disconnected(ovc, call);
+               return;
+
+       case CALL_STATUS_COMING:
+       case CALL_STATUS_PROCEEDING:
+               if ((call->mode_info & CALL_MODE_ORIGINATOR))
+                       /* Do not notify early MT calls */
+                       return;
+               break;
+
        case CALL_STATUS_MO_RELEASE:
        case CALL_STATUS_MT_RELEASE:
        case CALL_STATUS_TERMINATED:
-               isi_call_release(ovc, call);
-               return;
+               isi_call_set_disconnect_reason(call);
        }
 
        ocall = isi_call_as_ofono_call(call);
@@ -615,17 +632,33 @@ static void isi_call_status_ind_cb(const GIsiMessage *msg, void *data)
                }
        }
 
-       if (old_status != call->status) {
+       if (old_status == call->status)
+               return;
 
-               if (call->status == CALL_STATUS_IDLE) {
-                       call->status = CALL_STATUS_TERMINATED;
+       isi_call_notify(ovc, call);
+}
 
-                       isi_call_notify(ovc, call);
-                       isi_call_set_idle(call);
-                       return;
-               }
-       }
+static void isi_call_terminated_ind_cb(const GIsiMessage *msg, void *data)
+{
+       struct ofono_voicecall *ovc = data;
+       struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+       struct isi_call *call;
 
+       uint8_t call_id;
+       uint8_t old_status;
+
+       if (ivc == NULL || g_isi_msg_id(msg) != CALL_TERMINATED_IND ||
+                       !g_isi_msg_data_get_byte(msg, 0, &call_id) ||
+                       (call_id & 7) == 0)
+               return;
+
+       call = &ivc->calls[call_id & 7];
+       old_status = call->status;
+
+       if (old_status == CALL_STATUS_IDLE)
+               return;
+
+       call->status = CALL_STATUS_TERMINATED;
        isi_call_notify(ovc, call);
 }
 
@@ -1255,6 +1288,9 @@ static void isi_call_verify_cb(const GIsiMessage *msg, void *data)
        g_isi_client_ind_subscribe(ivc->client, CALL_STATUS_IND,
                                        isi_call_status_ind_cb, ovc);
 
+       g_isi_client_ind_subscribe(ivc->client, CALL_TERMINATED_IND,
+                                       isi_call_terminated_ind_cb, ovc);
+
        if (!isi_call_status_req(ovc, CALL_ID_ALL,
                                        CALL_STATUS_MODE_ADDR_AND_ORIGIN,
                                        NULL, NULL))