From: Pekka Pessi <[email protected]>

Add notifications on hold, retrieve, multiparty, call waiting, barrings,
and various notifications on call forwarding.

Note that driver uses the CUG index parameter to pass call IDs to core.
---
 drivers/isimodem/call.h |   12 +++
 drivers/isimodem/ssn.c  |  224 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 227 insertions(+), 9 deletions(-)

diff --git a/drivers/isimodem/call.h b/drivers/isimodem/call.h
index 2901971..9a8ba39 100644
--- a/drivers/isimodem/call.h
+++ b/drivers/isimodem/call.h
@@ -402,6 +402,18 @@ enum {
        CALL_DTMF_DISABLE_TONE_IND_SEND = 0x02
 };
 
+enum {
+       CALL_GSM_SSI_CALL_IS_WAITING =          0x01,
+       CALL_GSM_SSI_MPTY =                     0x02,
+       CALL_GSM_SSI_CLIR_SUPPR_REJ =           0x04,
+};
+
+enum {
+       CALL_GSM_SSN_INCOMING_IS_FWD =          0x01,
+       CALL_GSM_SSN_INCOMING_FWD =             0x02,
+       CALL_GSM_SSN_OUTGOING_FWD =             0x04,
+};
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/drivers/isimodem/ssn.c b/drivers/isimodem/ssn.c
index def3b0c..1e1f659 100644
--- a/drivers/isimodem/ssn.c
+++ b/drivers/isimodem/ssn.c
@@ -1,7 +1,7 @@
 /*
  * This file is part of oFono - Open Source Telephony
  *
- * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
  *
  * Contact: Aki Niemi <[email protected]>
  *
@@ -32,42 +32,248 @@
 #include <errno.h>
 
 #include <glib.h>
+#include <arpa/inet.h>
 
 #include <gisi/client.h>
+#include <gisi/iter.h>
 
 #include <ofono/log.h>
 #include <ofono/modem.h>
 #include <ofono/ssn.h>
 
 #include "isimodem.h"
+#include "call.h"
+#include "ss.h"
 
-#define PN_SS                  0x06
-
-struct ssn_data {
+struct isi_ssn {
        GIsiClient *client;
 };
 
+static void isi_ssn_ss_code(struct ofono_ssn *ssn, uint16_t ss_code)
+{
+       int cssi;
+
+       DBG("ss_code=%u", ss_code);
+
+       /* ss-code is MMI code from 22.030 */
+
+       switch (ss_code) {
+       case SS_GSM_FORW_UNCONDITIONAL:
+       case SS_GSM_ALL_FORWARDINGS:
+               /* 3GPP TS 22.082 clause 1.1.1 */
+               cssi = OFONO_SS_MO_UNCONDITIONAL_FORWARDING;
+               break;
+
+       case SS_GSM_FORW_NO_REPLY:
+       case SS_GSM_FORW_NO_REACH:
+       case SS_GSM_FORW_BUSY:
+       case SS_GSM_ALL_COND_FORWARDINGS:
+               /* 3GPP TS 22.082 clauses 2.1.1, 3.1.1, 4.1.1 */
+               cssi = OFONO_SS_MO_CONDITIONAL_FORWARDING;
+               break;
+
+       case SS_GSM_BARR_ALL_OUT:
+       case SS_GSM_OUTGOING_BARR_SERV:
+       case SS_GSM_BARR_OUT_INTER:
+       case SS_GSM_BARR_OUT_INTER_EXC_HOME:
+               /* 3GPP TS 22.088 clause 1.1 */
+               cssi = OFONO_SS_MO_OUTGOING_BARRING;
+               break;
+
+       case SS_GSM_INCOMING_BARR_SERV:
+       case SS_GSM_BARR_ALL_IN:
+       case SS_GSM_BARR_ALL_IN_ROAM:
+               /* 3GPP TS 22.088 clause 2.1 */
+               /* Called subscriber has barred incoming calls */
+               cssi = OFONO_SS_MO_INCOMING_BARRING;
+               break;
+
+       default:
+               return;
+       }
+
+       ofono_ssn_cssi_notify(ssn, cssi, 0);
+}
+
+static void isi_ssn_ss_notification(struct ofono_ssn *ssn, int id,
+                                       uint8_t ss_notification)
+{
+       int code;
+
+       struct ofono_phone_number number = { };
+
+       /* See SS-Notification in TS 22.080 clause 4.4.2 */
+
+       if (ss_notification & (1 << 2)) {
+               /* "Call is forwarded" indication to A-subscriber */
+               /* 3GPP TS 22.082 clauses 1.1.3, 2.1.3, 3.1.3, 4.1.3 */
+               code = OFONO_SS_MO_CALL_FORWARDED;
+               ofono_ssn_cssi_notify(ssn, code, id);
+       } else if (ss_notification & (1 << 1)) {
+               /* "Call is forwarded" indication to B subscriber */
+               /* 3GPP TS 24.082 clauses 2.1.1, 3.1.1 */
+               code = OFONO_SS_MT_OTHER_CALL_FORWARDED;
+               ofono_ssn_cssu_notify(ssn, code, 0, number);
+               /* A subscriber address is not relayed to mobile */
+       } else if (ss_notification & (1 << 0)) {
+               /* "Call is forwarded" indication to C subscriber */
+               /* 3GPP TS 22.082 clauses 1.1.2, 2.1.2, 3.1.2, 4.1.2 */
+               code = OFONO_SS_MT_CALL_FORWARDED;
+               ofono_ssn_cssu_notify(ssn, code, id, number);
+               /* The redirecting address is not part of notifySS */
+               /* However, it is available in CALL_COMING_IND */
+       }
+}
+
+static void isi_ssn_notify_indicator(struct ofono_ssn *ssn, int id,
+                                       uint8_t ss_indicators,
+                                       struct ofono_phone_number *number)
+{
+       DBG("");
+
+       if (ss_indicators & CALL_GSM_SSI_CALL_IS_WAITING) {
+               ofono_ssn_cssi_notify(ssn,
+                       OFONO_SS_MO_CALL_WAITING, id);
+       }
+
+       if (ss_indicators & CALL_GSM_SSI_MPTY) {
+               /* call is connected to multiparty by remote end */
+               ofono_ssn_cssu_notify(ssn,
+                       OFONO_SS_MT_MULTIPARTY_VOICECALL, id, number);
+       }
+
+       if (ss_indicators & CALL_GSM_SSI_CLIR_SUPPR_REJ) {
+               ofono_ssn_cssi_notify(ssn,
+                       OFONO_SS_MO_CLIR_SUPPRESSION_REJECTED, id);
+       }
+}
+
+static void isi_ssn_hold_indicator(struct ofono_ssn *ssn, int id, uint8_t hold)
+{
+       int code;
+
+       struct ofono_phone_number number = { };
+
+       DBG("CallOnHoldIndication=%u", hold);
+
+       if (hold)
+               code = OFONO_SS_MT_VOICECALL_ON_HOLD;
+       else
+               code = OFONO_SS_MT_VOICECALL_RETRIEVED;
+
+       ofono_ssn_cssu_notify(ssn, code, id, &number);
+}
+
+static void isi_ssn_ind(GIsiClient *client,
+                       void const *restrict data, size_t len,
+                       uint16_t object, void *user)
+{
+       struct ofono_ssn *ssn = user;
+       struct {
+               uint8_t message_id, call_id, sub_blocks;
+       } const *m = data;
+       int id;
+       uint16_t ss_code = 0;
+       uint8_t ss_notification = 0;
+       uint8_t ss_indicators;
+       uint8_t ss_hold;
+       struct {
+               int ss_notification;
+               int ss_status;
+               int ss_indicators;
+               int ss_hold;
+       } got = { };
+       GIsiSubBlockIter sb[1];
+
+       if (len < 3)
+               return;         /* runt */
+
+       id = m->call_id & 7;
+       if (id == 0)
+               return;
+
+       DBG("id %u, len = %zu", id, len);
+
+       for (g_isi_sb_iter_init(sb, data, len, (sizeof *m));
+                       g_isi_sb_iter_is_valid(sb);
+                               g_isi_sb_iter_next(sb)) {
+               switch (g_isi_sb_iter_get_id(sb)) {
+               case CALL_GSM_SS_CODE:
+                       g_isi_sb_iter_get_word(sb, &ss_code, 2);
+                       break;
+
+               case CALL_GSM_SS_STATUS:
+                       got.ss_status = 1;
+                       break;
+
+               case CALL_GSM_SS_NOTIFY:
+                       if (g_isi_sb_iter_get_byte(sb, &ss_notification, 2))
+                               got.ss_notification = 1;
+                       break;
+
+               case CALL_GSM_SS_NOTIFY_INDICATOR:
+                       if (g_isi_sb_iter_get_byte(sb, &ss_indicators, 2))
+                               got.ss_indicators = 1;
+                       break;
+
+               case CALL_GSM_SS_HOLD_INDICATOR:
+                       if (g_isi_sb_iter_get_byte(sb, &ss_hold, 2))
+                               got.ss_hold = 1;
+                       break;
+
+               case CALL_GSM_SS_ECT_INDICATOR:
+                       /* TODO */
+                       break;
+
+               case CALL_GSM_CUG_INFO:
+                       /* TODO */
+                       break;
+               }
+       }
+
+       if (got.ss_notification)
+               isi_ssn_ss_notification(ssn, id, ss_notification);
+       else if (got.ss_status)
+               isi_ssn_ss_code(ssn, ss_code);
+
+       if (got.ss_indicators)
+               isi_ssn_notify_indicator(ssn, id, ss_indicators);
+
+       if (got.ss_hold)
+               isi_ssn_hold_indicator(ssn, id, ss_hold);
+}
+
 static int isi_ssn_probe(struct ofono_ssn *ssn, unsigned int vendor,
                                void *user)
 {
-       GIsiModem *idx = user;
-       struct ssn_data *data = g_try_new0(struct ssn_data, 1);
+       GIsiModem *modem = user;
+       struct isi_ssn *data;
 
+       DBG("");
+
+       data = g_try_new0(struct isi_ssn, 1);
        if (!data)
                return -ENOMEM;
 
-       data->client = g_isi_client_create(idx, PN_SS);
-       if (!data->client)
+       data->client = g_isi_client_create(modem, PN_CALL);
+       if (!data->client) {
+               g_free(data);
                return -ENOMEM;
+       }
 
        ofono_ssn_set_data(ssn, data);
 
+       ofono_ssn_register(ssn);
+
+       g_isi_subscribe(data->client, CALL_GSM_NOTIFICATION_IND,
+                       isi_ssn_ind, ssn);
+
        return 0;
 }
 
 static void isi_ssn_remove(struct ofono_ssn *ssn)
 {
-       struct ssn_data *data = ofono_ssn_get_data(ssn);
+       struct isi_ssn *data = ofono_ssn_get_data(ssn);
 
        if (data) {
                g_isi_client_destroy(data->client);
-- 
1.7.0.4

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to