All of lore.kernel.org
 help / color / mirror / Atom feed
From: Piotr Haber <gluedig@gmail.com>
To: ofono@ofono.org
Subject: [PATCH 2/4] plugins: support for Telit LE910 V2 modem
Date: Wed, 25 Jan 2017 11:41:26 +0100	[thread overview]
Message-ID: <20170125104128.5254-3-gluedig@gmail.com> (raw)
In-Reply-To: <20170125104128.5254-1-gluedig@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 11089 bytes --]

LE910 V2 is next generation Telit LTE modem.
It supports 3GPP Rel. 9 LTE Cat. 4 over multiple bands.
Default USB composition uses PID 0x36 and
consists of 6 CDC-ACM serial ports and 1 CDC-NCM network adapter.
---
 Makefile.am       |   3 +
 plugins/le910v2.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 403 insertions(+)
 create mode 100644 plugins/le910v2.c

diff --git a/Makefile.am b/Makefile.am
index 2f49027c..72c4fcfc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -501,6 +501,9 @@ builtin_sources += plugins/quectel.c
 builtin_modules += ublox
 builtin_sources += plugins/ublox.c
 
+builtin_modules += le910v2
+builtin_sources += plugins/le910v2.c
+
 if BLUETOOTH
 if BLUEZ4
 builtin_modules += telit
diff --git a/plugins/le910v2.c b/plugins/le910v2.c
new file mode 100644
index 00000000..e758971d
--- /dev/null
+++ b/plugins/le910v2.c
@@ -0,0 +1,400 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2017 Piotr Haber. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+#include <gatchat.h>
+#include <gattty.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-barring.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/call-meter.h>
+#include <ofono/call-settings.h>
+#include <ofono/devinfo.h>
+#include <ofono/message-waiting.h>
+#include <ofono/location-reporting.h>
+#include <ofono/netreg.h>
+#include <ofono/phonebook.h>
+#include <ofono/sim.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/sms.h>
+#include <ofono/ussd.h>
+#include <ofono/voicecall.h>
+
+#include <drivers/atmodem/atutil.h>
+#include <drivers/atmodem/vendor.h>
+
+static const char *none_prefix[] = { NULL };
+static const char *qss_prefix[] = { "#QSS:", NULL };
+
+struct le910v2_data {
+	GAtChat *chat;		/* AT chat */
+	GAtChat *modem;		/* Data port */
+	struct ofono_sim *sim;
+	ofono_bool_t have_sim;
+	ofono_bool_t sms_phonebook_added;
+};
+
+static void le910v2_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, le910v2_debug, debug);
+
+	return chat;
+}
+
+static void switch_sim_state_status(struct ofono_modem *modem, int status)
+{
+	struct le910v2_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->have_sim == FALSE) {
+			ofono_sim_inserted_notify(data->sim, TRUE);
+			data->have_sim = TRUE;
+		}
+		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 le910v2_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 le910v2_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:", le910v2_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 int le910v2_enable(struct ofono_modem *modem)
+{
+	struct le910v2_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;
+	}
+
+	/*
+	 * 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);
+
+	/* Set phone functionality */
+	g_at_chat_send(data->chat, "AT+CFUN=1", none_prefix,
+				cfun_enable_cb, modem, NULL);
+
+	return -EINPROGRESS;
+}
+
+static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	struct ofono_modem *modem = user_data;
+	struct le910v2_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 le910v2_disable(struct ofono_modem *modem)
+{
+	struct le910v2_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 le910v2_pre_sim(struct ofono_modem *modem)
+{
+	struct le910v2_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);
+}
+
+static void le910v2_post_online(struct ofono_modem *modem)
+{
+	struct le910v2_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);
+	gprs = ofono_gprs_create(modem, OFONO_VENDOR_TELIT, "atmodem",
+					data->chat);
+	gc = ofono_gprs_context_create(modem, OFONO_VENDOR_TELIT, "telitncmmodem",
+					data->modem);
+
+	if (gprs && gc)
+		ofono_gprs_add_context(gprs, gc);
+}
+
+static int le910v2_probe(struct ofono_modem *modem)
+{
+	struct le910v2_data *data;
+
+	DBG("%p", modem);
+
+	data = g_try_new0(struct le910v2_data, 1);
+	if (data == NULL)
+		return -ENOMEM;
+
+	ofono_modem_set_data(modem, data);
+
+	return 0;
+}
+
+static void le910v2_remove(struct ofono_modem *modem)
+{
+	struct le910v2_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 le910v2_driver = {
+	.name		= "le910v2",
+	.probe		= le910v2_probe,
+	.remove		= le910v2_remove,
+	.enable		= le910v2_enable,
+	.disable	= le910v2_disable,
+	.pre_sim	= le910v2_pre_sim,
+	.post_online	= le910v2_post_online,
+};
+
+static int le910v2_init(void)
+{
+	DBG("");
+
+	return ofono_modem_driver_register(&le910v2_driver);
+}
+
+static void le910v2_exit(void)
+{
+	ofono_modem_driver_unregister(&le910v2_driver);
+}
+
+OFONO_PLUGIN_DEFINE(le910v2, "Telit LE910 V2 driver", VERSION,
+		OFONO_PLUGIN_PRIORITY_DEFAULT, le910v2_init, le910v2_exit)
-- 
2.11.0


  parent reply	other threads:[~2017-01-25 10:41 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-24 14:21 [PATCH v2] drivers: add support for Telit LE910 V2 modem Piotr Haber
2017-01-24 18:55 ` Denis Kenzior
2017-01-25 10:41   ` [PATCH 0/4] add support for Telit LE910V2 Piotr Haber
2017-01-25 10:41     ` [PATCH 1/4] telitmodem: support for CDC-NCM network adapter Piotr Haber
2017-01-25 16:33       ` Denis Kenzior
2017-01-25 10:41     ` Piotr Haber [this message]
2017-01-25 16:37       ` [PATCH 2/4] plugins: support for Telit LE910 V2 modem Denis Kenzior
2017-01-26  9:09         ` gluedig
2017-01-26  9:40           ` Antoine Aubert
2017-01-26 11:13             ` gluedig
2017-01-26 13:46           ` Denis Kenzior
2017-01-25 10:41     ` [PATCH 3/4] doc: description of Telit LE910V2 network setup Piotr Haber
2017-01-25 16:38       ` Denis Kenzior
2017-01-25 10:41     ` [PATCH 4/4] udevng: setup of Telit LE910V2 Piotr Haber

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170125104128.5254-3-gluedig@gmail.com \
    --to=gluedig@gmail.com \
    --cc=ofono@ofono.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.