isimodem: wgmodem2.5 added to voicecall
authorJessica Nilsson <jessica.j.nilsson@stericsson.com>
Wed, 23 Feb 2011 11:43:21 +0000 (12:43 +0100)
committerAki Niemi <aki.niemi@nokia.com>
Thu, 3 Mar 2011 15:43:29 +0000 (17:43 +0200)
drivers/isimodem/call.h
drivers/isimodem/voicecall.c

index 05f05a5..0bbef7d 100644 (file)
@@ -27,6 +27,8 @@ extern "C" {
 #endif
 
 #define PN_CALL                                        0x01
+#define PN_MODEM_CALL                          0xC9
+#define CALL_MODEM_PROP_PRESENT_DEFAULT                0x00
 
 enum call_message_id {
        CALL_CREATE_REQ =                       0x01,
@@ -333,6 +335,7 @@ enum call_subblock {
        CALL_MODE_CHANGE_INFO =                 0x36,
        CALL_ADDITIONAL_PARAMS =                0x37,
        CALL_DSAC_INFO =                        0x38,
+       CALL_LINE_ID =                          0x47,
 };
 
 enum call_id {
@@ -351,6 +354,10 @@ enum call_id {
        CALL_ID_ALL =                           0xF0,
 };
 
+enum call_dtmf_pause_values {
+       CALL_DTMF_PAUSE_1S = 0x01
+};
+
 enum call_mode {
        CALL_MODE_EMERGENCY =                   0x00,
        CALL_MODE_SPEECH =                      0x01,
@@ -369,6 +376,12 @@ enum {
        CALL_GSM_PRESENTATION_DEFAULT =         0x07,
 };
 
+enum call_modem_line_id {
+       CALL_MODEM_PRESENT_DEFAULT =            0x00,
+       CALL_MODEM_PRESENT_ALLOWED =            0x01,
+       CALL_MODEM_PRESENT_RESTRICTED =         0x02
+};
+
 enum call_operation {
        CALL_OP_HOLD =                          0x01,
        CALL_OP_RETRIEVE =                      0x02,
@@ -402,6 +415,82 @@ enum {
        CALL_DTMF_DISABLE_TONE_IND_SEND =       0x02,
 };
 
+enum call_notification_indicator {
+       CALL_NOTIFY_USER_SUSPENDED =            0x00,
+       CALL_NOTIFY_USER_RESUMED =              0x01,
+       CALL_NOTIFY_BEARER_CHANGE =             0x02
+};
+
+enum call_mmi_ss_codes {
+       CALL_SSC_ALL_FWDS =                     0x0002,
+       CALL_SSC_ALL_COND_FWD =                 0x0004,
+       CALL_SSC_CFU =                          0x0015,
+       CALL_SSC_CFB =                          0x0043,
+       CALL_SSC_CFNRY =                        0x003D,
+       CALL_SSC_CFGNC =                        0x003E,
+       CALL_SSC_OUTGOING_BARR_SERV =           0x014D,
+       CALL_SSC_INCOMING_BARR_SERV =           0x0161,
+       CALL_SSC_CALL_WAITING =                 0x002B,
+       CALL_SSC_CLIR =                         0x001F,
+       CALL_SSC_ETC =                          0x0060,
+       CALL_SSC_MPTY =                         0xFFFE,
+       CALL_SSC_CALL_HOLD =                    0xFFFF
+};
+
+enum call_ss_status {
+       CALL_SS_STATUS_ACTIVE =                 0x01,
+       CALL_SS_STATUS_REGISTERED =             0x02,
+       CALL_SS_STATUS_PROVISIONED =            0x04,
+       CALL_SS_STATUS_QUIESCENT =              0x08
+};
+
+enum call_ss_notification {
+       CALL_SSN_INCOMING_IS_FWD =              0x01,
+       CALL_SSN_INCOMING_FWD =                 0x02,
+       CALL_SSN_OUTGOING_FWD =                 0x04
+};
+
+enum call_ss_indicator {
+       CALL_SSI_CALL_IS_WAITING =              0x01,
+       CALL_SSI_MPTY =                         0x02,
+       CALL_SSI_CLIR_SUPPR_REJ =               0x04
+};
+
+enum call_ss_hold_indicator {
+       CALL_HOLD_IND_RETRIEVED =               0x00,
+       CALL_HOLD_IND_ON_HOLD =                 0x01
+};
+
+enum call_ss_ect_indicator {
+       CALL_ECT_CALL_STATE_ALERT =             0x00,
+       CALL_ECT_CALL_STATE_ACTIVE =            0x01
+};
+
+enum call_notification_sb_values {
+       CALL_SB_NOTIFY =                        0xB1,
+       CALL_SB_SS_NOTIFY =                     0xB2,
+       CALL_SB_SS_CODE =                       0xB3,
+       CALL_SB_SS_STATUS =                     0xB4,
+       CALL_SB_SS_NOTIFY_INDICATOR =           0xB5,
+       CALL_SB_SS_HOLD_INDICATOR =             0xB6,
+       CALL_SB_SS_ECT_INDICATOR =              0xB7,
+       CALL_SB_REMOTE_ADDRESS =                0xA6,
+       CALL_SB_REMOTE_SUBADDRESS =             0xA7,
+       CALL_SB_CUG_INFO =                      0xA0,
+       CALL_SB_ORIGIN_INFO =                   0x0E,
+       CALL_SB_ALERTING_PATTERN =              0xA1,
+       CALL_SB_ALERTING_INFO =                 0x0C
+};
+
+/* 27.007 Section 7.7 */
+enum clir_status {
+       CLIR_STATUS_NOT_PROVISIONED = 0,
+       CLIR_STATUS_PROVISIONED_PERMANENT,
+       CLIR_STATUS_UNKNOWN,
+       CLIR_STATUS_TEMPORARY_RESTRICTED,
+       CLIR_STATUS_TEMPORARY_ALLOWED
+};
+
 #ifdef __cplusplus
 };
 #endif
index 0870556..405db01 100644 (file)
@@ -84,10 +84,12 @@ struct call_info {
 
 struct isi_voicecall {
        GIsiClient *client;
-
+       GIsiClient *primary;
+       GIsiClient *secondary;
        struct isi_call_req_ctx *queue;
-
        struct isi_call calls[8];
+       void *control_req_irc;
+
 };
 
 typedef void isi_call_req_step(struct isi_call_req_ctx *ctx, int reason);
@@ -588,26 +590,66 @@ static struct isi_call_req_ctx *isi_call_create_req(struct ofono_voicecall *ovc,
                                                        ofono_voicecall_cb_t cb,
                                                        void *data)
 {
+       struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
        size_t addr_len = strlen(address);
        size_t sub_len = (6 + 2 * addr_len + 3) & ~3;
-       size_t i, offset = 3 + 4 + 8 + 6;
-       uint8_t req[3 + 4 + 8 + 6 + 40] = {
-               CALL_CREATE_REQ,
-               0,              /* No id */
-               3,              /* Mode, Clir, Number */
+       size_t origin_size = (g_isi_client_resource(ivc->client) ==
+                               PN_MODEM_CALL) ? 4 : 8;
+       size_t i, offset = 3 + 4 + origin_size + 6;
+       size_t rlen = 3 + 4 + origin_size + sub_len;
+       uint8_t req[3 + 4 + origin_size + 6 + 40];
+
+       memset(req, 0, 3 + 4 + origin_size + 6 + 40);
+
+       if (g_isi_client_resource(ivc->client) == PN_MODEM_CALL) {
+               req[0] = CALL_CREATE_REQ;
+               req[1] = 0; /* No id */
+               req[2] = 3; /* Mode, Clir, Number */
                /* MODE SB */
-               CALL_MODE, 4, CALL_MODE_SPEECH, CALL_MODE_INFO_NONE,
+               req[3] = CALL_MODE;
+               req[4] = 4;
+               req[5] = CALL_MODE_SPEECH;
+               req[6] = 0;
                /* ORIGIN_INFO SB */
-               CALL_ORIGIN_INFO, 8, presentation, 0, 0, 0, 0, 0,
+               req[7] = CALL_LINE_ID;
+               req[8] = origin_size;
+               req[9] = presentation;
+               req[10] = 0;
                /* DESTINATION_ADDRESS SB */
-               CALL_DESTINATION_ADDRESS,
-               sub_len,
-               addr_type & 0x7F,
-               0, 0,
-               addr_len,
+               req[11] = CALL_DESTINATION_ADDRESS;
+               req[12] = sub_len;
+               req[13] = addr_type & 0x7F;
+               req[14] = 0;
+               req[15] = 0;
+               req[16] = addr_len;
                /* uint16_t addr[20] */
-       };
-       size_t rlen = 3 + 4 + 8 + sub_len;
+       } else {
+               req[0] = CALL_CREATE_REQ;
+               req[1] = 0; /* No id */
+               req[2] = 3; /* Mode, Clir, Number */
+               /* MODE SB */
+               req[3] = CALL_MODE;
+               req[4] = 4;
+               req[5] = CALL_MODE_SPEECH;
+               req[6] = CALL_MODE_INFO_NONE;
+               /* ORIGIN_INFO SB */
+               req[7] = CALL_ORIGIN_INFO;
+               req[8] = origin_size;
+               req[9] = presentation;
+               req[10] = 0;
+               req[11] = 0;
+               req[12] = 0;
+               req[13] = 0;
+               req[14] = 0;
+               /* DESTINATION_ADDRESS SB */
+               req[15] = CALL_DESTINATION_ADDRESS;
+               req[16] = sub_len;
+               req[17] = addr_type & 0x7F;
+               req[18] = 0;
+               req[19] = 0;
+               req[20] = addr_len;
+               /* uint16_t addr[20] */
+       }
 
        if (addr_len > 20) {
                CALLBACK_WITH_FAILURE(cb, data);
@@ -772,7 +814,8 @@ error:
        isi_ctx_return_failure(irc);
 }
 
-static struct isi_call_req_ctx *isi_call_release_req(struct ofono_voicecall *ovc,
+static struct isi_call_req_ctx *isi_call_release_req(
+                                               struct ofono_voicecall *ovc,
                                                uint8_t call_id,
                                                enum call_cause_type cause_type,
                                                uint8_t cause,
@@ -816,7 +859,8 @@ static void isi_call_status_resp(const GIsiMessage *msg, void *data)
                        break;
 
                case CALL_ADDR_AND_STATUS_INFO:
-                       call = isi_call_addr_and_status_info_sb_proc(ivc, &iter);
+                       call = isi_call_addr_and_status_info_sb_proc(ivc,
+                                                                       &iter);
                        if (call)
                                isi_call_notify(ovc, call);
                        break;
@@ -882,12 +926,13 @@ error:
        isi_ctx_return_failure(irc);
 }
 
-static struct isi_call_req_ctx *isi_call_control_req(struct ofono_voicecall *ovc,
-                                                       uint8_t call_id,
-                                                       enum call_operation op,
-                                                       uint8_t info,
-                                                       ofono_voicecall_cb_t cb,
-                                                       void *data)
+static struct isi_call_req_ctx *isi_call_control_req(
+                                               struct ofono_voicecall *ovc,
+                                               uint8_t call_id,
+                                               enum call_operation op,
+                                               uint8_t info,
+                                               ofono_voicecall_cb_t cb,
+                                               void *data)
 {
        const uint8_t req[] = {
                CALL_CONTROL_REQ,
@@ -902,12 +947,13 @@ static struct isi_call_req_ctx *isi_call_control_req(struct ofono_voicecall *ovc
                                cb, data);
 }
 
-static struct isi_call_req_ctx *isi_call_deflect_req(struct ofono_voicecall *ovc,
-                                                       uint8_t call_id,
-                                                       uint8_t address_type,
-                                                       const char address[21],
-                                                       ofono_voicecall_cb_t cb,
-                                                       void *data)
+static struct isi_call_req_ctx *isi_call_deflect_req(
+                                               struct ofono_voicecall *ovc,
+                                               uint8_t call_id,
+                                               uint8_t address_type,
+                                               const char address[21],
+                                               ofono_voicecall_cb_t cb,
+                                               void *data)
 {
        size_t addr_len = strlen(address);
        size_t sub_len = (6 + 2 * addr_len + 3) & ~3;
@@ -939,6 +985,37 @@ static struct isi_call_req_ctx *isi_call_deflect_req(struct ofono_voicecall *ovc
        return isi_call_req(ovc, req, rlen, isi_call_control_resp, cb, data);
 }
 
+static void isi_call_control_ind_cb(const GIsiMessage *msg, void *data)
+{
+       struct ofono_voicecall *ovc = data;
+       struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+       GIsiSubBlockIter iter;
+       uint8_t cause_type = 0, cause = 0;
+
+       if (ivc == NULL || g_isi_msg_id(msg) != CALL_CONTROL_IND)
+               return;
+
+       for (g_isi_sb_iter_init(&iter, msg, 2);
+                       g_isi_sb_iter_is_valid(&iter);
+                       g_isi_sb_iter_next(&iter)) {
+
+               if (g_isi_sb_iter_get_id(&iter) != CALL_CAUSE)
+                       continue;
+               if (!g_isi_sb_iter_get_byte(&iter, &cause_type, 2) ||
+                               !g_isi_sb_iter_get_byte(&iter, &cause, 3))
+                       return;
+       }
+
+       if (ivc->control_req_irc) {
+               if (!cause)
+                       isi_ctx_return_success(ivc->control_req_irc);
+               else
+                       isi_ctx_return_failure(ivc->control_req_irc);
+
+               ivc->control_req_irc = NULL;
+       }
+}
+
 static void isi_call_dtmf_send_resp(const GIsiMessage *msg, void *data)
 {
        struct isi_call_req_ctx *irc = data;
@@ -970,11 +1047,12 @@ error:
        isi_ctx_return_failure(irc);
 }
 
-static struct isi_call_req_ctx *isi_call_dtmf_send_req(struct ofono_voicecall *ovc,
-                                                       uint8_t call_id,
-                                                       const char *string,
-                                                       ofono_voicecall_cb_t cb,
-                                                       void *data)
+static struct isi_call_req_ctx *isi_call_dtmf_send_req(
+                                               struct ofono_voicecall *ovc,
+                                               uint8_t call_id,
+                                               const char *string,
+                                               ofono_voicecall_cb_t cb,
+                                               void *data)
 {
        size_t str_len = strlen(string);
        size_t sub_len = 4 + ((2 * str_len + 3) & ~3);
@@ -1009,18 +1087,23 @@ static void isi_dial(struct ofono_voicecall *ovc,
                        enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
                        void *data)
 {
-       unsigned char presentation = CALL_GSM_PRESENTATION_DEFAULT;
+       unsigned char presentation;
+       struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
 
        switch (clir) {
-       case OFONO_CLIR_OPTION_DEFAULT:
-               presentation = CALL_GSM_PRESENTATION_DEFAULT;
-               break;
        case OFONO_CLIR_OPTION_INVOCATION:
                presentation = CALL_PRESENTATION_RESTRICTED;
                break;
        case OFONO_CLIR_OPTION_SUPPRESSION:
                presentation = CALL_PRESENTATION_ALLOWED;
                break;
+       case OFONO_CLIR_OPTION_DEFAULT:
+       default:
+               presentation = (g_isi_client_resource(ivc->client) ==
+                               PN_MODEM_CALL) ?
+                                       CALL_MODEM_PROP_PRESENT_DEFAULT :
+                                       CALL_GSM_PRESENTATION_DEFAULT;
+               break;
        }
 
        isi_call_create_req(ovc, presentation, number->type, number->number,
@@ -1321,7 +1404,7 @@ static void isi_send_tones(struct ofono_voicecall *ovc, const char *tones,
        isi_call_dtmf_send_req(ovc, CALL_ID_ALL, tones, cb, data);;
 }
 
-static void isi_call_verify_cb(const GIsiMessage *msg, void *data)
+static void isi_primary_call_verify_cb(const GIsiMessage *msg, void *data)
 {
        struct ofono_voicecall *ovc = data;
        struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
@@ -1331,8 +1414,42 @@ static void isi_call_verify_cb(const GIsiMessage *msg, void *data)
 
        ISI_VERSION_DBG(msg);
 
+       ivc->client = ivc->primary;
+       g_isi_client_destroy(ivc->secondary);
+
        g_isi_client_ind_subscribe(ivc->client, CALL_STATUS_IND,
-                                       isi_call_status_ind_cb, ovc);
+                       isi_call_status_ind_cb, ovc);
+       g_isi_client_ind_subscribe(ivc->client, CALL_CONTROL_IND,
+                       isi_call_control_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))
+               DBG("Failed to request call status");
+
+       ofono_voicecall_register(ovc);
+}
+
+static void isi_secondary_call_verify_cb(const GIsiMessage *msg, void *data)
+{
+       struct ofono_voicecall *ovc = data;
+       struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+
+       if (g_isi_msg_error(msg) < 0)
+               return;
+
+       ISI_VERSION_DBG(msg);
+
+       ivc->client = ivc->secondary;
+       g_isi_client_destroy(ivc->primary);
+
+       g_isi_client_ind_subscribe(ivc->client, CALL_STATUS_IND,
+                       isi_call_status_ind_cb, ovc);
+       g_isi_client_ind_subscribe(ivc->client, CALL_CONTROL_IND,
+                       isi_call_control_ind_cb, ovc);
 
        g_isi_client_ind_subscribe(ivc->client, CALL_TERMINATED_IND,
                                        isi_call_terminated_ind_cb, ovc);
@@ -1359,15 +1476,24 @@ static int isi_voicecall_probe(struct ofono_voicecall *ovc,
        for (id = 0; id <= 7; id++)
                ivc->calls[id].id = id;
 
-       ivc->client = g_isi_client_create(modem, PN_CALL);
-       if (ivc->client == NULL) {
+       ivc->primary = g_isi_client_create(modem, PN_MODEM_CALL);
+       if (ivc->primary == NULL) {
+               g_free(ivc);
+               return -ENOMEM;
+       }
+       ivc->secondary = g_isi_client_create(modem, PN_CALL);
+       if (ivc->secondary == NULL) {
                g_free(ivc);
+               g_isi_client_destroy(ivc->primary);
                return -ENOMEM;
        }
 
        ofono_voicecall_set_data(ovc, ivc);
 
-       g_isi_client_verify(ivc->client, isi_call_verify_cb, ovc, NULL);
+       g_isi_client_verify(ivc->primary, isi_primary_call_verify_cb, ovc,
+                               NULL);
+       g_isi_client_verify(ivc->secondary, isi_secondary_call_verify_cb, ovc,
+                               NULL);
 
        return 0;
 }