From ccd49f3fe6c5454b2c58a6c9bf79a27b0dbe0007 Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Thu, 2 Feb 2017 15:09:26 +0100 Subject: [PATCH] plugins: rename xe910 to telit Unify old telit and xe910 plugins. Dropping support for Bluetooth SAP. Add support for UC864 family. --- Makefile.am | 7 +- plugins/telit.c | 558 ++++++++++++++++++------------------------------ plugins/xe910.c | 546 ---------------------------------------------- 3 files changed, 211 insertions(+), 900 deletions(-) delete mode 100644 plugins/xe910.c diff --git a/Makefile.am b/Makefile.am index 6bc8eee3..e1579745 100644 --- a/Makefile.am +++ b/Makefile.am @@ -493,8 +493,8 @@ builtin_sources += plugins/sim900.c builtin_modules += connman builtin_sources += plugins/connman.c -builtin_modules += xe910 -builtin_sources += plugins/xe910.c +builtin_modules += telit +builtin_sources += plugins/telit.c builtin_modules += quectel builtin_sources += plugins/quectel.c @@ -504,9 +504,6 @@ builtin_sources += plugins/ublox.c if BLUETOOTH if BLUEZ4 -builtin_modules += telit -builtin_sources += plugins/telit.c plugins/bluez4.h - builtin_modules += sap builtin_sources += plugins/sap.c plugins/bluez4.h diff --git a/plugins/telit.c b/plugins/telit.c index 392283aa..742e06c0 100644 --- a/plugins/telit.c +++ b/plugins/telit.c @@ -2,7 +2,7 @@ * * oFono - Open Source Telephony * - * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2008-2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -58,10 +59,39 @@ #include #include -#include "bluez4.h" - static const char *none_prefix[] = { NULL }; -static const char *rsen_prefix[]= { "#RSEN:", NULL }; +static const char *qss_prefix[] = { "#QSS:", NULL }; + +enum modem_model { + HE910 = 1, + UE910, + LE910, + UC864, +}; + +static struct { + enum modem_model model; + const char *variant; + gboolean has_voice; + gboolean has_gps; +} variants_list[] = { + { HE910, NULL, FALSE, FALSE }, + { HE910, "G", TRUE, TRUE }, + { HE910, "GL", TRUE, FALSE }, + { HE910, "EUR", TRUE, FALSE }, + { HE910, "NAR", TRUE, FALSE }, + { HE910, "DG", FALSE, TRUE }, + { HE910, "EUG", FALSE, TRUE }, + { HE910, "NAG", FALSE, TRUE }, + { UE910, NULL, FALSE, FALSE }, + { UE910, "EUR", TRUE, FALSE }, + { UE910, "NAR", TRUE, FALSE }, + { LE910, NULL, FALSE, FALSE }, + { UC864, NULL, TRUE, FALSE }, + { UC864, "G", TRUE, TRUE }, + { UC864, "WD", FALSE, FALSE }, + { } +}; struct telit_data { GAtChat *chat; /* AT chat */ @@ -69,11 +99,9 @@ struct telit_data { struct ofono_sim *sim; ofono_bool_t have_sim; ofono_bool_t sms_phonebook_added; - struct ofono_modem *sap_modem; - GIOChannel *bt_io; - GIOChannel *hw_io; - guint bt_watch; - guint hw_watch; + enum modem_model model; + gboolean has_voice; + gboolean has_gps; }; static void telit_debug(const char *str, void *user_data) @@ -83,102 +111,6 @@ static void telit_debug(const char *str, void *user_data) ofono_info("%s%s", prefix, str); } -static void sap_close_io(struct ofono_modem *modem) -{ - struct telit_data *data = ofono_modem_get_data(modem); - - if (data->bt_io != NULL) { - int sk = g_io_channel_unix_get_fd(data->bt_io); - shutdown(sk, SHUT_RDWR); - - g_io_channel_unref(data->bt_io); - data->bt_io = NULL; - } - - if (data->bt_watch > 0) - g_source_remove(data->bt_watch); - - g_io_channel_unref(data->hw_io); - data->hw_io = NULL; - - if (data->hw_watch > 0) - g_source_remove(data->hw_watch); -} - -static void bt_watch_remove(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct telit_data *data = ofono_modem_get_data(modem); - - ofono_modem_set_powered(modem, FALSE); - - data->bt_watch = 0; -} - -static gboolean bt_event_cb(GIOChannel *bt_io, GIOCondition condition, - gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct telit_data *data = ofono_modem_get_data(modem); - - if (condition & G_IO_IN) { - GIOStatus status; - gsize bytes_read, bytes_written; - gchar buf[300]; - - status = g_io_channel_read_chars(bt_io, buf, 300, - &bytes_read, NULL); - - if (bytes_read > 0) - g_io_channel_write_chars(data->hw_io, buf, - bytes_read, &bytes_written, NULL); - - if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) - return FALSE; - - return TRUE; - } - - return FALSE; -} - -static void hw_watch_remove(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct telit_data *data = ofono_modem_get_data(modem); - - ofono_modem_set_powered(modem, FALSE); - - data->hw_watch = 0; -} - -static gboolean hw_event_cb(GIOChannel *hw_io, GIOCondition condition, - gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct telit_data *data = ofono_modem_get_data(modem); - - if (condition & G_IO_IN) { - GIOStatus status; - gsize bytes_read, bytes_written; - gchar buf[300]; - - status = g_io_channel_read_chars(hw_io, buf, 300, - &bytes_read, NULL); - - if (bytes_read > 0) - g_io_channel_write_chars(data->bt_io, buf, - bytes_read, &bytes_written, NULL); - - if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) - return FALSE; - - return TRUE; - } - - return FALSE; -} - static GAtChat *open_device(struct ofono_modem *modem, const char *key, char *debug) { @@ -199,15 +131,13 @@ static GAtChat *open_device(struct ofono_modem *modem, return NULL; g_hash_table_insert(options, "Baud", "115200"); - channel = g_at_tty_open(device, options); - g_hash_table_destroy(options); if (channel == NULL) return NULL; - syntax = g_at_syntax_new_gsmv1(); + syntax = g_at_syntax_new_gsm_permissive(); chat = g_at_chat_new(channel, syntax); g_at_syntax_unref(syntax); g_io_channel_unref(channel); @@ -273,19 +203,46 @@ static void telit_qss_notify(GAtResult *result, gpointer user_data) switch_sim_state_status(modem, status); } +static void qss_query_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + int status, mode; + GAtResultIter iter; + + DBG("%p", modem); + + if (!ok) + return; + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "#QSS:")) + return; + + if (!g_at_result_iter_next_number(&iter, &mode)) + return; + + if (!g_at_result_iter_next_number(&iter, &status)) + return; + + switch_sim_state_status(modem, status); +} + static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_modem *modem = user_data; struct telit_data *data = ofono_modem_get_data(modem); - struct ofono_modem *m = data->sap_modem ? : modem; DBG("%p", modem); if (!ok) { g_at_chat_unref(data->chat); data->chat = NULL; - ofono_modem_set_powered(m, FALSE); - sap_close_io(modem); + + g_at_chat_unref(data->modem); + data->modem = NULL; + + ofono_modem_set_powered(modem, FALSE); return; } @@ -299,7 +256,7 @@ static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data) data->have_sim = FALSE; data->sms_phonebook_added = FALSE; - ofono_modem_set_powered(m, TRUE); + ofono_modem_set_powered(modem, TRUE); /* * Tell the modem not to automatically initiate auto-attach @@ -314,6 +271,103 @@ static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data) /* Enable sim state notification */ g_at_chat_send(data->chat, "AT#QSS=2", none_prefix, NULL, NULL, NULL); + + g_at_chat_send(data->chat, "AT#QSS?", qss_prefix, + qss_query_cb, modem, NULL); +} + +static gboolean find_model_variant(struct ofono_modem *modem, + const char * model_variant) +{ + struct telit_data *data = ofono_modem_get_data(modem); + char model[32]; + char variant[32]; + gchar **tokens; + int i; + + if (!model_variant || model_variant[0] == '\0') + return FALSE; + + DBG("%s", model_variant); + + tokens = g_strsplit(model_variant, "-", 2); + + if (!tokens || !tokens[0] || !tokens[1]) + return FALSE; + + g_strlcpy(model, tokens[0], sizeof(model)); + g_strlcpy(variant, tokens[1], sizeof(variant)); + g_strfreev(tokens); + + if (g_str_equal(model, "HE910")) + data->model = HE910; + else if (g_str_equal(model, "UE910")) + data->model = UE910; + else if (g_str_equal(model, "LE910")) + data->model = LE910; + else if (g_str_equal(model, "UC864")) + data->model = UC864; + else + return FALSE; + + DBG("Model: %s", model); + + for (i = 0; variants_list[i].model; i++) { + if (variants_list[i].model != data->model) + continue; + + /* Set model defaults */ + if (variants_list[i].variant == NULL) { + data->has_voice = variants_list[i].has_voice; + data->has_gps = variants_list[i].has_gps; + continue; + } + + /* Specific variant match */ + if (g_str_equal(variant, variants_list[i].variant)) { + DBG("Variant: %s", variant); + data->has_voice = variants_list[i].has_voice; + data->has_gps = variants_list[i].has_gps; + } + } + + return TRUE; +} + +static void cfun_gmm_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct telit_data *data = ofono_modem_get_data(modem); + const char * model_variant; + + DBG("%p", modem); + + if (!ok) + goto error; + + /* Get +GMM response */ + if (!at_util_parse_attr(result, "", &model_variant)) + goto error; + + /* Try to find modem model and variant */ + if (!find_model_variant(modem, model_variant)) { + ofono_info("Unknown xE910 model/variant %s", model_variant); + goto error; + } + + /* Set phone functionality */ + if (g_at_chat_send(data->chat, "AT+CFUN=1", none_prefix, + cfun_enable_cb, modem, NULL) > 0) + return; + +error: + g_at_chat_unref(data->chat); + data->chat = NULL; + + g_at_chat_unref(data->modem); + data->modem = NULL; + + ofono_modem_set_powered(modem, FALSE); } static int telit_enable(struct ofono_modem *modem) @@ -341,67 +395,23 @@ static int telit_enable(struct ofono_modem *modem) */ g_at_chat_send(data->chat, "ATE0 +CMEE=1", none_prefix, NULL, NULL, NULL); + g_at_chat_send(data->modem, "ATE0", none_prefix, + NULL, NULL, NULL); - /* - * Disable sim state notification so that we sure get a notification - * when we enable it again later and don't have to query it. - */ - g_at_chat_send(data->chat, "AT#QSS=0", none_prefix, NULL, NULL, NULL); - /* Set phone functionality */ - g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix, - cfun_enable_cb, modem, NULL); + /* Get modem model and variant */ + g_at_chat_send(data->chat, "AT+GMM", NULL, + cfun_gmm_cb, modem, NULL); + return -EINPROGRESS; } -static void telit_rsen_notify(GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct telit_data *data = ofono_modem_get_data(modem); - int status; - GAtResultIter iter; - - DBG("%p", modem); - - g_at_result_iter_init(&iter, result); - - if (!g_at_result_iter_next(&iter, "#RSEN:")) - return; - - g_at_result_iter_next_number(&iter, &status); - - if (status == 0) { - ofono_modem_set_powered(data->sap_modem, FALSE); - sap_close_io(modem); - return; - } - - telit_enable(modem); -} - -static void rsen_enable_cb(gboolean ok, GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct telit_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - if (!ok) { - ofono_modem_set_powered(data->sap_modem, FALSE); - sap_close_io(modem); - return; - } -} - static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_modem *modem = user_data; struct telit_data *data = ofono_modem_get_data(modem); - if(data->sap_modem) - modem = data->sap_modem; - DBG("%p", modem); g_at_chat_unref(data->chat); @@ -409,13 +419,12 @@ static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data) if (ok) ofono_modem_set_powered(modem, FALSE); - - data->sap_modem = NULL; } static int telit_disable(struct ofono_modem *modem) { struct telit_data *data = ofono_modem_get_data(modem); + DBG("%p", modem); g_at_chat_cancel_all(data->modem); @@ -427,211 +436,66 @@ static int telit_disable(struct ofono_modem *modem) g_at_chat_unregister_all(data->chat); /* Power down modem */ - g_at_chat_send(data->chat, "AT+CFUN=0", none_prefix, + g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix, cfun_disable_cb, modem, NULL); return -EINPROGRESS; } -static void rsen_disable_cb(gboolean ok, GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - - DBG("%p", modem); - - sap_close_io(modem); - - telit_disable(modem); -} - -static int telit_sap_open(void) -{ - const char *device = "/dev/ttyUSB4"; - struct termios ti; - int fd; - - DBG("%s", device); - - fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (fd < 0) - return -EINVAL; - - /* Switch TTY to raw mode */ - memset(&ti, 0, sizeof(ti)); - cfmakeraw(&ti); - - ti.c_cflag |= (B115200 | CLOCAL | CREAD); - - tcflush(fd, TCIOFLUSH); - if (tcsetattr(fd, TCSANOW, &ti) < 0) { - close(fd); - return -EBADF; - } - - return fd; -} - -static int telit_sap_enable(struct ofono_modem *modem, - struct ofono_modem *sap_modem, - int bt_fd) -{ - struct telit_data *data = ofono_modem_get_data(modem); - int fd; - - DBG("%p", modem); - - fd = telit_sap_open(); - if (fd < 0) - goto error; - - data->hw_io = g_io_channel_unix_new(fd); - if (data->hw_io == NULL) { - close(fd); - goto error; - } - - g_io_channel_set_encoding(data->hw_io, NULL, NULL); - g_io_channel_set_buffered(data->hw_io, FALSE); - g_io_channel_set_close_on_unref(data->hw_io, TRUE); - - data->bt_io = g_io_channel_unix_new(bt_fd); - if (data->bt_io == NULL) - goto error; - - g_io_channel_set_encoding(data->bt_io, NULL, NULL); - g_io_channel_set_buffered(data->bt_io, FALSE); - g_io_channel_set_close_on_unref(data->bt_io, TRUE); - - data->hw_watch = g_io_add_watch_full(data->hw_io, G_PRIORITY_DEFAULT, - G_IO_HUP | G_IO_ERR | G_IO_NVAL | G_IO_IN, - hw_event_cb, modem, hw_watch_remove); - - data->bt_watch = g_io_add_watch_full(data->bt_io, G_PRIORITY_DEFAULT, - G_IO_HUP | G_IO_ERR | G_IO_NVAL | G_IO_IN, - bt_event_cb, modem, bt_watch_remove); - - data->sap_modem = sap_modem; - - g_at_chat_register(data->chat, "#RSEN:", telit_rsen_notify, - FALSE, modem, NULL); - - g_at_chat_send(data->chat, "AT#NOPT=0", NULL, NULL, NULL, NULL); - - /* Set SAP functionality */ - g_at_chat_send(data->chat, "AT#RSEN=1,1,0,2,0", rsen_prefix, - rsen_enable_cb, modem, NULL); - - return -EINPROGRESS; - -error: - shutdown(bt_fd, SHUT_RDWR); - close(bt_fd); - - sap_close_io(modem); - return -EINVAL; -} - -static int telit_sap_disable(struct ofono_modem *modem) -{ - struct telit_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - g_at_chat_send(data->chat, "AT#RSEN=0", rsen_prefix, - rsen_disable_cb, modem, NULL); - - return -EINPROGRESS; -} - static void telit_pre_sim(struct ofono_modem *modem) { struct telit_data *data = ofono_modem_get_data(modem); - if (data->sap_modem) - modem = data->sap_modem; - DBG("%p", modem); ofono_devinfo_create(modem, 0, "atmodem", data->chat); data->sim = ofono_sim_create(modem, OFONO_VENDOR_TELIT, "atmodem", data->chat); - ofono_voicecall_create(modem, 0, "atmodem", data->chat); -} -static void telit_post_sim(struct ofono_modem *modem) -{ - struct telit_data *data = ofono_modem_get_data(modem); - struct ofono_gprs *gprs; - struct ofono_gprs_context *gc; - - if (data->sap_modem) - modem = data->sap_modem; - - DBG("%p", modem); - - gprs = ofono_gprs_create(modem, OFONO_VENDOR_TELIT, "atmodem", - data->chat); - gc = ofono_gprs_context_create(modem, 0, "atmodem", data->modem); - - if (gprs && gc) - ofono_gprs_add_context(gprs, gc); -} - -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 telit_set_online(struct ofono_modem *modem, ofono_bool_t online, - ofono_modem_online_cb_t cb, void *user_data) -{ - struct telit_data *data = ofono_modem_get_data(modem); - struct cb_data *cbd = cb_data_new(cb, user_data); - char const *command = online ? "AT+CFUN=1,0" : "AT+CFUN=4,0"; - - DBG("modem %p %s", modem, online ? "online" : "offline"); - - g_at_chat_send(data->chat, command, none_prefix, set_online_cb, - cbd, g_free); + if (data->has_gps) + ofono_location_reporting_create(modem, 0, "telitmodem", + data->chat); } static void telit_post_online(struct ofono_modem *modem) { struct telit_data *data = ofono_modem_get_data(modem); - struct ofono_message_waiting *mw; - - if(data->sap_modem) - modem = data->sap_modem; + struct ofono_gprs *gprs; + struct ofono_gprs_context *gc; DBG("%p", modem); ofono_netreg_create(modem, OFONO_VENDOR_TELIT, "atmodem", data->chat); - ofono_ussd_create(modem, 0, "atmodem", data->chat); - ofono_call_forwarding_create(modem, 0, "atmodem", data->chat); - ofono_call_settings_create(modem, 0, "atmodem", data->chat); - ofono_call_meter_create(modem, 0, "atmodem", data->chat); - ofono_call_barring_create(modem, 0, "atmodem", data->chat); - mw = ofono_message_waiting_create(modem); - if (mw) - ofono_message_waiting_register(mw); + if (data->has_voice) { + struct ofono_message_waiting *mw; + + ofono_voicecall_create(modem, 0, "atmodem", data->chat); + ofono_ussd_create(modem, 0, "atmodem", data->chat); + ofono_call_forwarding_create(modem, 0, "atmodem", data->chat); + ofono_call_settings_create(modem, 0, "atmodem", data->chat); + ofono_call_meter_create(modem, 0, "atmodem", data->chat); + ofono_call_barring_create(modem, 0, "atmodem", data->chat); + + mw = ofono_message_waiting_create(modem); + if (mw) + ofono_message_waiting_register(mw); + } + + gprs = ofono_gprs_create(modem, OFONO_VENDOR_TELIT, "atmodem", + data->chat); + + if (data->model == LE910) + gc = ofono_gprs_context_create(modem, OFONO_VENDOR_TELIT, + "telitncmmodem", data->modem); + else + gc = ofono_gprs_context_create(modem, 0, "atmodem", + data->modem); + + if (gprs && gc) + ofono_gprs_add_context(gprs, gc); } -static struct bluetooth_sap_driver sap_driver = { - .name = "telit", - .enable = telit_sap_enable, - .pre_sim = telit_pre_sim, - .post_sim = telit_post_sim, - .set_online = telit_set_online, - .post_online = telit_post_online, - .disable = telit_sap_disable, -}; - static int telit_probe(struct ofono_modem *modem) { struct telit_data *data; @@ -644,8 +508,6 @@ static int telit_probe(struct ofono_modem *modem) ofono_modem_set_data(modem, data); - bluetooth_sap_client_register(&sap_driver, modem); - return 0; } @@ -655,8 +517,6 @@ static void telit_remove(struct ofono_modem *modem) DBG("%p", modem); - bluetooth_sap_client_unregister(modem); - ofono_modem_set_data(modem, NULL); /* Cleanup after hot-unplug */ @@ -672,14 +532,14 @@ static struct ofono_modem_driver telit_driver = { .remove = telit_remove, .enable = telit_enable, .disable = telit_disable, - .set_online = telit_set_online, .pre_sim = telit_pre_sim, - .post_sim = telit_post_sim, .post_online = telit_post_online, }; static int telit_init(void) { + DBG(""); + return ofono_modem_driver_register(&telit_driver); } @@ -688,5 +548,5 @@ static void telit_exit(void) ofono_modem_driver_unregister(&telit_driver); } -OFONO_PLUGIN_DEFINE(telit, "telit driver", VERSION, +OFONO_PLUGIN_DEFINE(telit, "Telit driver", VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, telit_init, telit_exit) diff --git a/plugins/xe910.c b/plugins/xe910.c deleted file mode 100644 index bf40a3de..00000000 --- a/plugins/xe910.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2008-2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define OFONO_API_SUBJECT_TO_CHANGE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static const char *none_prefix[] = { NULL }; -static const char *qss_prefix[] = { "#QSS:", NULL }; - -enum modem_model { - HE910 = 1, - UE910, - LE910 -}; - -static struct { - enum modem_model model; - const char *variant; - gboolean has_voice; - gboolean has_gps; -} variants_list[] = { - { HE910, NULL, FALSE, FALSE }, - { HE910, "G", TRUE, TRUE }, - { HE910, "GL", TRUE, FALSE }, - { HE910, "EUR", TRUE, FALSE }, - { HE910, "NAR", TRUE, FALSE }, - { HE910, "DG", FALSE, TRUE }, - { HE910, "EUG", FALSE, TRUE }, - { HE910, "NAG", FALSE, TRUE }, - { UE910, NULL, FALSE, FALSE }, - { UE910, "EUR", TRUE, FALSE }, - { UE910, "NAR", TRUE, FALSE }, - { LE910, NULL, FALSE, FALSE }, - { } -}; - -struct xe910_data { - GAtChat *chat; /* AT chat */ - GAtChat *modem; /* Data port */ - struct ofono_sim *sim; - ofono_bool_t have_sim; - ofono_bool_t sms_phonebook_added; - enum modem_model model; - gboolean has_voice; - gboolean has_gps; -}; - -static void xe910_debug(const char *str, void *user_data) -{ - const char *prefix = user_data; - - ofono_info("%s%s", prefix, str); -} - -static GAtChat *open_device(struct ofono_modem *modem, - const char *key, char *debug) -{ - const char *device; - GAtSyntax *syntax; - GIOChannel *channel; - GAtChat *chat; - GHashTable *options; - - device = ofono_modem_get_string(modem, key); - if (device == NULL) - return NULL; - - DBG("%s %s", key, device); - - options = g_hash_table_new(g_str_hash, g_str_equal); - if (options == NULL) - return NULL; - - g_hash_table_insert(options, "Baud", "115200"); - channel = g_at_tty_open(device, options); - g_hash_table_destroy(options); - - if (channel == NULL) - return NULL; - - syntax = g_at_syntax_new_gsm_permissive(); - chat = g_at_chat_new(channel, syntax); - g_at_syntax_unref(syntax); - g_io_channel_unref(channel); - - if (chat == NULL) - return NULL; - - if (getenv("OFONO_AT_DEBUG")) - g_at_chat_set_debug(chat, xe910_debug, debug); - - return chat; -} - -static void switch_sim_state_status(struct ofono_modem *modem, int status) -{ - struct xe910_data *data = ofono_modem_get_data(modem); - - DBG("%p, SIM status: %d", modem, status); - - switch (status) { - case 0: /* SIM not inserted */ - if (data->have_sim == TRUE) { - ofono_sim_inserted_notify(data->sim, FALSE); - data->have_sim = FALSE; - data->sms_phonebook_added = FALSE; - } - break; - case 1: /* SIM inserted */ - case 2: /* SIM inserted and PIN unlocked */ - if (data->have_sim == FALSE) { - ofono_sim_inserted_notify(data->sim, TRUE); - data->have_sim = TRUE; - } - break; - case 3: /* SIM inserted, SMS and phonebook ready */ - if (data->sms_phonebook_added == FALSE) { - ofono_phonebook_create(modem, 0, "atmodem", data->chat); - ofono_sms_create(modem, 0, "atmodem", data->chat); - data->sms_phonebook_added = TRUE; - } - break; - default: - ofono_warn("Unknown SIM state %d received", status); - break; - } -} - -static void xe910_qss_notify(GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - int status; - GAtResultIter iter; - - DBG("%p", modem); - - g_at_result_iter_init(&iter, result); - - if (!g_at_result_iter_next(&iter, "#QSS:")) - return; - - g_at_result_iter_next_number(&iter, &status); - - switch_sim_state_status(modem, status); -} - -static void qss_query_cb(gboolean ok, GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - int status, mode; - GAtResultIter iter; - - DBG("%p", modem); - - if (!ok) - return; - - g_at_result_iter_init(&iter, result); - - if (!g_at_result_iter_next(&iter, "#QSS:")) - return; - - if (!g_at_result_iter_next_number(&iter, &mode)) - return; - - if (!g_at_result_iter_next_number(&iter, &status)) - return; - - switch_sim_state_status(modem, status); -} - -static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct xe910_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - if (!ok) { - g_at_chat_unref(data->chat); - data->chat = NULL; - - g_at_chat_unref(data->modem); - data->modem = NULL; - - ofono_modem_set_powered(modem, FALSE); - return; - } - - /* - * Switch data carrier detect signal off. - * When the DCD is disabled the modem does not hangup anymore - * after the data connection. - */ - g_at_chat_send(data->chat, "AT&C0", NULL, NULL, NULL, NULL); - - data->have_sim = FALSE; - data->sms_phonebook_added = FALSE; - - ofono_modem_set_powered(modem, TRUE); - - /* - * Tell the modem not to automatically initiate auto-attach - * proceedures on its own. - */ - g_at_chat_send(data->chat, "AT#AUTOATT=0", none_prefix, - NULL, NULL, NULL); - - /* Follow sim state */ - g_at_chat_register(data->chat, "#QSS:", xe910_qss_notify, - FALSE, modem, NULL); - - /* Enable sim state notification */ - g_at_chat_send(data->chat, "AT#QSS=2", none_prefix, NULL, NULL, NULL); - - g_at_chat_send(data->chat, "AT#QSS?", qss_prefix, - qss_query_cb, modem, NULL); -} - -static gboolean find_model_variant(struct ofono_modem *modem, - const char * model_variant) -{ - struct xe910_data *data = ofono_modem_get_data(modem); - char model[32]; - char variant[32]; - gchar **tokens; - int i; - - if (!model_variant || model_variant[0] == '\0') - return FALSE; - - DBG("%s", model_variant); - - tokens = g_strsplit(model_variant, "-", 2); - - if (!tokens || !tokens[0] || !tokens[1]) - return FALSE; - - g_strlcpy(model, tokens[0], sizeof(model)); - g_strlcpy(variant, tokens[1], sizeof(variant)); - g_strfreev(tokens); - - if (g_str_equal(model, "HE910")) - data->model = HE910; - else if (g_str_equal(model, "UE910")) - data->model = UE910; - else if (g_str_equal(model, "LE910")) - data->model = LE910; - else - return FALSE; - - DBG("Model: %s", model); - - for (i = 0; variants_list[i].model; i++) { - if (variants_list[i].model != data->model) - continue; - - /* Set model defaults */ - if (variants_list[i].variant == NULL) { - data->has_voice = variants_list[i].has_voice; - data->has_gps = variants_list[i].has_gps; - continue; - } - - /* Specific variant match */ - if (g_str_equal(variant, variants_list[i].variant)) { - DBG("Variant: %s", variant); - data->has_voice = variants_list[i].has_voice; - data->has_gps = variants_list[i].has_gps; - } - } - - return TRUE; -} - -static void cfun_gmm_cb(gboolean ok, GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct xe910_data *data = ofono_modem_get_data(modem); - const char * model_variant; - - DBG("%p", modem); - - if (!ok) - goto error; - - /* Get +GMM response */ - if (!at_util_parse_attr(result, "", &model_variant)) - goto error; - - /* Try to find modem model and variant */ - if (!find_model_variant(modem, model_variant)) { - ofono_info("Unknown xE910 model/variant %s", model_variant); - goto error; - } - - /* Set phone functionality */ - if (g_at_chat_send(data->chat, "AT+CFUN=1", none_prefix, - cfun_enable_cb, modem, NULL) > 0) - return; - -error: - g_at_chat_unref(data->chat); - data->chat = NULL; - - g_at_chat_unref(data->modem); - data->modem = NULL; - - ofono_modem_set_powered(modem, FALSE); -} - -static int xe910_enable(struct ofono_modem *modem) -{ - struct xe910_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - data->modem = open_device(modem, "Modem", "Modem: "); - if (data->modem == NULL) - return -EINVAL; - - data->chat = open_device(modem, "Aux", "Aux: "); - if (data->chat == NULL) { - g_at_chat_unref(data->modem); - data->modem = NULL; - return -EIO; - } - - g_at_chat_set_slave(data->modem, data->chat); - - /* - * Disable command echo and - * enable the Extended Error Result Codes - */ - g_at_chat_send(data->chat, "ATE0 +CMEE=1", none_prefix, - NULL, NULL, NULL); - g_at_chat_send(data->modem, "ATE0", none_prefix, - NULL, NULL, NULL); - - - /* Get modem model and variant */ - g_at_chat_send(data->chat, "AT+GMM", NULL, - cfun_gmm_cb, modem, NULL); - - - return -EINPROGRESS; -} - -static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct xe910_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - g_at_chat_unref(data->chat); - data->chat = NULL; - - if (ok) - ofono_modem_set_powered(modem, FALSE); -} - -static int xe910_disable(struct ofono_modem *modem) -{ - struct xe910_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - g_at_chat_cancel_all(data->modem); - g_at_chat_unregister_all(data->modem); - g_at_chat_unref(data->modem); - data->modem = NULL; - - g_at_chat_cancel_all(data->chat); - g_at_chat_unregister_all(data->chat); - - /* Power down modem */ - g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix, - cfun_disable_cb, modem, NULL); - - return -EINPROGRESS; -} - -static void xe910_pre_sim(struct ofono_modem *modem) -{ - struct xe910_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - ofono_devinfo_create(modem, 0, "atmodem", data->chat); - data->sim = ofono_sim_create(modem, OFONO_VENDOR_TELIT, "atmodem", - data->chat); - - if (data->has_gps) - ofono_location_reporting_create(modem, 0, "telitmodem", - data->chat); -} - -static void xe910_post_online(struct ofono_modem *modem) -{ - struct xe910_data *data = ofono_modem_get_data(modem); - struct ofono_gprs *gprs; - struct ofono_gprs_context *gc; - - DBG("%p", modem); - - ofono_netreg_create(modem, OFONO_VENDOR_TELIT, "atmodem", data->chat); - - if (data->has_voice) { - struct ofono_message_waiting *mw; - - ofono_voicecall_create(modem, 0, "atmodem", data->chat); - ofono_ussd_create(modem, 0, "atmodem", data->chat); - ofono_call_forwarding_create(modem, 0, "atmodem", data->chat); - ofono_call_settings_create(modem, 0, "atmodem", data->chat); - ofono_call_meter_create(modem, 0, "atmodem", data->chat); - ofono_call_barring_create(modem, 0, "atmodem", data->chat); - - mw = ofono_message_waiting_create(modem); - if (mw) - ofono_message_waiting_register(mw); - } - - gprs = ofono_gprs_create(modem, OFONO_VENDOR_TELIT, "atmodem", - data->chat); - - if (data->model == LE910) - gc = ofono_gprs_context_create(modem, OFONO_VENDOR_TELIT, - "telitncmmodem", data->modem); - else - gc = ofono_gprs_context_create(modem, 0, "atmodem", - data->modem); - - if (gprs && gc) - ofono_gprs_add_context(gprs, gc); -} - -static int xe910_probe(struct ofono_modem *modem) -{ - struct xe910_data *data; - - DBG("%p", modem); - - data = g_try_new0(struct xe910_data, 1); - if (data == NULL) - return -ENOMEM; - - ofono_modem_set_data(modem, data); - - return 0; -} - -static void xe910_remove(struct ofono_modem *modem) -{ - struct xe910_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - ofono_modem_set_data(modem, NULL); - - /* Cleanup after hot-unplug */ - g_at_chat_unref(data->chat); - g_at_chat_unref(data->modem); - - g_free(data); -} - -static struct ofono_modem_driver xe910_driver = { - .name = "xe910", - .probe = xe910_probe, - .remove = xe910_remove, - .enable = xe910_enable, - .disable = xe910_disable, - .pre_sim = xe910_pre_sim, - .post_online = xe910_post_online, -}; - -static int xe910_init(void) -{ - DBG(""); - - return ofono_modem_driver_register(&xe910_driver); -} - -static void xe910_exit(void) -{ - ofono_modem_driver_unregister(&xe910_driver); -} - -OFONO_PLUGIN_DEFINE(xe910, "Telit HE910 driver", VERSION, - OFONO_PLUGIN_PRIORITY_DEFAULT, xe910_init, xe910_exit)