ofono fails to compile on gcc-6.3
by Pavel Machek
Hi!
I'm getting this:
CC drivers/rilmodem/network-registration.o
drivers/rilmodem/network-registration.c:40:32: error: unknown option
after ‘#pragma GCC diagnostic’ kind [-Werror=pragmas]
#pragma GCC diagnostic ignored "-Wrestrict"
cc1: error: unrecognized command line option ‘-Wno-format-truncation’
[-Werror]
cc1: all warnings being treated as errors
I commented out #pragma, and this allows compilation to
continue... until I hit same issue in
drivers/rilmodem/call-forwarding.c:41:32:
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
2 years, 1 month
[PATCH 1/3] sim800: add support for sim800 modem.
by Clement Viel
---
plugins/sim900.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 80 insertions(+), 9 deletions(-)
diff --git a/plugins/sim900.c b/plugins/sim900.c
index a7728cd..9f3f334 100644
--- a/plugins/sim900.c
+++ b/plugins/sim900.c
@@ -24,6 +24,7 @@
#endif
#include <errno.h>
+#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include <gatchat.h>
@@ -60,13 +61,59 @@ static char *dlc_prefixes[NUM_DLC] = { "Voice: ", "Net: ", "SMS: ",
static const char *none_prefix[] = { NULL };
+typedef enum type {
+ SIM800,
+ SIM900,
+ SIM_UNKNOWN,
+} type_t;
+
struct sim900_data {
GIOChannel *device;
GAtMux *mux;
GAtChat * dlcs[NUM_DLC];
guint frame_size;
+ type_t modem_type;
};
+static void set_modem_type (struct ofono_modem *modem)
+{
+ struct sim900_data *data = ofono_modem_get_data(modem);
+ const char *path = ofono_modem_get_path(modem);
+
+ if (strstr(path, "sim800"))
+ data->modem_type = SIM800;
+ else if (strstr(path, "sim900"))
+ data->modem_type = SIM900;
+ else
+ data->modem_type = SIM_UNKNOWN;
+
+}
+
+static void mux_ready_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sim900_data *data = ofono_modem_get_data(modem);
+ struct ofono_gprs *gprs = NULL;
+ struct ofono_gprs_context *gc;
+ static int notified = 0;
+
+ if (!notified) {
+ ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
+ data->dlcs[SMS_DLC]);
+
+
+ gprs = ofono_gprs_create(modem, 0, "atmodem", data->dlcs[GPRS_DLC]);
+ if (gprs == NULL)
+ return;
+
+ gc = ofono_gprs_context_create(modem, OFONO_VENDOR_SIMCOM,
+ "atmodem", data->dlcs[GPRS_DLC]);
+ if (gc)
+ ofono_gprs_add_context(gprs, gc);
+ }
+
+}
+
static int sim900_probe(struct ofono_modem *modem)
{
struct sim900_data *data;
@@ -79,6 +126,7 @@ static int sim900_probe(struct ofono_modem *modem)
ofono_modem_set_data(modem, data);
+ set_modem_type(modem);
return 0;
}
@@ -111,6 +159,7 @@ static GAtChat *open_device(struct ofono_modem *modem,
GHashTable *options;
device = ofono_modem_get_string(modem, key);
+
if (device == NULL)
return NULL;
@@ -232,6 +281,11 @@ static void setup_internal_mux(struct ofono_modem *modem)
goto error;
}
}
+ if (data->modem_type == SIM800) {
+ for (i = 0; i<NUM_DLC; i++) {
+ g_at_chat_register(data->dlcs[i], "SMS Ready", mux_ready_notify, FALSE, modem, NULL);
+ }
+ }
ofono_modem_set_powered(modem, TRUE);
@@ -353,18 +407,20 @@ static void sim900_post_sim(struct ofono_modem *modem)
DBG("%p", modem);
- ofono_phonebook_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
- ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
+ if (data->modem_type != SIM800) {
+ ofono_phonebook_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
data->dlcs[SMS_DLC]);
- gprs = ofono_gprs_create(modem, 0, "atmodem", data->dlcs[GPRS_DLC]);
- if (gprs == NULL)
- return;
+ gprs = ofono_gprs_create(modem, 0, "atmodem", data->dlcs[GPRS_DLC]);
+ if (gprs == NULL)
+ return;
- gc = ofono_gprs_context_create(modem, OFONO_VENDOR_SIMCOM_SIM900,
+ gc = ofono_gprs_context_create(modem, OFONO_VENDOR_SIMCOM_SIM900,
"atmodem", data->dlcs[GPRS_DLC]);
- if (gc)
- ofono_gprs_add_context(gprs, gc);
+ if (gc)
+ ofono_gprs_add_context(gprs, gc);
+ }
}
static void sim900_post_online(struct ofono_modem *modem)
@@ -391,9 +447,24 @@ static struct ofono_modem_driver sim900_driver = {
.post_online = sim900_post_online,
};
+
+static struct ofono_modem_driver sim800_driver = {
+ .name = "sim800",
+ .probe = sim900_probe,
+ .remove = sim900_remove,
+ .enable = sim900_enable,
+ .disable = sim900_disable,
+ .pre_sim = sim900_pre_sim,
+ .post_sim = sim900_post_sim,
+ .post_online = sim900_post_online,
+};
+
static int sim900_init(void)
{
- return ofono_modem_driver_register(&sim900_driver);
+ int ret = 0;
+ ret = ofono_modem_driver_register(&sim800_driver);
+ ret += ofono_modem_driver_register(&sim900_driver);
+ return ret;
}
static void sim900_exit(void)
--
2.7.4
2 years, 4 months
[RFC PATCH] new gemalto plugin
by Giacinto Cifelli
I would like to submit to your attention the new version of the Gemalto
plugin. It is not ready, but would already benefit from some feedback.
The purpose of this new plugin is to address most of the Gemalto modules
(excluding perhaps some LTE CatM and CatNB), interfaced either via USB
or RS232 interface.
I have included the totality of file plugins/gemalto.c because it is
quite different from the current one.
I would appreciate a generic comment on how to split it in commits
this file.
I have added an include/gemalto.h file, as suggested by Jonas Bonn.
There isn't much in it yet, but some additional code should be moved into
it.
The gprs and gprs-context's are perhaps not finished.
In udevng there are 3 additional commits, please just comment if you
like and find them useful and I will submit separately.
There are some review comments, in // format, not part of the code.
---
include/gemalto.h | 27 +
plugins/gemalto.c | 2715 +++++++++++++++++++++++++++++++++++++++++++++
plugins/udevng.c | 208 ++--
3 files changed, 2885 insertions(+), 65 deletions(-)
create mode 100644 include/gemalto.h
create mode 100644 plugins/gemalto.c
diff --git a/include/gemalto.h b/include/gemalto.h
new file mode 100644
index 00000000..26165eb1
--- /dev/null
+++ b/include/gemalto.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2018 Gemalto M2M
+ *
+ * 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
+ *
+ */
+
+enum auth_option {
+ GEMALTO_AUTH_DEFAULTS = 0,
+ GEMALTO_AUTH_USE_SGAUTH = 1<<0,
+ GEMALTO_AUTH_ORDER_PWD_USR = 1<<1,
+ GEMALTO_AUTH_ALWAYS_ALL_PARAMS = 1<<2,
+};
diff --git a/plugins/gemalto.c b/plugins/gemalto.c
new file mode 100644
index 00000000..6b208572
--- /dev/null
+++ b/plugins/gemalto.c
@@ -0,0 +1,2715 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Vincent Cesson. All rights reserved.
+ * Copyright (C) 2018 Gemalto M2M
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <linux/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <glib.h>
+#include <gatchat.h>
+#include <gattty.h>
+#include <gdbus.h>
+#include "ofono.h"
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/dbus.h>
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+#include <ofono/netreg.h>
+#include <ofono/phonebook.h>
+#include <ofono/sim.h>
+#include <ofono/sms.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/location-reporting.h>
+#include <drivers/atmodem/atutil.h>
+#include <drivers/atmodem/vendor.h>
+#include <string.h>
+
+#ifdef HAVE_ELL
+#include <ell/ell.h>
+#include <drivers/mbimmodem/mbim.h>
+#include <drivers/mbimmodem/mbim-message.h>
+#include <drivers/mbimmodem/mbim-desc.h>
+#endif
// some models can use MBIM, but if the option is not included,
// they fall back to PPP
+
+#include <drivers/qmimodem/qmi.h>
+#include <src/storage.h>
+#include "gemalto.h"
+
// the next part will not be in the official commit
+/* debug utilities - begin */
+
+#define REDCOLOR "\x1b\x5b\x30\x31\x3b\x33\x31\x6d"
+#define NOCOLOR "\x1b\x5b\x30\x30\x6d"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+void print_trace();
+
+void print_trace() {
+ char pid_buf[30];
+ char name_buf[512];
+ int child_pid;
+ sprintf(pid_buf, "%d", getpid());
+ name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
+ child_pid = fork();
+ if (!child_pid) {
+ dup2(2,1); // redirect output to stderr
+ fprintf(stdout,"stack trace for %s pid=%s\n",name_buf,pid_buf);
+ execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
+ abort(); /* If gdb failed to start */
+ } else {
+ waitpid(child_pid,NULL,0);
+ }
+}
+
+/* debug utilities - end */
+
+enum gemalto_connection_type {
+ GEMALTO_CONNECTION_SERIAL = 1,
+ GEMALTO_CONNECTION_USB = 2,
+};
+
+enum gemalto_device_state {
+ STATE_ABSENT = 0,
+ STATE_PROBE = 1,
+ STATE_PRESENT = 2,
+};
+
+enum gprs_option {
+ NO_GPRS = 0,
+ USE_SWWAN = 1,
+ USE_CTX17 = 2,
+ USE_CTX3 = 3,
+ USE_PPP = 4,
+ USE_SWWAN_INV = 5, /* inverted syntax idx,act */
+ USE_CTX_INV = 6, /* inverted syntax idx,act */
+};
+
+static const char *none_prefix[] = { NULL };
+static const char *cfun_prefix[] = { "+CFUN:", NULL };
+static const char *sctm_prefix[] = { "^SCTM:", NULL };
+static const char *sbv_prefix[] = { "^SBV:", NULL };
+static const char *sqport_prefix[] = { "^SQPORT:", NULL };
+static const char *sgpsc_prefix[] = { "^SGPSC:", NULL };
+
+typedef void (*OpenResultFunc)(gboolean success, struct ofono_modem *modem);
+
+struct gemalto_data {
+ gboolean init_done;
+ GIOChannel *channel;
+ GAtChat *tmp_chat;
+ OpenResultFunc open_cb;
+ guint read_src;
+ GAtChat *app;
+ GAtChat *mdm;
+ int cfun;
+
+ struct ofono_sim *sim;
+ gboolean have_sim;
+ struct at_util_sim_state_query *sim_state_query;
+ guint modem_ready_id;
+
+ char modelstr[32];
+ char sqport[32];
+
+ guint model;
+ guint probing_timer;
+ guint init_waiting_time;
+ guint waiting_time;
+
+ enum gemalto_connection_type conn;
+ enum gemalto_device_state mbim;
+ enum gemalto_device_state qmi;
+ enum gemalto_device_state ecmncm;
+ enum gemalto_device_state gina;
+ gboolean inverse_enum;
+ gboolean use_mdm_for_app;
+ gboolean voice_avail;
+ enum auth_option auth_syntax;
+ enum gprs_option gprs_opt;
+ gboolean has_lte;
+ gboolean autoattach;
+ gboolean autoconfig;
+ gboolean autoactivation;
+ gboolean vts_with_quotes;
+
+ void *device; /* struct mbim_device* or struct qmi_device* */
+
+ /* mbim data */
+ uint16_t max_segment;
+ uint8_t max_outstanding;
+ uint8_t max_sessions;
+
+ /* hardware monitor variables */
+ DBusMessage *hm_msg;
+ int32_t temperature;
+ int32_t voltage;
+ /* gnss variables */
+ DBusMessage *gnss_msg;
+ /* hardware control variables */
+ DBusMessage *hc_msg;
+ gboolean powersave;
+};
+
+/*******************************************************************************
+ * Generic functions
+ ******************************************************************************/
+
+static void gemalto_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ ofono_info("%s%s", prefix, str);
+}
+
+static const char *gemalto_get_string(struct ofono_modem *modem, const char *k)
+{
+ const char *v;
+
+ if (!modem || !k || !*k)
+ return NULL;
+
+ v = ofono_modem_get_string(modem, k);
+
+ if (!v || !*v)
+ return NULL;
+
+ return v;
+}
+
+static void gemalto_signal(const char *iface, const char *name,
+ const char *value, struct ofono_modem *modem)
+{
+ DBusMessageIter sub_iter,iter;
+ const char *path = ofono_modem_get_path(modem);
+ DBusConnection *conn = ofono_dbus_get_connection();
+
+ DBusMessage *signal = dbus_message_new_signal(path,
+ iface,
+ name);
+
+ DBG("");
+
+ if (signal == NULL) {
+ DBG("Cannot create new signal message");
+ return;
+ }
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ "s", &sub_iter);
+ if (!dbus_message_iter_append_basic(&sub_iter,
+ DBUS_TYPE_STRING, &value)) {
+ DBG("Out of memory!");
+ return;
+ }
+
+ dbus_message_iter_close_container(&iter, &sub_iter);
+ g_dbus_send_message(conn, signal);
+}
+
+static void executeWithPrompt(GAtChat *port, const char *command,
+ const char *prompt, const char *argument, void *cb,
+ void *cbd, void *freecall)
+{
+ char *buf;
+ const char *expected_array[2] = {0,0};
+
+ buf = g_strdup_printf("%s\r%s", command, argument);
+
+ if (strlen(argument)>=2 && g_str_equal(argument+strlen(argument)-2,
+ "^Z"))
+ sprintf(buf+strlen(buf)-2,"\x1a");
+
+ if (strlen(argument)>=2 && g_str_equal(argument+strlen(argument)-2,
+ "\\r"))
+ sprintf(buf+strlen(buf)-2,"\r");
+
+ expected_array[0]=prompt;
+ g_at_chat_send_and_expect_short_prompt(port, buf, expected_array,
+ cb, cbd, freecall);
+ free(buf);
+}
+
+static void gemalto_exec_stored_cmd(struct ofono_modem *modem,
+ const char *filename)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ const char *vid = gemalto_get_string(modem, "Vendor");
+ const char *pid = gemalto_get_string(modem, "Model");
+ char store[64];
+ int index;
+ char *command, *prompt, *argument;
+ char key[32];
+ GKeyFile *f;
+
+ sprintf(store,"%s-%s/%s", vid, pid, filename);
+ f = storage_open(NULL, store);
+
+ if (!f)
+ return;
+
+ for (index = 0; ; index++) {
+ sprintf(key, "command_%d", index);
+ command = g_key_file_get_string(f, "Simple", key, NULL);
+
+ if (!command)
+ break;
+
+ DBG(REDCOLOR"executing stored command simple: %s"NOCOLOR, command);
+ g_at_chat_send(data->app, command, NULL, NULL, NULL, NULL);
+ }
+
+ for (index = 0; ; index++) {
+ sprintf(key, "command_%d", index);
+ command = g_key_file_get_string(f, "WithPrompt", key, NULL);
+ sprintf(key, "prompt_%d", index);
+ prompt = g_key_file_get_string(f, "WithPrompt", key, NULL);
+ sprintf(key, "argument_%d", index);
+ argument = g_key_file_get_string(f, "WithPrompt", key, NULL);
+
+ if (!command || !prompt || !argument)
+ break;
+
+ DBG("executing stored command with prompt: %s", command);
+ executeWithPrompt(data->app, command, prompt, argument,
+ NULL, NULL, NULL);
+ }
+
+ storage_close(NULL, store, f, FALSE);
+}
+
+/*******************************************************************************
+ * Hardware monitor interface
+ ******************************************************************************/
+
+#define HARDWARE_MONITOR_INTERFACE OFONO_SERVICE ".gemalto.HardwareMonitor"
+#define CINTERION_LEGACY_HWMON_INTERFACE OFONO_SERVICE ".cinterion.HardwareMonitor"
+
+static void gemalto_sctmb_notify(GAtResult *result, gpointer user_data)
+{
+ GAtResultIter iter;
+ gint value;
+ char *val;
+
+ g_at_result_iter_init(&iter, result);
+ g_at_result_iter_next(&iter, "^SCTM_B:");
+ g_at_result_iter_next_number(&iter, &value);
+
+ switch(value) {
+ case -1:
+ val="Below low temperature alert limit";
+ break;
+ case 0:
+ val="Normal operating temperature";
+ break;
+ case 1:
+ val="Above upper temperature alert limit";
+ break;
+ case 2:
+ val="Above uppermost temperature limit";
+ break;
+ default: /* unvalid value, do not output signal*/
+ return;
+ }
+
+ gemalto_signal(HARDWARE_MONITOR_INTERFACE, "CriticalTemperature", val,
+ user_data);
+}
+
+static void gemalto_sbc_notify(GAtResult *result, gpointer user_data)
+{
+ GAtResultIter iter;
+ const char *value;
+
+ g_at_result_iter_init(&iter, result);
+ g_at_result_iter_next(&iter, "^SBC:");
+ g_at_result_iter_next_unquoted_string(&iter, &value);
+ gemalto_signal(HARDWARE_MONITOR_INTERFACE, "CriticalVoltage", value,
+ user_data);
+}
+
+static void gemalto_sctm_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct gemalto_data *data = user_data;
+ DBusMessage *reply;
+ GAtResultIter iter;
+ DBusMessageIter dbus_iter;
+ DBusMessageIter dbus_dict;
+
+ if (data->hm_msg == NULL)
+ return;
+
+ if (!ok)
+ goto error;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "^SCTM:"))
+ goto error;
+
+ if (!g_at_result_iter_skip_next(&iter))
+ goto error;
+
+ if (!g_at_result_iter_skip_next(&iter))
+ goto error;
+
+ if (!g_at_result_iter_next_number(&iter, &data->temperature))
+ goto error;
+
+ reply = dbus_message_new_method_return(data->hm_msg);
+
+ dbus_message_iter_init_append(reply, &dbus_iter);
+
+ dbus_message_iter_open_container(&dbus_iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dbus_dict);
+
+ ofono_dbus_dict_append(&dbus_dict, "Temperature",
+ DBUS_TYPE_INT32, &data->temperature);
+
+ ofono_dbus_dict_append(&dbus_dict, "Voltage",
+ DBUS_TYPE_UINT32, &data->voltage);
+
+ dbus_message_iter_close_container(&dbus_iter, &dbus_dict);
+
+ __ofono_dbus_pending_reply(&data->hm_msg, reply);
+
+ return;
+
+error:
+ __ofono_dbus_pending_reply(&data->hm_msg,
+ __ofono_error_failed(data->hm_msg));
+}
+
+static void gemalto_sbv_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct gemalto_data *data = user_data;
+ GAtResultIter iter;
+
+ if (!ok)
+ goto error;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "^SBV:"))
+ goto error;
+
+ if (!g_at_result_iter_next_number(&iter, &data->voltage))
+ goto error;
+
+ if (g_at_chat_send(data->app, "AT^SCTM?", sctm_prefix, gemalto_sctm_cb,
+ data, NULL) > 0)
+ return;
+
+error:
+ __ofono_dbus_pending_reply(&data->hm_msg,
+ __ofono_error_failed(data->hm_msg));
+}
+
+static DBusMessage *hardware_monitor_get_statistics(DBusConnection *conn,
+ DBusMessage *msg,
+ void *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ if (data->hm_msg != NULL)
+ return __ofono_error_busy(msg);
+
+ if (!g_at_chat_send(data->app, "AT^SBV", sbv_prefix, gemalto_sbv_cb,
+ data, NULL))
+ return __ofono_error_failed(msg);
+
+ data->hm_msg = dbus_message_ref(msg);
+
+ return NULL;
+}
+
+static const GDBusMethodTable hardware_monitor_methods[] = {
+ { GDBUS_ASYNC_METHOD("GetStatistics",
+ NULL, GDBUS_ARGS({ "Statistics", "a{sv}" }),
+ hardware_monitor_get_statistics) },
+ {}
+};
+
+static const GDBusSignalTable hardware_monitor_signals[] = {
+ { GDBUS_SIGNAL("CriticalTemperature",
+ GDBUS_ARGS({ "temperature", "a{sv}" }) )},
+ { GDBUS_SIGNAL("CriticalVoltage",
+ GDBUS_ARGS({ "voltage", "a{sv}" }) )},
+ {}
+};
+
+static void gemalto_hardware_monitor_enable(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(modem);
+
+ /* Listen to over/undertemperature URCs (activated with AT^SCTM) */
+ g_at_chat_register(data->app, "^SCTM_B:",
+ gemalto_sctmb_notify, FALSE, NULL, NULL);
+ /* Listen to over/under voltage URCs (automatic URC) */
+ g_at_chat_register(data->app, "^SBC:",
+ gemalto_sbc_notify, FALSE, NULL, NULL);
+ /* Enable temperature URC and value output */
+ g_at_chat_send(data->app, "AT^SCTM=1,1", none_prefix, NULL, NULL, NULL);
+
+ if (!g_dbus_register_interface(conn, path, HARDWARE_MONITOR_INTERFACE,
+ hardware_monitor_methods,
+ hardware_monitor_signals,
+ NULL,
+ modem,
+ NULL)) {
+ ofono_error("Could not register %s interface under %s",
+ HARDWARE_MONITOR_INTERFACE, path);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, HARDWARE_MONITOR_INTERFACE);
+
+ if (!g_dbus_register_interface(conn, path,
+ CINTERION_LEGACY_HWMON_INTERFACE,
+ hardware_monitor_methods,
+ NULL,
+ NULL,
+ modem,
+ NULL)) {
+ ofono_error("Could not register %s interface under %s",
+ CINTERION_LEGACY_HWMON_INTERFACE, path);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, CINTERION_LEGACY_HWMON_INTERFACE);
+}
+
+/*******************************************************************************
+ * Time services interface
+ ******************************************************************************/
+
+#define GEMALTO_NITZ_TIME_INTERFACE OFONO_SERVICE ".gemalto.TimeServices"
+
+static DBusMessage *set_modem_datetime(DBusConnection *conn,
+ DBusMessage *msg,
+ void *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ time_t t = time(NULL);
+ struct tm tm;
+ gchar cclk_cmd[32];
+
+ /* Set date and time */
+ tm = *localtime(&t);
+ strftime(cclk_cmd, 32, "AT+CCLK=\"%y/%m/%d,%T\"", &tm);
+ g_at_chat_send(data->app, cclk_cmd, none_prefix, NULL, NULL, NULL);
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable gsmTime_methods[] = {
+ { GDBUS_ASYNC_METHOD("SetModemDatetime",
+ NULL, NULL, set_modem_datetime) },
+ {}
+};
+
+static const GDBusSignalTable gsmTime_signals[] = {
+ { GDBUS_SIGNAL("NitzUpdated",
+ GDBUS_ARGS({ "time", "a{sv}" }) )},
+ {}
+};
+
+static void gemalto_time_enable(struct ofono_modem *modem)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(modem);
+
+ if (!g_dbus_register_interface(conn, path,
+ GEMALTO_NITZ_TIME_INTERFACE,
+ gsmTime_methods,
+ gsmTime_signals,
+ NULL,
+ modem,
+ NULL)) {
+ ofono_error("Could not register %s interface under %s",
+ GEMALTO_NITZ_TIME_INTERFACE, path);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, GEMALTO_NITZ_TIME_INTERFACE);
+}
+
+/*******************************************************************************
+ * Command passtrhough interface
+ ******************************************************************************/
+
+#define COMMAND_PASSTHROUGH_INTERFACE OFONO_SERVICE ".gemalto.CommandPassthrough"
+
+static int command_passthrough_signal_answer(const char *answer,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(modem);
+ DBusMessage *signal;
+ DBusMessageIter iter;
+
+ if (!conn || !path)
+ return -1;
+
+ signal = dbus_message_new_signal(path, COMMAND_PASSTHROUGH_INTERFACE,
+ "Answer");
+ if (!signal) {
+ ofono_error("Unable to allocate new %s.PropertyChanged signal",
+ COMMAND_PASSTHROUGH_INTERFACE);
+ return -1;
+ }
+
+ dbus_message_iter_init_append(signal, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &answer);
+
+ DBG("");
+
+ return g_dbus_send_message(conn, signal);
+}
+
+static void command_passthrough_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ GAtResultIter iter;
+ guint len = 0;
+ char *answer;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, NULL)) {
+ len += strlen(g_at_result_iter_raw_line(&iter))+2;
+ }
+
+ len += strlen(g_at_result_final_response(result))+3;
+ answer = g_new0(char, len);
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, NULL)) {
+ sprintf(answer+strlen(answer),"%s\r\n",
+ g_at_result_iter_raw_line(&iter));
+ }
+
+ sprintf(answer+strlen(answer),"%s\r\n",
+ g_at_result_final_response(result));
+
+ DBG("answer_len: %u, answer_string: %s", len, answer);
+ command_passthrough_signal_answer(answer, user_data);
+
+ g_free(answer);
+}
+
+static DBusMessage *command_passthrough_simple(DBusConnection *conn,
+ DBusMessage *msg,
+ void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessageIter iter;
+ const char *command;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+ "No arguments given");
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+ "Invalid argument type: '%c'",
+ dbus_message_iter_get_arg_type(&iter));
+
+ dbus_message_iter_get_basic(&iter, &command);
+
+ g_at_chat_send(data->app, command, NULL, command_passthrough_cb,
+ modem, NULL);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *command_passthrough_with_prompt(DBusConnection *conn,
+ DBusMessage *msg,
+ void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessageIter iter;
+ const char *command, *prompt, *argument;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+ "No arguments given");
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+ "Invalid argument type: '%c'",
+ dbus_message_iter_get_arg_type(&iter));
+
+ dbus_message_iter_get_basic(&iter, &command);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+ "Invalid argument type: '%c'",
+ dbus_message_iter_get_arg_type(&iter));
+
+ dbus_message_iter_get_basic(&iter, &prompt);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+ "Invalid argument type: '%c'",
+ dbus_message_iter_get_arg_type(&iter));
+
+ dbus_message_iter_get_basic(&iter, &argument);
+
+ executeWithPrompt(data->app, command, prompt, argument,
+ command_passthrough_cb, modem, NULL);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *command_passthrough_send_break(DBusConnection *conn,
+ DBusMessage *msg,
+ void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ GIOChannel *channel = g_at_chat_get_channel(data->app);
+
+ g_io_channel_write_chars(channel, "\r", 1, NULL, NULL);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable command_passthrough_methods[] = {
+ { GDBUS_ASYNC_METHOD("Simple",
+ GDBUS_ARGS({ "command", "s" }),
+ NULL,
+ command_passthrough_simple) },
+ { GDBUS_ASYNC_METHOD("WithPrompt",
+ GDBUS_ARGS({ "command", "s" }, { "prompt", "s" },
+ { "argument", "s" }),
+ NULL,
+ command_passthrough_with_prompt) },
+ { GDBUS_ASYNC_METHOD("SendBreak",
+ NULL,
+ NULL,
+ command_passthrough_send_break) },
+ {}
+};
+
+static const GDBusSignalTable command_passthrough_signals[] = {
+ { GDBUS_SIGNAL("Answer",
+ GDBUS_ARGS({ "answer", "s" })) },
+ { }
+};
+
+static void gemalto_command_passthrough_enable(struct ofono_modem *modem)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(modem);
+
+ /* Create Command Passthrough DBus interface */
+ if (!g_dbus_register_interface(conn, path, COMMAND_PASSTHROUGH_INTERFACE,
+ command_passthrough_methods,
+ command_passthrough_signals,
+ NULL,
+ modem,
+ NULL)) {
+ ofono_error("Could not register %s interface under %s",
+ COMMAND_PASSTHROUGH_INTERFACE, path);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, COMMAND_PASSTHROUGH_INTERFACE);
+}
+
+/*******************************************************************************
+ * GNSS interface
+ ******************************************************************************/
+
+#define GNSS_INTERFACE OFONO_SERVICE ".gemalto.GNSS"
+
+static void gnss_get_properties_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ const char *port = ofono_modem_get_string(modem, "GNSS");
+ GAtResultIter iter;
+ DBusMessage *reply;
+ DBusMessageIter dbusiter;
+ DBusMessageIter dict;
+
+ if (data->gnss_msg == NULL)
+ return;
+
+ if (!ok)
+ goto error;
+
+ reply = dbus_message_new_method_return(data->gnss_msg);
+ dbus_message_iter_init_append(reply, &dbusiter);
+ dbus_message_iter_open_container(&dbusiter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+ g_at_result_iter_init(&iter, result);
+
+ /* supported format: ^SGPSC: "Nmea/Output","off" */
+ while (g_at_result_iter_next(&iter, "^SGPSC:")) {
+ const char *name = "";
+ const char *val = "";
+
+ if (!g_at_result_iter_next_string(&iter, &name))
+ continue;
+
+ /*
+ * skip the "Info" property:
+ * different line format and different usage
+ */
+ if (g_str_equal(name,"Info"))
+ continue;
+
+ if (!g_at_result_iter_next_string(&iter, &val))
+ continue;
+
+ ofono_dbus_dict_append(&dict, name, DBUS_TYPE_STRING, &val);
+ }
+
+ ofono_dbus_dict_append(&dict, "Port", DBUS_TYPE_STRING, &port);
+ dbus_message_iter_close_container(&dbusiter, &dict);
+ __ofono_dbus_pending_reply(&data->gnss_msg, reply);
+ return;
+
+error:
+ __ofono_dbus_pending_reply(&data->gnss_msg,
+ __ofono_error_failed(data->gnss_msg));
+}
+
+static DBusMessage *gnss_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ if (data->gnss_msg != NULL)
+ return __ofono_error_busy(msg);
+
+ if (!g_at_chat_send(data->app, "AT^SGPSC?", sgpsc_prefix,
+ gnss_get_properties_cb, modem, NULL))
+ return __ofono_error_failed(msg);
+
+ data->gnss_msg = dbus_message_ref(msg);
+
+ return NULL;
+}
+
+static void gnss_set_properties_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessage *reply;
+
+ if (data->gnss_msg == NULL)
+ return;
+
+ if (!ok) {
+ __ofono_dbus_pending_reply(&data->gnss_msg,
+ __ofono_error_failed(data->gnss_msg));
+ return;
+ }
+
+ reply = dbus_message_new_method_return(data->gnss_msg);
+ __ofono_dbus_pending_reply(&data->gnss_msg, reply);
+}
+
+static DBusMessage *gnss_set_property(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessageIter iter, var;
+ const char *name;
+ char *value;
+ char buf[256];
+
+ if (data->gnss_msg != NULL)
+ return __ofono_error_busy(msg);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ 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, &name);
+ 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 (dbus_message_iter_get_arg_type(&var) !=
+ DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &value);
+
+ snprintf(buf, sizeof(buf), "AT^SGPSC=\"%s\",\"%s\"", name, value);
+
+ if (!g_at_chat_send(data->app, buf, sgpsc_prefix,
+ gnss_set_properties_cb, modem, NULL))
+ return __ofono_error_failed(msg);
+
+ data->gnss_msg = dbus_message_ref(msg);
+ return NULL;
+}
+
+static const GDBusMethodTable gnss_methods[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ gnss_get_properties) },
+ { GDBUS_ASYNC_METHOD("SetProperty",
+ GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
+ NULL, gnss_set_property) },
+ { }
+};
+
+static void gnss_exec_stored_param(struct ofono_modem *modem,
+ const char *filename) {
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ const char *vid = ofono_modem_get_string(modem, "Vendor");
+ const char *pid = ofono_modem_get_string(modem, "Model");
+ char store[64];
+ int index;
+ char *property, *value;
+ char key[32];
+ GKeyFile *f;
+ char *command;
+
+ sprintf(store,"%s-%s/%s", vid, pid, filename);
+ f = storage_open(NULL, store);
+
+ if (!f)
+ return;
+
+ for (index=0;;index++) {
+ sprintf(key, "property_%d", index);
+ property = g_key_file_get_string(f, "Properties", key, NULL);
+
+ sprintf(key, "value_%d", index);
+ value = g_key_file_get_string(f, "Properties", key, NULL);
+
+ if(!property || !value)
+ break;
+
+ command = g_strdup_printf("AT^SGPSC=%s,%s", property, value);
+ DBG(REDCOLOR"setting GNSS property: %sNOCOLOR", command);
+ g_at_chat_send(data->app, command, NULL, NULL, NULL, NULL);
+ free(command);
+ }
+
+ storage_close(NULL, store, f, FALSE);
+}
+
+static void gemalto_gnss_enable_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(modem);
+
+ if (!ok)
+ return; /* the module does not support GNSS */
+
+ gnss_exec_stored_param(modem, "gnss_startup");
+
+ /* Create GNSS DBus interface */
+ if (!g_dbus_register_interface(conn, path, GNSS_INTERFACE,
+ gnss_methods,
+ NULL,
+ NULL,
+ modem,
+ NULL)) {
+ ofono_error("Could not register %s interface under %s",
+ GNSS_INTERFACE, path);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, GNSS_INTERFACE);
+}
+
+static void gemalto_gnss_enable(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ g_at_chat_send(data->app, "AT^SGPSC?", sgpsc_prefix,
+ gemalto_gnss_enable_cb, modem, NULL);
+}
+
+/*******************************************************************************
+ * Hardware control interface
+ ******************************************************************************/
+
+#define HARDWARE_CONTROL_INTERFACE OFONO_SERVICE ".gemalto.HardwareControl"
+
+static DBusMessage *hc_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessage *reply;
+ DBusMessageIter dbusiter;
+ DBusMessageIter dict;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &dbusiter);
+ dbus_message_iter_open_container(&dbusiter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ ofono_dbus_dict_append(&dict, "Powersave", DBUS_TYPE_BOOLEAN,
+ &data->powersave);
+ dbus_message_iter_close_container(&dbusiter, &dict);
+
+ return reply;
+}
+
+/*
+ * powersave for older modules:
+ * command_0=AT+CFUN=7
+ * return:
+ * command_0=AT+CFUN=1
+ *
+ * powersave example for modules with GNSS (could also only stop the output):
+ * command_0=AT+CREG=0
+ * command_1=AT+CGREG=0
+ * command_2=AT+CEREG=0
+ * command_3=AT^SGPSC="Engine","0"
+ * command_4=AT^SGPSC="Power/Antenna","off"
+ * return:
+ * command_0=AT+CREG=2
+ * command_1=AT+CGREG=2
+ * command_2=AT+CEREG=2
+ * command_4=AT^SGPSC="Power/Antenna","on"
+ * command_3=AT^SGPSC="Engine","1"
+ */
+
+static void gemalto_powersave_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessage *reply;
+
+ /* flip the state in any case */
+ data->powersave = !data->powersave;
+
+ if (data->hc_msg == NULL)
+ return;
+
+ reply = dbus_message_new_method_return(data->hc_msg);
+ __ofono_dbus_pending_reply(&data->hc_msg, reply);
+}
+
+static DBusMessage *hc_set_property(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessageIter iter, var;
+ const char *name;
+ gboolean enable;
+
+ if (data->hc_msg != NULL)
+ return __ofono_error_busy(msg);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ 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, &name);
+
+ if (!g_str_equal(name, "Powersave"))
+ return __ofono_error_invalid_args(msg);
+
+ 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 (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &enable);
+
+ if (data->powersave == enable)
+ return dbus_message_new_method_return(msg);
+
+ gemalto_exec_stored_cmd(modem, enable ? "power_mode_powersave" :
+ "power_mode_normal");
+
+ gnss_exec_stored_param(modem, enable ? "gnss_powersave" :
+ "gnss_normal");
+
+ if (!g_at_chat_send(data->app, "AT", none_prefix,
+ gemalto_powersave_cb, modem, NULL))
+ return __ofono_error_failed(msg);
+
+ data->hc_msg = dbus_message_ref(msg);
+ return NULL;
+}
+
+static void gemalto_smso_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessage *reply;
+
+ if (data->hc_msg == NULL)
+ return;
+
+ if (data->conn != GEMALTO_CONNECTION_SERIAL)
+ goto finished;
+
+ if (data->mdm)
+ g_at_chat_unref(data->mdm);
+ data->mdm = NULL;
+
+ if (data->app)
+ g_at_chat_unref(data->app);
+ data->app = NULL;
+
+ if (ok)
+ ofono_modem_set_powered(modem, FALSE);
+
+finished:
+ reply = dbus_message_new_method_return(data->hc_msg);
+ __ofono_dbus_pending_reply(&data->hc_msg, reply);
+}
+
+static DBusMessage *hc_shutdown(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ if (data->hc_msg != NULL)
+ return __ofono_error_busy(msg);
+
+ if (!g_at_chat_send(data->app, "AT^SMSO", none_prefix,
+ gemalto_smso_cb, modem, NULL))
+ return __ofono_error_failed(msg);
+
+ data->hc_msg = dbus_message_ref(msg);
+ return NULL;
+}
+
+static void gemalto_detect_sysstart(GAtResult *result, gpointer user_data);
+
+static void gemalto_reset_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ DBusMessage *reply;
+
+ if (data->hc_msg == NULL)
+ return;
+
+ if (data->conn != GEMALTO_CONNECTION_SERIAL)
+ goto finished;
+
+ data->modem_ready_id = g_at_chat_register(data->app,
+ "^SYSSTART", gemalto_detect_sysstart, FALSE,
+ modem, NULL);
+
+finished:
+ reply = dbus_message_new_method_return(data->hc_msg);
+ __ofono_dbus_pending_reply(&data->hc_msg, reply);
+}
+
+static DBusMessage *hc_reset(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ if (data->hc_msg != NULL)
+ return __ofono_error_busy(msg);
+
+ if (!g_at_chat_send(data->app, "AT+CFUN=1,1", none_prefix,
+ gemalto_reset_cb, modem, NULL))
+ return __ofono_error_failed(msg);
+
+ data->hc_msg = dbus_message_ref(msg);
+ return NULL;
+}
+
+static const GDBusMethodTable hardware_control_methods[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ hc_get_properties) },
+ { GDBUS_ASYNC_METHOD("SetProperty",
+ GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
+ NULL, hc_set_property) },
+ { GDBUS_ASYNC_METHOD("Shutdown",
+ NULL, NULL, hc_shutdown) },
+ { GDBUS_ASYNC_METHOD("Reset",
+ NULL, NULL, hc_reset) },
+ { }
+};
+
+static void gemalto_hardware_control_enable(struct ofono_modem *modem)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(modem);
+
+ /* Create Hardware Control DBus interface */
+ if (!g_dbus_register_interface(conn, path, HARDWARE_CONTROL_INTERFACE,
+ hardware_control_methods,
+ NULL,
+ NULL,
+ modem,
+ NULL)) {
+ ofono_error("Could not register %s interface under %s",
+ HARDWARE_CONTROL_INTERFACE, path);
+ return;
+ }
+
+ ofono_modem_add_interface(modem, HARDWARE_CONTROL_INTERFACE);
+}
+
+/*******************************************************************************
+ * modem plugin
+ ******************************************************************************/
+
+#ifdef HAVE_ELL
+static int mbim_parse_descriptors(struct gemalto_data *md, const char *file)
+{
+ void *data;
+ size_t len;
+ const struct mbim_desc *desc = NULL;
+ const struct mbim_extended_desc *ext_desc = NULL;
+
+ data = l_file_get_contents(file, &len);
+ if (!data)
+ return -EIO;
+
+ if (!mbim_find_descriptors(data, len, &desc, &ext_desc)) {
+ l_free(data);
+ return -ENOENT;
+ }
+
+ if (desc)
+ md->max_segment = L_LE16_TO_CPU(desc->wMaxControlMessage);
+
+ if (ext_desc)
+ md->max_outstanding = ext_desc->bMaxOutstandingCommandMessages;
+
+ l_free(data);
+ return 0;
+}
+
+static int mbim_probe(struct ofono_modem *modem, struct gemalto_data *data)
+{
+ const char *descriptors;
+ int err;
+
+ descriptors = gemalto_get_string(modem, "DescriptorFile");
+
+ if (!descriptors)
+ return -EINVAL;
+
+ data->max_outstanding = 1;
+
+ err = mbim_parse_descriptors(data, descriptors);
+ if (err < 0) {
+ DBG("Warning, unable to load descriptors, setting defaults");
+ data->max_segment = 512;
+ }
+
+ DBG("MaxSegment: %d, MaxOutstanding: %d",
+ data->max_segment, data->max_outstanding);
+
+ return 0;
+}
+#endif
+
+static int gemalto_probe(struct ofono_modem *modem)
+{
+ struct gemalto_data *data;
+
+ data = g_try_new0(struct gemalto_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+#ifdef HAVE_ELL
+ mbim_probe(modem, data);
+#endif
+
+ ofono_modem_set_data(modem, data);
+
+ return 0;
+}
+
+static void gemalto_remove(struct ofono_modem *modem)
+{
+ struct gemalto_data *data;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path;
+
+ if (!modem)
+ return;
+
+ data = ofono_modem_get_data(modem);
+ path = ofono_modem_get_path(modem);
+
+ if (!data)
+ return;
+
+#ifdef HAVE_ELL
+ if (data->mbim == STATE_PRESENT) {
+ mbim_device_shutdown(data->device);
+ }
+#endif
+
+ if (data->qmi == STATE_PRESENT) {
+ qmi_device_unref(data->device);
+ }
+
+ if (data->app) {
+ /* Cleanup potential SIM state polling */
+ at_util_sim_state_query_free(data->sim_state_query);
+ data->sim_state_query = NULL;
+
+ g_at_chat_cancel_all(data->app);
+ g_at_chat_unregister_all(data->app);
+ g_at_chat_unref(data->app);
+ data->app = NULL;
+ }
+
+ if (data->mdm) {
+ g_at_chat_cancel_all(data->app);
+ g_at_chat_unregister_all(data->mdm);
+ g_at_chat_unref(data->mdm);
+ data->mdm = NULL;
+ }
+
+ if (conn && path) {
+ if (g_dbus_unregister_interface(conn, path,
+ HARDWARE_MONITOR_INTERFACE))
+ ofono_modem_remove_interface(modem,
+ HARDWARE_MONITOR_INTERFACE);
+
+ if (g_dbus_unregister_interface(conn, path,
+ CINTERION_LEGACY_HWMON_INTERFACE))
+ ofono_modem_remove_interface(modem,
+ CINTERION_LEGACY_HWMON_INTERFACE);
+
+ if (g_dbus_unregister_interface(conn, path,
+ GEMALTO_NITZ_TIME_INTERFACE))
+ ofono_modem_remove_interface(modem,
+ GEMALTO_NITZ_TIME_INTERFACE);
+
+ if (g_dbus_unregister_interface(conn, path,
+ COMMAND_PASSTHROUGH_INTERFACE))
+ ofono_modem_remove_interface(modem,
+ COMMAND_PASSTHROUGH_INTERFACE);
+
+ if (g_dbus_unregister_interface(conn, path,
+ GNSS_INTERFACE))
+ ofono_modem_remove_interface(modem,
+ GNSS_INTERFACE);
+
+ if (g_dbus_unregister_interface(conn, path,
+ HARDWARE_CONTROL_INTERFACE))
+ ofono_modem_remove_interface(modem,
+ HARDWARE_CONTROL_INTERFACE);
+ }
+
+ //if (data->conn == GEMALTO_CONNECTION_SERIAL)
+ // return;
+
+ ofono_modem_set_data(modem, NULL);
+ g_free(data);
+}
+
+static void sim_ready_cb(gboolean present, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ struct ofono_sim *sim = data->sim;
+
+ at_util_sim_state_query_free(data->sim_state_query);
+ data->sim_state_query = NULL;
+
+ DBG("sim present: %d", present);
+
+ ofono_sim_inserted_notify(sim, present);
+}
+
+static void gemalto_ciev_simstatus_notify(GAtResultIter *iter,
+ struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ struct ofono_sim *sim = data->sim;
+ int status;
+
+ DBG("sim status %d", status);
+
+ if (!g_at_result_iter_next_number(iter, &status))
+ return;
+
+ switch (status) {
+ /* SIM is removed from the holder */
+ case 0:
+ ofono_sim_inserted_notify(sim, FALSE);
+ break;
+
+ /* SIM is inserted inside the holder */
+ case 1:
+ /* The SIM won't be ready yet */
+ data->sim_state_query = at_util_sim_state_query_new(data->app,
+ 1, 20, sim_ready_cb, modem,
+ NULL);
+ break;
+
+ /* USIM initialization completed. UE has finished reading USIM data. */
+ case 5:
+ ofono_sim_initialized_notify(sim);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void gemalto_ciev_nitz_notify(GAtResultIter *iter,
+ struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ const char *nitz_data;
+ char buf[32];
+
+ /* Example: +CIEV: nitz,<time>,<timezone>,<daylight> */
+ if (!g_at_result_iter_next_string(iter, &nitz_data))
+ return;
+
+ DBG("nitz_data %s", nitz_data);
+
+ sprintf(buf, "AT+CCLK=\"%s\"", nitz_data);
+ g_at_chat_send(data->app, buf, none_prefix, NULL, NULL, NULL);
+
+ gemalto_signal(GEMALTO_NITZ_TIME_INTERFACE, "NitzUpdated", nitz_data,
+ modem);
+}
+
+static void gemalto_ciev_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+
+ const char *sim_status = "simstatus";
+ const char *nitz_status = "nitz";
+ const char *ind_str;
+ GAtResultIter iter;
+
+ g_at_result_iter_init(&iter, result);
+
+ /* Example: +CIEV: simstatus,<status> */
+ if (!g_at_result_iter_next(&iter, "+CIEV:"))
+ return;
+
+ if (!g_at_result_iter_next_unquoted_string(&iter, &ind_str))
+ return;
+
+ if (g_str_equal(sim_status, ind_str)) {
+ gemalto_ciev_simstatus_notify(&iter, modem);
+ } else if (g_str_equal(nitz_status, ind_str)) {
+ gemalto_ciev_nitz_notify(&iter, modem);
+ }
+}
+
+static void sim_state_cb(gboolean present, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ at_util_sim_state_query_free(data->sim_state_query);
+ data->sim_state_query = NULL;
+
+ data->have_sim = present;
+ ofono_modem_set_powered(modem, TRUE);
+
+ /* Register for specific sim status reports */
+ g_at_chat_register(data->app, "+CIEV:",
+ gemalto_ciev_notify, FALSE, modem, NULL);
+
+ g_at_chat_send(data->app, "AT^SIND=\"simstatus\",1", none_prefix,
+ NULL, NULL, NULL);
+ g_at_chat_send(data->app, "AT^SIND=\"nitz\",1", none_prefix,
+ NULL, NULL, NULL);
+}
+
+static void gemalto_exit_urc_notify(GAtResult *result, gpointer user_data)
+{
+ GAtResultIter iter;
+ const char *error_message;
+
+ g_at_result_iter_init(&iter, result);
+ g_at_result_iter_next(&iter, "^EXIT:");
+ g_at_result_iter_next_unquoted_string(&iter, &error_message);
+ ofono_error("Modem exited! Cause: %s", error_message);
+}
+
+static void saic_probe(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct gemalto_data *data = ofono_modem_get_data(user_data);
+
+ if (ok)
+ data->voice_avail = TRUE;
+ else
+ data->voice_avail = FALSE;
+}
+
+static void sgauth_probe(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct gemalto_data *data = ofono_modem_get_data(user_data);
+
+ if (ok)
+ data->auth_syntax = GEMALTO_AUTH_USE_SGAUTH |
+ GEMALTO_AUTH_ORDER_PWD_USR;
+ else
+ data->auth_syntax = GEMALTO_AUTH_DEFAULTS;
+}
+
+static void gemalto_set_cfun_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ if (!ok || data->cfun == 41) {
+ g_at_chat_cancel_all(data->app);
+ ofono_modem_set_powered(modem, FALSE);
+ } else {
+ data->sim_state_query = at_util_sim_state_query_new(data->app,
+ 2, 20, sim_state_cb, modem, NULL);
+ }
+}
+
+static void gemalto_cfun_query(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(user_data);
+ char buf[256];
+ GAtResultIter iter;
+ int mode;
+
+ sprintf(buf, "AT+CFUN=%d", data->cfun==41?4:data->cfun);
+
+ if (!ok)
+ goto error;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CFUN:"))
+ goto error;
+
+ if (!g_at_result_iter_next_number(&iter, &mode))
+ goto error;
+
+ if (mode == data->cfun)
+ sprintf(buf, "AT");
+
+error:
+ if (g_at_chat_send(data->app, buf, none_prefix, gemalto_set_cfun_cb,
+ modem, NULL) > 0)
+ return;
+
+ if (data->cfun == 41)
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static void gemalto_set_cfun(GAtChat *app, int mode, struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ data->cfun=mode;
+ g_at_chat_send(app, "AT+CFUN?", cfun_prefix, gemalto_cfun_query, modem, NULL);
+}
+
+static void gemalto_initialize(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ char *urcdest;
+ guint m = data->model;
+
+ DBG("app:%d, mdm:%d, mbim:%d, qmi:%d",
+ data->app!=NULL,
+ data->mdm!=NULL,
+ data->mbim == STATE_PRESENT,
+ data->qmi == STATE_PRESENT);
+
+ if (!data->app && !data->mdm) {
+ DBG("no AT interface available. Removing this device.");
+ ofono_modem_set_powered(modem, FALSE);
+ return;
+ }
+
+ urcdest = "AT^SCFG=\"URC/DstIfc\",\"app\"";
+
+ if (!data->app) {
+ data->use_mdm_for_app = TRUE;
+ data->app = data->mdm;
+ urcdest = "AT^SCFG=\"URC/DstIfc\",\"mdm\"";
+ }
+
+ if (!data->mdm && (data->gina == STATE_PRESENT)) {
+ /*these modems can start PPP from any port*/
+ data->mdm = data->app;
+ }
+
+ if (data->mdm && data->gprs_opt == NO_GPRS)
+ data->gprs_opt = USE_PPP;
+
+ g_at_chat_set_wakeup_command(data->app, "AT\r", 1000, 5000);
+
+ g_at_chat_send(data->app, "ATE0", none_prefix, NULL, NULL, NULL);
+
+ if (data->gina != STATE_PRESENT)
+ g_at_chat_send(data->app, urcdest, none_prefix, NULL, NULL,
+ NULL);
+
+ /* numeric error codes are interpreted by atmodem/atutil.c functions */
+ g_at_chat_send(data->app, "AT+CMEE=1", none_prefix, NULL, NULL, NULL);
+
+ if (data->mdm)
+ g_at_chat_send(data->mdm, "AT&C0", none_prefix, NULL, NULL,
+ NULL);
+
+ g_at_chat_send(data->app, "AT&C0", none_prefix, NULL, NULL, NULL);
+
+ /* watchdog */
+ g_at_chat_register(data->app, "^EXIT", gemalto_exit_urc_notify, FALSE,
+ modem, NULL);
+ ofono_devinfo_create(modem, OFONO_VENDOR_GEMALTO, "atmodem", data->app);
+ g_at_chat_send(data->app,
+ "AT^SCFG=\"MEopMode/PwrSave\",\"enabled\",52,50", none_prefix,
+ NULL, NULL, NULL);
// this command was in some gemalto.c versions, but it would better be
// placed in one of the configuration files
+
+ if (m != 0x5b && m != 0x5c && m != 0x5d && m != 0xa0) {
+ g_at_chat_send(data->app, "AT^SGAUTH?", NULL, sgauth_probe,
+ modem, NULL);
+ }
+
+ g_at_chat_send(data->app, "AT^SAIC?", NULL, saic_probe, modem, NULL);
+
+ gemalto_exec_stored_cmd(modem, "enable");
+
+ gemalto_command_passthrough_enable(modem);
+ gemalto_hardware_monitor_enable(modem);
+ gemalto_time_enable(modem);
+ gemalto_gnss_enable(modem);
+ gemalto_hardware_control_enable(modem);
+
+ gemalto_set_cfun(data->app, 4, modem);
+ data->init_done = TRUE;
+}
+
+static gboolean gemalto_open_cb(GIOChannel *source, GIOCondition condition,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ GAtSyntax *syntax;
+
+ if (data->channel == NULL)
+ return TRUE;
+
+ if ((condition & G_IO_IN) == 0)
+ return TRUE;
+
+ g_source_remove(data->probing_timer);
+ data->probing_timer = 0;
+ g_source_remove(data->read_src);
+ g_io_channel_flush(data->channel, NULL);
+ /* reset channel defaults*/
+ g_io_channel_set_buffered(data->channel, TRUE);
+ g_io_channel_set_encoding(data->channel, "UTF-8", NULL);
+
+ syntax = g_at_syntax_new_gsm_permissive();
+ data->tmp_chat = g_at_chat_new(data->channel, syntax);
+ g_at_syntax_unref(syntax);
+
+ if (data->tmp_chat == NULL)
+ goto failed;
+
+ g_io_channel_unref(data->channel);
+ data->channel = NULL;
+ g_at_chat_set_debug(data->tmp_chat, gemalto_debug, "App: ");
+ data->open_cb(TRUE, modem);
+ return TRUE; // finished
+failed:
+ DBG("chat creation failed. aborting.");
+ g_io_channel_unref(data->channel);
+ data->channel = NULL;
+ DBG("aborted.");
+ data->open_cb(FALSE, modem);
+ return FALSE; // abort
+}
+
+static int gemalto_probe_device(void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ GIOStatus status;
+
+ if (data->channel==NULL)
+ return FALSE;
+
+ data->waiting_time++;
+ DBG("%d/%d", data->waiting_time, data->init_waiting_time);
+
+ if (data->waiting_time > data->init_waiting_time) {
+ data->waiting_time = 0;
+ goto failed;
+ }
+
+ status = g_io_channel_write_chars(data->channel, "AT\r", 3, NULL, NULL);
+
+ if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
+ goto failed;
+
+ return TRUE; // to be called again
+
+failed:
+ g_source_remove(data->probing_timer);
+ data->probing_timer = 0; /* remove the timer reference */
+ DBG("timeout: abort");
+ g_io_channel_unref(data->channel);
+ data->channel = NULL;
+ data->tmp_chat = NULL;
+ data->open_cb(FALSE, modem);
+ return FALSE; // abort
+}
+
+#include <asm/ioctls.h>
+#include <linux/serial.h>
+
+int ioctl(int, int, void *);
// these are temporarily in the middle. Discussed with Denis,
// maybe these and their use below is better placed in g_at_tty_open
+
+static void gemalto_open_device(const char *device,
+ OpenResultFunc func, struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ GHashTable *options;
+ int fd;
+ struct serial_struct old, new;
+
+ if (!device || !*device) {
+ func(FALSE, modem);
+ return;
+ }
+
+ options = g_hash_table_new(g_str_hash, g_str_equal);
+ if (options == NULL) {
+ func(FALSE, modem);
+ return;
+ }
+
+ g_hash_table_insert(options, "Baud", "115200");
+ g_hash_table_insert(options, "StopBits", "1");
+ g_hash_table_insert(options, "DataBits", "8");
+ g_hash_table_insert(options, "Parity", "none");
+ g_hash_table_insert(options, "XonXoff", "off");
+ g_hash_table_insert(options, "RtsCts", "on");
+ g_hash_table_insert(options, "Local", "on");
+ g_hash_table_insert(options, "Read", "on");
+
+ DBG("Opening device %s", device);
+
+ data->channel = g_at_tty_open(device, options);
+ g_hash_table_destroy(options);
+
+ if (!data->channel) {
+ func(FALSE, modem);
+ return;
+ }
+
+ fd = g_io_channel_unix_get_fd(data->channel);
+ ioctl(fd, TIOCGSERIAL, &old);
+ new = old;
+ new.closing_wait = ASYNC_CLOSING_WAIT_NONE;
+ ioctl(fd, TIOCSSERIAL, &new);
// without this, even if the g_at_tty_open sets the port non-blocking,
// it waits anyway 30 seconds if the port is not responding.
+
+ g_io_channel_flush(data->channel, NULL);
+ /* the channel is set by default to "UTF-8" and buffered */
+ g_io_channel_set_encoding(data->channel, NULL, NULL);
+ g_io_channel_set_buffered(data->channel, FALSE);
+ data->open_cb = func;
+ data->read_src = g_io_add_watch(data->channel, G_IO_IN, gemalto_open_cb,
+ modem);
+ data->probing_timer = g_timeout_add_seconds(1, gemalto_probe_device,
+ modem);
+}
// the 3 functions above:
// - open the channel as usual
// - test the port with AT once per second until timeout. Maybe this can be an
// additional wakeup function in GAtChat
// - attach a GAtChat to it or close it
+
+static void gemalto_enable_mdm_cb(gboolean success, struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ data->mdm = data->tmp_chat;
+ data->tmp_chat = NULL;
+ gemalto_initialize(modem);
+}
+
+static void gemalto_enable_app_cb(gboolean success, struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ const char *mdm = gemalto_get_string(modem, "Modem");
+
+ data->app = data->tmp_chat;
+ data->tmp_chat = NULL;
+ gemalto_open_device(mdm, gemalto_enable_mdm_cb, modem);
+}
+
+static int gemalto_enable_app(struct ofono_modem *modem)
+{
+ const char *app = gemalto_get_string(modem, "Application");
+
+ gemalto_open_device(app, gemalto_enable_app_cb, modem);
+ return -EINPROGRESS;
+}
+
+#ifdef HAVE_ELL
+static void mbim_device_caps_info_cb(struct mbim_message *message, void *user)
+{
+ struct ofono_modem *modem = user;
+ struct gemalto_data *md = ofono_modem_get_data(modem);
+ uint32_t device_type;
+ uint32_t cellular_class;
+ uint32_t voice_class;
+ uint32_t sim_class;
+ uint32_t data_class;
+ uint32_t sms_caps;
+ uint32_t control_caps;
+ uint32_t max_sessions;
+ char *custom_data_class;
+ char *device_id;
+ char *firmware_info;
+ char *hardware_info;
+ bool r;
+
+ if (mbim_message_get_error(message) != 0)
+ goto error;
+
+ r = mbim_message_get_arguments(message, "uuuuuuuussss",
+ &device_type, &cellular_class,
+ &voice_class, &sim_class, &data_class,
+ &sms_caps, &control_caps, &max_sessions,
+ &custom_data_class, &device_id,
+ &firmware_info, &hardware_info);
+ if (!r)
+ goto error;
+
+ md->max_sessions = max_sessions;
+
+ DBG("DeviceId: %s", device_id);
+ DBG("FirmwareInfo: %s", firmware_info);
+ DBG("HardwareInfo: %s", hardware_info);
+
+ ofono_modem_set_string(modem, "DeviceId", device_id);
+ ofono_modem_set_string(modem, "FirmwareInfo", firmware_info);
+
+ l_free(custom_data_class);
+ l_free(device_id);
+ l_free(firmware_info);
+ l_free(hardware_info);
+
+ message = mbim_message_new(mbim_uuid_basic_connect,
+ MBIM_CID_DEVICE_SERVICE_SUBSCRIBE_LIST,
+ MBIM_COMMAND_TYPE_SET);
+
+ mbim_message_set_arguments(message, "av", 2,
+ "16yuuuuuuu",
+ mbim_uuid_basic_connect, 6,
+ MBIM_CID_SUBSCRIBER_READY_STATUS,
+ MBIM_CID_RADIO_STATE,
+ MBIM_CID_REGISTER_STATE,
+ MBIM_CID_PACKET_SERVICE,
+ MBIM_CID_SIGNAL_STATE,
+ MBIM_CID_CONNECT,
+ "16yuuuu", mbim_uuid_sms, 3,
+ MBIM_CID_SMS_CONFIGURATION,
+ MBIM_CID_SMS_READ,
+ MBIM_CID_SMS_MESSAGE_STORE_STATUS);
+
+ if (mbim_device_send(md->device, 0, message,
+ NULL, NULL, NULL)) {
+ md->mbim = STATE_PRESENT;
+ goto other_devices;
+ }
+
+
+error:
+ mbim_device_shutdown(md->device);
+
+other_devices:
+
+ if (md->init_done)
+ return;
+
+ gemalto_enable_app(modem); /* continue with mdm interface */
+}
+
+static void mbim_device_ready(void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *md = ofono_modem_get_data(modem);
+ struct mbim_message *message =
+ mbim_message_new(mbim_uuid_basic_connect,
+ 1, MBIM_COMMAND_TYPE_QUERY);
+
+ mbim_message_set_arguments(message, "");
+ mbim_device_send(md->device, 0, message, mbim_device_caps_info_cb,
+ modem, NULL);
+}
+
+static void mbim_device_closed(void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *md = ofono_modem_get_data(modem);
+
+ if (!md)
+ return;
+
+ /*
+ * if state=probe, it means that we are in the init phase
+ * and that we have failed the MBIM_OPEN
+ */
+ if (md->mbim == STATE_PROBE) {
+ DBG(REDCOLOR"MBIM OPEN failed!"NOCOLOR);
+ gemalto_enable_app(modem); /* continue with other interfaces */
+ }
+
+ /* reset the state for future attempts */
+ md->mbim = STATE_PROBE;
+
+ if(md->device)
+ mbim_device_unref(md->device);
+
+ md->device = NULL;
+}
+
+static int mbim_enable(struct ofono_modem *modem)
+{
+ const char *device;
+ int fd;
+ struct gemalto_data *md = ofono_modem_get_data(modem);
+
+ DBG("modem struct: %p", modem);
+
+ device = gemalto_get_string(modem, "NetworkControl");
+ if (!device)
+ goto other_devices;
+
+ DBG("modem device: %s", device);
+ fd = open(device, O_EXCL | O_NONBLOCK | O_RDWR);
+
+ if (fd < 0)
+ goto other_devices;
+
+ DBG("device: %s opened successfully", device);
+ md->device = mbim_device_new(fd, md->max_segment);
+ DBG("created new device %p", md->device);
+
+ mbim_device_set_close_on_unref(md->device, true);
+ mbim_device_set_max_outstanding(md->device, md->max_outstanding);
+ mbim_device_set_ready_handler(md->device,
+ mbim_device_ready, modem, NULL);
+ mbim_device_set_disconnect_handler(md->device,
+ mbim_device_closed, modem, NULL);
+ mbim_device_set_debug(md->device, gemalto_debug, "MBIM:", NULL);
+
+ return -EINPROGRESS;
+
+other_devices:
+
+ if (md->init_done)
+ return 0;
+
+ return gemalto_enable_app(modem);
+}
+#endif
+
+static void qmi_enable_cb(void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *md = ofono_modem_get_data(modem);
+ md->qmi = STATE_PRESENT;
+ gemalto_enable_app(modem); /* qmi done, continue with app interface */
+}
+
+static int qmi_enable(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ const char *device;
+ int fd;
+
+ DBG("modem struct: %p", modem);
+
+ device = gemalto_get_string(modem, "NetworkControl");
+ if (!device)
+ return gemalto_enable_app(modem);
+
+ fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0)
+ return gemalto_enable_app(modem);
+
+ data->device = qmi_device_new(fd);
+ if (!data->device) {
+ close(fd);
+ return gemalto_enable_app(modem);
+ }
+
+ qmi_device_set_close_on_unref(data->device, true);
+
+ qmi_device_set_debug(data->device, gemalto_debug, "QMI: ");
+
+ qmi_device_discover(data->device, qmi_enable_cb, modem, NULL);
+
+ return -EINPROGRESS;
+}
+
+static void set_from_model(struct gemalto_data *data) {
+ guint m = data->model;
+
+ data->has_lte = TRUE; /* default */
+
+ /* pre-configure non-MBIM network interfaces */
+ if (m != 0x62 && m != 0x5d && m != 0x65) {
+ /*
+ * note: we probe for ECM/NCM even if the port is not present
+ * (for serial connection type or serial-like)
+ */
+ if (m == 0x53 || m == 0x60 || m == 0x63)
+ data->qmi = STATE_PROBE;
+ /*these families have PPP only*/
+ else if (m != 0x58 && m != 0x47 && m != 0x54)
+ data->ecmncm = STATE_PROBE;
+ }
+
+ /* pre-configure SW features */
+ if (m == 0xa0) {
+ data->gprs_opt = USE_CTX3;
+ data->ecmncm = STATE_ABSENT;
+ }
+ if (m == 0x63 || m == 0x65 || m == 0x5b || m == 0x5c || m == 0x5d)
+ data->gina = STATE_PRESENT;
+
+ data->init_waiting_time = 30;
+
+ if (m == 0x55 || m == 0x47) {
+ data->has_lte = FALSE;
+ data->init_waiting_time = 5;
+ }
+
+ if (m == 0x58) {
+ data->has_lte = FALSE;
+ data->init_waiting_time = 15;
+ }
+
+ data->vts_with_quotes = TRUE;
+
+ if (m == 0x5b || m == 0x5c || m == 0x5d || m == 0xa0) {
+ data->vts_with_quotes = FALSE;
+ data->auth_syntax = GEMALTO_AUTH_USE_SGAUTH |
+ GEMALTO_AUTH_ALWAYS_ALL_PARAMS;
+ }
+}
+
+static void store_cgmm(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+ char const *model;
+ char buf[16];
+
+ /* if no model, fallback to a basic 2G one */
+ data->model = 0x47;
+ strncpy(data->modelstr, "", sizeof(data->modelstr));
+
+ if (!ok)
+ return;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, NULL)) {
+ if (!g_at_result_iter_next_unquoted_string(&iter, &model))
+ continue;
+
+ if (model && *model) {
+ strncpy(data->modelstr, model, sizeof(data->modelstr));
+
+ if (g_ascii_strncasecmp(model, "TC", 2) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "MC", 2) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "AC", 2) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "HC", 2) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "HM", 2) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "XT", 2) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "AGS", 3) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "BGS", 3) == 0)
+ data->model = 0x47;
+ else if (g_ascii_strncasecmp(model, "AH3", 3) == 0)
+ data->model = 0x55;
+ else if (g_ascii_strncasecmp(model, "AHS", 3) == 0)
+ data->model = 0x55;
+ else if (g_ascii_strncasecmp(model, "PHS", 3) == 0)
+ data->model = 0x55;
+ else if (g_ascii_strncasecmp(model, "PH8", 3) == 0)
+ data->model = 0x55;
+ else if (g_ascii_strncasecmp(model, "AHS", 3) == 0)
+ data->model = 0x55;
+ else if (g_ascii_strncasecmp(model, "EHS", 3) == 0)
+ data->model = 0x58;
+ else if (g_ascii_strncasecmp(model, "ELS31-", 6) == 0)
+ data->model = 0xa0;
+ else if (g_ascii_strncasecmp(model, "ELS61-", 6) == 0)
+ data->model = 0x5b;
+ else if (g_ascii_strncasecmp(model, "PLS62-", 6) == 0)
+ data->model = 0x5b;
+ else if (g_ascii_strncasecmp(model, "PLS8-", 5) == 0)
+ data->model = 0x61;
+ else if (g_ascii_strncasecmp(model, "ALS3-", 5) == 0)
+ data->model = 0x61;
+ else if (g_ascii_strncasecmp(model, "ALAS5-", 6) == 0)
+ data->model = 0x65;
+ return;
+ }
+ }
+
+ sprintf(buf, "%04x", data->model);
+ ofono_modem_set_string(modem, "Model", buf);
+}
+
+static void store_sqport(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+ char const *sqport;
+
+ /* in case of error, the port is of Modem type */
+ strncpy(data->sqport, "Modem", sizeof(data->sqport));
+
+ if (!ok)
+ goto done;
+
+ g_at_result_iter_init(&iter, result);
+
+ /* answer format: "^SQPORT: Application" */
+ if (!g_at_result_iter_next(&iter, "^SQPORT:"))
+ goto done;
+
+ if (!g_at_result_iter_next_unquoted_string(&iter, &sqport))
+ goto done;
+
+ if (!sqport || !*sqport)
+ goto done;
+
+ strncpy(data->sqport, sqport, sizeof(data->sqport));
+
+done:
+ /* select mdm, app or gina port type */
+ data->ecmncm = STATE_PROBE;
+
+ if (g_str_equal(sqport, "Modem")) {
+ data->mdm = data->app;
+ data->app = NULL;
+ data->ecmncm = STATE_ABSENT;
+ }
+
+ if ((*sqport >= '0' && *sqport <= '9'))
+ data->gina = STATE_PRESENT;
+
+ set_from_model(data);
+ gemalto_initialize(modem);
+}
+
+static void gemalto_detect_serial(gboolean success, struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ data->app = data->tmp_chat;
+ data->tmp_chat = NULL;
+
+ g_at_chat_send(data->app, "AT+CGMM", none_prefix, store_cgmm,
+ modem, NULL);
+ g_at_chat_send(data->app, "AT^SQPORT", sqport_prefix, store_sqport,
+ modem, NULL);
+}
+
+static void gemalto_detect_sysstart(GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ if (data->modem_ready_id) {
+ g_at_chat_unregister(data->app, data->modem_ready_id);
+ data->modem_ready_id = 0;
+ }
+
+ data->tmp_chat = data->app;
+ gemalto_detect_serial(TRUE, modem);
+}
+
+static int gemalto_enable_serial(struct ofono_modem *modem)
+{
+ const char *device = ofono_modem_get_string(modem, "ATport");
+
+ if (!device)
+ return -EINVAL;
+
+ gemalto_open_device(device, gemalto_detect_serial, modem);
+ return -EINPROGRESS;
+}
+
+static int gemalto_enable(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ const char *model = gemalto_get_string(modem, "Model"),
+ *conn_type = gemalto_get_string(modem, "ConnType");
+ const char
+ *ctl = gemalto_get_string(modem, "NetworkControl"),
+ *net = gemalto_get_string(modem, "NetworkInterface");
+ guint m = 0;
+
+ if (!modem || !data)
+ return -EINVAL;
+
+ data->conn = g_str_equal(conn_type,"Serial") ? GEMALTO_CONNECTION_SERIAL
+ : GEMALTO_CONNECTION_USB;
+
+ if (data->conn == GEMALTO_CONNECTION_SERIAL)
+ return gemalto_enable_serial(modem);
+
+ DBG("modem struct: %p, gemalto_data: %p", modem, data);
+
+ if (data->init_done) {
+ gemalto_set_cfun(data->app, 4, modem);
+
+#ifdef HAVE_ELL
+ if (data->mbim != STATE_ABSENT)
+ mbim_enable(modem);
+#endif
+
+ return -EINPROGRESS;
+ }
+
+ if (model) {
+ data->model = strtoul(model, NULL, 16);
+ m = data->model;
+ }
+
+ /* single ACM interface 02: assign application to modem */
+ if (m == 0xa0) {
+ const char *app = gemalto_get_string(modem, "Application");
+ ofono_modem_set_string(modem, "Modem", app);
+ }
+
+ if (m == 0x60) {
+ const char *app = gemalto_get_string(modem, "Diag");
+ ofono_modem_set_string(modem, "Modem", app);
+ }
+
+ /* if single ACM interface, remove possible extra devices */
+ if (m == 0x58 || m == 0x47 || m == 0x54 || m == 0xa0 || m == 0x60) {
+ ofono_modem_set_string(modem, "Application", NULL);
+ ofono_modem_set_string(modem, "GNSS", NULL);
+ ofono_modem_set_string(modem, "RSA", NULL);
+ ofono_modem_set_string(modem, "Diag", NULL);
+ }
+
+#ifdef HAVE_ELL
+ /* pre-configure MBIM network interface */
+ if (m == 0x62 || m == 0x5d || m == 0x65) {
+ data->mbim = STATE_PROBE;
+ }
+#endif
+
+ set_from_model(data);
+
+#ifdef HAVE_ELL
+ if ((data->mbim == STATE_PROBE) && ctl && net) {
+ data->init_waiting_time = 3;
+ return mbim_enable(modem);
+ }
+#endif
+
+ if ((data->qmi == STATE_PROBE) && ctl && net) {
+ data->init_waiting_time = 10;
+ return qmi_enable(modem);
+ }
+
+ return gemalto_enable_app(modem);
+}
+
+#ifdef HAVE_ELL
+static int mbim_sim_probe(void *device)
+{
+ struct mbim_message *message;
+ /* SIM_GROUP is defined in mbimmodem.h that cannot be included */
+ uint32_t SIM_GROUP = 1;
+
+ message = mbim_message_new(mbim_uuid_basic_connect,
+ MBIM_CID_SUBSCRIBER_READY_STATUS,
+ MBIM_COMMAND_TYPE_QUERY);
+ if (!message)
+ return -ENOMEM;
+
+ mbim_message_set_arguments(message, "");
+
+ if (!mbim_device_send(device, SIM_GROUP, message,
+ NULL, NULL, NULL)) {
+ mbim_message_unref(message);
+ return -EIO;
+ }
+ return 0;
+}
+#endif
+
+static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_modem_online_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ cb(&error, cbd->data);
+}
+
+static void gemalto_set_online_serial(struct ofono_modem *modem,
+ ofono_bool_t online, ofono_modem_online_cb_t cb,
+ void *user_data)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+ char const *command;
+
+ gemalto_exec_stored_cmd(modem, "set_online");
+
+ if (data->model == 0x47) {
+ command = online ? "AT^SCFG=\"MEopMode/Airplane\",\"off\"" :
+ "AT^SCFG=\"MEopMode/Airplane\",\"on\"";
+ } else {
+ command = online ? "AT+CFUN=1" : "AT+CFUN=4";
+ }
+
+ DBG("modem %p %s", modem, online ? "online" : "offline");
+
+ if (g_at_chat_send(data->app, command, NULL, set_online_cb, cbd,
+ g_free))
+ return;
+
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ g_free(cbd);
+}
+
+static void gemalto_set_online(struct ofono_modem *modem, ofono_bool_t online,
+ ofono_modem_online_cb_t cb, void *user_data)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+ char const *cmd = online ? "AT+CFUN=1" : "AT+CFUN=4";
+
+ if (data->conn == GEMALTO_CONNECTION_SERIAL) {
+ gemalto_set_online_serial(modem, online, cb, user_data);
+ return;
+ }
+
+ DBG("modem %p %s", modem, online ? "online" : "offline");
+
+ if (g_at_chat_send(data->app, cmd, NULL, set_online_cb, cbd, g_free))
+ return;
+
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+ g_free(cbd);
+}
+
+static void gemalto_pre_sim(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ gemalto_exec_stored_cmd(modem, "pre_sim");
+
+ ofono_location_reporting_create(modem, 0, "gemaltomodem", data->app);
+
+ data->sim = ofono_sim_create(modem, OFONO_VENDOR_GEMALTO,
+ "atmodem", data->app);
+
+ if (data->sim && data->have_sim == TRUE)
+ ofono_sim_inserted_notify(data->sim, TRUE);
+}
+
+static void gemalto_post_sim(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ gemalto_exec_stored_cmd(modem, "post_sim");
+
+#ifdef HAVE_ELL
+ if (data->mbim == STATE_PRESENT) {
+ /* very important to set the interface ready */
+ mbim_sim_probe(data->device);
+ }
+#endif
+
+ ofono_phonebook_create(modem, 0, "atmodem", data->app);
+ ofono_modem_set_integer(modem, "GemaltoAuthType", data->auth_syntax);
+
+ if (data->has_lte)
+ ofono_lte_create(modem, 0, "gemaltomodem", data->app);
+}
+
+static void cgdcont17_probe(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct gemalto_data *data = ofono_modem_get_data(user_data);
+
+ if (ok)
+ data->gprs_opt = USE_CTX17;
+}
+
+static void swwan_probe(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct gemalto_data *data = ofono_modem_get_data(user_data);
+
+ if (ok)
+ data->gprs_opt = USE_SWWAN;
+}
+
+static void autoattach_probe_and_continue(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem* modem = user_data;
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+ struct ofono_message_waiting *mw;
+ struct ofono_gprs *gprs = NULL;
+ struct ofono_gprs_context *gc = NULL;
+
+ data->autoattach = FALSE;
+ ofono_modem_set_integer(modem, "GemaltoAutoAttach", 0);
+
+ if (ok) {
+ g_at_result_iter_init(&iter, result);
+ while (g_at_result_iter_next(&iter, NULL)) {
+ if (strstr(g_at_result_iter_raw_line(&iter),
+ "\"enabled\"")) {
+ data->autoattach = TRUE;
+ ofono_modem_set_integer(modem,
+ "GemaltoAutoAttach", 1);
+
+ }
+ }
+ }
+
+ // TODO: the ofono_gprs_create may require gemaltomodem instead of atmodem
// for now this code works with a modified version of atmodem/gprs.c,
// where the ofono_gprs_set_cid_range is not called, so it can be called below
+
+#ifdef HAVE_ELL
+ if (data->mbim == STATE_PRESENT) {
+ gprs = ofono_gprs_create(modem, OFONO_VENDOR_GEMALTO, "atmodem",
+ data->app);
+ ofono_gprs_set_cid_range(gprs, 0, data->max_sessions);
+ if (data->model == 0x62 || data->model == 0x65) {
+ struct gemalto_mbim_composite comp;
+ comp.device = data->device;
+ comp.chat = data->app;
+ comp.at_cid = 4;
+ gc = ofono_gprs_context_create(modem, 0, "gemaltomodemmbim", &comp);
+ } else /* model == 0x5d */
+ gc = ofono_gprs_context_create(modem, 0, "mbim", data->device);
+ } else
+#endif
+ if (data->qmi == STATE_PRESENT) {
+ gprs = ofono_gprs_create(modem, OFONO_VENDOR_GEMALTO, "atmodem",
+ data->app);
+ // TODO: verify if need be to create the contexts and auth params beforehand
+ // if so, may need a gprs-context gemaltomodem-at-qmi
+
+ /* on QMI devices, only a single context is supported */
+ // TODO: Is 1 ok for attach_APN != context_APN?
+ ofono_gprs_set_cid_range(gprs, 1, 1);
+ gc = ofono_gprs_context_create(modem, 0, "qmimodem",
+ data->device);
+ } else if (data->gprs_opt == USE_SWWAN || data->gprs_opt == USE_CTX17 ||
+ data->gprs_opt == USE_CTX3) {
+ ofono_modem_set_integer(modem, "GemaltoWwan",
+ data->gprs_opt == USE_SWWAN);
+ gprs = ofono_gprs_create(modem, OFONO_VENDOR_GEMALTO, "atmodem",
+ data->app);
+ if (data->gprs_opt == USE_CTX3)
+ ofono_gprs_set_cid_range(gprs, 3, 3);
+ else if (data->model == 0x5b)
+ /*
+ * limitation: same APN as for attach
+ * in this case create more contexts
+ */
+ ofono_gprs_set_cid_range(gprs, 1, 11);
+ else
+ ofono_gprs_set_cid_range(gprs, 4, 16);
+ // maybe rename the next to gemaltomodem-wwan
+ gc = ofono_gprs_context_create(modem, 0, "gemaltomodemswwan",
+ data->app);
+ } else if (data->gprs_opt == USE_PPP) {
+ /* plain PPP only works from mdm ports */
+ gprs = ofono_gprs_create(modem, OFONO_VENDOR_GEMALTO, "atmodem",
+ data->app);
+ if (data->model == 0x47)
+ ofono_gprs_set_cid_range(gprs, 1, 2);
+ else if (data->has_lte)
+ ofono_gprs_set_cid_range(gprs, 4, 16);
+ else
+ ofono_gprs_set_cid_range(gprs, 1, 16);
+
+ gc = ofono_gprs_context_create(modem, 0, "atmodem", data->mdm);
+
+ } /*
+ * in case of no match above, we have no gprs possibilities
+ * this is common when using the module through serial interfaces
+ * nevertheless other services (voice, gpio, gnss) could be available
+ */
+
+ if (gc)
+ ofono_gprs_context_set_type(gc,
+ OFONO_GPRS_CONTEXT_TYPE_INTERNET);
+
+ if (gprs && gc)
+ ofono_gprs_add_context(gprs, gc);
+
+ /* might have also without voicecall support */
+ ofono_ussd_create(modem, 0, "atmodem", data->app);
+
+ /*
+ * Call support is technically possible only after sim insertion
+ * with the module online. However the EMERGENCY_SETUP procedure of
+ * the 3GPP TS_24.008 is triggered by the same AT command,
+ * and namely 'ATD112;', 'ATD911;', etc.
+ * On the other hand, in airplane-mode it is not possible to do it, nor
+ * to create all relevant URCs for the atom.
+ *
+ * Ofono does not make a distinction between no-sim and
+ * airplane-mode scenarios, so we create the voicecall in post-online.
+ * This is half-compatible with the European directives that require
+ * a SIM inserted also for emergency setup.
+ */
// this needs further thinking
+
+ if (data->voice_avail) {
+ ofono_modem_set_integer(modem, "GemaltoVtsQuotes",
+ data->vts_with_quotes);
+ ofono_voicecall_create(modem, 0, "gemaltomodem", data->app);
+
+ ofono_call_forwarding_create(modem, 0, "atmodem", data->app);
+ ofono_call_settings_create(modem, 0, "atmodem", data->app);
+ ofono_call_meter_create(modem, 0, "atmodem", data->app);
+ ofono_call_barring_create(modem, 0, "atmodem", data->app);
+ }
+
+ /* modules require to be online to accept at+cnmi */
+ ofono_sms_create(modem, OFONO_VENDOR_GEMALTO, "atmodem", data->app);
+ mw = ofono_message_waiting_create(modem);
+
+ if (mw)
+ ofono_message_waiting_register(mw);
+
+ ofono_netreg_create(modem, OFONO_VENDOR_GEMALTO, "atmodem", data->app);
+}
+
+static int gemalto_post_online_delayed(void *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ /*
+ * check module capabilities once online and SIM really ready.
+ *
+ * Note: the g_at_chat_send calls only insert the commands in a list:
+ * they are not executed synchronously
+ *
+ * Note: ofono executes each AT commands and the related callback before
+ * proceeding with the next. So continuing on the last AT command is all
+ * it takes
+ */
+
+ gemalto_exec_stored_cmd(modem, "post_online");
+
+ if (data->ecmncm == STATE_PROBE) {
+ data->gprs_opt = USE_PPP; /* fallback */
+ g_at_chat_send(data->app, "AT+CGDCONT=17", NULL,
+ cgdcont17_probe, modem, NULL);
+ g_at_chat_send(data->app, "AT^SWWAN?", NULL, swwan_probe, modem,
+ NULL);
+ }
+
+ g_at_chat_send(data->app, "AT^SCFG=\"GPRS/AutoAttach\"", NULL,
+ autoattach_probe_and_continue, modem, NULL);
+
+ return FALSE; /* to kill the timer */
+}
+
+static void gemalto_post_online(struct ofono_modem *modem)
+{
+ /*
+ * in this version of ofono we must wait for SIM 'really-ready'
+ * can be avoided when capturing the right URCs
// waiting for the URC (like '+PBREADY') is anyway not risk-free
// because if ofono is started when the module is already initialized
// the URC is missing, and on some models cannot be queried.
// This needs further thinking.
+ */
+ g_timeout_add_seconds(5, gemalto_post_online_delayed, modem);
+}
+
+#ifdef HAVE_ELL
+static void mbim_radio_off_for_disable(struct mbim_message *message, void *user)
+{
+ struct ofono_modem *modem = user;
+ struct gemalto_data *md = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ mbim_device_shutdown(md->device);
+}
+#endif
+
+static int gemalto_disable_serial(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+
+ if (data->app != NULL) {
+ if (data->model == 0x47) {
+ g_at_chat_send(data->app,
+ "AT^SCFG=\"MEopMode/Airplane\",\"on\"",
+ NULL, NULL, NULL, NULL);
+ } else {
+ gemalto_set_cfun(data->app, 41, modem);
+ return -EINPROGRESS;
+ }
+ g_at_chat_cancel_all(data->app);
+ }
+
+ ofono_modem_set_powered(modem, FALSE);
+ return 0;
+}
+
+static int gemalto_disable(struct ofono_modem *modem)
+{
+ struct gemalto_data *data = ofono_modem_get_data(modem);
+#ifdef HAVE_ELL
+ struct mbim_message *message;
+#endif
+
+ DBG("%p", modem);
+
+ if (data->conn == GEMALTO_CONNECTION_SERIAL)
+ return gemalto_disable_serial(modem);
+
+#ifdef HAVE_ELL
+ if (data->mbim == STATE_PRESENT) {
+ message = mbim_message_new(mbim_uuid_basic_connect,
+ MBIM_CID_RADIO_STATE,
+ MBIM_COMMAND_TYPE_SET);
+ mbim_message_set_arguments(message, "u", 0);
+
+ if (mbim_device_send(data->device, 0, message,
+ mbim_radio_off_for_disable, modem, NULL)==0)
+ mbim_device_closed(modem);
+ }
+#endif
+
+ if (data->app == NULL)
+ return 0;
+
+ gemalto_exec_stored_cmd(modem, "disable");
+
+ gemalto_set_cfun(data->app, 41, modem);
+
+ return -EINPROGRESS;
+}
+
+static struct ofono_modem_driver gemalto_driver = {
+ .name = "gemalto",
+ .probe = gemalto_probe,
+ .remove = gemalto_remove,
+ .enable = gemalto_enable,
+ .disable = gemalto_disable,
+ .set_online = gemalto_set_online,
+ .pre_sim = gemalto_pre_sim,
+ .post_sim = gemalto_post_sim,
+ .post_online = gemalto_post_online,
+};
+
+static int gemalto_init(void)
+{
+ return ofono_modem_driver_register(&gemalto_driver);
+}
+
+static void gemalto_exit(void)
+{
+ ofono_modem_driver_unregister(&gemalto_driver);
+}
+
+OFONO_PLUGIN_DEFINE(gemalto, "Gemalto modem plugin", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, gemalto_init, gemalto_exit)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 3c39e681..6c82eb81 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2018 Gemalto M2M
*
* 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
@@ -979,20 +980,6 @@ static gboolean setup_serial_modem(struct modem_info* modem)
return TRUE;
}
-static gboolean setup_tc65(struct modem_info* modem)
-{
- ofono_modem_set_driver(modem->modem, "cinterion");
-
- return setup_serial_modem(modem);
-}
-
-static gboolean setup_ehs6(struct modem_info* modem)
-{
- ofono_modem_set_driver(modem->modem, "cinterion");
-
- return setup_serial_modem(modem);
-}
-
static gboolean setup_ifx(struct modem_info* modem)
{
struct serial_device_info* info;
@@ -1121,60 +1108,133 @@ static gboolean setup_ublox(struct modem_info *modem)
static gboolean setup_gemalto(struct modem_info* modem)
{
- const char *app = NULL, *gps = NULL, *mdm = NULL,
- *net = NULL, *qmi = NULL;
+ const char *mdm = NULL, *app = NULL, *gnss = NULL, *rsa = NULL,
+ *diag = NULL,
+ *ctl = NULL, *net = NULL, *net2 = NULL;
+ char descriptors[PATH_MAX];
+ guint m;
+ const char *prevNet = NULL;
GSList *list;
- DBG("%s", modem->syspath);
+ DBG("type:%d, syspath:%s [%s:%s]", modem->type, modem->syspath,
+ modem->vendor, modem->model);
+
+ if (modem->type==MODEM_TYPE_SERIAL) {
+ struct serial_device_info* info = modem->serial;
+ ofono_modem_set_string(modem->modem, "ConnType", "Serial");
+ ofono_modem_set_string(modem->modem, "ATport", info->devnode);
+ ofono_modem_set_string(modem->modem, "Vendor", "gemalto");
+ ofono_modem_set_string(modem->modem, "Model", "0000");
+ return TRUE;
+
+ }
+
+ m = strtoul(modem->model, NULL, 16);
+ /* map devices */
for (list = modem->devices; list; list = list->next) {
struct device_info *info = list->data;
- DBG("%s %s %s %s %s", info->devnode, info->interface,
- info->number, info->label, info->subsystem);
-
- /* PHS8-P */
- if (g_strcmp0(info->interface, "255/255/255") == 0) {
- if (g_strcmp0(info->number, "01") == 0)
- gps = info->devnode;
- else if (g_strcmp0(info->number, "02") == 0)
- app = info->devnode;
- else if (g_strcmp0(info->number, "03") == 0)
- mdm = info->devnode;
- else if (g_strcmp0(info->subsystem, "net") == 0)
- net = info->devnode;
- else if (g_strcmp0(info->subsystem, "usbmisc") == 0)
- qmi = info->devnode;
+ DBG("node:%s, sub:%s, interface:%s, number:%s, sysattr:%s",
+ info->devnode, info->subsystem, info->interface,
+ info->number, info->sysattr);
+
+ if (g_str_equal(info->subsystem,"tty")) {
+ /* option devices (ttyUSBx) */
+ /* note: option devices order in VMs under windows may vary */
+ if (g_str_equal(info->interface, "255/255/255") ||
+ g_str_equal(info->interface, "255/66/1") ||
+ g_str_equal(info->interface, "255/0/0")) {
+ if (g_str_equal(info->number, "00")) {
+ app = info->devnode;
+ } else if (g_str_equal(info->number, "01")) {
+ gnss = rsa = info->devnode;
+ } else if (g_str_equal(info->number, "02")) {
+ diag = info->devnode;
+ } else if (g_str_equal(info->number, "03")) {
+ mdm = info->devnode;
+ }
+ /* cdc-acm devices (ttyACMx) */
+ } else if (g_str_equal(info->interface,"2/2/0") ||
+ g_str_equal(info->interface,"2/2/1")) {
+ if (g_str_equal(info->number, "00")) {
+ mdm = info->devnode;
+ } else if (g_str_equal(info->number, "02")) {
+ app = info->devnode;
+ } else if (g_str_equal(info->number, "04")) {
+ gnss = info->devnode;
+ } else if (g_str_equal(info->number, "06")) {
+ rsa = info->devnode;
+ } else if (g_str_equal(info->number, "08")) {
+ diag = info->devnode;
+ }
+ }
}
- /* Cinterion ALS3, PLS8-E, PLS8-X */
- if (g_strcmp0(info->interface, "2/2/1") == 0) {
- if (g_strcmp0(info->number, "00") == 0)
- mdm = info->devnode;
- else if (g_strcmp0(info->number, "02") == 0)
- app = info->devnode;
- else if (g_strcmp0(info->number, "04") == 0)
- gps = info->devnode;
- }
- if (g_strcmp0(info->interface, "2/6/0") == 0) {
- if (g_strcmp0(info->subsystem, "net") == 0)
- net = info->devnode;
+ if (g_str_equal(info->subsystem,"usbmisc"))
+ /* control device for qmi/mbim: /dev/cdc-wdmX */
+ ctl = info->devnode;
+
+ /* network interfaces */
+ if (g_str_equal(info->subsystem,"net")) {
+ /* cdc-mbim */
+ if (g_str_equal(info->interface,"2/14/0") ||
+ /* qmi-wwan */
+ g_str_equal(info->interface,"255/255/255")) {
+ net = info->devnode; /* wwanX */
+ /* cdc-ecm */
+ } else if (g_str_equal(info->interface, "2/6/0") ||
+ /* cdc-ncm */
+ g_str_equal(info->interface, "2/13/0")) {
+ /*
+ * there could be 2 interfaces in this case,
+ * and need to have them sorted to be sure to
+ * report the right interface to activate
+ */
+ if (!prevNet ||
+ g_strcmp0(info->number,prevNet)<0) {
+ prevNet = info->number;
+ net2 = net; /* can be NULL, ok */
+ net = info->devnode; /* usbX */
+ } else { // invert
+ net2 = info->devnode; /* usbX */
// not sure this logic of sorting the network interfaces is needed
// but I don't see another way of being sure of having them in order
+ }
+ }
}
}
- DBG("application=%s gps=%s modem=%s network=%s qmi=%s",
- app, gps, mdm, net, qmi);
+ sprintf(descriptors, "%s/descriptors", modem->syspath);
+ ofono_modem_set_string(modem->modem, "ConnType", "Usb");
+ ofono_modem_set_string(modem->modem, "DescriptorFile", descriptors);
+ ofono_modem_set_string(modem->modem, "Vendor", modem->vendor);
+ ofono_modem_set_string(modem->modem, "Model", modem->model);
- if (app == NULL || mdm == NULL)
- return FALSE;
+ /*
+ * special cases.
+ * TODO: selected by external parameters:
+ * GEMALTO_CONFIG_MBIM_ONLY -> _set_driver(modem->modem, "mbim");
+ * GEMALTO_CONFIG_QMI_ONLY -> _set_driver(modem->modem, "gobi");
+ * ...
+ */
+ if (m==0x64) {
+ ofono_modem_set_string(modem->modem, "Device", ctl);
+ ofono_modem_set_string(modem->modem, "NetworkInterface", net);
+ ofono_modem_set_driver(modem->modem, "mbim");
+ return TRUE;
+ }
- ofono_modem_set_string(modem->modem, "Application", app);
- ofono_modem_set_string(modem->modem, "GPS", gps);
ofono_modem_set_string(modem->modem, "Modem", mdm);
- ofono_modem_set_string(modem->modem, "Device", qmi);
- ofono_modem_set_string(modem->modem, "Model", modem->model);
+ ofono_modem_set_string(modem->modem, "Application", app);
+ ofono_modem_set_string(modem->modem, "GNSS", gnss);
+ ofono_modem_set_string(modem->modem, "RSA", rsa);
+ ofono_modem_set_string(modem->modem, "Diag", diag);
+
+ ofono_modem_set_string(modem->modem, "NetworkControl", ctl);
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
+ ofono_modem_set_string(modem->modem, "NetworkInterface2", net2);
+
+ ofono_modem_set_powered_timeout_hint(modem->modem, 60);
return TRUE;
}
@@ -1290,7 +1350,7 @@ static struct {
{ "quectel", setup_quectel },
{ "quectelqmi", setup_quectelqmi},
{ "ublox", setup_ublox },
- { "gemalto", setup_gemalto },
+ { "gemalto", setup_gemalto, "device/interface" },
{ "xmm7xxx", setup_xmm7xxx },
{ "mbim", setup_mbim },
/* Following are non-USB modems */
@@ -1298,12 +1358,12 @@ static struct {
{ "u8500", setup_isi_serial },
{ "n900", setup_isi_serial },
{ "calypso", setup_serial_modem },
- { "cinterion", setup_serial_modem },
+ { "cinterion", setup_gemalto },
{ "nokiacdma", setup_serial_modem },
{ "sim900", setup_serial_modem },
{ "wavecom", setup_wavecom },
- { "tc65", setup_tc65 },
- { "ehs6", setup_ehs6 },
+ { "tc65", setup_gemalto },
+ { "ehs6", setup_gemalto },
{ }
};
@@ -1464,11 +1524,10 @@ static void add_serial_device(struct udev_device *dev)
struct udev_device* mdev;
const char* driver;
+ /* discard if the device doesn't have the property OFONO_DRIVER */
mdev = get_serial_modem_device(dev);
- if (!mdev) {
- DBG("Device is missing required OFONO_DRIVER property");
+ if (!mdev)
// separate commit to remove this polluting message. On some systems
// it can emit the line 256 times.
// By default a typical linux distro presents 64 ttySx ports, so even if a
// few are used, there are too many unneeded notifications.
return;
- }
driver = udev_device_get_property_value(mdev, "OFONO_DRIVER");
@@ -1674,11 +1733,13 @@ static struct {
{ "ublox", "cdc_acm", "1546", "1102" },
{ "ublox", "rndis_host", "1546", "1146" },
{ "ublox", "cdc_acm", "1546", "1146" },
- { "gemalto", "option", "1e2d", "0053" },
- { "gemalto", "cdc_wdm", "1e2d", "0053" },
- { "gemalto", "qmi_wwan", "1e2d", "0053" },
- { "gemalto", "cdc_acm", "1e2d", "0061" },
- { "gemalto", "cdc_ether", "1e2d", "0061" },
+ { "gemalto", "cdc_acm", "1e2d" },
+ { "gemalto", "option", "1e2d" },
+ { "gemalto", "cdc_wdm", "1e2d" },
+ { "gemalto", "qmi_wwan", "1e2d" },
+ { "gemalto", "cdc_ether", "1e2d", },
+ { "gemalto", "cdc_mbim", "1e2d", },
+ { "gemalto", "cdc_ncm", "1e2d", },
{ "telit", "cdc_ncm", "1bc7", "0036" },
{ "telit", "cdc_acm", "1bc7", "0036" },
{ "xmm7xxx", "cdc_acm", "8087" },
@@ -1708,6 +1769,7 @@ static void check_usb_device(struct udev_device *device)
vendor = udev_device_get_property_value(usb_device, "ID_VENDOR_ID");
model = udev_device_get_property_value(usb_device, "ID_MODEL_ID");
+ /* for serial2usb-like devices, enum as usb/usb_device */
// separate commit or discard
driver = udev_device_get_property_value(usb_device, "OFONO_DRIVER");
if (!driver) {
struct udev_device *usb_interface =
@@ -1719,7 +1781,17 @@ static void check_usb_device(struct udev_device *device)
usb_interface, "OFONO_DRIVER");
}
- if (driver == NULL) {
+ if (!driver)
+ {
+ /* for serial2usb devices (enum as tty/generic) */
+ const char *serialdriver =
+ udev_device_get_property_value(device, "OFONO_DRIVER");
+ DBG("vId=%s, pId=%s, driver=%s", vendor, model, serialdriver);
+ if (serialdriver)
+ add_serial_device(device);
+ }
// separate commit to match the devices connected through an FDMI chip
+
+ if (!driver) { /* use linux driver */
const char *drv;
unsigned int i;
@@ -1772,6 +1844,7 @@ static void check_usb_device(struct udev_device *device)
static void check_device(struct udev_device *device)
{
const char *bus;
+ const char *ofono_ignore_device;
bus = udev_device_get_property_value(device, "ID_BUS");
if (bus == NULL) {
@@ -1780,6 +1853,11 @@ static void check_device(struct udev_device *device)
return;
}
+ ofono_ignore_device = udev_device_get_property_value(device,
+ "OFONO_IGNORE_DEVICE");
+ if (ofono_ignore_device)
+ return; /* skip this device */
+
// separate commit to ignore some devices
if ((g_str_equal(bus, "usb") == TRUE) ||
(g_str_equal(bus, "usbmisc") == TRUE))
check_usb_device(device);
--
2.17.1
2 years, 4 months
[PATCH] udev: enhance udev detection for intel 7xxx modems
by Nandini Rebello
Handle newer 7xxx modem enumeration based on ProductId.
Preserving the previous gen support too.
---
plugins/udevng.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 11338f7..e9f16e8 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1193,13 +1193,24 @@ static gboolean setup_xmm7xxx(struct modem_info *modem)
info->interface, info->number, info->label,
info->sysattr, info->subsystem);
- if (g_strcmp0(info->subsystem, "tty") == 0) {
- if (g_strcmp0(info->number, "02") == 0)
- mdm = info->devnode;
- } else if (g_strcmp0(info->subsystem, "net") == 0) {
- if (g_strcmp0(info->number, "00") == 0)
- net = info->devnode;
+ if (g_strcmp0(modem->model,"095a") == 0) {
+ if (g_strcmp0(info->subsystem, "tty") == 0) {
+ if (g_strcmp0(info->number, "00") == 0)
+ mdm = info->devnode;
+ } else if (g_strcmp0(info->subsystem, "net") == 0) {
+ if (g_strcmp0(info->number, "06") == 0)
+ net = info->devnode;
+ }
}
+ else {
+ if (g_strcmp0(info->subsystem, "tty") == 0) {
+ if (g_strcmp0(info->number, "02") == 0)
+ mdm = info->devnode;
+ } else if (g_strcmp0(info->subsystem, "net") == 0) {
+ if (g_strcmp0(info->number, "00") == 0)
+ net = info->devnode;
+ }
+ }
}
if (mdm == NULL || net == NULL)
--
2.7.4
2 years, 4 months
[PATCH] udev: udpate udev to detect new 7xxx modems
by Nandini Rebello
Newer intel modems enumerate with different subsystem numbers,
adding code to detect newer 7xxx modules.
Plan to add patch for backward compatibility of intels modems soon,
to based on interface number instead of subsystem name string.
---
plugins/udevng.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 11338f7..bf0b1c4 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1194,10 +1194,10 @@ static gboolean setup_xmm7xxx(struct modem_info *modem)
info->sysattr, info->subsystem);
if (g_strcmp0(info->subsystem, "tty") == 0) {
- if (g_strcmp0(info->number, "02") == 0)
+ if (g_strcmp0(info->number, "00") == 0)
mdm = info->devnode;
} else if (g_strcmp0(info->subsystem, "net") == 0) {
- if (g_strcmp0(info->number, "00") == 0)
+ if (g_strcmp0(info->number, "06") == 0)
net = info->devnode;
}
}
--
2.7.4
2 years, 4 months
[PATCH 0/6] Driver registration rework
by Jonas Bonn
Hi Denis,
Since I don't know if you'd even be interested in a series like this,
here's a draft that touches just a few places to give you an idea of
where this would take us... take a look and let me know what you think.
/Jonas
******
ofono has historically had a system in place whereby modems are
encapsulated as 'plugins', the idea being that these could be loosely
coupled to the core and added/removed flexibly as requirements changed.
Theoretically, the plugin would register a set of new drivers (atoms)
with the core and then call ofono_modem_register(...) after having
configured the modem object appropriately (device node, etc). In
practice, however, this does not work well and the modem plugins don't
really follow this model.
- drivers (atoms) use a lot of core functionality and cannot be built
externally using only the exported ofono headers. As such, the
drivers really need to be part of core ofono, irregardless of whether
they are packed into separate modules (plugins) or linked into one
monolithici mage
- ofono no longer provides the ability to built the plugins in the
source tree as external libs; they are all linked into one monolithic
image by default with no option to change this
- the modem 'plugins' are 99% modem driver and 1% plugin; the plugin bit
just takes care of registering the modem driver with the core and does
nothing else
- udevng takes care of setting up the modem objects and binding them
with their drivers
This patch series tries to addres this in the following way:
i) Add driver registration macros that lift registration with the core
into init() (constructor) functions; this allows the drivers to
automatically be registered at startup or on module load if they happen
be part of a plugin
ii) Move the 'modem driver' part of the modem plugins into the drivers/
directory.
iii) If the plugins are doing nothing other than registering the modem
driver, drop it altogether.
Jonas Bonn (6):
include: add macros for declaring drivers
qmimodem: simplify driver registration
gobi: modem driver cannot be a plugin
atmodem: add missing headers to atutil.h
telitmodem: simplify driver registration
telitmodem: modem driver is not a plugin
Makefile.am | 12 ++----
drivers/atmodem/atutil.h | 3 ++
{plugins => drivers/qmimodem}/gobi.c | 13 +------
drivers/qmimodem/gprs-context.c | 10 +----
drivers/qmimodem/location-reporting.c | 10 +----
drivers/qmimodem/qmimodem.c | 4 --
drivers/qmimodem/qmimodem.h | 6 ---
drivers/telitmodem/gprs-context-ncm.c | 15 +-------
drivers/telitmodem/location-reporting.c | 16 ++------
{plugins => drivers/telitmodem}/telit.c | 15 +-------
drivers/telitmodem/telitmodem.c | 51 -------------------------
drivers/telitmodem/telitmodem.h | 27 -------------
include/gprs-context.h | 11 ++++++
include/location-reporting.h | 10 +++++
include/modem.h | 11 ++++++
15 files changed, 47 insertions(+), 167 deletions(-)
rename {plugins => drivers/qmimodem}/gobi.c (97%)
rename {plugins => drivers/telitmodem}/telit.c (97%)
delete mode 100644 drivers/telitmodem/telitmodem.c
delete mode 100644 drivers/telitmodem/telitmodem.h
--
2.17.1
2 years, 4 months
[PATCH 1/5] plugins/gemalto: vendor Gemalto on LTE atom
by Giacinto Cifelli
---
plugins/gemalto.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/gemalto.c b/plugins/gemalto.c
index 5d3c77a9..43d66eb5 100644
--- a/plugins/gemalto.c
+++ b/plugins/gemalto.c
@@ -610,7 +610,7 @@ static void gemalto_post_sim(struct ofono_modem *modem)
ofono_call_barring_create(modem, 0, "atmodem", data->app);
if (!g_strcmp0(model, GEMALTO_MODEL_ALS3_PLS8x))
- ofono_lte_create(modem, OFONO_VENDOR_CINTERION,
+ ofono_lte_create(modem, OFONO_VENDOR_GEMALTO,
"atmodem", data->app);
}
--
2.17.1
2 years, 4 months
[PATCH 0/9] Miscellaneous patches
by Jonas Bonn
This series is just some miscellaneous patches, addressing some compiler
warnings, etc. The patches are independent of each other.
/Jonas
Jonas Bonn (9):
test: use python3 for set-ddr
mbim: remove unused modem data
atmodem: enlarge command buffer
qmimodem: prevent use of unitialized variable
simutil: remove check for impossible condition
stkutil: remove test for impossible condition
huaweimodme: prevent use of uninitialized variable
atmodem: prevent use of uninitialized value
modem: global data is pre-zeroed
drivers/atmodem/sms.c | 2 +-
drivers/atmodem/ussd.c | 6 +++---
drivers/huaweimodem/ussd.c | 6 +++---
drivers/qmimodem/lte.c | 2 +-
plugins/udevng.c | 2 --
src/modem.c | 14 +++++++-------
src/simutil.c | 3 ---
src/stkutil.c | 3 ---
test/set-ddr | 2 +-
9 files changed, 16 insertions(+), 24 deletions(-)
--
2.17.1
2 years, 4 months
Re: [PATCH 7/9] huaweimodme: prevent use of uninitialized variable
by Giacinto Cifelli
Hi,
On Fri, Oct 26, 2018 at 12:45 PM Jonas Bonn <jonas(a)southpole.se> wrote:
>
>
> On 26/10/2018 12:32, Giacinto Cifelli wrote:
> > hi Jonas,
> >
> > On Fri, 26 Oct 2018, 12:13 Jonas Bonn, <jonas(a)norrbonn.se
> > <mailto:jonas@norrbonn.se>> wrote:
> >
> > From: Jonas Bonn <jonas(a)southpole.se <mailto:jonas@southpole.se>>
> >
> > Move initialization of 'dcs' ahead of 'content' fetch to prevent
> > uninitialized use.
> > ---
> > drivers/huaweimodem/ussd.c | 6 +++---
> > 1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/huaweimodem/ussd.c b/drivers/huaweimodem/ussd.c
> > index fbed3cd0..f4001108 100644
> > --- a/drivers/huaweimodem/ussd.c
> > +++ b/drivers/huaweimodem/ussd.c
> > @@ -62,12 +62,12 @@ static void cusd_parse(GAtResult *result, struct
> > ofono_ussd *ussd)
> > if (!g_at_result_iter_next_number(&iter, &status))
> > return;
> >
> > - if (!g_at_result_iter_next_string(&iter, &content))
> > - goto out;
> > -
> > if (!g_at_result_iter_next_number(&iter, &dcs))
> > dcs = 0;
> >
> > + if (!g_at_result_iter_next_string(&iter, &content))
> > + goto out;
> > +
> >
> >
> > aren't you changing the order of the parameters in the command response?
>
> Ah, of course. Good catch.
>
> Disregard this patch... it's not the right fix.
>
> > Have you tested this on an actual modem?
>
> Don't have one of these. This patch was addressing a compiler warning,
> but the fix is obviously wrong.
here and in patch 8/9 the it looks like you can get rid of the warning
by initializing the variable:
int dcs = 0;
>
> Thanks,
> Jonas
>
> >
> > msg_ptr = decode_hex_own_buf(content, -1, &msg_len, 0, msg);
> >
> > regards,
> > Giacinto
> >
Regards,
Giacinto
2 years, 4 months
[PATCH] doc/common-patterns.txt: initial version
by Giacinto Cifelli
---
doc/common-patterns.txt | 165 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 165 insertions(+)
create mode 100644 doc/common-patterns.txt
diff --git a/doc/common-patterns.txt b/doc/common-patterns.txt
new file mode 100644
index 00000000..dd615fcb
--- /dev/null
+++ b/doc/common-patterns.txt
@@ -0,0 +1,165 @@
+Every project has its own recursive patterns, and oFono is not an exception.
+This document describes the most common ones found in the code.
+
+
+How do callbacks work
+=====================
+Most of the time, the core atom for a given request calls a function in
+the atom, which generally executes some commands against the modem, and
+can then return the results to the core.
+
+For example:
+
+dbus call: lte/SetProperty(DefaultAPN)
+ |
+ v
+core: check APN validity, call the modem atom for execution in the modem
+ |
+ v
+atom: pipes for execution the command: AT+CGDCONT=0,"IP","MyNiceAPN"
+ |
+[ break in the flow: the functions return back to the core, the dbus request ]
+[ is not answered at this time ]
+ ...
+[GLibMain event loop schedules the command, it is executed, and modem answers]
+ |
+ v
+a callback function, registered along with the command, is now called
+ this processes the modem answers, and decides whether it is good or not
+ |
+ v
+a core callback function is now called. This was passed as an argument earlier,
+when the atom was called, along with some context data (opaque info for the
+atom, but would contain the reference to the modem, the dbus pending call, etc)
+ |
+ v
+the core can now answer the dbus message
+
+
+In the code, it looks like this:
+
+//core call:
+static DBusMessage *lte_set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_lte *lte = data;
+
+ /*
+ * a block of code here processes the msg and fills the
+ * lte->pending_info structure
+ */
+
+ lte->driver->set_default_attach_info(lte, <e->pending_info,
+ lte_set_default_attach_info_cb, lte);
+
+ return NULL;
+}
+// lte_set_default_attach_info_cb is the core callback function,
+// the lte structure is the parameter that it takes
+
+//atom:
+static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
+ const struct ofono_lte_default_attach_info *info,
+ ofono_lte_cb_t cb, void *data)
+{
+ struct lte_driver_data *ldd = ofono_lte_get_data(lte);
+
+ // next line creates a structure for the in-atom callback
+ struct cb_data *cbd = cb_data_new(cb, data);
+
+ if (g_at_chat_send(ldd->chat, "AT", NULL,
+ at_lte_set_default_attach_info_cb,
+ cbd, g_free) > 0)
+ return;
+
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+// here the structure is allocate dynamically, and since it is quite common,
+// the function g_at_chat_send accepts the last 3 parameters:
+// - in-atom callback function
+// - in-atom callback data
+// - release/disallocation function for dynamically-allocated callback data
+// NOTE: if g_at_chat_send fails, it does not free the memory, so it must be
+// done after the call.
+// Note also the callback to the core directly here if the g_at_chat_send fails.
+
+//atom callback:
+
+static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+
+ if (result == NULL) {
+ CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
+ return;
+ }
+
+ decode_at_error(&error, g_at_result_final_response(result));
+ cbd->cb(&error, cbd->data);
+}
+// note that here cbd must not be released, it will be done by the function
+// calling at_lte_set_default_attach_info_cb when it returns.
+// note also that the core function will be executed before cbd is released,
+// so the last line of the code is ok.
+
+
+use of the cb_data structure in the atoms
+=========================================
+
+the cb_data can be used by creating the structure with cb_data_new,
+and then there are two possibilities:
+- use it in a single callback function, and destroy it with a call to
+ g_free.
+ Example:
+ - calling function:
+ struct cb_data *cbd = cb_data_new(cb, data);
+ if (g_at_chat_send(chat, buf, NULL, at_cgatt_cb, cbd, g_free) > 0)
+ return;
+ g_free(cbd);
+ - called function (here at_cgatt_cb):
+ static void at_cgatt_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+ {
+ struct cb_data *cbd = user_data;
+ ofono_gprs_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error,
+ g_at_result_final_response(result));
+
+ cb(&error, cbd->data);
+ }
+ note the absence of explicit g_free(cbd);
+
+- pass it through a train of callback functions, adding a reference at
+ each pass cb_data_ref, and removing it with cb_data_unref.
+ the use of cb_data_ref would replace a new object creation, while the
+ use of cb_data_unref the use of g_free.
+ Example:
+ - calling function:
+ struct cb_data *cbd = cb_data_new(cb, data);
+ // no cb_ref at the creation
+ if (g_at_chat_send(chat, buf, NULL,
+ at_lte_set_default_attach_info_cb,
+ cbd, cb_data_unref) > 0)
+ goto end;
+ cb_data_unref(cbd);
+ - called function 1 (at_lte_set_default_attach_info_cb):
+ static void at_lte_set_default_attach_info_cb(gboolean ok,
+ GAtResult *result, gpointer user_data)
+ {
+ struct cb_data *cbd = user_data;
+
+ cbd = cb_data_ref(cbd);
+ if (g_at_chat_send(chat, buf, NULL,
+ at_cgatt_cb, cbd, cb_data_unref) > 0)
+ return;
+ cb_data_unref(cbd);
+ }
+ - called function 2 (at_cgatt_cb):
+ like above. no call to g_free or cb_data_unref. The terminal function
+ doesn't need to know about the reference scheme.
+
+
--
2.17.1
2 years, 4 months