summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/atmodem/network-registration.c184
1 files changed, 122 insertions, 62 deletions
diff --git a/drivers/atmodem/network-registration.c b/drivers/atmodem/network-registration.c
index f5ccbb1c..4366e1e2 100644
--- a/drivers/atmodem/network-registration.c
+++ b/drivers/atmodem/network-registration.c
@@ -46,6 +46,7 @@ static const char *creg_prefix[] = { "+CREG:", NULL };
static const char *cops_prefix[] = { "+COPS:", NULL };
static const char *csq_prefix[] = { "+CSQ:", NULL };
static const char *cind_prefix[] = { "+CIND:", NULL };
+static const char *option_tech_prefix[] = { "_OCTI:", "_OUWCTI:", NULL };
struct netreg_data {
GAtChat *chat;
@@ -58,6 +59,13 @@ struct netreg_data {
unsigned int vendor;
};
+struct tech_query {
+ int status;
+ int lac;
+ int ci;
+ struct ofono_netreg *netreg;
+};
+
static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)
{
/* Three digit country code */
@@ -69,6 +77,64 @@ static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)
mnc[OFONO_MAX_MNC_LENGTH] = '\0';
}
+static int option_parse_tech(GAtResult *result)
+{
+ GAtResultIter iter;
+ int s, octi, ouwcti;
+ int tech = -1;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "_OCTI:"))
+ return -1;
+
+ if (!g_at_result_iter_next_number(&iter, &s))
+ return -1;
+
+ if (!g_at_result_iter_next_number(&iter, &octi))
+ return -1;
+
+ if (!g_at_result_iter_next(&iter, "_OUWCTI:"))
+ return -1;
+
+ if (!g_at_result_iter_next_number(&iter, &s))
+ return -1;
+
+ if (!g_at_result_iter_next_number(&iter, &ouwcti))
+ return -1;
+
+ switch (octi) {
+ case 1: /* GSM */
+ tech = 0;
+ break;
+ case 2: /* GPRS */
+ tech = 1;
+ break;
+ case 3: /* EDGE */
+ tech = 3;
+ break;
+ }
+
+ switch (ouwcti) {
+ case 1: /* UMTS */
+ tech = 2;
+ break;
+ case 2: /* HSDPA */
+ tech = 4;
+ break;
+ case 3: /* HSUPA */
+ tech = 5;
+ break;
+ case 4: /* HSPA */
+ tech = 6;
+ break;
+ }
+
+ DBG("octi %d ouwcti %d tech %d", octi, ouwcti, tech);
+
+ return tech;
+}
+
static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -96,6 +162,18 @@ static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
cb(&error, status, lac, ci, tech, cbd->data);
}
+static void option_tech_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_netreg *netreg = cbd->data;
+ struct netreg_data *nd = ofono_netreg_get_data(netreg);
+
+ if (ok)
+ nd->tech = option_parse_tech(result);
+ else
+ nd->tech = -1;
+}
+
static void at_registration_status(struct ofono_netreg *netreg,
ofono_netreg_status_cb_t cb,
void *data)
@@ -125,6 +203,16 @@ static void at_registration_status(struct ofono_netreg *netreg,
g_at_chat_send(nd->chat, "AT$CNTI=0", none_prefix,
NULL, NULL, NULL);
break;
+ case OFONO_VENDOR_OPTION_HSO:
+ /*
+ * Send AT_OCTI?;_OUWCTI? to find out the current tech,
+ * option_tech_cb will call fire CREG? to do the rest.
+ */
+ if (g_at_chat_send(nd->chat, "AT_OCTI?;_OUWCTI?",
+ option_tech_prefix,
+ option_tech_cb, cbd, NULL) == 0)
+ nd->tech = -1;
+ break;
}
if (g_at_chat_send(nd->chat, "AT+CREG?", creg_prefix,
@@ -533,38 +621,6 @@ static void option_osigq_notify(GAtResult *result, gpointer user_data)
at_util_convert_signal_strength(strength));
}
-static void option_ouwcti_notify(GAtResult *result, gpointer user_data)
-{
- int mode;
- GAtResultIter iter;
-
- g_at_result_iter_init(&iter, result);
-
- if (!g_at_result_iter_next(&iter, "_OUWCTI:"))
- return;
-
- if (!g_at_result_iter_next_number(&iter, &mode))
- return;
-
- ofono_info("OWCTI mode: %d", mode);
-}
-
-static void option_octi_notify(GAtResult *result, gpointer user_data)
-{
- int mode;
- GAtResultIter iter;
-
- g_at_result_iter_init(&iter, result);
-
- if (!g_at_result_iter_next(&iter, "_OCTI:"))
- return;
-
- if (!g_at_result_iter_next_number(&iter, &mode))
- return;
-
- ofono_info("OCTI mode: %d", mode);
-}
-
static void ciev_notify(GAtResult *result, gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
@@ -624,22 +680,6 @@ static void cind_cb(gboolean ok, GAtResult *result, gpointer user_data)
cb(&error, strength, cbd->data);
}
-static void option_ossysi_notify(GAtResult *result, gpointer user_data)
-{
- int mode;
- GAtResultIter iter;
-
- g_at_result_iter_init(&iter, result);
-
- if (!g_at_result_iter_next(&iter, "_OSSYSI:"))
- return;
-
- if (!g_at_result_iter_next_number(&iter, &mode))
- return;
-
- ofono_info("OSSYSI mode: %d", mode);
-}
-
static void huawei_rssi_notify(GAtResult *result, gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
@@ -803,16 +843,50 @@ static void nw_cnti_notify(GAtResult *result, gpointer user_data)
ofono_info("CNTI: %s", tech);
}
+static void option_query_tech_cb(gboolean ok,
+ GAtResult *result, gpointer user_data)
+{
+ struct tech_query *tq = user_data;
+ int tech = -1;
+
+ if (ok)
+ tech = option_parse_tech(result);
+
+ ofono_netreg_status_notify(tq->netreg,
+ tq->status, tq->lac, tq->ci, tech);
+}
+
static void creg_notify(GAtResult *result, gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
int status, lac, ci, tech;
struct netreg_data *nd = ofono_netreg_get_data(netreg);
+ struct tech_query *tq;
if (at_util_parse_reg_unsolicited(result, "+CREG:", &status,
&lac, &ci, &tech, nd->vendor) == FALSE)
return;
+ switch (nd->vendor) {
+ case OFONO_VENDOR_OPTION_HSO:
+ tq = g_new0(struct tech_query, 1);
+ if (!tq)
+ break;
+
+ tq->status = status;
+ tq->lac = lac;
+ tq->ci = ci;
+ tq->netreg = netreg;
+
+ if (g_at_chat_send(nd->chat, "AT_OCTI?;_OUWCTI?",
+ option_tech_prefix, option_query_tech_cb,
+ tq, g_free) > 0)
+ return;
+
+ g_free(tq);
+ break;
+ }
+
if ((status == 1 || status == 5) && tech == -1)
tech = nd->tech;
@@ -909,27 +983,13 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
case OFONO_VENDOR_OPTION_HSO:
g_at_chat_send(nd->chat, "AT_OSSYS=1", none_prefix,
NULL, NULL, NULL);
- g_at_chat_send(nd->chat, "AT_OUWCTI=1", none_prefix,
- NULL, NULL, NULL);
- g_at_chat_send(nd->chat, "AT_OCTI=1", none_prefix,
- NULL, NULL, NULL);
g_at_chat_send(nd->chat, "AT_OSQI=1", none_prefix,
NULL, NULL, NULL);
g_at_chat_register(nd->chat, "_OSIGQ:", option_osigq_notify,
FALSE, netreg, NULL);
- g_at_chat_register(nd->chat, "_OUWCTI:", option_ouwcti_notify,
- FALSE, netreg, NULL);
- g_at_chat_register(nd->chat, "_OCTI:", option_octi_notify,
- FALSE, netreg, NULL);
- g_at_chat_register(nd->chat, "_OSSYSI:", option_ossysi_notify,
- FALSE, netreg, NULL);
g_at_chat_send(nd->chat, "AT_OSSYS?", none_prefix,
NULL, NULL, NULL);
- g_at_chat_send(nd->chat, "AT_OWCTI?", none_prefix,
- NULL, NULL, NULL);
- g_at_chat_send(nd->chat, "AT_OCTI?", none_prefix,
- NULL, NULL, NULL);
g_at_chat_send(nd->chat, "AT_OSQI?", none_prefix,
NULL, NULL, NULL);
break;