From: Daniel Wagner <daniel.wagner(a)bmw-carit.de>
---
drivers/atmodem/gprs.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 170 insertions(+), 0 deletions(-)
diff --git a/drivers/atmodem/gprs.c b/drivers/atmodem/gprs.c
index bf82d06..9988217 100644
--- a/drivers/atmodem/gprs.c
+++ b/drivers/atmodem/gprs.c
@@ -48,8 +48,84 @@ static const char *none_prefix[] = { NULL };
struct gprs_data {
GAtChat *chat;
unsigned int vendor;
+ int ossysi; /* option hso 2G/3G info */
+ int octi; /* option hso 2G info details */
+ int ouwcti; /* otpion hso 3G info details */
};
+static int option_octi_to_tech(struct gprs_data *gd)
+{
+ int tech = -1;
+ switch (gd->octi) {
+ case 1: /* GSM */
+ tech = 0;
+ break;
+ case 2: /* GPRS */
+ tech = 1;
+ break;
+ case 3: /* EDGE */
+ tech = 3;
+ }
+
+ return tech;
+}
+
+static int option_ouwcti_to_tech(struct gprs_data *gd)
+{
+ int tech = -1;
+
+ switch (gd->ouwcti) {
+ case 1: /* UMTS */
+ tech = 2;
+ break;
+ case 2: /* HSDPA */
+ tech = 4;
+ break;
+ case 3: /* HSUPA */
+ tech = 5;
+ break;
+ case 4: /* HSPA */
+ tech = 6;
+ }
+
+ return tech;
+}
+
+static int option_get_tech(struct gprs_data *gd)
+{
+ int tech = -1;
+ int tech_2g, tech_3g;
+
+ switch (gd->ossysi) {
+ case -1:
+ tech_2g = option_octi_to_tech(gd);
+ tech_3g = option_ouwcti_to_tech(gd);
+
+ /* 3G tech takes precedence over 2G tech */
+ if (tech_3g == -1)
+ tech = tech_2g;
+ else
+ tech = tech_3g;
+ break;
+ case 0: /* 2G */
+ tech = option_octi_to_tech(gd);
+ break;
+ case 2: /* 3G */
+ tech = option_ouwcti_to_tech(gd);
+ break;
+ case 3: /* Unknown */
+ /* reset all ossysi and octi */
+ gd->octi = -1;
+ gd->ossysi = -1;
+ break;
+ }
+
+ DBG("ossysi %d octi %d ouwcti %d tech %d",
+ gd->ossysi, gd->octi, gd->ouwcti, tech);
+
+ return tech;
+}
+
static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -142,6 +218,67 @@ error:
CALLBACK_WITH_FAILURE(cb, -1, data);
}
+static void option_ossysi_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_gprs *gprs = user_data;
+ struct gprs_data *gd = ofono_gprs_get_data(gprs);
+ 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, &gd->ossysi))
+ return;
+
+ ofono_gprs_technology_notify(gprs, option_get_tech(gd));
+}
+
+static void option_octi_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_gprs *gprs = user_data;
+ struct gprs_data *gd = ofono_gprs_get_data(gprs);
+ GAtResultIter iter;
+ int mode;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "_OCTI:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &gd->octi))
+ return;
+
+ /* Handle query responses too */
+ if (!g_at_result_iter_next_number(&iter, &mode) == FALSE)
+ gd->octi = mode;
+
+ ofono_gprs_technology_notify(gprs, option_get_tech(gd));
+}
+
+static void option_ouwcti_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_gprs *gprs = user_data;
+ struct gprs_data *gd = ofono_gprs_get_data(gprs);
+ GAtResultIter iter;
+ int mode;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "_OUWCTI:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &gd->ouwcti))
+ return;
+
+ /* Handle query responses too */
+ if (!g_at_result_iter_next_number(&iter, &mode) == FALSE)
+ gd->ouwcti = mode;
+
+ ofono_gprs_technology_notify(gprs, option_get_tech(gd));
+}
+
static void cgreg_notify(GAtResult *result, gpointer user_data)
{
struct ofono_gprs *gprs = user_data;
@@ -153,6 +290,20 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
return;
ofono_gprs_status_notify(gprs, status);
+
+ switch (gd->vendor) {
+ case OFONO_VENDOR_OPTION_HSO:
+ /*
+ * After attaching Option modems will send an unsolicited
+ * CGREG. Unfortunalty, the technology messages
+ * appear before we are attached. So we need to update the core
+ * about the current technology after we tell the core we are
+ * attached. Otherwise, the CurrentTechnology property wont be
+ * updated until a technology change happends.
+ */
+ ofono_gprs_technology_notify(gprs, option_get_tech(gd));
+ break;
+ }
}
static void cgev_notify(GAtResult *result, gpointer user_data)
@@ -181,6 +332,25 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer
user_data)
struct ofono_gprs *gprs = user_data;
struct gprs_data *gd = ofono_gprs_get_data(gprs);
+ switch (gd->vendor) {
+ case OFONO_VENDOR_OPTION_HSO:
+ g_at_chat_register(gd->chat, "_OSSYSI:", option_ossysi_notify,
+ FALSE, gprs, NULL);
+ g_at_chat_register(gd->chat, "_OCTI:", option_octi_notify,
+ FALSE, gprs, NULL);
+ g_at_chat_register(gd->chat, "_OUWCTI:", option_ouwcti_notify,
+ FALSE, gprs, NULL);
+ g_at_chat_send(gd->chat, "AT_OCTI=1", none_prefix,
+ NULL, NULL, NULL);
+ g_at_chat_send(gd->chat, "AT_OUWCTI=1", none_prefix,
+ NULL, NULL, NULL);
+ g_at_chat_send(gd->chat, "AT_OCTI?", none_prefix,
+ NULL, NULL, NULL);
+ g_at_chat_send(gd->chat, "AT_OUWCTI?", none_prefix,
+ NULL, NULL, NULL);
+ break;
+ }
+
g_at_chat_register(gd->chat, "+CGEV:", cgev_notify, FALSE, gprs, NULL);
g_at_chat_register(gd->chat, "+CGREG:", cgreg_notify,
FALSE, gprs, NULL);
--
1.6.6.1