* [PATCH 0/7] Support for mtk modems
@ 2015-11-13 12:25 Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 1/7] gitignore: Ignore rilmodem-cs test binary Alfonso Sanchez-Beato
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2601 bytes --]
This patch series add support for MediaTek modems. The mtkmodem driver
is heavily based on rilmodem.
Alfonso Sanchez-Beato (7):
gitignore: Ignore rilmodem-cs test binary
include: Add flag for drivers that watch SIM state
modem: Add flag for drivers that watch SIM state
rilmodem: Export functions needed by mtkmodem
mtkmodem: Add mtkmodem driver
mtk: Plugin for mtkmodems
build: Add mtkmodem driver and mtk plugin
.gitignore | 1 +
Makefile.am | 19 +
drivers/mtkmodem/gprs.c | 188 ++++
drivers/mtkmodem/mtk_constants.h | 84 ++
drivers/mtkmodem/mtkmodem.c | 58 ++
drivers/mtkmodem/mtkmodem.h | 32 +
drivers/mtkmodem/mtkreply.c | 98 +++
drivers/mtkmodem/mtkreply.h | 43 +
drivers/mtkmodem/mtkrequest.c | 163 ++++
drivers/mtkmodem/mtkrequest.h | 143 ++++
drivers/mtkmodem/mtksettings.c | 261 ++++++
drivers/mtkmodem/mtksettings.h | 43 +
drivers/mtkmodem/mtkunsol.c | 199 +++++
drivers/mtkmodem/mtkunsol.h | 59 ++
drivers/mtkmodem/mtkutil.c | 143 ++++
drivers/mtkmodem/mtkutil.h | 47 +
drivers/mtkmodem/radio-settings.c | 193 +++++
drivers/mtkmodem/voicecall.c | 155 ++++
drivers/rilmodem/radio-settings.c | 21 +-
drivers/rilmodem/radio-settings.h | 46 +
drivers/rilmodem/voicecall.c | 18 +-
drivers/rilmodem/voicecall.h | 4 +
include/modem.h | 4 +
plugins/mtk.c | 1704 +++++++++++++++++++++++++++++++++++++
src/modem.c | 38 +-
25 files changed, 3735 insertions(+), 29 deletions(-)
create mode 100644 drivers/mtkmodem/gprs.c
create mode 100644 drivers/mtkmodem/mtk_constants.h
create mode 100644 drivers/mtkmodem/mtkmodem.c
create mode 100644 drivers/mtkmodem/mtkmodem.h
create mode 100644 drivers/mtkmodem/mtkreply.c
create mode 100644 drivers/mtkmodem/mtkreply.h
create mode 100644 drivers/mtkmodem/mtkrequest.c
create mode 100644 drivers/mtkmodem/mtkrequest.h
create mode 100644 drivers/mtkmodem/mtksettings.c
create mode 100644 drivers/mtkmodem/mtksettings.h
create mode 100644 drivers/mtkmodem/mtkunsol.c
create mode 100644 drivers/mtkmodem/mtkunsol.h
create mode 100644 drivers/mtkmodem/mtkutil.c
create mode 100644 drivers/mtkmodem/mtkutil.h
create mode 100644 drivers/mtkmodem/radio-settings.c
create mode 100644 drivers/mtkmodem/voicecall.c
create mode 100644 drivers/rilmodem/radio-settings.h
create mode 100644 plugins/mtk.c
--
2.5.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/7] gitignore: Ignore rilmodem-cs test binary
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
@ 2015-11-13 12:25 ` Alfonso Sanchez-Beato
2015-11-13 16:06 ` Denis Kenzior
2015-11-13 12:25 ` [PATCH 2/7] include: Add flag for drivers that watch SIM state Alfonso Sanchez-Beato
` (5 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 331 bytes --]
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index b9c23a0..a433dad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,7 @@ unit/test-mux
unit/test-caif
unit/test-stkutil
unit/test-cdmasms
+unit/test-rilmodem-cs
unit/test-*.log
unit/test-*.trs
--
2.5.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/7] include: Add flag for drivers that watch SIM state
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 1/7] gitignore: Ignore rilmodem-cs test binary Alfonso Sanchez-Beato
@ 2015-11-13 12:25 ` Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 3/7] modem: " Alfonso Sanchez-Beato
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 862 bytes --]
Add flag for drivers that handle modems that cannot access the SIM when
in offline state. These drivers watch the SIM state to create/destroy
certain atoms.
---
include/modem.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/modem.h b/include/modem.h
index e40b23e..54ce862 100644
--- a/include/modem.h
+++ b/include/modem.h
@@ -115,6 +115,10 @@ int ofono_modem_set_boolean(struct ofono_modem *modem,
ofono_bool_t ofono_modem_get_boolean(struct ofono_modem *modem,
const char *key);
+void ofono_modem_set_driver_watches_sim(struct ofono_modem *modem,
+ ofono_bool_t value);
+ofono_bool_t ofono_modem_get_driver_watches_sim(struct ofono_modem *modem);
+
int ofono_modem_driver_register(const struct ofono_modem_driver *);
void ofono_modem_driver_unregister(const struct ofono_modem_driver *);
--
2.5.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/7] modem: Add flag for drivers that watch SIM state
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 1/7] gitignore: Ignore rilmodem-cs test binary Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 2/7] include: Add flag for drivers that watch SIM state Alfonso Sanchez-Beato
@ 2015-11-13 12:25 ` Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 4/7] rilmodem: Export functions needed by mtkmodem Alfonso Sanchez-Beato
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2416 bytes --]
Add flag for drivers that handle modems that cannot access the SIM when
in offline state. These drivers watch the SIM state to create/destroy
certain atoms.
---
src/modem.c | 38 +++++++++++++++++++++++++++-----------
1 file changed, 27 insertions(+), 11 deletions(-)
diff --git a/src/modem.c b/src/modem.c
index 01b0e35..dec398c 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -87,6 +87,7 @@ struct ofono_modem {
void *driver_data;
char *driver_type;
char *name;
+ ofono_bool_t driver_watches_sim;
};
struct ofono_devinfo {
@@ -708,22 +709,26 @@ static void sim_state_watch(enum ofono_sim_state new_state, void *user)
case OFONO_SIM_STATE_RESETTING:
break;
case OFONO_SIM_STATE_LOCKED_OUT:
- modem_change_state(modem, MODEM_STATE_PRE_SIM);
+ if (modem->driver_watches_sim == FALSE)
+ modem_change_state(modem, MODEM_STATE_PRE_SIM);
break;
case OFONO_SIM_STATE_READY:
- modem_change_state(modem, MODEM_STATE_OFFLINE);
+ /* Avoid state regressions */
+ if (modem->modem_state != MODEM_STATE_ONLINE) {
+ modem_change_state(modem, MODEM_STATE_OFFLINE);
- /* Modem is always online, proceed to online state. */
- if (modem_is_always_online(modem) == TRUE)
- set_online(modem, TRUE);
+ /* Modem is always online, proceed to online state. */
+ if (modem_is_always_online(modem) == TRUE)
+ set_online(modem, TRUE);
- if (modem->online == TRUE)
- modem_change_state(modem, MODEM_STATE_ONLINE);
- else if (modem->get_online)
- modem->driver->set_online(modem, 1, common_online_cb,
- modem);
+ if (modem->online == TRUE)
+ modem_change_state(modem, MODEM_STATE_ONLINE);
+ else if (modem->get_online)
+ modem->driver->set_online(modem, 1,
+ common_online_cb, modem);
- modem->get_online = FALSE;
+ modem->get_online = FALSE;
+ }
break;
}
@@ -1809,6 +1814,17 @@ void ofono_modem_set_driver(struct ofono_modem *modem, const char *type)
modem->driver_type = g_strdup(type);
}
+void ofono_modem_set_driver_watches_sim(struct ofono_modem *modem,
+ ofono_bool_t value)
+{
+ modem->driver_watches_sim = value;
+}
+
+ofono_bool_t ofono_modem_get_driver_watches_sim(struct ofono_modem *modem)
+{
+ return modem->driver_watches_sim;
+}
+
struct ofono_modem *ofono_modem_create(const char *name, const char *type)
{
struct ofono_modem *modem;
--
2.5.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/7] rilmodem: Export functions needed by mtkmodem
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
` (2 preceding siblings ...)
2015-11-13 12:25 ` [PATCH 3/7] modem: " Alfonso Sanchez-Beato
@ 2015-11-13 12:25 ` Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 5/7] mtkmodem: Add mtkmodem driver Alfonso Sanchez-Beato
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 7160 bytes --]
---
drivers/rilmodem/radio-settings.c | 21 +++++++-----------
drivers/rilmodem/radio-settings.h | 46 +++++++++++++++++++++++++++++++++++++++
drivers/rilmodem/voicecall.c | 18 ++++++++++-----
drivers/rilmodem/voicecall.h | 4 ++++
4 files changed, 71 insertions(+), 18 deletions(-)
create mode 100644 drivers/rilmodem/radio-settings.h
diff --git a/drivers/rilmodem/radio-settings.c b/drivers/rilmodem/radio-settings.c
index 90b49c6..5b47089 100644
--- a/drivers/rilmodem/radio-settings.c
+++ b/drivers/rilmodem/radio-settings.c
@@ -40,6 +40,7 @@
#include "gril.h"
#include "rilmodem.h"
+#include "radio-settings.h"
/* Preferred network types */
#define PREF_NET_TYPE_GSM_WCDMA 0
@@ -64,12 +65,6 @@
#define MTK_PREF_NET_TYPE_LTE_GSM_TYPE (MTK_PREF_NET_TYPE_BASE + 5)
#define MTK_PREF_NET_TYPE_LTE_GSM_MMDC_TYPE (MTK_PREF_NET_TYPE_BASE + 6)
-struct radio_data {
- GRil *ril;
- gboolean fast_dormancy;
- gboolean pending_fd;
-};
-
static void ril_set_rat_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -86,7 +81,7 @@ static void ril_set_rat_cb(struct ril_msg *message, gpointer user_data)
}
}
-static void ril_set_rat_mode(struct ofono_radio_settings *rs,
+void ril_set_rat_mode(struct ofono_radio_settings *rs,
enum ofono_radio_access_mode mode,
ofono_radio_settings_rat_mode_set_cb_t cb,
void *data)
@@ -205,7 +200,7 @@ error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
-static void ril_query_rat_mode(struct ofono_radio_settings *rs,
+void ril_query_rat_mode(struct ofono_radio_settings *rs,
ofono_radio_settings_rat_mode_query_cb_t cb,
void *data)
{
@@ -220,7 +215,7 @@ static void ril_query_rat_mode(struct ofono_radio_settings *rs,
CALLBACK_WITH_FAILURE(cb, -1, data);
}
-static void ril_query_fast_dormancy(struct ofono_radio_settings *rs,
+void ril_query_fast_dormancy(struct ofono_radio_settings *rs,
ofono_radio_settings_fast_dormancy_query_cb_t cb,
void *data)
{
@@ -247,7 +242,7 @@ static void ril_display_state_cb(struct ril_msg *message, gpointer user_data)
}
}
-static void ril_set_fast_dormancy(struct ofono_radio_settings *rs,
+void ril_set_fast_dormancy(struct ofono_radio_settings *rs,
ofono_bool_t enable,
ofono_radio_settings_fast_dormancy_set_cb_t cb,
void *data)
@@ -272,7 +267,7 @@ static void ril_set_fast_dormancy(struct ofono_radio_settings *rs,
CALLBACK_WITH_FAILURE(cb, data);
}
-static void ril_query_available_rats(struct ofono_radio_settings *rs,
+void ril_query_available_rats(struct ofono_radio_settings *rs,
ofono_radio_settings_available_rats_query_cb_t cb,
void *data)
{
@@ -288,7 +283,7 @@ static void ril_query_available_rats(struct ofono_radio_settings *rs,
CALLBACK_WITH_SUCCESS(cb, available_rats, data);
}
-static void ril_delayed_register(const struct ofono_error *error,
+void ril_delayed_register(const struct ofono_error *error,
void *user_data)
{
struct ofono_radio_settings *rs = user_data;
@@ -314,7 +309,7 @@ static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
return 0;
}
-static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
+void ril_radio_settings_remove(struct ofono_radio_settings *rs)
{
struct radio_data *rd = ofono_radio_settings_get_data(rs);
ofono_radio_settings_set_data(rs, NULL);
diff --git a/drivers/rilmodem/radio-settings.h b/drivers/rilmodem/radio-settings.h
new file mode 100644
index 0000000..6c61551
--- /dev/null
+++ b/drivers/rilmodem/radio-settings.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct radio_data {
+ GRil *ril;
+ gboolean fast_dormancy;
+ gboolean pending_fd;
+};
+
+void ril_delayed_register(const struct ofono_error *error, void *user_data);
+void ril_radio_settings_remove(struct ofono_radio_settings *rs);
+void ril_query_rat_mode(struct ofono_radio_settings *rs,
+ ofono_radio_settings_rat_mode_query_cb_t cb,
+ void *data);
+void ril_set_rat_mode(struct ofono_radio_settings *rs,
+ enum ofono_radio_access_mode mode,
+ ofono_radio_settings_rat_mode_set_cb_t cb,
+ void *data);
+void ril_query_fast_dormancy(struct ofono_radio_settings *rs,
+ ofono_radio_settings_fast_dormancy_query_cb_t cb,
+ void *data);
+void ril_set_fast_dormancy(struct ofono_radio_settings *rs,
+ ofono_bool_t enable,
+ ofono_radio_settings_fast_dormancy_set_cb_t cb,
+ void *data);
+void ril_query_available_rats(struct ofono_radio_settings *rs,
+ ofono_radio_settings_available_rats_query_cb_t cb,
+ void *data);
diff --git a/drivers/rilmodem/voicecall.c b/drivers/rilmodem/voicecall.c
index 45e8ffb..c28274f 100644
--- a/drivers/rilmodem/voicecall.c
+++ b/drivers/rilmodem/voicecall.c
@@ -752,12 +752,11 @@ static gboolean ril_delayed_register(gpointer user_data)
return FALSE;
}
-int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
- void *data)
+void ril_voicecall_start(GRil *ril,
+ struct ofono_voicecall *vc,
+ unsigned int vendor,
+ struct ril_voicecall_data *vd)
{
- GRil *ril = data;
- struct ril_voicecall_data *vd = g_new0(struct ril_voicecall_data, 1);
-
vd->ril = g_ril_clone(ril);
vd->vendor = vendor;
vd->cb = NULL;
@@ -768,6 +767,15 @@ int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
ofono_voicecall_set_data(vc, vd);
g_idle_add(ril_delayed_register, vc);
+}
+
+int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
+ void *data)
+{
+ GRil *ril = data;
+ struct ril_voicecall_data *vd = g_new0(struct ril_voicecall_data, 1);
+
+ ril_voicecall_start(ril, vc, vendor, vd);
return 0;
}
diff --git a/drivers/rilmodem/voicecall.h b/drivers/rilmodem/voicecall.h
index 31e120e..8888450 100644
--- a/drivers/rilmodem/voicecall.h
+++ b/drivers/rilmodem/voicecall.h
@@ -62,5 +62,9 @@ void ril_set_udub(struct ofono_voicecall *vc,
void ril_release_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data);
+void ril_voicecall_start(GRil *ril,
+ struct ofono_voicecall *vc,
+ unsigned int vendor,
+ struct ril_voicecall_data *vd);
void ril_call_state_notify(struct ril_msg *message, gpointer user_data);
gboolean ril_poll_clcc(gpointer user_data);
--
2.5.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/7] mtkmodem: Add mtkmodem driver
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
` (3 preceding siblings ...)
2015-11-13 12:25 ` [PATCH 4/7] rilmodem: Export functions needed by mtkmodem Alfonso Sanchez-Beato
@ 2015-11-13 12:25 ` Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 6/7] mtk: Plugin for mtkmodems Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 7/7] build: Add mtkmodem driver and mtk plugin Alfonso Sanchez-Beato
6 siblings, 0 replies; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 61431 bytes --]
mtkmodem handles modems MediaTek modems and is based on rilmodem driver.
---
drivers/mtkmodem/gprs.c | 188 +++++++++++++++++++++++++++
drivers/mtkmodem/mtk_constants.h | 84 ++++++++++++
drivers/mtkmodem/mtkmodem.c | 58 +++++++++
drivers/mtkmodem/mtkmodem.h | 32 +++++
drivers/mtkmodem/mtkreply.c | 98 ++++++++++++++
drivers/mtkmodem/mtkreply.h | 43 +++++++
drivers/mtkmodem/mtkrequest.c | 163 ++++++++++++++++++++++++
drivers/mtkmodem/mtkrequest.h | 143 +++++++++++++++++++++
drivers/mtkmodem/mtksettings.c | 261 ++++++++++++++++++++++++++++++++++++++
drivers/mtkmodem/mtksettings.h | 43 +++++++
drivers/mtkmodem/mtkunsol.c | 199 +++++++++++++++++++++++++++++
drivers/mtkmodem/mtkunsol.h | 59 +++++++++
drivers/mtkmodem/mtkutil.c | 143 +++++++++++++++++++++
drivers/mtkmodem/mtkutil.h | 47 +++++++
drivers/mtkmodem/radio-settings.c | 193 ++++++++++++++++++++++++++++
drivers/mtkmodem/voicecall.c | 155 ++++++++++++++++++++++
16 files changed, 1909 insertions(+)
create mode 100644 drivers/mtkmodem/gprs.c
create mode 100644 drivers/mtkmodem/mtk_constants.h
create mode 100644 drivers/mtkmodem/mtkmodem.c
create mode 100644 drivers/mtkmodem/mtkmodem.h
create mode 100644 drivers/mtkmodem/mtkreply.c
create mode 100644 drivers/mtkmodem/mtkreply.h
create mode 100644 drivers/mtkmodem/mtkrequest.c
create mode 100644 drivers/mtkmodem/mtkrequest.h
create mode 100644 drivers/mtkmodem/mtksettings.c
create mode 100644 drivers/mtkmodem/mtksettings.h
create mode 100644 drivers/mtkmodem/mtkunsol.c
create mode 100644 drivers/mtkmodem/mtkunsol.h
create mode 100644 drivers/mtkmodem/mtkutil.c
create mode 100644 drivers/mtkmodem/mtkutil.h
create mode 100644 drivers/mtkmodem/radio-settings.c
create mode 100644 drivers/mtkmodem/voicecall.c
diff --git a/drivers/mtkmodem/gprs.c b/drivers/mtkmodem/gprs.c
new file mode 100644
index 0000000..073c3f1
--- /dev/null
+++ b/drivers/mtkmodem/gprs.c
@@ -0,0 +1,188 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2010 ST-Ericsson AB.
+ * Copyright (C) 2013-2014 Canonical Ltd.
+ * Copyright (C) 2013 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs.h>
+#include <ofono/types.h>
+
+#include "common.h"
+
+#include "mtkutil.h"
+#include "mtkmodem.h"
+#include "mtk_constants.h"
+#include "mtkrequest.h"
+#include "drivers/rilmodem/rilutil.h"
+#include "drivers/rilmodem/gprs.h"
+
+/* Time between get data status retries */
+#define GET_STATUS_TIMER_MS 5000
+
+/*
+ * This module is the ofono_gprs_driver implementation for mtkmodem. Most of the
+ * implementation can be found in the rilmodem gprs atom. The main reason for
+ * creating a new atom is the need to handle specific MTK requests that are
+ * needed to set-up the data call.
+ *
+ * Notes:
+ *
+ * 1. ofono_gprs_suspend/resume() are not used by this module, as
+ * the concept of suspended GPRS is not exposed by RILD.
+ */
+
+struct gprs_attach_data {
+ struct ril_gprs_data *gd;
+ gboolean set_attached;
+};
+
+static void mtk_gprs_set_connect_type_cb(struct ril_msg *message,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_gprs_cb_t cb = cbd->cb;
+ struct gprs_attach_data *attach_data = cbd->user;
+ struct ril_gprs_data *gd = attach_data->gd;
+
+ if (message->error == RIL_E_SUCCESS) {
+ g_ril_print_response_no_args(gd->ril, message);
+
+ gd->ofono_attached = attach_data->set_attached;
+ mtk_set_attach_state(gd->modem, gd->ofono_attached);
+
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ } else {
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ }
+
+ g_free(attach_data);
+}
+
+static void mtk_gprs_set_attached(struct ofono_gprs *gprs, int attached,
+ ofono_gprs_cb_t cb, void *data)
+{
+ struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+ struct cb_data *cbd;
+ struct parcel rilp;
+ struct gprs_attach_data *attach_data =
+ g_try_new0(struct gprs_attach_data, 1);
+
+ if (attach_data == NULL) {
+ ofono_error("%s: out of memory", __func__);
+ return;
+ }
+
+ DBG("attached: %d", attached);
+
+ attach_data->gd = gd;
+ attach_data->set_attached = attached;
+
+ cbd = cb_data_new(cb, data, attach_data);
+
+ /* MTK controls attachment with this request, as opposed to rilmodem */
+
+ g_mtk_request_set_gprs_connect_type(gd->ril, attached, &rilp);
+
+ if (g_ril_send(gd->ril, MTK_RIL_REQUEST_SET_GPRS_CONNECT_TYPE, &rilp,
+ mtk_gprs_set_connect_type_cb, cbd, g_free) == 0) {
+ ofono_error("%s: send failed", __func__);
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+ }
+}
+
+static void detach_event(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_gprs *gprs = user_data;
+ struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+ g_ril_print_unsol_no_args(gd->ril, message);
+
+ mtk_detach_received(gd->modem);
+}
+
+static int mtk_gprs_probe(struct ofono_gprs *gprs,
+ unsigned int vendor, void *data)
+{
+ struct ril_gprs_driver_data *driver_data = data;
+ struct ril_gprs_data *gd;
+
+ gd = g_try_new0(struct ril_gprs_data, 1);
+ if (gd == NULL)
+ return -ENOMEM;
+
+ ril_gprs_start(driver_data, gprs, gd);
+
+ /*
+ * In MTK the event emitted when the gprs state changes is different
+ * from the one in AOSP ril. Overwrite the one set in parent.
+ */
+ gd->state_changed_unsol =
+ MTK_RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED;
+
+ g_ril_register(gd->ril, MTK_RIL_UNSOL_GPRS_DETACH, detach_event, gprs);
+
+ return 0;
+}
+
+static void mtk_gprs_remove(struct ofono_gprs *gprs)
+{
+ struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+ gd->ofono_attached = FALSE;
+ mtk_set_attach_state(gd->modem, gd->ofono_attached);
+
+ ril_gprs_remove(gprs);
+}
+
+static struct ofono_gprs_driver driver = {
+ .name = MTKMODEM,
+ .probe = mtk_gprs_probe,
+ .remove = mtk_gprs_remove,
+ .set_attached = mtk_gprs_set_attached,
+ .attached_status = ril_gprs_registration_status,
+};
+
+void mtk_gprs_init(void)
+{
+ ofono_gprs_driver_register(&driver);
+}
+
+void mtk_gprs_exit(void)
+{
+ ofono_gprs_driver_unregister(&driver);
+}
diff --git a/drivers/mtkmodem/mtk_constants.h b/drivers/mtkmodem/mtk_constants.h
new file mode 100644
index 0000000..bd9891b
--- /dev/null
+++ b/drivers/mtkmodem/mtk_constants.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * RIL constants for MTK modem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MTK_CONSTANTS_H
+#define MTK_CONSTANTS_H
+
+/* RIL Request Messages */
+#define MTK_RIL_REQUEST_RADIO_POWEROFF 2011
+#define MTK_RIL_REQUEST_DUAL_SIM_MODE_SWITCH 2012
+#define MTK_RIL_REQUEST_SET_GPRS_CONNECT_TYPE 2016
+#define MTK_RIL_REQUEST_SET_GPRS_TRANSFER_TYPE 2017
+#define MTK_RIL_REQUEST_RADIO_POWERON 2033
+#define MTK_RIL_REQUEST_SET_CALL_INDICATION 2036
+#define MTK_RIL_REQUEST_GET_3G_CAPABILITY 2038
+#define MTK_RIL_REQUEST_SET_3G_CAPABILITY 2039
+#define MTK_RIL_REQUEST_SET_TRM 2053
+#define MTK_RIL_REQUEST_SET_FD_MODE 2073
+#define MTK_RIL_REQUEST_RESUME_REGISTRATION 2077
+#define MTK_RIL_REQUEST_STORE_MODEM_TYPE 2078
+#define MTK_RIL_REQUEST_QUERY_MODEM_TYPE 2079
+
+/* RIL Unsolicited Messages */
+#define MTK_RIL_UNSOL_MTK_BASE 3000
+
+#define MTK_RIL_UNSOL_NEIGHBORING_CELL_INFO (MTK_RIL_UNSOL_MTK_BASE + 0)
+#define MTK_RIL_UNSOL_NETWORK_INFO (MTK_RIL_UNSOL_MTK_BASE + 1)
+#define MTK_RIL_UNSOL_CALL_FORWARDING (MTK_RIL_UNSOL_MTK_BASE + 2)
+#define MTK_RIL_UNSOL_CRSS_NOTIFICATION (MTK_RIL_UNSOL_MTK_BASE + 3)
+#define MTK_RIL_UNSOL_CALL_PROGRESS_INFO (MTK_RIL_UNSOL_MTK_BASE + 4)
+#define MTK_RIL_UNSOL_PHB_READY_NOTIFICATION (MTK_RIL_UNSOL_MTK_BASE + 5)
+#define MTK_RIL_UNSOL_SPEECH_INFO (MTK_RIL_UNSOL_MTK_BASE + 6)
+#define MTK_RIL_UNSOL_SIM_INSERTED_STATUS (MTK_RIL_UNSOL_MTK_BASE + 7)
+#define MTK_RIL_UNSOL_RADIO_TEMPORARILY_UNAVAILABLE (MTK_RIL_UNSOL_MTK_BASE + 8)
+#define MTK_RIL_UNSOL_ME_SMS_STORAGE_FULL (MTK_RIL_UNSOL_MTK_BASE + 9)
+#define MTK_RIL_UNSOL_SMS_READY_NOTIFICATION (MTK_RIL_UNSOL_MTK_BASE + 10)
+#define MTK_RIL_UNSOL_SCRI_RESULT (MTK_RIL_UNSOL_MTK_BASE + 11)
+#define MTK_RIL_UNSOL_VT_STATUS_INFO (MTK_RIL_UNSOL_MTK_BASE + 12)
+#define MTK_RIL_UNSOL_VT_RING_INFO (MTK_RIL_UNSOL_MTK_BASE + 13)
+#define MTK_RIL_UNSOL_INCOMING_CALL_INDICATION (MTK_RIL_UNSOL_MTK_BASE + 14)
+#define MTK_RIL_UNSOL_SIM_MISSING (MTK_RIL_UNSOL_MTK_BASE + 15)
+#define MTK_RIL_UNSOL_GPRS_DETACH (MTK_RIL_UNSOL_MTK_BASE + 16)
+#define MTK_RIL_UNSOL_ATCI_RESPONSE (MTK_RIL_UNSOL_MTK_BASE + 17)
+#define MTK_RIL_UNSOL_SIM_RECOVERY (MTK_RIL_UNSOL_MTK_BASE + 18)
+#define MTK_RIL_UNSOL_VIRTUAL_SIM_ON (MTK_RIL_UNSOL_MTK_BASE + 19)
+#define MTK_RIL_UNSOL_VIRTUAL_SIM_OFF (MTK_RIL_UNSOL_MTK_BASE + 20)
+#define MTK_RIL_UNSOL_INVALID_SIM (MTK_RIL_UNSOL_MTK_BASE + 21)
+#define MTK_RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED \
+ (MTK_RIL_UNSOL_MTK_BASE + 22)
+#define MTK_RIL_UNSOL_RESPONSE_ACMT (MTK_RIL_UNSOL_MTK_BASE + 23)
+#define MTK_RIL_UNSOL_EF_CSP_PLMN_MODE_BIT (MTK_RIL_UNSOL_MTK_BASE + 24)
+#define MTK_RIL_UNSOL_IMEI_LOCK (MTK_RIL_UNSOL_MTK_BASE + 25)
+#define MTK_RIL_UNSOL_RESPONSE_MMRR_STATUS_CHANGED (MTK_RIL_UNSOL_MTK_BASE + 26)
+#define MTK_RIL_UNSOL_SIM_PLUG_OUT (MTK_RIL_UNSOL_MTK_BASE + 27)
+#define MTK_RIL_UNSOL_SIM_PLUG_IN (MTK_RIL_UNSOL_MTK_BASE + 28)
+#define MTK_RIL_UNSOL_RESPONSE_ETWS_NOTIFICATION (MTK_RIL_UNSOL_MTK_BASE + 29)
+#define MTK_RIL_UNSOL_RESPONSE_PLMN_CHANGED (MTK_RIL_UNSOL_MTK_BASE + 30)
+#define MTK_RIL_UNSOL_RESPONSE_REGISTRATION_SUSPENDED \
+ (MTK_RIL_UNSOL_MTK_BASE + 31)
+#define MTK_RIL_UNSOL_STK_EVDL_CALL (MTK_RIL_UNSOL_MTK_BASE + 32)
+#define MTK_RIL_UNSOL_DATA_PACKETS_FLUSH (MTK_RIL_UNSOL_MTK_BASE + 33)
+#define MTK_RIL_UNSOL_CIPHER_INDICATION (MTK_RIL_UNSOL_MTK_BASE + 34)
+#define MTK_RIL_UNSOL_FEMTOCELL_INFO (MTK_RIL_UNSOL_MTK_BASE + 35)
+#define MTK_RIL_UNSOL_CNAP (MTK_RIL_UNSOL_MTK_BASE + 36)
+#define MTK_RIL_UNSOL_RAC_UPDATE (MTK_RIL_UNSOL_MTK_BASE + 37)
+
+#endif /* MTK_CONSTANTS_H */
diff --git a/drivers/mtkmodem/mtkmodem.c b/drivers/mtkmodem/mtkmodem.c
new file mode 100644
index 0000000..91cd8ab
--- /dev/null
+++ b/drivers/mtkmodem/mtkmodem.c
@@ -0,0 +1,58 @@
+/*
+ *
+ * oFono - Open Source Telephony - RIL Modem Support
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2014 Canonical, Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gril.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/types.h>
+
+#include "mtkmodem.h"
+
+static int mtkmodem_init(void)
+{
+ DBG("");
+
+ mtk_voicecall_init();
+ mtk_gprs_init();
+ mtk_radio_settings_init();
+
+ return 0;
+}
+
+static void mtkmodem_exit(void)
+{
+ DBG("");
+
+ mtk_voicecall_exit();
+ mtk_gprs_exit();
+ mtk_radio_settings_exit();
+}
+
+OFONO_PLUGIN_DEFINE(mtkmodem, "MTK modem driver", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, mtkmodem_init, mtkmodem_exit)
diff --git a/drivers/mtkmodem/mtkmodem.h b/drivers/mtkmodem/mtkmodem.h
new file mode 100644
index 0000000..037a57c
--- /dev/null
+++ b/drivers/mtkmodem/mtkmodem.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * oFono - Open Source Telephony - RIL Modem Support
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define MTKMODEM "mtkmodem"
+
+extern void mtk_voicecall_init(void);
+extern void mtk_voicecall_exit(void);
+
+extern void mtk_gprs_init(void);
+extern void mtk_gprs_exit(void);
+
+extern void mtk_radio_settings_init(void);
+extern void mtk_radio_settings_exit(void);
diff --git a/drivers/mtkmodem/mtkreply.c b/drivers/mtkmodem/mtkreply.c
new file mode 100644
index 0000000..9c7625e
--- /dev/null
+++ b/drivers/mtkmodem/mtkreply.c
@@ -0,0 +1,98 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+
+#include "mtkreply.h"
+
+int g_mtk_reply_parse_get_3g_capability(GRil *gril,
+ const struct ril_msg *message)
+{
+ struct parcel rilp;
+ int slot_3g, numint;
+
+ g_ril_init_parcel(message, &rilp);
+
+ numint = parcel_r_int32(&rilp);
+ if (numint < 1) {
+ ofono_error("%s: wrong format", __func__);
+ goto error;
+ }
+
+ /*
+ * Bitmap with 3g capability per slot. Reply is the same regardless of
+ * the socket used to sent the request.
+ */
+ slot_3g = parcel_r_int32(&rilp);
+
+ if (rilp.malformed) {
+ ofono_error("%s: malformed parcel", __func__);
+ goto error;
+ }
+
+ g_ril_append_print_buf(gril, "{%d}", slot_3g);
+ g_ril_print_response(gril, message);
+
+ /* Do it zero-based */
+ return slot_3g - 1;
+
+error:
+ return -1;
+}
+
+int g_mtk_reply_parse_query_modem_type(GRil *gril,
+ const struct ril_msg *message)
+{
+ struct parcel rilp;
+ int numint, type;
+
+ g_ril_init_parcel(message, &rilp);
+
+ numint = parcel_r_int32(&rilp);
+ if (numint != 1) {
+ ofono_error("%s Wrong format", __func__);
+ goto error;
+ }
+
+ type = parcel_r_int32(&rilp);
+
+ if (rilp.malformed) {
+ ofono_error("%s: malformed parcel", __func__);
+ goto error;
+ }
+
+ g_ril_append_print_buf(gril, "{%d}", type);
+ g_ril_print_response(gril, message);
+
+ return type;
+
+error:
+ return -1;
+
+}
diff --git a/drivers/mtkmodem/mtkreply.h b/drivers/mtkmodem/mtkreply.h
new file mode 100644
index 0000000..7a616b6
--- /dev/null
+++ b/drivers/mtkmodem/mtkreply.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MTKREPLY_H
+#define MTKREPLY_H
+
+#include <ofono/types.h>
+
+#include "gril.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int g_mtk_reply_parse_get_3g_capability(GRil *gril,
+ const struct ril_msg *message);
+
+int g_mtk_reply_parse_query_modem_type(GRil *gril,
+ const struct ril_msg *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MTKREPLY_H */
diff --git a/drivers/mtkmodem/mtkrequest.c b/drivers/mtkmodem/mtkrequest.c
new file mode 100644
index 0000000..4c63df3
--- /dev/null
+++ b/drivers/mtkmodem/mtkrequest.c
@@ -0,0 +1,163 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-context.h>
+
+#include "mtkrequest.h"
+#include "simutil.h"
+#include "util.h"
+#include "common.h"
+
+void g_mtk_request_dual_sim_mode_switch(GRil *gril,
+ int mode,
+ struct parcel *rilp)
+{
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 1);
+ parcel_w_int32(rilp, mode);
+
+ g_ril_append_print_buf(gril, "(%d)", mode);
+}
+
+void g_mtk_request_set_gprs_connect_type(GRil *gril,
+ int always,
+ struct parcel *rilp)
+{
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 1);
+ parcel_w_int32(rilp, always);
+
+ g_ril_append_print_buf(gril, "(%d)", always);
+};
+
+void g_mtk_request_set_gprs_transfer_type(GRil *gril,
+ int callprefer,
+ struct parcel *rilp)
+{
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 1);
+ parcel_w_int32(rilp, callprefer);
+
+ g_ril_append_print_buf(gril, "(%d)", callprefer);
+}
+
+void g_mtk_request_set_call_indication(GRil *gril, int mode, int call_id,
+ int seq_number, struct parcel *rilp)
+{
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 3);
+ /* What the parameters set is unknown */
+ parcel_w_int32(rilp, mode);
+ parcel_w_int32(rilp, call_id);
+ parcel_w_int32(rilp, seq_number);
+
+ g_ril_append_print_buf(gril, "(%d,%d,%d)", mode, call_id, seq_number);
+}
+
+void g_mtk_request_set_fd_mode(GRil *gril, int mode, int param1,
+ int param2, struct parcel *rilp)
+{
+ int num_args;
+
+ switch (mode) {
+ case MTK_FD_MODE_DISABLE:
+ case MTK_FD_MODE_ENABLE:
+ num_args = 1;
+ break;
+ case MTK_FD_MODE_SET_TIMER:
+ num_args = 3;
+ break;
+ case MTK_FD_MODE_SCREEN_STATUS:
+ num_args = 2;
+ break;
+ default:
+ ofono_error("%s: mode %d is wrong", __func__, mode);
+ return;
+ }
+
+ parcel_init(rilp);
+ parcel_w_int32(rilp, num_args);
+ parcel_w_int32(rilp, mode);
+
+ g_ril_append_print_buf(gril, "(%d,%d", num_args, mode);
+
+ if (mode == MTK_FD_MODE_SCREEN_STATUS) {
+ parcel_w_int32(rilp, param1);
+ g_ril_append_print_buf(gril, "%s,%d)", print_buf, param1);
+ } else if (mode == MTK_FD_MODE_SET_TIMER) {
+ parcel_w_int32(rilp, param1);
+ parcel_w_int32(rilp, param2);
+ g_ril_append_print_buf(gril, "%s,%d,%d)", print_buf,
+ param1, param2);
+ } else {
+ g_ril_append_print_buf(gril, "%s)", print_buf);
+ }
+}
+
+void g_mtk_request_set_3g_capability(GRil *gril, struct parcel *rilp)
+{
+ int mode = g_ril_get_slot(gril) + 1;
+
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 1);
+ parcel_w_int32(rilp, mode);
+
+ g_ril_append_print_buf(gril, "(%d)", mode);
+}
+
+void g_mtk_request_store_modem_type(GRil *gril, int mode, struct parcel *rilp)
+{
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 1);
+ parcel_w_int32(rilp, mode);
+
+ g_ril_append_print_buf(gril, "(%d)", mode);
+}
+
+void g_mtk_request_set_trm(GRil *gril, int trm, struct parcel *rilp)
+{
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 1);
+ parcel_w_int32(rilp, trm);
+
+ g_ril_append_print_buf(gril, "(%d)", trm);
+}
+
+void g_mtk_request_resume_registration(GRil *gril, int session_id,
+ struct parcel *rilp)
+{
+ parcel_init(rilp);
+ parcel_w_int32(rilp, 1);
+ parcel_w_int32(rilp, session_id);
+
+ g_ril_append_print_buf(gril, "(%d)", session_id);
+}
diff --git a/drivers/mtkmodem/mtkrequest.h b/drivers/mtkmodem/mtkrequest.h
new file mode 100644
index 0000000..a393124
--- /dev/null
+++ b/drivers/mtkmodem/mtkrequest.h
@@ -0,0 +1,143 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MTKREQUEST_H
+#define MTKREQUEST_H
+
+#include <ofono/types.h>
+#include <ofono/sim.h>
+
+#include "gril.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MTK_SWITCH_MODE_SIM_1_ACTIVE 1
+#define MTK_SWITCH_MODE_SIM_2_ACTIVE 2
+#define MTK_SWITCH_MODE_ALL_INACTIVE -1
+
+#define MTK_GPRS_CONNECT_WHEN_NEEDED 0
+#define MTK_GPRS_CONNECT_ALWAYS 1
+
+#define MTK_GPRS_TRANSFER_DATA_PREFER 0
+#define MTK_GPRS_TRANSFER_CALL_PREFER 1
+
+#define MTK_CALL_INDIC_MODE_AVAIL 0
+#define MTK_CALL_INDIC_MODE_NOT_AVAIL 1
+
+#define MTK_FD_MODE_DISABLE 0
+#define MTK_FD_MODE_ENABLE 1
+#define MTK_FD_MODE_SET_TIMER 2
+#define MTK_FD_MODE_SCREEN_STATUS 3
+
+#define MTK_FD_PAR1_SCREEN_OFF 0
+#define MTK_FD_PAR1_SCREEN_ON 1
+
+#define MTK_MD_TYPE_INVALID 0
+#define MTK_MD_TYPE_2G 1
+#define MTK_MD_TYPE_3G 2
+#define MTK_MD_TYPE_WG 3
+#define MTK_MD_TYPE_TG 4
+/* FDD CSFB modem: LTE FDD - WCDMA - GSM */
+#define MTK_MD_TYPE_LWG 5
+/* TDD CSFB modem: LTE TDD - TD-SCDMA - GSM */
+#define MTK_MD_TYPE_LTG 6
+/* SGLTE modem */
+#define MTK_MD_TYPE_LTNG 7
+
+/*
+ * The meaning of mode seems to be:
+ * -1 -> Both SIMs inactive
+ * 1 -> SIM 1 active
+ * 2 -> SIM 2 active
+ * 3 -> Both SIMs active
+ */
+void g_mtk_request_dual_sim_mode_switch(GRil *gril,
+ int mode,
+ struct parcel *rilp);
+
+/* 0:WHEN_NEEDED , 1: ALWAYS */
+void g_mtk_request_set_gprs_connect_type(GRil *gril,
+ int always,
+ struct parcel *rilp);
+
+/* 0:data prefer , 1: call prefer */
+void g_mtk_request_set_gprs_transfer_type(GRil *gril,
+ int callprefer,
+ struct parcel *rilp);
+
+/*
+ * mode. MTK_CALL_INDIC_MODE_AVAIL: indicates that the specified call can be
+ * answered.
+ * MTK_CALL_INDIC_MODE_NOT_AVAIL: indicates we are busy, and that the
+ * specified call cannot be handled
+ * "mode" seems useful for full dual SIM. An example would be that we have an
+ * active call and an incoming call from the other SIM is signalled.
+ *
+ * call_id and seq_number are used to identify a specific call in the modem and
+ * are taken from a previous RIL_UNSOL_INCOMING_CALL_INDICATION.
+ */
+void g_mtk_request_set_call_indication(GRil *gril, int mode, int call_id,
+ int seq_number, struct parcel *rilp);
+
+/*
+ * mode . MTK_FD_MODE_DISABLE: Disable fast dormancy
+ * MTK_FD_MODE_ENABLE: Enable fast formancy
+ * MTK_FD_MODE_SET_TIMER: Set fast dormancy timer
+ * MTK_FD_MODE_SCREEN_STATUS: Inform modem of screen status, to select
+ * timers to use for FD.
+ * param1 Id of timer to set or screen status
+ * param2 Value of timer, in units of 0.1 seconds
+ *
+ * Setting timers and enabling FD is done by rild initialization, so we do not
+ * need to do it again in ofono.
+ */
+void g_mtk_request_set_fd_mode(GRil *gril, int mode, int param1,
+ int param2, struct parcel *rilp);
+
+/*
+ * Sets the slot to which the GRil object is connected as the one with 3G
+ * capabilities. This makes the other slot just 2G.
+ */
+void g_mtk_request_set_3g_capability(GRil *gril, struct parcel *rilp);
+
+/*
+ * Set the MTK modem mode. See MTK_MD_TYPE_*.
+ */
+void g_mtk_request_store_modem_type(GRil *gril, int mode, struct parcel *rilp);
+
+/*
+ * Set TRM
+ */
+void g_mtk_request_set_trm(GRil *gril, int trm, struct parcel *rilp);
+
+/*
+ * Request to resume registration.
+ */
+void g_mtk_request_resume_registration(GRil *gril, int session_id,
+ struct parcel *rilp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MTKREQUEST_H */
diff --git a/drivers/mtkmodem/mtksettings.c b/drivers/mtkmodem/mtksettings.c
new file mode 100644
index 0000000..165c4d9
--- /dev/null
+++ b/drivers/mtkmodem/mtksettings.c
@@ -0,0 +1,261 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <glib.h>
+#include <gdbus.h>
+#include <ofono.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/dbus.h>
+
+#include "drivers/mtkmodem/mtk_constants.h"
+#include "drivers/mtkmodem/mtkrequest.h"
+#include "drivers/mtkmodem/mtkutil.h"
+#include "mtksettings.h"
+
+#define MTK_SETTINGS_INTERFACE "org.ofono.MtkSettings"
+
+struct mtk_settings_data {
+ struct ofono_modem *modem;
+ GRil *ril;
+ ofono_bool_t has_3g;
+ ofono_bool_t has_3g_pending;
+ DBusMessage *pending;
+};
+
+static void set_3g(struct mtk_settings_data *msd, ofono_bool_t has_3g)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(msd->modem);
+ dbus_bool_t value = has_3g;
+
+ if (msd->has_3g == has_3g)
+ return;
+
+ ofono_dbus_signal_property_changed(conn, path, MTK_SETTINGS_INTERFACE,
+ "Has3G", DBUS_TYPE_BOOLEAN,
+ &value);
+ msd->has_3g = has_3g;
+}
+
+static void set_3g_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct mtk_settings_data *msd = user_data;
+ DBusMessage *reply;
+
+ if (message->error != RIL_E_SUCCESS) {
+ ofono_error("%s: Error setting 3G", __func__);
+
+ msd->has_3g_pending = msd->has_3g;
+
+ reply = __ofono_error_failed(msd->pending);
+ __ofono_dbus_pending_reply(&msd->pending, reply);
+
+ return;
+ }
+
+ g_ril_print_response_no_args(msd->ril, message);
+
+ reply = dbus_message_new_method_return(msd->pending);
+ __ofono_dbus_pending_reply(&msd->pending, reply);
+
+ set_3g(msd, msd->has_3g_pending);
+
+ mtk_reset_all_modems();
+}
+
+static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct mtk_settings_data *msd = data;
+ DBusMessageIter iter;
+ DBusMessageIter var;
+ const char *property;
+
+ if (msd->pending)
+ return __ofono_error_busy(msg);
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return __ofono_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &property);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &var);
+
+ if (g_strcmp0(property, "Has3G") == 0) {
+ dbus_bool_t value;
+ struct parcel rilp;
+
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &value);
+
+ if (msd->has_3g_pending == (ofono_bool_t) value)
+ return dbus_message_new_method_return(msg);
+
+ /*
+ * We can only set to true, as setting to false could be
+ * confusing in a multi-sim environment (>2 SIM)
+ */
+ if (value == FALSE)
+ return __ofono_error_invalid_args(msg);
+
+ g_mtk_request_set_3g_capability(msd->ril, &rilp);
+
+ if (g_ril_send(msd->ril, MTK_RIL_REQUEST_SET_3G_CAPABILITY,
+ &rilp, set_3g_cb, msd, NULL) == 0) {
+ ofono_error("%s: unable to set 3G for slot", __func__);
+ return __ofono_error_failed(msg);
+ }
+
+ msd->pending = dbus_message_ref(msg);
+ msd->has_3g_pending = value;
+
+ return NULL;
+ }
+
+ return __ofono_error_invalid_args(msg);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct mtk_settings_data *msd = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ ofono_dbus_dict_append(&dict, "Has3G",
+ DBUS_TYPE_BOOLEAN, &msd->has_3g);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static const GDBusMethodTable mtk_settings_methods[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ get_properties) },
+ { GDBUS_ASYNC_METHOD("SetProperty",
+ GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
+ NULL, set_property) },
+ { }
+};
+
+static const GDBusSignalTable mtk_settings_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+ { }
+};
+
+
+static void register_interface(struct mtk_settings_data *msd)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+
+ if (!g_dbus_register_interface(conn, ofono_modem_get_path(msd->modem),
+ MTK_SETTINGS_INTERFACE,
+ mtk_settings_methods,
+ mtk_settings_signals,
+ NULL, msd, NULL)) {
+ ofono_error("Could not create %s interface",
+ MTK_SETTINGS_INTERFACE);
+ return;
+ }
+
+ ofono_modem_add_interface(msd->modem, MTK_SETTINGS_INTERFACE);
+}
+
+static void unregister_interface(struct mtk_settings_data *msd)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+
+ ofono_modem_remove_interface(msd->modem, MTK_SETTINGS_INTERFACE);
+
+ g_dbus_unregister_interface(conn,
+ ofono_modem_get_path(msd->modem),
+ MTK_SETTINGS_INTERFACE);
+}
+
+struct mtk_settings_data *mtk_settings_create(struct ofono_modem *modem,
+ GRil *ril, ofono_bool_t has_3g)
+{
+ struct mtk_settings_data *msd = g_try_malloc0(sizeof(*msd));
+
+ DBG("");
+
+ if (msd == NULL) {
+ ofono_error("%s: Cannot allocate mtk_settings_data", __func__);
+ return NULL;
+ }
+
+ msd->modem = modem;
+ msd->ril = g_ril_clone(ril);
+
+ msd->has_3g = has_3g;
+ msd->has_3g_pending = has_3g;
+
+ register_interface(msd);
+
+ return msd;
+}
+
+void mtk_settings_remove(struct mtk_settings_data *msd)
+{
+ DBG("");
+
+ if (msd == NULL)
+ return;
+
+ unregister_interface(msd);
+
+ g_ril_unref(msd->ril);
+ g_free(msd);
+}
diff --git a/drivers/mtkmodem/mtksettings.h b/drivers/mtkmodem/mtksettings.h
new file mode 100644
index 0000000..978f33d
--- /dev/null
+++ b/drivers/mtkmodem/mtksettings.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MTKSETTINGS_H
+#define MTKSETTINGS_H
+
+#include <ofono/types.h>
+
+#include "gril.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mtk_settings_data;
+
+struct mtk_settings_data *mtk_settings_create(struct ofono_modem *modem,
+ GRil *ril, ofono_bool_t has_3g);
+void mtk_settings_remove(struct mtk_settings_data *msd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MTKSETTINGS_H */
diff --git a/drivers/mtkmodem/mtkunsol.c b/drivers/mtkmodem/mtkunsol.c
new file mode 100644
index 0000000..dcd58cc
--- /dev/null
+++ b/drivers/mtkmodem/mtkunsol.c
@@ -0,0 +1,199 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+
+#include "mtkunsol.h"
+#include "util.h"
+#include "common.h"
+
+void g_mtk_unsol_free_call_indication(struct unsol_call_indication *unsol)
+{
+ g_free(unsol);
+}
+
+struct unsol_call_indication *g_mtk_unsol_parse_incoming_call_indication(
+ GRil *gril, struct ril_msg *message)
+{
+ struct parcel rilp;
+ int numstr;
+ struct unsol_call_indication *unsol;
+ char *call_id, *phone, *mystery, *call_mode, *seq_num;
+ char *endp;
+
+ unsol = g_try_malloc0(sizeof(*unsol));
+ if (unsol == NULL) {
+ ofono_error("%s: out of memory", __func__);
+ goto error;
+ }
+
+ g_ril_init_parcel(message, &rilp);
+
+ numstr = parcel_r_int32(&rilp);
+ if (numstr != 5) {
+ ofono_error("%s: wrong array size (%d)", __func__, numstr);
+ goto error;
+ }
+
+ call_id = parcel_r_string(&rilp);
+ phone = parcel_r_string(&rilp);
+ mystery = parcel_r_string(&rilp);
+ call_mode = parcel_r_string(&rilp);
+ seq_num = parcel_r_string(&rilp);
+
+ g_ril_append_print_buf(gril, "{%s,%s,%s,%s,%s}", call_id, phone,
+ mystery, call_mode, seq_num);
+
+ g_ril_print_unsol(gril, message);
+
+ if (rilp.malformed) {
+ ofono_error("%s: malformed parcel", __func__);
+ goto err_conv;
+ }
+
+ if (call_id != NULL && *call_id != '\0') {
+ unsol->call_id = (int) strtol(call_id, &endp, 10);
+ if (*endp != '\0') {
+ ofono_error("%s: cannot parse call id", __func__);
+ goto err_conv;
+ }
+ } else {
+ ofono_error("%s: no call id", __func__);
+ goto err_conv;
+ }
+
+ if (call_mode != NULL && *call_mode != '\0') {
+ unsol->call_mode = (int) strtol(call_mode, &endp, 10);
+ if (*endp != '\0') {
+ ofono_error("%s: cannot parse call mode", __func__);
+ goto err_conv;
+ }
+ } else {
+ ofono_error("%s: no call mode", __func__);
+ goto err_conv;
+ }
+
+ if (seq_num != NULL && *seq_num != '\0') {
+ unsol->seq_number = (int) strtol(seq_num, &endp, 10);
+ if (*endp != '\0') {
+ ofono_error("%s: cannot parse seq num", __func__);
+ goto err_conv;
+ }
+ } else {
+ ofono_error("%s: no seq num", __func__);
+ goto err_conv;
+ }
+
+ g_free(call_id);
+ g_free(phone);
+ g_free(mystery);
+ g_free(call_mode);
+ g_free(seq_num);
+
+ return unsol;
+
+err_conv:
+ g_free(call_id);
+ g_free(phone);
+ g_free(mystery);
+ g_free(call_mode);
+ g_free(seq_num);
+
+error:
+ g_free(unsol);
+
+ return NULL;
+}
+
+int g_mtk_unsol_parse_registration_suspended(GRil *gril,
+ const struct ril_msg *message)
+{
+ struct parcel rilp;
+ int numint, session_id;
+
+ g_ril_init_parcel(message, &rilp);
+
+ numint = parcel_r_int32(&rilp);
+ if (numint != 1) {
+ ofono_error("%s Wrong format", __func__);
+ goto error;
+ }
+
+ session_id = parcel_r_int32(&rilp);
+
+ if (rilp.malformed) {
+ ofono_error("%s: malformed parcel", __func__);
+ goto error;
+ }
+
+ g_ril_append_print_buf(gril, "{%d}", session_id);
+ g_ril_print_unsol(gril, message);
+
+ return session_id;
+
+error:
+ return -1;
+
+}
+
+struct parcel_str_array *g_mtk_unsol_parse_plmn_changed(GRil *gril,
+ const struct ril_msg *message)
+{
+ struct parcel rilp;
+ struct parcel_str_array *str_arr;
+ int i;
+
+ g_ril_init_parcel(message, &rilp);
+
+ str_arr = parcel_r_str_array(&rilp);
+ if (str_arr == NULL || str_arr->num_str == 0) {
+ ofono_error("%s: parse error for %s", __func__,
+ ril_request_id_to_string(message->req));
+ parcel_free_str_array(str_arr);
+ str_arr = NULL;
+ goto out;
+ }
+
+ g_ril_append_print_buf(gril, "{");
+
+ for (i = 0; i < str_arr->num_str; ++i) {
+ if (i + 1 == str_arr->num_str)
+ g_ril_append_print_buf(gril, "%s%s}", print_buf,
+ str_arr->str[i]);
+ else
+ g_ril_append_print_buf(gril, "%s%s, ", print_buf,
+ str_arr->str[i]);
+ }
+
+ g_ril_print_unsol(gril, message);
+
+out:
+ return str_arr;
+}
diff --git a/drivers/mtkmodem/mtkunsol.h b/drivers/mtkmodem/mtkunsol.h
new file mode 100644
index 0000000..135e57e
--- /dev/null
+++ b/drivers/mtkmodem/mtkunsol.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MTKUNSOL_H
+#define MTKUNSOL_H
+
+#include <ofono/types.h>
+
+#include "gril.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct unsol_call_indication {
+ int call_id;
+ int call_mode;
+ int seq_number;
+};
+
+void g_mtk_unsol_free_call_indication(struct unsol_call_indication *unsol);
+
+struct unsol_call_indication *g_mtk_unsol_parse_incoming_call_indication(
+ GRil *gril, struct ril_msg *message);
+
+/* Returns a session id that must be used in resume registration request */
+int g_mtk_unsol_parse_registration_suspended(GRil *gril,
+ const struct ril_msg *message);
+
+/*
+ * Returns a minimum of one PLMN or NULL. parcel_free_str_array must be invoked
+ * to free the returned pointer.
+ */
+struct parcel_str_array *g_mtk_unsol_parse_plmn_changed(GRil *gril,
+ const struct ril_msg *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MTKUNSOL_H */
diff --git a/drivers/mtkmodem/mtkutil.c b/drivers/mtkmodem/mtkutil.c
new file mode 100644
index 0000000..9f3f42e
--- /dev/null
+++ b/drivers/mtkmodem/mtkutil.c
@@ -0,0 +1,143 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stddef.h>
+
+#include "mtkutil.h"
+#include "mtk_constants.h"
+
+const char *mtk_request_id_to_string(int req)
+{
+ switch (req) {
+ case MTK_RIL_REQUEST_RADIO_POWEROFF:
+ return "MTK_RIL_REQUEST_RADIO_POWEROFF";
+ case MTK_RIL_REQUEST_DUAL_SIM_MODE_SWITCH:
+ return "MTK_RIL_REQUEST_DUAL_SIM_MODE_SWITCH";
+ case MTK_RIL_REQUEST_SET_GPRS_CONNECT_TYPE:
+ return "MTK_RIL_REQUEST_SET_GPRS_CONNECT_TYPE";
+ case MTK_RIL_REQUEST_SET_GPRS_TRANSFER_TYPE:
+ return "MTK_RIL_REQUEST_SET_GPRS_TRANSFER_TYPE";
+ case MTK_RIL_REQUEST_RADIO_POWERON:
+ return "MTK_RIL_REQUEST_RADIO_POWERON";
+ case MTK_RIL_REQUEST_SET_CALL_INDICATION:
+ return "MTK_RIL_REQUEST_SET_CALL_INDICATION";
+ case MTK_RIL_REQUEST_GET_3G_CAPABILITY:
+ return "MTK_RIL_REQUEST_GET_3G_CAPABILITY";
+ case MTK_RIL_REQUEST_SET_3G_CAPABILITY:
+ return "MTK_RIL_REQUEST_SET_3G_CAPABILITY";
+ case MTK_RIL_REQUEST_SET_TRM:
+ return "MTK_RIL_REQUEST_SET_TRM";
+ case MTK_RIL_REQUEST_SET_FD_MODE:
+ return "MTK_RIL_REQUEST_SET_FD_MODE";
+ case MTK_RIL_REQUEST_STORE_MODEM_TYPE:
+ return "MTK_RIL_REQUEST_STORE_MODEM_TYPE";
+ case MTK_RIL_REQUEST_RESUME_REGISTRATION:
+ return "MTK_RIL_REQUEST_RESUME_REGISTRATION";
+ case MTK_RIL_REQUEST_QUERY_MODEM_TYPE:
+ return "MTK_RIL_REQUEST_QUERY_MODEM_TYPE";
+ default:
+ return NULL;
+ }
+}
+
+const char *mtk_unsol_request_to_string(int req)
+{
+ switch (req) {
+ case MTK_RIL_UNSOL_NEIGHBORING_CELL_INFO:
+ return "MTK_RIL_UNSOL_NEIGHBORING_CELL_INFO";
+ case MTK_RIL_UNSOL_NETWORK_INFO:
+ return "MTK_RIL_UNSOL_NETWORK_INFO";
+ case MTK_RIL_UNSOL_CALL_FORWARDING:
+ return "MTK_RIL_UNSOL_CALL_FORWARDING";
+ case MTK_RIL_UNSOL_CRSS_NOTIFICATION:
+ return "MTK_RIL_UNSOL_CRSS_NOTIFICATION";
+ case MTK_RIL_UNSOL_CALL_PROGRESS_INFO:
+ return "MTK_RIL_UNSOL_CALL_PROGRESS_INFO";
+ case MTK_RIL_UNSOL_PHB_READY_NOTIFICATION:
+ return "MTK_RIL_UNSOL_PHB_READY_NOTIFICATION";
+ case MTK_RIL_UNSOL_SPEECH_INFO:
+ return "MTK_RIL_UNSOL_SPEECH_INFO";
+ case MTK_RIL_UNSOL_SIM_INSERTED_STATUS:
+ return "MTK_RIL_UNSOL_SIM_INSERTED_STATUS";
+ case MTK_RIL_UNSOL_RADIO_TEMPORARILY_UNAVAILABLE:
+ return "MTK_RIL_UNSOL_RADIO_TEMPORARILY_UNAVAILABLE";
+ case MTK_RIL_UNSOL_ME_SMS_STORAGE_FULL:
+ return "MTK_RIL_UNSOL_ME_SMS_STORAGE_FULL";
+ case MTK_RIL_UNSOL_SMS_READY_NOTIFICATION:
+ return "MTK_RIL_UNSOL_SMS_READY_NOTIFICATION";
+ case MTK_RIL_UNSOL_SCRI_RESULT:
+ return "MTK_RIL_UNSOL_SCRI_RESULT";
+ case MTK_RIL_UNSOL_VT_STATUS_INFO:
+ return "MTK_RIL_UNSOL_VT_STATUS_INFO";
+ case MTK_RIL_UNSOL_VT_RING_INFO:
+ return "MTK_RIL_UNSOL_VT_RING_INFO";
+ case MTK_RIL_UNSOL_INCOMING_CALL_INDICATION:
+ return "MTK_RIL_UNSOL_INCOMING_CALL_INDICATION";
+ case MTK_RIL_UNSOL_SIM_MISSING:
+ return "MTK_RIL_UNSOL_SIM_MISSING";
+ case MTK_RIL_UNSOL_GPRS_DETACH:
+ return "MTK_RIL_UNSOL_GPRS_DETACH";
+ case MTK_RIL_UNSOL_ATCI_RESPONSE:
+ return "MTK_RIL_UNSOL_ATCI_RESPONSE";
+ case MTK_RIL_UNSOL_SIM_RECOVERY:
+ return "MTK_RIL_UNSOL_SIM_RECOVERY";
+ case MTK_RIL_UNSOL_VIRTUAL_SIM_ON:
+ return "MTK_RIL_UNSOL_VIRTUAL_SIM_ON";
+ case MTK_RIL_UNSOL_VIRTUAL_SIM_OFF:
+ return "MTK_RIL_UNSOL_VIRTUAL_SIM_OFF";
+ case MTK_RIL_UNSOL_INVALID_SIM:
+ return "MTK_RIL_UNSOL_INVALID_SIM";
+ case MTK_RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED:
+ return "MTK_RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED";
+ case MTK_RIL_UNSOL_RESPONSE_ACMT:
+ return "MTK_RIL_UNSOL_RESPONSE_ACMT";
+ case MTK_RIL_UNSOL_EF_CSP_PLMN_MODE_BIT:
+ return "MTK_RIL_UNSOL_EF_CSP_PLMN_MODE_BIT";
+ case MTK_RIL_UNSOL_IMEI_LOCK:
+ return "MTK_RIL_UNSOL_IMEI_LOCK";
+ case MTK_RIL_UNSOL_RESPONSE_MMRR_STATUS_CHANGED:
+ return "MTK_RIL_UNSOL_RESPONSE_MMRR_STATUS_CHANGED";
+ case MTK_RIL_UNSOL_SIM_PLUG_OUT:
+ return "MTK_RIL_UNSOL_SIM_PLUG_OUT";
+ case MTK_RIL_UNSOL_SIM_PLUG_IN:
+ return "MTK_RIL_UNSOL_SIM_PLUG_IN";
+ case MTK_RIL_UNSOL_RESPONSE_ETWS_NOTIFICATION:
+ return "MTK_RIL_UNSOL_RESPONSE_ETWS_NOTIFICATION";
+ case MTK_RIL_UNSOL_RESPONSE_PLMN_CHANGED:
+ return "MTK_RIL_UNSOL_RESPONSE_PLMN_CHANGED";
+ case MTK_RIL_UNSOL_RESPONSE_REGISTRATION_SUSPENDED:
+ return "MTK_RIL_UNSOL_RESPONSE_REGISTRATION_SUSPENDED";
+ case MTK_RIL_UNSOL_STK_EVDL_CALL:
+ return "MTK_RIL_UNSOL_STK_EVDL_CALL";
+ case MTK_RIL_UNSOL_DATA_PACKETS_FLUSH:
+ return "MTK_RIL_UNSOL_DATA_PACKETS_FLUSH";
+ case MTK_RIL_UNSOL_CIPHER_INDICATION:
+ return "MTK_RIL_UNSOL_CIPHER_INDICATION";
+ case MTK_RIL_UNSOL_FEMTOCELL_INFO:
+ return "MTK_RIL_UNSOL_FEMTOCELL_INFO";
+ case MTK_RIL_UNSOL_CNAP:
+ return "MTK_RIL_UNSOL_CNAP";
+ case MTK_RIL_UNSOL_RAC_UPDATE:
+ return "MTK_RIL_UNSOL_RAC_UPDATE";
+ default:
+ return NULL;
+ }
+}
diff --git a/drivers/mtkmodem/mtkutil.h b/drivers/mtkmodem/mtkutil.h
new file mode 100644
index 0000000..b7e6a2a
--- /dev/null
+++ b/drivers/mtkmodem/mtkutil.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * MTK driver for ofono/rilmodem
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MTKUTIL_H
+#define MTKUTIL_H
+
+#include <ofono/types.h>
+#include <gril.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ofono_modem;
+
+void mtk_set_attach_state(struct ofono_modem *modem, ofono_bool_t attached);
+void mtk_detach_received(struct ofono_modem *modem);
+
+void mtk_reset_all_modems(void);
+void mtk_reset_modem(struct ofono_modem *modem);
+
+const char *mtk_request_id_to_string(int req);
+const char *mtk_unsol_request_to_string(int req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MTKUTIL_H */
diff --git a/drivers/mtkmodem/radio-settings.c b/drivers/mtkmodem/radio-settings.c
new file mode 100644
index 0000000..8f46b0d
--- /dev/null
+++ b/drivers/mtkmodem/radio-settings.c
@@ -0,0 +1,193 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/radio-settings.h>
+
+#include "mtk_constants.h"
+#include "mtkunsol.h"
+#include "mtkreply.h"
+#include "mtkrequest.h"
+
+#include "common.h"
+#include "mtkmodem.h"
+#include "drivers/rilmodem/radio-settings.h"
+#include "drivers/rilmodem/rilutil.h"
+
+/*
+ * This is the radio settings atom implementation for mtkmodem. Most of the
+ * implementation can be found in the rilmodem atom. The main reason for
+ * creating a new atom is the need to handle specific MTK requests.
+ */
+
+struct set_fd_mode {
+ struct ofono_radio_settings *rst;
+ gboolean on;
+};
+
+static void mtk_set_fd_mode_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct set_fd_mode *user = cbd->user;
+ struct ofono_radio_settings *rs = user->rst;
+ struct radio_data *rsd = ofono_radio_settings_get_data(rs);
+ ofono_radio_settings_fast_dormancy_set_cb_t cb = cbd->cb;
+
+ if (message->error == RIL_E_SUCCESS ||
+ message->error == RIL_E_RADIO_NOT_AVAILABLE) {
+
+ if (message->error == RIL_E_RADIO_NOT_AVAILABLE)
+ ofono_warn("Could not set fast dormancy "
+ "as radio is not available");
+
+ g_ril_print_response_no_args(rsd->ril, message);
+ ril_set_fast_dormancy(rs, user->on, cb, cbd->data);
+ } else {
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ }
+
+ g_free(user);
+}
+
+static void mtk_set_fast_dormancy(struct ofono_radio_settings *rs,
+ ofono_bool_t enable,
+ ofono_radio_settings_fast_dormancy_set_cb_t cb,
+ void *data)
+{
+ struct radio_data *rsd = ofono_radio_settings_get_data(rs);
+ struct set_fd_mode *user = g_malloc0(sizeof(*user));
+ struct cb_data *cbd;
+ struct parcel rilp;
+
+ user->rst = rs;
+ user->on = enable;
+
+ cbd = cb_data_new(cb, data, user);
+
+ g_mtk_request_set_fd_mode(rsd->ril, MTK_FD_MODE_SCREEN_STATUS,
+ enable ? FALSE : TRUE, 0, &rilp);
+
+ if (g_ril_send(rsd->ril, MTK_RIL_REQUEST_SET_FD_MODE, &rilp,
+ mtk_set_fd_mode_cb, cbd, g_free) <= 0) {
+ g_free(cbd);
+ g_free(user);
+ CALLBACK_WITH_FAILURE(cb, data);
+ }
+}
+
+static int mtk_radio_settings_probe(struct ofono_radio_settings *rs,
+ unsigned int vendor, void *user)
+{
+ GRil *ril = user;
+ struct radio_data *rsd = g_new0(struct radio_data, 1);
+
+ rsd->ril = g_ril_clone(ril);
+
+ ofono_radio_settings_set_data(rs, rsd);
+
+ mtk_set_fast_dormancy(rs, FALSE, ril_delayed_register, rs);
+
+ return 0;
+}
+
+static void mtk_query_available_rats_cb(struct ril_msg *message,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_radio_settings *rs = cbd->user;
+ struct radio_data *rd = ofono_radio_settings_get_data(rs);
+ ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
+ unsigned int available_rats = OFONO_RADIO_ACCESS_MODE_GSM;
+ int slot_3g, is_3g;
+
+ if (message->error != RIL_E_SUCCESS) {
+ ofono_error("%s: error %s", __func__,
+ ril_error_to_string(message->error));
+ CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+ return;
+ }
+
+ slot_3g = g_mtk_reply_parse_get_3g_capability(rd->ril, message);
+ if (slot_3g < 0) {
+ ofono_error("%s: parse error", __func__);
+ CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+ return;
+ }
+
+ is_3g = (g_ril_get_slot(rd->ril) == slot_3g);
+
+ if (is_3g) {
+ struct ofono_modem *modem = ofono_radio_settings_get_modem(rs);
+ available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
+
+ if (ofono_modem_get_boolean(modem, MODEM_PROP_LTE_CAPABLE))
+ available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
+ }
+
+ CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
+}
+
+static void mtk_query_available_rats(struct ofono_radio_settings *rs,
+ ofono_radio_settings_available_rats_query_cb_t cb,
+ void *data)
+{
+ struct radio_data *rd = ofono_radio_settings_get_data(rs);
+ struct cb_data *cbd = cb_data_new(cb, data, rs);
+
+ if (g_ril_send(rd->ril, MTK_RIL_REQUEST_GET_3G_CAPABILITY, NULL,
+ mtk_query_available_rats_cb, cbd, g_free) <= 0) {
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, 0, data);
+ }
+}
+
+static struct ofono_radio_settings_driver driver = {
+ .name = MTKMODEM,
+ .probe = mtk_radio_settings_probe,
+ .remove = ril_radio_settings_remove,
+ .query_rat_mode = ril_query_rat_mode,
+ .set_rat_mode = ril_set_rat_mode,
+ .query_fast_dormancy = ril_query_fast_dormancy,
+ .set_fast_dormancy = mtk_set_fast_dormancy,
+ .query_available_rats = mtk_query_available_rats
+};
+
+void mtk_radio_settings_init(void)
+{
+ ofono_radio_settings_driver_register(&driver);
+}
+
+void mtk_radio_settings_exit(void)
+{
+ ofono_radio_settings_driver_unregister(&driver);
+}
diff --git a/drivers/mtkmodem/voicecall.c b/drivers/mtkmodem/voicecall.c
new file mode 100644
index 0000000..bfb3c9d
--- /dev/null
+++ b/drivers/mtkmodem/voicecall.c
@@ -0,0 +1,155 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2012-2014 Canonical Ltd.
+ * Copyright (C) 2013 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/voicecall.h>
+
+#include "mtk_constants.h"
+#include "mtkunsol.h"
+#include "mtkrequest.h"
+
+#include "common.h"
+#include "mtkmodem.h"
+#include "drivers/rilmodem/rilutil.h"
+#include "drivers/rilmodem/voicecall.h"
+
+/*
+ * This is the voicecall atom implementation for mtkmodem. Most of the
+ * implementation can be found in the rilmodem atom. The main reason for
+ * creating a new atom is the need to handle specific MTK requests and
+ * unsolicited events.
+ */
+
+static void mtk_set_indication_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+ if (message->error == RIL_E_SUCCESS)
+ g_ril_print_response_no_args(vd->ril, message);
+ else
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+}
+
+static void mtk_incoming_notify(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+ struct parcel rilp;
+ struct unsol_call_indication *call_ind;
+
+ call_ind = g_mtk_unsol_parse_incoming_call_indication(vd->ril, message);
+ if (call_ind == NULL) {
+ ofono_error("%s: error parsing event", __func__);
+ return;
+ }
+
+ g_mtk_request_set_call_indication(vd->ril, MTK_CALL_INDIC_MODE_AVAIL,
+ call_ind->call_id,
+ call_ind->seq_number, &rilp);
+
+ if (g_ril_send(vd->ril, MTK_RIL_REQUEST_SET_CALL_INDICATION,
+ &rilp, mtk_set_indication_cb, vc, NULL) == 0)
+ ofono_error("%s: cannot send indication", __func__);
+
+ g_mtk_unsol_free_call_indication(call_ind);
+}
+
+static gboolean mtk_delayed_register(gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+ /* MTK generates this event instead of CALL_STATE_CHANGED */
+ g_ril_register(vd->ril, MTK_RIL_UNSOL_CALL_PROGRESS_INFO,
+ ril_call_state_notify, vc);
+
+ /* Indicates incoming call, before telling the network our state */
+ g_ril_register(vd->ril, MTK_RIL_UNSOL_INCOMING_CALL_INDICATION,
+ mtk_incoming_notify, vc);
+
+ /* This makes the timeout a single-shot */
+ return FALSE;
+}
+
+static int mtk_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
+ void *data)
+{
+ GRil *ril = data;
+ struct ril_voicecall_data *vd;
+
+ vd = g_try_new0(struct ril_voicecall_data, 1);
+ if (vd == NULL)
+ return -ENOMEM;
+
+ ril_voicecall_start(ril, vc, vendor, vd);
+
+ /*
+ * Register events after ofono_voicecall_register() is called from
+ * ril_delayed_register().
+ */
+ g_idle_add(mtk_delayed_register, vc);
+
+ return 0;
+}
+
+static struct ofono_voicecall_driver driver = {
+ .name = MTKMODEM,
+ .probe = mtk_voicecall_probe,
+ .remove = ril_voicecall_remove,
+ .dial = ril_dial,
+ .answer = ril_answer,
+ .hangup_all = ril_hangup_all,
+ .release_specific = ril_hangup_specific,
+ .send_tones = ril_send_dtmf,
+ .create_multiparty = ril_create_multiparty,
+ .private_chat = ril_private_chat,
+ .swap_without_accept = ril_swap_without_accept,
+ .hold_all_active = ril_hold_all_active,
+ .release_all_held = ril_release_all_held,
+ .set_udub = ril_set_udub,
+ .release_all_active = ril_release_all_active,
+};
+
+void mtk_voicecall_init(void)
+{
+ ofono_voicecall_driver_register(&driver);
+}
+
+void mtk_voicecall_exit(void)
+{
+ ofono_voicecall_driver_unregister(&driver);
+}
--
2.5.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6/7] mtk: Plugin for mtkmodems
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
` (4 preceding siblings ...)
2015-11-13 12:25 ` [PATCH 5/7] mtkmodem: Add mtkmodem driver Alfonso Sanchez-Beato
@ 2015-11-13 12:25 ` Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 7/7] build: Add mtkmodem driver and mtk plugin Alfonso Sanchez-Beato
6 siblings, 0 replies; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 49372 bytes --]
---
plugins/mtk.c | 1704 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1704 insertions(+)
create mode 100644 plugins/mtk.c
diff --git a/plugins/mtk.c b/plugins/mtk.c
new file mode 100644
index 0000000..8a9a720
--- /dev/null
+++ b/plugins/mtk.c
@@ -0,0 +1,1704 @@
+/*
+ *
+ * oFono - Open Source Telephony - RIL-based devices
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2012-2014 Canonical Ltd.
+ * Copyright (C) 2013 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+#include <ofono/phonebook.h>
+#include <ofono/netreg.h>
+#include <ofono/voicecall.h>
+#include <ofono/sms.h>
+#include <ofono/cbs.h>
+#include <ofono/sim.h>
+#include <ofono/ussd.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/call-settings.h>
+#include <ofono/call-barring.h>
+#include <ofono/call-meter.h>
+#include <ofono/call-volume.h>
+#include <ofono/radio-settings.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/audio-settings.h>
+#include <ofono/types.h>
+
+#include "ofono.h"
+#include <common.h>
+
+#include <gril.h>
+#include <grilreply.h>
+#include <grilrequest.h>
+#include <grilunsol.h>
+
+#include "drivers/rilmodem/rilmodem.h"
+#include "drivers/rilmodem/vendor.h"
+
+#include "drivers/mtkmodem/mtkmodem.h"
+#include "drivers/mtkmodem/mtk_constants.h"
+#include "drivers/mtkmodem/mtkutil.h"
+#include "drivers/mtkmodem/mtkrequest.h"
+#include "drivers/mtkmodem/mtkreply.h"
+#include "drivers/mtkmodem/mtkunsol.h"
+#include "drivers/mtkmodem/mtksettings.h"
+
+#define MAX_SIM_STATUS_RETRIES 15
+
+#define MULTISIM_SLOT_0 0
+#define MULTISIM_SLOT_1 1
+
+#define SIM_1_ACTIVE 1
+#define SIM_2_ACTIVE 2
+#define NO_SIM_ACTIVE 0
+
+#define SOCKET_NUM_FOR_DBG_0 -1
+#define SOCKET_NUM_FOR_DBG_1 -2
+
+/* this gives 30s for rild to initialize */
+#define RILD_MAX_CONNECT_RETRIES 5
+#define RILD_CONNECT_RETRY_TIME_S 5
+
+#define T_WAIT_DISCONN_MS 1000
+#define T_SIM_SWITCH_FAILSAFE_MS 1000
+
+#define INVALID_SUSPEND_ID -1
+#define T_FW_SWITCH_S 60
+
+enum mtk_plmn_type {
+ MTK_PLMN_TYPE_UNKNOWN = 0,
+ MTK_PLMN_TYPE_1,
+ MTK_PLMN_TYPE_2,
+ MTK_PLMN_TYPE_3
+};
+
+static const char hex_slot_0[] = "Slot 0: ";
+static const char hex_slot_1[] = "Slot 1: ";
+
+typedef void (*pending_cb_t)(struct cb_data *cbd);
+
+struct mtk_data {
+ GRil *ril;
+ int sim_status_retries;
+ ofono_bool_t ofono_online;
+ ofono_bool_t ofono_online_target;
+ int radio_state;
+ struct ofono_sim *sim;
+ /* pending_* are used in case we are disconnected from the socket */
+ pending_cb_t pending_cb;
+ struct cb_data *pending_cbd;
+ int slot;
+ struct ril_sim_data sim_data;
+ struct ofono_devinfo *devinfo;
+ struct ofono_voicecall *voicecall;
+ struct ofono_call_volume *callvolume;
+ struct cb_data *pending_online_cbd;
+ ofono_bool_t pending_online;
+ ofono_bool_t gprs_attach;
+ int rild_connect_retries;
+ struct ofono_sms *sms;
+ struct ofono_netreg *netreg;
+ struct ofono_ussd *ussd;
+ struct ofono_call_settings *call_settings;
+ struct ofono_call_forwarding *call_forwarding;
+ struct ofono_call_barring *call_barring;
+ struct ofono_phonebook *phonebook;
+ struct ofono_gprs *gprs;
+ struct ofono_message_waiting *message_waiting;
+ struct ofono_modem *modem;
+ ofono_bool_t has_3g;
+ struct mtk_settings_data *mtk_settings;
+ int fw_type;
+ ofono_modem_online_cb_t online_cb;
+ void *online_data;
+ enum mtk_plmn_type sim_plmn_type;
+ enum mtk_plmn_type sensed_plmn_type;
+ int suspend_id;
+ ofono_bool_t trm_pending;
+ unsigned netreg_watch;
+ unsigned status_watch;
+ int netreg_status;
+ guint switch_fw_id;
+};
+
+/*
+ * MTK dual SIM sockets are not completely symmetric: some requests (essentially
+ * those related for radio power management and SIM slot enablement) can be sent
+ * only through the socket for slot 0. So we need a pointer to the main socket.
+ * Also, we need to access information of one channel from the other channel.
+ */
+static struct mtk_data *mtk_data_0;
+static struct mtk_data *mtk_data_1;
+
+/* Some variables control global state of the modem and are then static */
+static gboolean disconnect_expected;
+static guint not_disconn_cb_id;
+
+struct socket_data {
+ GRil *ril;
+ const char *path;
+ int radio_state;
+ guint radio_state_ev_id;
+};
+
+static struct socket_data *sock_0, *sock_1;
+
+static int create_gril(struct ofono_modem *modem);
+static gboolean mtk_connected(gpointer user_data);
+static void mtk_set_online(struct ofono_modem *modem, ofono_bool_t online,
+ ofono_modem_online_cb_t callback, void *data);
+static void query_3g_caps(struct socket_data *sock);
+static void socket_disconnected(gpointer user_data);
+static void start_slot(struct mtk_data *md, struct socket_data *sock,
+ const char *hex_prefix);
+static void exec_pending_online(struct mtk_data *md);
+
+static void mtk_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ ofono_info("%s%s", prefix, str);
+}
+
+static struct mtk_data *mtk_data_complement(struct mtk_data *md)
+{
+ if (md->slot == MULTISIM_SLOT_0)
+ return mtk_data_1;
+ else
+ return mtk_data_0;
+}
+
+static struct socket_data *socket_complement(struct socket_data *sock)
+{
+ if (sock == sock_0)
+ return sock_1;
+ else
+ return sock_0;
+}
+
+/*
+ * mtk_set_attach_state and mtk_detach_received are called by mtkmodem's gprs
+ * driver. They are needed to solve an issue with data attachment: in case
+ * org.ofono.ConnectionManager Powered property is set for, say, slot 1 while
+ * slot 0 has that property also set, slot 1 will not change the data
+ * registration state even after slot 0 data connection is finally dropped. To
+ * force slot 1 to try to attach we need to send an additional
+ * MTK_RIL_REQUEST_SET_GPRS_CONNECT_TYPE. The way to know when to do this is to
+ * detect when slot 0 has finally detached. This is done listening for
+ * MTK_RIL_UNSOL_GPRS_DETACH events, but unfortunately these events are received
+ * in the modem that does not need to know about them, so we have to pass them
+ * to the mtk plugin (which has knowledge of both modems) that will take proper
+ * action in the other modem.
+ */
+
+void mtk_set_attach_state(struct ofono_modem *modem, ofono_bool_t attached)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ md->gprs_attach = attached;
+}
+
+static void detach_received_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct mtk_data *md = user_data;
+
+ if (message->error == RIL_E_SUCCESS)
+ g_ril_print_response_no_args(md->ril, message);
+ else
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+}
+
+void mtk_detach_received(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ struct mtk_data *md_c = mtk_data_complement(md);
+
+ if (md_c != NULL && md_c->gprs_attach) {
+ struct parcel rilp;
+
+ g_mtk_request_set_gprs_connect_type(md_c->ril,
+ md_c->gprs_attach, &rilp);
+
+ if (g_ril_send(md_c->ril,
+ MTK_RIL_REQUEST_SET_GPRS_CONNECT_TYPE,
+ &rilp, detach_received_cb, md_c, NULL) == 0)
+ ofono_error("%s: send failed", __func__);
+ }
+}
+
+static void radio_state_changed(struct ril_msg *message, gpointer user_data)
+{
+ struct socket_data *sock = user_data;
+ int radio_state = g_ril_unsol_parse_radio_state_changed(sock->ril,
+ message);
+
+ if (radio_state != sock->radio_state) {
+ struct socket_data *sock_c = socket_complement(sock);
+
+ ofono_info("%s, %s, state: %s", __func__, sock->path,
+ ril_radio_state_to_string(radio_state));
+
+ /*
+ * If there is just one slot, just start it. Otherwise, we ask
+ * who owns the 3G capabilities in case both slots have already
+ * radio state different from UNAVAILABLE.
+ */
+ if (mtk_data_1 == NULL) {
+ mtk_data_0->has_3g = TRUE;
+ start_slot(mtk_data_0, sock, hex_slot_0);
+ } else if (sock->radio_state == RADIO_STATE_UNAVAILABLE &&
+ sock_c != NULL && sock_c->radio_state !=
+ RADIO_STATE_UNAVAILABLE) {
+ query_3g_caps(sock);
+ }
+
+ sock->radio_state = radio_state;
+ }
+}
+
+static void exec_online_callback(struct mtk_data *md)
+{
+ if (md->online_cb != NULL) {
+ /*
+ * We assume success, as the sim switch request was successful
+ * too. Also, the SIM_* states can be returned independently of
+ * the radio state, so we cannot reliably use it to know if the
+ * sim switch command really did what was requested.
+ */
+ CALLBACK_WITH_SUCCESS(md->online_cb, md->online_data);
+ md->online_cb = NULL;
+ md->online_data = NULL;
+
+ if (md->ofono_online)
+ md->mtk_settings =
+ mtk_settings_create(md->modem, md->ril,
+ md->has_3g);
+ else
+ mtk_settings_remove(md->mtk_settings);
+
+ exec_pending_online(md);
+ }
+}
+
+static void mtk_radio_state_changed(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ int radio_state = g_ril_unsol_parse_radio_state_changed(md->ril,
+ message);
+
+ ofono_info("%s, slot %d: state: %s md->ofono_online: %d",
+ __func__, md->slot,
+ ril_radio_state_to_string(radio_state),
+ md->ofono_online);
+
+ md->radio_state = radio_state;
+
+ switch (radio_state) {
+ case RADIO_STATE_ON:
+ /* RADIO_STATE_SIM_* are deprecated in AOSP, but still used by MTK */
+ case RADIO_STATE_SIM_NOT_READY:
+ case RADIO_STATE_SIM_LOCKED_OR_ABSENT:
+ case RADIO_STATE_SIM_READY:
+ case RADIO_STATE_UNAVAILABLE:
+ case RADIO_STATE_OFF:
+ break;
+ default:
+ /* Malformed parcel; no radio state == broken rild */
+ g_assert(FALSE);
+ }
+
+ exec_online_callback(md);
+}
+
+static void resume_reg_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (message->error != RIL_E_SUCCESS) {
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+ return;
+ }
+
+ g_ril_print_response_no_args(md->ril, message);
+}
+
+static void resume_reg(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ struct parcel rilp;
+
+ if (md->suspend_id == INVALID_SUSPEND_ID)
+ return;
+
+ g_mtk_request_resume_registration(md->ril, md->suspend_id, &rilp);
+
+ if (g_ril_send(md->ril, MTK_RIL_REQUEST_RESUME_REGISTRATION, &rilp,
+ resume_reg_cb, modem, NULL) == 0)
+ ofono_error("%s: failure sending request", __func__);
+
+ md->suspend_id = INVALID_SUSPEND_ID;
+}
+
+static void sim_removed(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = (struct ofono_modem *) user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ g_ril_print_unsol_no_args(md->ril, message);
+
+ md->sim_plmn_type = MTK_PLMN_TYPE_UNKNOWN;
+
+ ofono_modem_set_powered(modem, FALSE);
+ g_idle_add(mtk_connected, modem);
+}
+
+static void sim_inserted(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = (struct ofono_modem *) user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ g_ril_print_unsol_no_args(md->ril, message);
+
+ if (getenv("OFONO_RIL_HOT_SIM_SWAP")) {
+ ofono_modem_set_powered(modem, FALSE);
+ g_idle_add(mtk_connected, modem);
+ }
+}
+
+static void set_trm_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (message->error != RIL_E_SUCCESS) {
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+ return;
+ }
+
+ g_ril_print_response_no_args(md->ril, message);
+}
+
+static void store_type_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ struct parcel rilp;
+ int trm = 0;
+
+ if (message->error != RIL_E_SUCCESS) {
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+ md->trm_pending = FALSE;
+ return;
+ }
+
+ g_ril_print_response_no_args(md->ril, message);
+
+ /*
+ * Send SET_TRM, which reloads the FW. We do not know the meaning of the
+ * magic TRM numbers (no source code for muxreport daemon).
+ */
+ if (md->fw_type == MTK_MD_TYPE_LWG) {
+ trm = 11;
+ } else if (md->fw_type == MTK_MD_TYPE_LTG) {
+ trm = 12;
+ } else {
+ ofono_error("%s: wrong modem type %d", __func__, md->fw_type);
+ g_assert(FALSE);
+ }
+
+ g_mtk_request_set_trm(md->ril, trm, &rilp);
+
+ if (g_ril_send(md->ril, MTK_RIL_REQUEST_SET_TRM, &rilp,
+ set_trm_cb, modem, NULL) == 0)
+ ofono_error("%s: failure sending request", __func__);
+
+ /*
+ * rild will close now the socket, and the response to SET_TRM might be
+ * received before that or not.
+ * Measurements showed that rild takes around 5 seconds to re-start, but
+ * we use an 8 seconds timeout as times can vary and that value is also
+ * compatible with krillin modem.
+ */
+}
+
+static gboolean find_in_table(const char *str,
+ const char **table, int num_elem)
+{
+ int i;
+
+ for (i = 0; i < num_elem; ++i)
+ if (strncmp(str, table[i], strlen(table[i])) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static enum mtk_plmn_type get_plmn_type(const char *code)
+{
+ /* China Mobile (CMCC) MCC/MNC codes */
+ const char *table_type1[] = { "46000", "46002", "46007" };
+ /* China Unicom (CU) and China Telecom MCC/MNC codes */
+ const char *table_type3[] =
+ { "46001", "46006", "46009", "45407", "46005", "45502" };
+
+ if (find_in_table(code, table_type1, G_N_ELEMENTS(table_type1)))
+ return MTK_PLMN_TYPE_1;
+
+ if (find_in_table(code, table_type3, G_N_ELEMENTS(table_type3)))
+ return MTK_PLMN_TYPE_3;
+
+ return MTK_PLMN_TYPE_2;
+}
+
+static int select_modem_fw(enum mtk_plmn_type sim_plmn_type,
+ enum mtk_plmn_type sensed_plmn_type)
+{
+ DBG("PLMN (sim, sensed)=(%d, %d)", sim_plmn_type, sensed_plmn_type);
+
+ /*
+ * Outside China (sensed t2) -> FDD always
+ * In China (sensed t1, t3) -> sim t1 is TDD, t2 or t3 is FDD,
+ * or wait for imsi to know sim type
+ * Unknown country -> sim t2 or t3 are FDD, wait network if t1, wait
+ * network/imsi events if both unknown
+ */
+ switch (sensed_plmn_type) {
+ case MTK_PLMN_TYPE_2:
+ return MTK_MD_TYPE_LWG;
+ case MTK_PLMN_TYPE_1:
+ case MTK_PLMN_TYPE_3:
+ switch (sim_plmn_type) {
+ case MTK_PLMN_TYPE_1:
+ return MTK_MD_TYPE_LTG;
+ case MTK_PLMN_TYPE_2:
+ case MTK_PLMN_TYPE_3:
+ return MTK_MD_TYPE_LWG;
+ case MTK_PLMN_TYPE_UNKNOWN:
+ return MTK_MD_TYPE_INVALID;
+ };
+ case MTK_PLMN_TYPE_UNKNOWN:
+ switch (sim_plmn_type) {
+ case MTK_PLMN_TYPE_2:
+ case MTK_PLMN_TYPE_3:
+ return MTK_MD_TYPE_LWG;
+ case MTK_PLMN_TYPE_1:
+ case MTK_PLMN_TYPE_UNKNOWN:
+ return MTK_MD_TYPE_INVALID;
+ };
+ };
+
+ /* We should never arrive here */
+ ofono_error("%s: UNREACHABLE POINT REACHED, aborting", __func__);
+ g_assert(FALSE);
+
+ return MTK_MD_TYPE_INVALID;
+}
+
+static void set_fw_type(struct ofono_modem *modem, int type)
+{
+ ofono_bool_t lte_cap;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ md->fw_type = type;
+
+ lte_cap = (type >= MTK_MD_TYPE_LWG) ? TRUE : FALSE;
+ ofono_modem_set_boolean(modem, MODEM_PROP_LTE_CAPABLE, lte_cap);
+}
+
+static const char *fw_type_to_str(int fw_type)
+{
+ switch (fw_type) {
+ case MTK_MD_TYPE_2G:
+ return "2G";
+ case MTK_MD_TYPE_3G:
+ return "3G";
+ case MTK_MD_TYPE_WG:
+ return "WG";
+ case MTK_MD_TYPE_TG:
+ return "TG";
+ case MTK_MD_TYPE_LWG:
+ return "LWG";
+ case MTK_MD_TYPE_LTG:
+ return "LTG";
+ case MTK_MD_TYPE_LTNG:
+ return "LTNG";
+ }
+
+ return "<INVALID>";
+}
+
+static void switch_fw(struct ofono_modem *modem, int fw_type)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ struct parcel rilp;
+
+ ofono_info("Switching modem FW from %s to %s",
+ fw_type_to_str(md->fw_type), fw_type_to_str(fw_type));
+
+ md->trm_pending = TRUE;
+
+ set_fw_type(modem, fw_type);
+
+ g_mtk_request_store_modem_type(md->ril, fw_type, &rilp);
+
+ if (g_ril_send(md->ril, MTK_RIL_REQUEST_STORE_MODEM_TYPE, &rilp,
+ store_type_cb, modem, NULL) == 0) {
+ ofono_error("%s: failure sending request", __func__);
+ md->trm_pending = FALSE;
+ }
+}
+
+static void check_modem_fw(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ int best_fw;
+
+ /* We handle only LWG <-> LTG modem fw changes (arale case) */
+ if (md->fw_type != MTK_MD_TYPE_LTG && md->fw_type != MTK_MD_TYPE_LWG)
+ return;
+
+ if (md->trm_pending) {
+ DBG("TRM pending, returning");
+ return;
+ }
+
+ /* Right modem fw type for our SIM/sensed PLMN */
+ best_fw = select_modem_fw(md->sim_plmn_type, md->sensed_plmn_type);
+
+ DBG("Modem type selected is %d", best_fw);
+
+ /* Best FW not known yet: wait for imsi/sensed network */
+ if (best_fw == MTK_MD_TYPE_INVALID)
+ return;
+
+ if (md->fw_type == best_fw) {
+ resume_reg(modem);
+ return;
+ }
+
+ /* We need to reload FW and reset transactionally */
+ switch_fw(modem, best_fw);
+}
+
+static void plmn_changed(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ struct parcel_str_array *plmns;
+
+ plmns = g_mtk_unsol_parse_plmn_changed(md->ril, message);
+ if (plmns == NULL) {
+ ofono_error("%s: parse error", __func__);
+ return;
+ }
+
+ md->sensed_plmn_type = get_plmn_type(plmns->str[0]);
+
+ DBG("Best PLMN is %s (type %d)", plmns->str[0], md->sensed_plmn_type);
+
+ parcel_free_str_array(plmns);
+
+ check_modem_fw(modem);
+}
+
+static void reg_suspended(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ int suspend_id;
+
+ suspend_id = g_mtk_unsol_parse_registration_suspended(md->ril, message);
+ if (suspend_id < 0) {
+ ofono_error("%s: parse error", __func__);
+ return;
+ }
+
+ md->suspend_id = suspend_id;
+
+ check_modem_fw(modem);
+}
+
+static gboolean tout_not_registered(gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (md->trm_pending)
+ goto end;
+
+ DBG("type was %d", md->fw_type);
+
+ if (md->fw_type == MTK_MD_TYPE_LTG)
+ switch_fw(modem, MTK_MD_TYPE_LWG);
+ else
+ switch_fw(modem, MTK_MD_TYPE_LTG);
+
+end:
+ md->switch_fw_id = 0;
+
+ return FALSE;
+}
+
+static void cancel_fw_load_timer(struct mtk_data *md)
+{
+ if (md->switch_fw_id) {
+ g_source_remove(md->switch_fw_id);
+ md->switch_fw_id = 0;
+ }
+}
+
+static void netreg_status_update(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (md->sim_plmn_type != MTK_PLMN_TYPE_1)
+ return;
+
+ if (md->fw_type != MTK_MD_TYPE_LTG && md->fw_type != MTK_MD_TYPE_LWG)
+ return;
+
+ DBG("%d", md->netreg_status);
+
+ if (md->switch_fw_id) {
+ if (md->netreg_status == NETWORK_REGISTRATION_STATUS_REGISTERED
+ || md->netreg_status ==
+ NETWORK_REGISTRATION_STATUS_ROAMING)
+ cancel_fw_load_timer(md);
+ return;
+ }
+
+ if (md->netreg_status == NETWORK_REGISTRATION_STATUS_NOT_REGISTERED)
+ md->switch_fw_id = g_timeout_add_seconds(T_FW_SWITCH_S,
+ tout_not_registered, modem);
+}
+
+static void netreg_status_changed(int status, int lac, int ci, int tech,
+ const char *mcc, const char *mnc,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (md->netreg_status == status)
+ return;
+
+ md->netreg_status = status;
+
+ netreg_status_update(modem);
+}
+
+static void netreg_watch(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ void *netreg;
+
+ DBG("%d", cond);
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ cancel_fw_load_timer(md);
+ md->status_watch = 0;
+ return;
+ }
+
+ netreg = __ofono_atom_get_data(atom);
+ md->netreg_status = ofono_netreg_get_status(netreg);
+ md->status_watch = __ofono_netreg_add_status_watch(netreg,
+ netreg_status_changed, modem, NULL);
+
+ netreg_status_update(modem);
+}
+
+static int mtk_probe(struct ofono_modem *modem)
+{
+ struct mtk_data *md = g_try_new0(struct mtk_data, 1);
+
+ if (md == NULL) {
+ errno = ENOMEM;
+ goto error;
+ }
+
+ md->ofono_online = FALSE;
+ md->radio_state = RADIO_STATE_UNAVAILABLE;
+ md->suspend_id = INVALID_SUSPEND_ID;
+
+ md->slot = ofono_modem_get_integer(modem, "Slot");
+
+ if (md->slot == MULTISIM_SLOT_0)
+ mtk_data_0 = md;
+ else
+ mtk_data_1 = md;
+
+ DBG("slot %d", md->slot);
+
+ md->modem = modem;
+
+ ofono_modem_set_data(modem, md);
+
+ return 0;
+
+error:
+ g_free(md);
+
+ return -errno;
+}
+
+static void mtk_remove(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ ofono_modem_set_data(modem, NULL);
+
+ if (!md)
+ return;
+
+ g_ril_unref(md->ril);
+
+ g_free(md);
+}
+
+static void mtk_pre_sim(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ DBG("slot %d", md->slot);
+}
+
+static void mtk_post_sim(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ DBG("slot %d", md->slot);
+}
+
+/*
+ * sim_state_watch listens to SIM state changes and creates/removes atoms
+ * accordingly. This is needed because we cannot rely on the modem core code,
+ * which handles modem state transitions, to do this due to the SIM not being
+ * accessible in the offline state for mtk modems. This causes a mismatch
+ * between what the core thinks it can do in some states and what the mtk modem
+ * can really do in those. This is a workaround to solve that.
+ */
+static void sim_state_watch(enum ofono_sim_state new_state, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (new_state == OFONO_SIM_STATE_READY) {
+ struct ofono_gprs_context *gc;
+ struct ril_gprs_driver_data gprs_data = { md->ril, modem };
+ struct ril_gprs_context_data inet_ctx =
+ { md->ril, modem, OFONO_GPRS_CONTEXT_TYPE_INTERNET };
+ struct ril_gprs_context_data mms_ctx =
+ { md->ril, modem, OFONO_GPRS_CONTEXT_TYPE_MMS };
+
+ DBG("SIM ready, creating more atoms");
+
+ /*
+ * TODO: this function should setup:
+ * - stk ( SIM toolkit )
+ */
+ md->sms = ofono_sms_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+
+ /* netreg needs access to the SIM (SPN, SPDI) */
+ md->netreg = ofono_netreg_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+ md->ussd = ofono_ussd_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+ md->call_settings =
+ ofono_call_settings_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+ md->call_forwarding =
+ ofono_call_forwarding_create(modem,
+ OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+ md->call_barring =
+ ofono_call_barring_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+ md->phonebook =
+ ofono_phonebook_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, modem);
+ md->gprs = ofono_gprs_create(modem, OFONO_RIL_VENDOR_MTK,
+ MTKMODEM, &gprs_data);
+
+ gc = ofono_gprs_context_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, &inet_ctx);
+ if (gc) {
+ ofono_gprs_context_set_type(gc,
+ OFONO_GPRS_CONTEXT_TYPE_INTERNET);
+ ofono_gprs_add_context(md->gprs, gc);
+ }
+
+ gc = ofono_gprs_context_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, &mms_ctx);
+ if (gc) {
+ ofono_gprs_context_set_type(gc,
+ OFONO_GPRS_CONTEXT_TYPE_MMS);
+ ofono_gprs_add_context(md->gprs, gc);
+ }
+
+ md->message_waiting = ofono_message_waiting_create(modem);
+ if (md->message_waiting)
+ ofono_message_waiting_register(md->message_waiting);
+
+ /*
+ * Now that we can access IMSI, see if a FW change is needed.
+ */
+
+ md->sim_plmn_type = get_plmn_type(ofono_sim_get_imsi(md->sim));
+
+ check_modem_fw(modem);
+
+ } else if (new_state == OFONO_SIM_STATE_LOCKED_OUT) {
+
+ DBG("SIM locked, removing atoms");
+
+ if (md->message_waiting) {
+ ofono_message_waiting_remove(md->message_waiting);
+ md->message_waiting = NULL;
+ }
+ if (md->gprs) {
+ ofono_gprs_remove(md->gprs);
+ md->gprs = NULL;
+ }
+ if (md->phonebook) {
+ ofono_phonebook_remove(md->phonebook);
+ md->phonebook = NULL;
+ }
+ if (md->call_barring) {
+ ofono_call_barring_remove(md->call_barring);
+ md->call_barring = NULL;
+ }
+ if (md->call_forwarding) {
+ ofono_call_forwarding_remove(md->call_forwarding);
+ md->call_forwarding = NULL;
+ }
+ if (md->call_settings) {
+ ofono_call_settings_remove(md->call_settings);
+ md->call_settings = NULL;
+ }
+ if (md->ussd) {
+ ofono_ussd_remove(md->ussd);
+ md->ussd = NULL;
+ }
+ if (md->netreg) {
+ ofono_netreg_remove(md->netreg);
+ md->netreg = NULL;
+ }
+ if (md->sms) {
+ ofono_sms_remove(md->sms);
+ md->sms = NULL;
+ }
+ }
+}
+
+static void create_online_atoms(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ md->sim_data.gril = md->ril;
+ md->sim_data.modem = modem;
+ md->sim_data.ril_state_watch = sim_state_watch;
+
+ md->sim = ofono_sim_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, &md->sim_data);
+ g_assert(md->sim != NULL);
+
+ /* Radio settings does not depend on the SIM */
+ ofono_radio_settings_create(modem, OFONO_RIL_VENDOR_MTK,
+ MTKMODEM, md->ril);
+
+ if (md->netreg_watch == 0)
+ md->netreg_watch =
+ __ofono_modem_add_atom_watch(modem,
+ OFONO_ATOM_TYPE_NETREG,
+ netreg_watch, modem, NULL);
+}
+
+static void query_type_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ int type;
+
+ if (message->error != RIL_E_SUCCESS) {
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+ return;
+ }
+
+ type = g_mtk_reply_parse_query_modem_type(md->ril, message);
+ if (type < 0) {
+ ofono_error("%s: parse error", __func__);
+ return;
+ }
+
+ set_fw_type(modem, type);
+
+ create_online_atoms(modem);
+}
+
+static void mtk_post_online(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ DBG("slot %d", md->slot);
+
+ /* With modem powered we can query the type in krillin */
+ if (g_ril_send(md->ril, MTK_RIL_REQUEST_QUERY_MODEM_TYPE,
+ NULL, query_type_cb, md->modem, NULL) == 0)
+ ofono_error("%s: failure sending QUERY_MODEM_TYPE", __func__);
+
+ /* Register for changes in SIM insertion */
+ g_ril_register(md->ril, MTK_RIL_UNSOL_SIM_PLUG_OUT,
+ sim_removed, modem);
+ g_ril_register(md->ril, MTK_RIL_UNSOL_SIM_PLUG_IN,
+ sim_inserted, modem);
+}
+
+static void exec_pending_online(struct mtk_data *md)
+{
+ struct mtk_data *md_c;
+
+ DBG("");
+
+ mtk_data_0->pending_cb = NULL;
+
+ /* Execute possible pending operation on the other modem */
+
+ md_c = mtk_data_complement(md);
+
+ if (md_c != NULL && md_c->pending_online_cbd) {
+ struct cb_data *pending_cbd = md_c->pending_online_cbd;
+ ofono_modem_online_cb_t pending_cb = pending_cbd->cb;
+
+ mtk_set_online(pending_cbd->user, md_c->pending_online,
+ pending_cb, pending_cbd->data);
+
+ g_free(md_c->pending_online_cbd);
+ md_c->pending_online_cbd = NULL;
+ }
+}
+
+static gboolean sim_switch_failsafe(gpointer user_data)
+{
+ struct mtk_data *md = user_data;
+
+ exec_online_callback(md);
+
+ return FALSE;
+}
+
+static void mtk_sim_mode_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_modem_online_cb_t cb = cbd->cb;
+ struct ofono_modem *modem = cbd->user;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (message->error == RIL_E_SUCCESS) {
+ g_ril_print_response_no_args(md->ril, message);
+ /*
+ * Although the request was successful, radio state might not
+ * have changed yet. So we wait for the upcoming radio event,
+ * otherwise RIL requests that depend on radio state will fail.
+ * If we are switching the 3G slot, we cannot really trust this
+ * behaviour, so we add a failsafe timer.
+ */
+ md->online_cb = cb;
+ md->online_data = cbd->data;
+
+ g_timeout_add(T_SIM_SWITCH_FAILSAFE_MS,
+ sim_switch_failsafe, md);
+ } else {
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ exec_pending_online(md);
+ }
+}
+
+static int sim_state()
+{
+ int state = mtk_data_0->ofono_online ? SIM_1_ACTIVE : NO_SIM_ACTIVE;
+ if (mtk_data_1 && mtk_data_1->ofono_online)
+ state |= SIM_2_ACTIVE;
+
+ return state;
+}
+
+static void mtk_send_sim_mode(GRilResponseFunc func, gpointer user_data)
+{
+ struct parcel rilp;
+ struct cb_data *cbd = user_data;
+ ofono_modem_online_cb_t cb = NULL;
+ GDestroyNotify notify = NULL;
+ int sim_mode;
+
+ if (cbd != NULL) {
+ notify = g_free;
+ cb = cbd->cb;
+ }
+
+ /* Case of modems with just one slot */
+ if (mtk_data_1 == NULL) {
+ mtk_data_0->pending_cb = NULL;
+
+ if (cbd != NULL) {
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ g_free(cbd);
+ }
+ return;
+ }
+
+ sim_mode = sim_state();
+
+ if (sim_mode == NO_SIM_ACTIVE)
+ sim_mode = MTK_SWITCH_MODE_ALL_INACTIVE;
+
+ g_mtk_request_dual_sim_mode_switch(mtk_data_0->ril, sim_mode, &rilp);
+
+ /* This request is always sent through the main socket */
+ if (g_ril_send(mtk_data_0->ril, MTK_RIL_REQUEST_DUAL_SIM_MODE_SWITCH,
+ &rilp, func, cbd, notify) == 0 && cbd != NULL) {
+ ofono_error("%s: failure sending request", __func__);
+ mtk_data_0->pending_cb = NULL;
+
+ if (cbd != NULL) {
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ g_free(cbd);
+ }
+ }
+}
+
+static gboolean no_disconnect_case(gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+
+ ofono_info("%s: Execute pending sim mode switch", __func__);
+ not_disconn_cb_id = 0;
+
+ mtk_send_sim_mode(mtk_sim_mode_cb, cbd);
+
+ return FALSE;
+}
+
+static void poweron_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_modem *modem = cbd->user;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ ofono_modem_online_cb_t cb = cbd->cb;
+
+ DBG("");
+
+ /*
+ * MTK's rild behavior when a POWERON is sent to it is different
+ * depending on whether a previous POWEROFF had been sent. When
+ * the modem is initialized during device startup, POWERON is
+ * sent without a prior POWEROFF, rild responds with an OK reply,
+ * and the modem is brought up. Any subsequent POWERON requests
+ * are sent whenever both modems have been offlined before ( meaning a
+ * POWEROFF has been sent prior ). rild may respond to the POWERON
+ * request, but will usually ( always? ) trigger a socket disconnect in
+ * this case.
+ *
+ * This means there's a race condition between the POWERON reply
+ * callback and the socket disconnect function ( which triggers a
+ * SIM_MODE_SWITCH request ). In some cases rild is slower than
+ * usual closing the socket, so we add a timeout to avoid following
+ * the code path used when there is not a disconnection. Otherwise,
+ * there would be a race and some requests would return errors due to
+ * having been sent through the about-to-be-disconnected socket, leaving
+ * ofono in an inconsistent state. So, we delay sending the
+ * SIM_MODE_SWITCH for 1s, to allow the disconnect to happen when we
+ * know that we have sent previously a POWEROFF.
+ *
+ * Also, I saw once that sending SIM_MODE while the
+ * socket was being disconnected provoked a crash due to SIGPIPE being
+ * issued. The timeout should also fix this.
+ */
+
+ if (message->error == RIL_E_SUCCESS) {
+ g_ril_print_response_no_args(md->ril, message);
+
+ if (disconnect_expected) {
+ if (not_disconn_cb_id != 0)
+ g_source_remove(not_disconn_cb_id);
+
+ not_disconn_cb_id = g_timeout_add(T_WAIT_DISCONN_MS,
+ no_disconnect_case, cbd);
+ } else {
+ mtk_send_sim_mode(mtk_sim_mode_cb, cbd);
+ }
+ } else {
+ ofono_error("%s RADIO_POWERON error %s", __func__,
+ ril_error_to_string(message->error));
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ g_free(cbd);
+ }
+}
+
+static void poweron_disconnect(struct cb_data *cbd)
+{
+ DBG("Execute pending sim mode switch");
+
+ mtk_send_sim_mode(mtk_sim_mode_cb, cbd);
+}
+
+static void poweroff_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_modem_online_cb_t cb = cbd->cb;
+ struct ofono_modem *modem = cbd->user;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (message->error == RIL_E_SUCCESS) {
+ g_ril_print_response_no_args(md->ril, message);
+
+ mtk_settings_remove(md->mtk_settings);
+
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ } else {
+ ofono_error("%s: RIL error %s", __func__,
+ ril_error_to_string(message->error));
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ }
+}
+
+static int power_on_off(GRil *ril, gboolean on, struct cb_data *cbd)
+{
+ int cancel_id;
+ int req;
+ struct parcel rilp;
+ struct parcel *p_rilp;
+ GRilResponseFunc resp;
+ GDestroyNotify notify;
+ ofono_modem_online_cb_t cb = cbd->cb;
+
+ /* Case of modems with just one slot */
+ if (mtk_data_1 == NULL) {
+ /* Fall back to generic RIL_REQUEST_RADIO_POWER */
+ req = RIL_REQUEST_RADIO_POWER;
+
+ parcel_init(&rilp);
+ parcel_w_int32(&rilp, 1);
+ parcel_w_int32(&rilp, on);
+ g_ril_append_print_buf(ril, "(%d)", on);
+
+ p_rilp = &rilp;
+ } else {
+ req = on ? MTK_RIL_REQUEST_RADIO_POWERON
+ : MTK_RIL_REQUEST_RADIO_POWEROFF;
+ p_rilp = NULL;
+ }
+
+ if (on) {
+ resp = poweron_cb;
+ notify = NULL;
+ } else {
+ resp = poweroff_cb;
+ notify = g_free;
+ }
+
+ cancel_id = g_ril_send(ril, req, p_rilp, resp, cbd, notify);
+ if (cancel_id == 0) {
+ ofono_error("%s: failure sending request", __func__);
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ g_free(cbd);
+ return 0;
+ }
+
+ return cancel_id;
+}
+
+static void mtk_set_online(struct ofono_modem *modem, ofono_bool_t online,
+ ofono_modem_online_cb_t callback, void *data)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ struct cb_data *cbd = cb_data_new(callback, data, modem);
+ ofono_modem_online_cb_t cb = cbd->cb;
+ int current_state, next_state;
+
+ /*
+ * Serialize online requests to avoid incoherent states. When changing
+ * the online state of *one* of the modems, we need to send a
+ * DUAL_SIM_MODE_SWITCH request, which affects *both* modems. Also, when
+ * we want to online one modem and at that time both modems are
+ * offline a RADIO_POWERON needs to be sent before DUAL_SIM_MODE_SWITCH,
+ * with the additional complexity of being disconnected from the rild
+ * socket while doing the sequence. This can take some time, and we
+ * cannot change the state of the other modem while the sequence is
+ * happenig, as DUAL_SIM_MODE_SWITCH affects both states. Therefore, we
+ * need to do this serialization, which is different from the one done
+ * per modem by ofono core.
+ */
+ if (mtk_data_0->pending_cb != NULL) {
+ md->pending_online_cbd = cbd;
+ md->pending_online = online;
+ return;
+ }
+
+ current_state = sim_state();
+
+ md->ofono_online = online;
+
+ /* Changes as md points to either mtk_data_0 or mtk_data_1 variables */
+ next_state = sim_state();
+
+ DBG("setting md_%d->ofono_online to: %d (from %d to %d)",
+ md->slot, online, current_state, next_state);
+
+ if (current_state == next_state) {
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ g_free(cbd);
+ return;
+ }
+
+ /* Reset mtk_data variables */
+ if (online == FALSE)
+ md->sim_status_retries = 0;
+
+ if (current_state == NO_SIM_ACTIVE) {
+ /* Old state was off, need to power on the modem */
+ if (power_on_off(mtk_data_0->ril, TRUE, cbd)) {
+ /* Socket might disconnect... failsafe */
+ mtk_data_0->pending_cb = poweron_disconnect;
+ mtk_data_0->pending_cbd = cbd;
+ }
+ } else if (next_state == NO_SIM_ACTIVE) {
+ /* Disconnection expected for dual SIM only */
+ if (power_on_off(mtk_data_0->ril, FALSE, cbd)
+ && mtk_data_1 != NULL)
+ disconnect_expected = TRUE;
+ } else {
+ mtk_send_sim_mode(mtk_sim_mode_cb, cbd);
+ }
+}
+
+static void set_online_cb(const struct ofono_error *error, void *data)
+{
+ if (mtk_data_1->ofono_online_target && !mtk_data_1->ofono_online)
+ mtk_set_online(mtk_data_1->modem, TRUE, set_online_cb, NULL);
+}
+
+static void set_offline_cb(const struct ofono_error *error, void *data)
+{
+ if (mtk_data_1->ofono_online)
+ mtk_set_online(mtk_data_1->modem, FALSE, set_offline_cb, NULL);
+ else if (mtk_data_0->ofono_online_target)
+ mtk_set_online(mtk_data_0->modem, TRUE, set_online_cb, NULL);
+ else
+ mtk_set_online(mtk_data_1->modem, TRUE, set_online_cb, NULL);
+}
+
+void mtk_reset_all_modems(void)
+{
+ if (!mtk_data_0->ofono_online && !mtk_data_1->ofono_online)
+ return;
+
+ mtk_data_0->ofono_online_target = mtk_data_0->ofono_online;
+ mtk_data_1->ofono_online_target = mtk_data_1->ofono_online;
+
+ ofono_modem_set_powered(mtk_data_0->modem, FALSE);
+ ofono_modem_set_powered(mtk_data_1->modem, FALSE);
+
+ if (mtk_data_0->ofono_online)
+ mtk_set_online(mtk_data_0->modem, FALSE, set_offline_cb, NULL);
+ else
+ mtk_set_online(mtk_data_1->modem, FALSE, set_offline_cb, NULL);
+}
+
+void mtk_reset_modem(struct ofono_modem *modem)
+{
+
+ if (ofono_modem_get_powered(modem) == FALSE)
+ return;
+
+ ofono_modem_set_powered(modem, FALSE);
+ g_idle_add(mtk_connected, modem);
+}
+
+static void create_atoms_on_connection(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ md->devinfo = ofono_devinfo_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+
+ /* Create interfaces useful for emergency calls */
+ md->voicecall = ofono_voicecall_create(modem, OFONO_RIL_VENDOR_MTK,
+ MTKMODEM, md->ril);
+ md->callvolume = ofono_call_volume_create(modem, OFONO_RIL_VENDOR_MTK,
+ RILMODEM, md->ril);
+}
+
+static void remove_atoms_on_disconnection(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ if (__ofono_modem_find_atom(modem, OFONO_ATOM_TYPES_CALL_VOLUME))
+ ofono_call_volume_remove(md->callvolume);
+ md->callvolume = NULL;
+ if (__ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_VOICECALL))
+ ofono_voicecall_remove(md->voicecall);
+ md->voicecall = NULL;
+ if (__ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_DEVINFO))
+ ofono_devinfo_remove(md->devinfo);
+ md->devinfo = NULL;
+}
+
+static void start_slot(struct mtk_data *md, struct socket_data *sock,
+ const char *hex_prefix)
+{
+ ofono_info("Physical slot %d in socket %s", md->slot, sock->path);
+
+ md->ril = sock->ril;
+ md->radio_state = sock->radio_state;
+
+ g_ril_set_slot(md->ril, md->slot);
+
+ if (getenv("OFONO_RIL_TRACE"))
+ g_ril_set_trace(md->ril, TRUE);
+
+ if (getenv("OFONO_RIL_HEX_TRACE"))
+ g_ril_set_debugf(md->ril, mtk_debug, (char *) hex_prefix);
+
+ g_ril_set_disconnect_function(md->ril, socket_disconnected,
+ md->modem);
+
+ g_ril_unregister(sock->ril, sock->radio_state_ev_id);
+
+ g_ril_register(md->ril, RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
+ mtk_radio_state_changed, md->modem);
+
+ mtk_connected(md->modem);
+}
+
+static void query_3g_caps_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct socket_data *sock = user_data;
+ struct socket_data *sock_for_md_0, *sock_for_md_1;
+ int slot_3g;
+
+ if (message->error != RIL_E_SUCCESS) {
+ ofono_error("%s: error %s", __func__,
+ ril_error_to_string(message->error));
+ return;
+ }
+
+ slot_3g = g_mtk_reply_parse_get_3g_capability(sock->ril, message);
+
+ /*
+ * The socket at sock_slot_0 always connects to the slot with 3G
+ * capabilities, while sock_slot_1 connects to the slot that is just 2G.
+ * However, the physical slot that owns the 3G capabilities can be
+ * changed dynamically using a RILd request, so the sockets can connect
+ * to different physical slots depending on the current configuration.
+ * We want to keep the relationship between the physical slots and
+ * the modem names in DBus (so /ril_0 and /ril_1 always refer to the
+ * same physical slots), so here we assign the sockets needed by
+ * mtk_data_0 and mtk_data_1 structures to make sure that happens.
+ */
+ if (slot_3g == MULTISIM_SLOT_0) {
+ sock_for_md_0 = sock_0;
+ sock_for_md_1 = sock_1;
+ mtk_data_0->has_3g = TRUE;
+ mtk_data_1->has_3g = FALSE;
+ } else {
+ sock_for_md_0 = sock_1;
+ sock_for_md_1 = sock_0;
+ mtk_data_0->has_3g = FALSE;
+ mtk_data_1->has_3g = TRUE;
+ }
+
+ start_slot(mtk_data_0, sock_for_md_0, hex_slot_0);
+ start_slot(mtk_data_1, sock_for_md_1, hex_slot_1);
+
+ g_free(sock_0);
+ sock_0 = NULL;
+ g_free(sock_1);
+ sock_1 = NULL;
+}
+
+static void query_3g_caps(struct socket_data *sock)
+{
+ if (g_ril_send(sock->ril, MTK_RIL_REQUEST_GET_3G_CAPABILITY, NULL,
+ query_3g_caps_cb, sock, NULL) <= 0)
+ ofono_error("%s Error querying 3G capabilities", __func__);
+}
+
+static gboolean mtk_connected(gpointer user_data)
+{
+ struct ofono_modem *modem = (struct ofono_modem *) user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ ofono_info("[slot %d] CONNECTED", md->slot);
+
+ DBG("calling set_powered(TRUE)");
+
+ if (!ofono_modem_get_powered(modem))
+ ofono_modem_set_powered(modem, TRUE);
+
+ create_atoms_on_connection(modem);
+
+ if (md->pending_cb)
+ md->pending_cb(md->pending_cbd);
+
+ /* Call the function just once */
+ return FALSE;
+}
+
+static gboolean reconnect_rild(gpointer user_data)
+{
+ struct ofono_modem *modem = (struct ofono_modem *) user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ ofono_info("[slot %d] trying to reconnect", md->slot);
+
+ if (create_gril(modem) < 0)
+ return TRUE;
+
+ /* Reconnected: do not call this again */
+ return FALSE;
+}
+
+#define WAIT_FOR_RILD_TO_RESTART_MS 8000 /* Milliseconds */
+
+static void socket_disconnected(gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ DBG("slot %d", md->slot);
+
+ /* Atoms use old gril object, remove and recreate later */
+ remove_atoms_on_disconnection(modem);
+
+ g_ril_unref(md->ril);
+ md->ril = NULL;
+
+ md->sensed_plmn_type = MTK_PLMN_TYPE_UNKNOWN;
+ md->suspend_id = INVALID_SUSPEND_ID;
+ if (md->trm_pending) {
+ md->ofono_online = FALSE;
+ ofono_modem_set_powered(md->modem, FALSE);
+ md->trm_pending = FALSE;
+ }
+
+ /* Disconnection happened so we do not call failsafe function */
+ if (not_disconn_cb_id != 0) {
+ g_source_remove(not_disconn_cb_id);
+ not_disconn_cb_id = 0;
+ }
+
+ /* The disconnection happens because rild is re-starting, wait for it */
+ g_timeout_add(WAIT_FOR_RILD_TO_RESTART_MS, reconnect_rild, modem);
+}
+
+static const char sock_slot_0[] = "/dev/socket/rild";
+static const char sock_slot_1[] = "/dev/socket/rild2";
+
+static int create_gril(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+ struct socket_data *sock;
+ int sock_num;
+
+ DBG("slot %d", md->slot);
+
+ if (md->ril != NULL)
+ return 0;
+
+ sock = g_try_malloc0(sizeof(*sock));
+ if (sock == NULL) {
+ ofono_error("%s: Cannot allocate socket_data", __func__);
+ return -ENOMEM;
+ }
+
+ if (md->slot == MULTISIM_SLOT_0) {
+ sock_num = SOCKET_NUM_FOR_DBG_0;
+ sock->path = sock_slot_0;
+ } else {
+ sock_num = SOCKET_NUM_FOR_DBG_1;
+ sock->path = sock_slot_1;
+ }
+
+ /* Opens the socket to RIL */
+ sock->ril = g_ril_new(sock->path, OFONO_RIL_VENDOR_MTK);
+
+ /*
+ * NOTE: Since AT modems open a tty, and then call
+ * g_at_chat_new(), they're able to return -EIO if
+ * the first fails, and -ENOMEM if the second fails.
+ * in our case, we already return -EIO if the ril_new
+ * fails. If this is important, we can create a ril_socket
+ * abstraction... ( probaby not a bad idea ).
+ */
+
+ if (sock->ril == NULL) {
+ ofono_error("g_ril_new() failed to connect to %s!", sock->path);
+ g_free(sock);
+ return -EIO;
+ } else if (md->slot == MULTISIM_SLOT_0) {
+ sock_0 = sock;
+ } else {
+ sock_1 = sock;
+ }
+
+ sock->radio_state = RADIO_STATE_UNAVAILABLE;
+ sock->radio_state_ev_id =
+ g_ril_register(sock->ril,
+ RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
+ radio_state_changed, sock);
+
+ g_ril_register(sock->ril, MTK_RIL_UNSOL_RESPONSE_PLMN_CHANGED,
+ plmn_changed, modem);
+ g_ril_register(sock->ril, MTK_RIL_UNSOL_RESPONSE_REGISTRATION_SUSPENDED,
+ reg_suspended, modem);
+
+ /* sock_num is negative to avoid confusion with physical slots */
+ g_ril_set_slot(sock->ril, sock_num);
+
+ g_ril_set_vendor_print_msg_id_funcs(sock->ril,
+ mtk_request_id_to_string,
+ mtk_unsol_request_to_string);
+
+ if (getenv("OFONO_RIL_TRACE"))
+ g_ril_set_trace(sock->ril, TRUE);
+
+ if (getenv("OFONO_RIL_HEX_TRACE"))
+ g_ril_set_debugf(sock->ril, mtk_debug, (char *) sock->path);
+
+ return 0;
+}
+
+static gboolean connect_rild(gpointer user_data)
+{
+ struct ofono_modem *modem = (struct ofono_modem *) user_data;
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ ofono_info("Trying to reconnect to slot %d...", md->slot);
+
+ if (md->rild_connect_retries++ < RILD_MAX_CONNECT_RETRIES) {
+ if (create_gril(modem) < 0)
+ return TRUE;
+ } else {
+ ofono_error("Exiting, can't connect to rild.");
+ exit(0);
+ }
+
+ return FALSE;
+}
+
+static int mtk_enable(struct ofono_modem *modem)
+{
+ int ret;
+
+ /* We handle SIM states due to MTK peculiarities */
+ ofono_modem_set_driver_watches_sim(modem, TRUE);
+
+ ret = create_gril(modem);
+ if (ret < 0)
+ g_timeout_add_seconds(RILD_CONNECT_RETRY_TIME_S,
+ connect_rild, modem);
+
+ /*
+ * We will mark the modem as powered when we receive an event that
+ * confirms that the radio is in a state different from unavailable
+ */
+
+ return -EINPROGRESS;
+}
+
+static int mtk_disable(struct ofono_modem *modem)
+{
+ struct mtk_data *md = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ if (md->slot == MULTISIM_SLOT_0 && not_disconn_cb_id != 0) {
+ g_source_remove(not_disconn_cb_id);
+ not_disconn_cb_id = 0;
+ }
+
+ if (md->ofono_online) {
+ md->ofono_online = FALSE;
+ mtk_send_sim_mode(NULL, NULL);
+ }
+
+ return 0;
+}
+
+static struct ofono_modem_driver mtk_driver = {
+ .name = "mtk",
+ .probe = mtk_probe,
+ .remove = mtk_remove,
+ .enable = mtk_enable,
+ .disable = mtk_disable,
+ .pre_sim = mtk_pre_sim,
+ .post_sim = mtk_post_sim,
+ .post_online = mtk_post_online,
+ .set_online = mtk_set_online,
+};
+
+static int mtk_init(void)
+{
+ int retval = ofono_modem_driver_register(&mtk_driver);
+
+ if (retval != 0)
+ DBG("ofono_modem_driver_register returned: %d", retval);
+
+ return retval;
+}
+
+static void mtk_exit(void)
+{
+ DBG("");
+ ofono_modem_driver_unregister(&mtk_driver);
+}
+
+OFONO_PLUGIN_DEFINE(mtk, "MTK modem driver", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, mtk_init, mtk_exit)
--
2.5.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 7/7] build: Add mtkmodem driver and mtk plugin
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
` (5 preceding siblings ...)
2015-11-13 12:25 ` [PATCH 6/7] mtk: Plugin for mtkmodems Alfonso Sanchez-Beato
@ 2015-11-13 12:25 ` Alfonso Sanchez-Beato
6 siblings, 0 replies; 9+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-11-13 12:25 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1134 bytes --]
---
Makefile.am | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index fba25ba..6a2acf2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,9 +126,28 @@ builtin_sources += plugins/rildev.c
builtin_modules += ril
builtin_sources += plugins/ril.c plugins/ril.h
+builtin_modules += mtk
+builtin_sources += plugins/mtk.c
+
builtin_modules += infineon
builtin_sources += plugins/infineon.c
+builtin_modules += mtkmodem
+builtin_sources += drivers/mtkmodem/mtkmodem.h \
+ drivers/mtkmodem/mtkmodem.c \
+ drivers/mtkmodem/mtkutil.h \
+ drivers/mtkmodem/mtkutil.c \
+ drivers/mtkmodem/mtkrequest.h \
+ drivers/mtkmodem/mtkrequest.c \
+ drivers/mtkmodem/mtkunsol.h \
+ drivers/mtkmodem/mtkunsol.c \
+ drivers/mtkmodem/mtkreply.h \
+ drivers/mtkmodem/mtkreply.c \
+ drivers/mtkmodem/voicecall.c \
+ drivers/mtkmodem/gprs.c \
+ drivers/mtkmodem/radio-settings.c \
+ drivers/mtkmodem/mtksettings.c
+
builtin_modules += rilmodem
builtin_sources += drivers/rilmodem/rilmodem.h \
drivers/rilmodem/vendor.h \
--
2.5.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/7] gitignore: Ignore rilmodem-cs test binary
2015-11-13 12:25 ` [PATCH 1/7] gitignore: Ignore rilmodem-cs test binary Alfonso Sanchez-Beato
@ 2015-11-13 16:06 ` Denis Kenzior
0 siblings, 0 replies; 9+ messages in thread
From: Denis Kenzior @ 2015-11-13 16:06 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 179 bytes --]
Hi Alfonso,
On 11/13/2015 06:25 AM, Alfonso Sanchez-Beato wrote:
> ---
> .gitignore | 1 +
> 1 file changed, 1 insertion(+)
>
Applied, thanks.
Regards,
-Denis
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-11-13 16:06 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-13 12:25 [PATCH 0/7] Support for mtk modems Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 1/7] gitignore: Ignore rilmodem-cs test binary Alfonso Sanchez-Beato
2015-11-13 16:06 ` Denis Kenzior
2015-11-13 12:25 ` [PATCH 2/7] include: Add flag for drivers that watch SIM state Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 3/7] modem: " Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 4/7] rilmodem: Export functions needed by mtkmodem Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 5/7] mtkmodem: Add mtkmodem driver Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 6/7] mtk: Plugin for mtkmodems Alfonso Sanchez-Beato
2015-11-13 12:25 ` [PATCH 7/7] build: Add mtkmodem driver and mtk plugin Alfonso Sanchez-Beato
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.