[PATCH] qmimodem: fix roaming status report
by Christophe Ronco
Hi,
With a MC7304 modem and a roaming SIM card, Status in org.ofono.NetworkRegistration
properties ends up in "registered" instead of roaming.
Both AT command and qmicli indicates we are roaming.
What's happening is the following:
1) first QMI_NAS_SS_INFO_IND indicating we are registered contains a QMI_NAS_RESULT_ROAMING_STATUS parameter.
Parameter inside says we are roaming and qmimidem driver correctly reports status NETWORK_REGISTRATION_STATUS_ROAMING.
2) other QMI_NAS_SS_INFO_IND arrive, saying we are registered without QMI_NAS_RESULT_ROAMING_STATUS parameter.
Driver reports NETWORK_REGISTRATION_STATUS_REGISTERED.
Extract of traces with QMI binary debug interpreted (as far as I can...):
a) first "searching" indication
Dec 13 13:19:40 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: < 01 3b 00 80 03 01 04 00 00 24 00 2f 00
29 05 00 d0 00 14 00 00 MCC:208 MNC:20
22 05 00 01 02 00 01 00 Detailed Service Status: QMI_NAS_SERVICE_STATUS_LIMITED, QMI_NAS_NETWORK_SERVICE_DOMAIN_PS, ...
15 03 00 01 08 01 LTE, no roaming
12 05 00 d0 00 14 00 00 Current PLMN: MCC:208 MNC:20, no desc
11 01 00 00
10 01 00 01 No roaming
01 06 00 02 02 02 02 01 08 QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, CS detached, PS detached, NETWORK_TYPE_3GPP, QMI_NAS_RADIO_INTERFACE_LTE
Dec 13 13:19:40 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: NAS_ind msg=36 len=47 [client=1,type=4,tid=0,len=59]
Dec 13 13:19:40 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=41,len=5} {type=34,len=5} {type=21,len=3} {type=18,len=5}
Dec 13 13:19:40 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=17,len=1} {type=16,len=1} {type=1,len=6}
Dec 13 13:19:40 klk-lpbs-0504B4 daemon.debug ofonod[855]: ofono_netreg_status_notify modem /sierra_0 status 2 lac -1 cellid -1 tech 7
b) second "searching" indication
Dec 13 13:19:41 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: < 01 21 00 80 03 01 04 00 00 24 00 15 00
22 05 00 03 03 00 01 00 Detailed Service Status: QMI_NAS_SERVICE_STATUS_LIMITED_REGIONAL, CS_PS, ...
11 01 00 00
01 06 00 02 02 02 02 01 08 QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, CS detached, PS detached, NETWORK_TYPE_3GPP, QMI_NAS_RADIO_INTERFACE_LTE
Dec 13 13:19:41 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: NAS_ind msg=36 len=21 [client=1,type=4,tid=0,len=33]
Dec 13 13:19:41 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=34,len=5} {type=17,len=1} {type=1,len=6}
c) First indication while "registered"
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: < 01 5e 00 80 03 01 04 00 00 24 00 52 00
2a 01 00 00
29 05 00 d0 00 14 00 00 MCC:208 MNC:20
28 02 00 15 01 UMTS Primary Scrambling Code
26 08 00 03 00 00 00 03 00 00 00 CS: all calls allowed, PS: all calls allowed
22 05 00 02 03 00 01 00 Detailed Service Status: QMI_NAS_SERVICE_STATUS_AVAILABLE, CS_PS, ...
1e 04 00 f7 00 95 04 CID 3GPP
1d 02 00 fb 50 LAC 3GPP
15 03 00 01 05 00 UMTS: roaming
12 05 00 d0 00 14 00 00 Current PLMN: MCC:208 MNC:20, no desc
11 04 00 03 03 04 05
10 01 00 00 ROAMING ON
01 06 00 01 01 01 02 01 05 QMI_NAS_REGISTRATION_STATE_REGISTERED, CS attached, PS attached, NETWORK_TYPE_3GPP, QMI_NAS_RADIO_INTERFACE_UMTS
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: NAS_ind msg=36 len=82 [client=1,type=4,tid=0,len=94]
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=42,len=1} {type=41,len=5} {type=40,len=2} {type=38,len=8}
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=34,len=5} {type=30,len=4} {type=29,len=2} {type=21,len=3}
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=18,len=5} {type=17,len=4} {type=16,len=1} {type=1,len=6}
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.debug ofonod[855]: ofono_gprs_status_notify modem /sierra_0 status 1
==================> ROAMING status reported <==========================
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.debug ofonod[855]: ofono_netreg_status_notify modem /sierra_0 status 5 lac 20731 cellid 76873975 tech 2
d) second indication while "registered"
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: < 01 31 00 80 03 01 04 00 00 24 00 25 00
29 05 00 d0 00 14 00 00 MCC:208 MNC:20
28 02 00 15 01 UMTS Primary Scrambling Code
12 05 00 d0 00 14 00 00 Current PLMN: MCC:208 MNC:20, no desc
11 04 00 03 03 04 05
01 06 00 01 01 01 02 01 05 QMI_NAS_REGISTRATION_STATE_REGISTERED, CS attached, PS attached, NETWORK_TYPE_3GPP, QMI_NAS_RADIO_INTERFACE_UMTS
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: NAS_ind msg=36 len=37 [client=1,type=4,tid=0,len=49]
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=41,len=5} {type=40,len=2} {type=18,len=5} {type=17,len=4}
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.info ofonod[855]: QMI: {type=1,len=6}
==================> ROAMING information lost <==========================
Dec 13 13:19:56 klk-lpbs-0504B4 daemon.debug ofonod[855]: ofono_netreg_status_notify modem /sierra_0 status 1 lac -1 cellid -1 tech 2
I don't know if this is a problem specific to MC7304 or even to my firmware version or if this is a normal behavior to have ROAMING_STATUS parameter only when status change from anything to registered.
Best Regards,
Christophe
Christophe Ronco (1):
qmimodem: fix roaming status report
drivers/qmimodem/network-registration.c | 50 ++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 7 deletions(-)
--
2.7.4
2 years, 5 months
Periodic AT commands
by Mattias Månsson
I would like to implement a periodic status check for our modem and wonder if there is any support for this in ofono already. Some way to get a periodic callback perhaps, where I could then run a few AT commands.
2 years, 5 months
[PATCH 0/1] atmodem: Handle broken +CMT notifications of some cinterion modems
by tournier.julien@gmail.com
From: Julien Tournier <tournier.julien(a)gmail.com>
Hi Denis,
Here is the fixed patch for the +CMT notification parsing on some cinterion
modems that have a leading coma. I hope i took all your remarks into account
drivers/atmodem/sms.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
--
2.18.0
>From 937a78ccdac4975e1a292a8e9259060d2d94adc2 Mon Sep 17 00:00:00 2001
From: Julien Tournier <tournier.julien(a)gmail.com>
Date: Wed, 29 Aug 2018 15:55:58 +0200
Subject: [PATCH 1/1] atmodem: Handle broken +CMT notifications of some cinterion modems
---
drivers/atmodem/sms.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c
index 68b89862..9c920667 100644
--- a/drivers/atmodem/sms.c
+++ b/drivers/atmodem/sms.c
@@ -412,9 +412,24 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
switch (data->vendor) {
case OFONO_VENDOR_CINTERION:
- if (!g_at_result_iter_next_number(&iter, &tpdu_len))
- goto err;
- break;
+ if (!g_at_result_iter_next_number(&iter, &tpdu_len)) {
+ /*
+ * On some cinterions modems (ALS3,PLS8...), we can't directly
+ * get the PDU length, we need to skip the leading coma
+ * \r\n+CMT: ,23\r\nCAFECAFECAFE... ...\r\n
+ * ^------- PDU length
+ */
+ DBG("Retrying to find the PDU length");
+
+ if (!g_at_result_iter_skip_next(&iter))
+ goto err;
+
+ /* Next attempt at finding the PDU length. */
+ if (!g_at_result_iter_next_number(&iter, &tpdu_len))
+ goto err;
+ }
+
+ break;
default:
if (!g_at_result_iter_skip_next(&iter))
goto err;
--
2.18.0
2 years, 6 months
place to intercept BT audio packets?
by dev@rivaretica.com
New to ofono: looking for documentation/pointers that can inform about
the best point in ofono to intercept Bluetooth audio packets from/to
headset to implement custom audio processing (and does audio stream even
thread through ofono?).
All info appreciated!
2 years, 6 months
[PATCHv2 1/2] atmodem: add Quectel M95 special case for PIN query
by Martin Hundebøll
The AT command reference for Quectel M95 specifies that remaining SIM
pin retires can be queried using AT+QTRPIN, which responds with one
count for each pin-type:
+QTRPIN: 3,3,10,10
After entering the PIN code, enable an extra AT+CPIN? for the M95
vendor.
---
Changes since v1:
* Add quirk to resend AT+CPIN? after sending pin code
drivers/atmodem/sim.c | 50 ++++++++++++++++++++++++++++++++++++++++
drivers/atmodem/vendor.h | 1 +
2 files changed, 51 insertions(+)
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index 10dc8009..0907635d 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -70,6 +70,7 @@ static const char *cinterion_spic_prefix[] = { "^SPIC:", NULL };
static const char *pct_prefix[] = { "#PCT:", NULL };
static const char *pnnm_prefix[] = { "+PNNM:", NULL };
static const char *qpinc_prefix[] = { "+QPINC:", NULL };
+static const char *qtrpin_prefix[] = { "+QTRPIN:", NULL };
static const char *upincnt_prefix[] = { "+UPINCNT:", NULL };
static const char *cuad_prefix[] = { "+CUAD:", NULL };
static const char *ccho_prefix[] = { "+CCHO:", NULL };
@@ -982,6 +983,49 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
+static void at_qtrpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_sim_pin_retries_cb_t cb = cbd->cb;
+ const char *final = g_at_result_final_response(result);
+ GAtResultIter iter;
+ struct ofono_error error;
+ int retries[OFONO_SIM_PASSWORD_INVALID];
+ size_t i;
+
+ decode_at_error(&error, final);
+
+ if (!ok) {
+ cb(&error, NULL, cbd->data);
+ return;
+ }
+
+ for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
+ retries[i] = -1;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, "+QTRPIN:")) {
+ int pin, pin2, puk, puk2;
+
+ if (!g_at_result_iter_next_number(&iter, &pin))
+ continue;
+ if (!g_at_result_iter_next_number(&iter, &pin2))
+ continue;
+ if (!g_at_result_iter_next_number(&iter, &puk))
+ continue;
+ if (!g_at_result_iter_next_number(&iter, &puk2))
+ continue;
+
+ retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin;
+ retries[OFONO_SIM_PASSWORD_SIM_PUK] = puk;
+ retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin2;
+ retries[OFONO_SIM_PASSWORD_SIM_PUK2] = puk2;
+ }
+
+ cb(&error, retries, cbd->data);
+}
+
static void at_qpinc_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -1172,6 +1216,11 @@ static void at_pin_retries_query(struct ofono_sim *sim,
at_qpinc_cb, cbd, g_free) > 0)
return;
break;
+ case OFONO_VENDOR_QUECTEL_M95:
+ if (g_at_chat_send(sd->chat, "AT+QTRPIN", qtrpin_prefix,
+ at_qtrpin_cb, cbd, g_free) > 0)
+ return;
+ break;
case OFONO_VENDOR_UBLOX:
case OFONO_VENDOR_UBLOX_TOBY_L2:
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
@@ -1305,6 +1354,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
case OFONO_VENDOR_HUAWEI:
case OFONO_VENDOR_SIMCOM:
case OFONO_VENDOR_SIERRA:
+ case OFONO_VENDOR_QUECTEL_M95:
/*
* On ZTE modems, after pin is entered, SIM state is checked
* by polling CPIN as their modem doesn't provide unsolicited
diff --git a/drivers/atmodem/vendor.h b/drivers/atmodem/vendor.h
index d52ad521..721796e4 100644
--- a/drivers/atmodem/vendor.h
+++ b/drivers/atmodem/vendor.h
@@ -44,6 +44,7 @@ enum ofono_vendor {
OFONO_VENDOR_WAVECOM_Q2XXX,
OFONO_VENDOR_ALCATEL,
OFONO_VENDOR_QUECTEL,
+ OFONO_VENDOR_QUECTEL_M95,
OFONO_VENDOR_UBLOX,
OFONO_VENDOR_UBLOX_TOBY_L2,
OFONO_VENDOR_CINTERION,
--
2.18.0
2 years, 6 months
[PATCH] fixing SMS notification parsing for some cinterion modem
by tournier.julien@gmail.com
Hi Denis,
I've recently found a bug in the +CMT notification parsing on some cinterion
modems. Some of them (ALS3, PLS8, maybe others...) have a leading coma right
after "+CTM : ", before the PDU size, which makes the parser rejecting the
message since the PDU size is not found.
Please find attached my proposed patch.
---
drivers/atmodem/sms.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c
index 68b89862..d650c0f6 100644
--- a/drivers/atmodem/sms.c
+++ b/drivers/atmodem/sms.c
@@ -412,8 +412,21 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
switch (data->vendor) {
case OFONO_VENDOR_CINTERION:
- if (!g_at_result_iter_next_number(&iter, &tpdu_len))
- goto err;
+ if (!g_at_result_iter_next_number(&iter, &tpdu_len)) {
+ /*
+ * Can't get the PDU length, we need to skip
+ * the leading coma for some modems (ALS3,PLS8...).
+ */
+ DBG("Retrying to find the PDU length");
+
+ if (!g_at_result_iter_skip_next(&iter))
+ goto err;
+
+ /* Next attempt at finding the PDU length. */
+ if (!g_at_result_iter_next_number(&iter, &tpdu_len))
+ goto err;
+ }
+
break;
default:
if (!g_at_result_iter_skip_next(&iter))
--
2.18.0
2 years, 6 months
[PATCH 1/2] atmodem: add Quectel M95 special case for PIN query
by Martin Hundebøll
The AT command reference for Quectel M95 specifies that remaining SIM
pin retires can be queried using AT+QTRPIN, which responds with one
count for each pin-type:
+QTRPIN: 3,3,10,10
---
drivers/atmodem/sim.c | 49 ++++++++++++++++++++++++++++++++++++++++
drivers/atmodem/vendor.h | 1 +
2 files changed, 50 insertions(+)
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index 10dc8009..d1d24e73 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -70,6 +70,7 @@ static const char *cinterion_spic_prefix[] = { "^SPIC:", NULL };
static const char *pct_prefix[] = { "#PCT:", NULL };
static const char *pnnm_prefix[] = { "+PNNM:", NULL };
static const char *qpinc_prefix[] = { "+QPINC:", NULL };
+static const char *qtrpin_prefix[] = { "+QTRPIN:", NULL };
static const char *upincnt_prefix[] = { "+UPINCNT:", NULL };
static const char *cuad_prefix[] = { "+CUAD:", NULL };
static const char *ccho_prefix[] = { "+CCHO:", NULL };
@@ -982,6 +983,49 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
+static void at_qtrpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_sim_pin_retries_cb_t cb = cbd->cb;
+ const char *final = g_at_result_final_response(result);
+ GAtResultIter iter;
+ struct ofono_error error;
+ int retries[OFONO_SIM_PASSWORD_INVALID];
+ size_t i;
+
+ decode_at_error(&error, final);
+
+ if (!ok) {
+ cb(&error, NULL, cbd->data);
+ return;
+ }
+
+ for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
+ retries[i] = -1;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, "+QTRPIN:")) {
+ int pin, pin2, puk, puk2;
+
+ if (!g_at_result_iter_next_number(&iter, &pin))
+ continue;
+ if (!g_at_result_iter_next_number(&iter, &pin2))
+ continue;
+ if (!g_at_result_iter_next_number(&iter, &puk))
+ continue;
+ if (!g_at_result_iter_next_number(&iter, &puk2))
+ continue;
+
+ retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin;
+ retries[OFONO_SIM_PASSWORD_SIM_PUK] = puk;
+ retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin2;
+ retries[OFONO_SIM_PASSWORD_SIM_PUK2] = puk2;
+ }
+
+ cb(&error, retries, cbd->data);
+}
+
static void at_qpinc_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -1172,6 +1216,11 @@ static void at_pin_retries_query(struct ofono_sim *sim,
at_qpinc_cb, cbd, g_free) > 0)
return;
break;
+ case OFONO_VENDOR_QUECTEL_M95:
+ if (g_at_chat_send(sd->chat, "AT+QTRPIN", qtrpin_prefix,
+ at_qtrpin_cb, cbd, g_free) > 0)
+ return;
+ break;
case OFONO_VENDOR_UBLOX:
case OFONO_VENDOR_UBLOX_TOBY_L2:
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
diff --git a/drivers/atmodem/vendor.h b/drivers/atmodem/vendor.h
index d52ad521..721796e4 100644
--- a/drivers/atmodem/vendor.h
+++ b/drivers/atmodem/vendor.h
@@ -44,6 +44,7 @@ enum ofono_vendor {
OFONO_VENDOR_WAVECOM_Q2XXX,
OFONO_VENDOR_ALCATEL,
OFONO_VENDOR_QUECTEL,
+ OFONO_VENDOR_QUECTEL_M95,
OFONO_VENDOR_UBLOX,
OFONO_VENDOR_UBLOX_TOBY_L2,
OFONO_VENDOR_CINTERION,
--
2.18.0
2 years, 6 months
[RFC] m95: Add driver for Quectel M95 modem
by Martin Hundebøll
So far the driver is only tested with GPRS.
The modem uses GSM 07.10 multiplexing, which breaks when changing
functional modes (i.e. going from CFUN=4 to CFUN=1), the driver doesn't
implement online/offline states. It does support disabling the device to
save power though, but users must go through the full setup procedure to
enable the device again.
---
Makefile.am | 3 +
plugins/m95.c | 492 +++++++++++++++++++++++++++++++++++++++++++++++
plugins/udevng.c | 1 +
3 files changed, 496 insertions(+)
create mode 100644 plugins/m95.c
diff --git a/Makefile.am b/Makefile.am
index 6dee4ce3..6fe4258a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -511,6 +511,9 @@ builtin_sources += plugins/telit.c
builtin_modules += quectel
builtin_sources += plugins/quectel.c
+builtin_modules += m95
+builtin_sources += plugins/m95.c
+
builtin_modules += ublox
builtin_sources += plugins/ublox.c
diff --git a/plugins/m95.c b/plugins/m95.c
new file mode 100644
index 00000000..32746996
--- /dev/null
+++ b/plugins/m95.c
@@ -0,0 +1,492 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2018 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 <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+#include <gatchat.h>
+#include <gattty.h>
+#include <gatmux.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+#include <ofono/netreg.h>
+#include <ofono/sim.h>
+#include <ofono/sms.h>
+#include <ofono/ussd.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/phonebook.h>
+#include <ofono/history.h>
+#include <ofono/log.h>
+#include <ofono/voicecall.h>
+#include <ofono/call-volume.h>
+#include <drivers/atmodem/vendor.h>
+
+#define NUM_DLC 5
+
+#define VOICE_DLC 0
+#define NETREG_DLC 1
+#define SMS_DLC 2
+#define GPRS_DLC 3
+#define SETUP_DLC 4
+
+static char *dlc_prefixes[NUM_DLC] = {"Voice: ", "Net: ", "SMS: ",
+ "GPRS: " , "Setup: "};
+
+static const char *reset_prefix[] = {"+CFUN:", NULL};
+static const char *enable_prefix[] = {"+CPIN:", NULL};
+
+struct m95_data {
+ GIOChannel *tty;
+ GAtMux *mux;
+ GAtChat *dlcs[NUM_DLC];
+ guint cfun_reset;
+ guint cfun_enable;
+ guint cfun_disable_timeout;
+};
+
+static int m95_probe(struct ofono_modem *modem)
+{
+ struct m95_data *data;
+
+ DBG("%p", modem);
+
+ data = g_try_new0(struct m95_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ ofono_modem_set_data(modem, data);
+
+ return 0;
+}
+
+static void m95_remove(struct ofono_modem *modem)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ ofono_modem_set_data(modem, NULL);
+
+ g_free(data);
+}
+
+static void m95_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)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+ const char *device;
+ GAtSyntax *syntax;
+ 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");
+ g_hash_table_insert(options, "Parity", "none");
+ g_hash_table_insert(options, "StopBits", "1");
+ g_hash_table_insert(options, "DataBits", "8");
+ g_hash_table_insert(options, "XonXoff", "off");
+ g_hash_table_insert(options, "Local", "off");
+ g_hash_table_insert(options, "RtsCts", "off");
+ g_hash_table_insert(options, "Read", "on");
+
+ /* open serial device */
+ data->tty = g_at_tty_open(device, options);
+ g_hash_table_destroy(options);
+
+ if (data->tty == NULL)
+ return NULL;
+
+ /* create AT chat instance */
+ syntax = g_at_syntax_new_gsm_permissive();
+ chat = g_at_chat_new(data->tty, syntax);
+ g_at_syntax_unref(syntax);
+
+ if (chat == NULL) {
+ g_io_channel_unref(data->tty);
+ data->tty = NULL;
+
+ return NULL;
+ }
+
+ if (getenv("OFONO_AT_DEBUG"))
+ g_at_chat_set_debug(chat, m95_debug, debug);
+
+ return chat;
+}
+
+static GAtChat *create_chat(GIOChannel *channel, struct ofono_modem *modem,
+ char *debug)
+{
+ GAtSyntax *syntax;
+ GAtChat *chat;
+
+ if (channel == NULL)
+ return NULL;
+
+ syntax = g_at_syntax_new_gsmv1();
+ chat = g_at_chat_new(channel, syntax);
+ g_at_syntax_unref(syntax);
+
+ if (chat == NULL)
+ return NULL;
+
+ if (getenv("OFONO_AT_DEBUG"))
+ g_at_chat_set_debug(chat, m95_debug, debug);
+
+ return chat;
+}
+
+static void shutdown_device(struct m95_data *data)
+{
+ int i;
+
+ for (i = 0; i < NUM_DLC; i++) {
+ if (data->dlcs[i] == NULL)
+ continue;
+
+ DBG("clean AT chat channel %i", i);
+ g_at_chat_cancel_all(data->dlcs[i]);
+ g_at_chat_unregister_all(data->dlcs[i]);
+ g_at_chat_unref(data->dlcs[i]);
+ data->dlcs[i] = NULL;
+ }
+
+ if (data->mux) {
+ DBG("clean mux instance");
+ g_at_mux_shutdown(data->mux);
+ g_at_mux_unref(data->mux);
+ data->mux = NULL;
+ }
+
+ if (data->tty) {
+ DBG("clean tty io instance");
+ g_io_channel_unref(data->tty);
+ data->tty = NULL;
+ }
+}
+
+static void setup_internal_mux(struct ofono_modem *modem)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+ int i;
+
+ DBG("");
+
+ /* prepare the multiplexing instance */
+ data->mux = g_at_mux_new_gsm0710_basic(data->tty, 127);
+ if (data->mux == NULL)
+ goto error;
+
+ if (getenv("OFONO_MUX_DEBUG"))
+ g_at_mux_set_debug(data->mux, m95_debug, "MUX: ");
+
+ if (!g_at_mux_start(data->mux)) {
+ g_at_mux_shutdown(data->mux);
+ g_at_mux_unref(data->mux);
+ goto error;
+ }
+
+ /* create multiplexing channels for gprs, net, voice, text, and
+ * control */
+ for (i = 0; i < NUM_DLC; i++) {
+ GIOChannel *channel = g_at_mux_create_channel(data->mux);
+
+ data->dlcs[i] = create_chat(channel, modem, dlc_prefixes[i]);
+ if (data->dlcs[i] == NULL) {
+ ofono_error("Failed to create channel");
+ goto error;
+ }
+
+ g_io_channel_unref(channel);
+ }
+
+ ofono_modem_set_powered(modem, TRUE);
+
+ return;
+
+error:
+ shutdown_device(data);
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static void mux_setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct m95_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ if (!ok)
+ goto error;
+
+ /* free the initial setup channel, as it is going to be created
+ * using multiplexing */
+ g_at_chat_unref(data->dlcs[SETUP_DLC]);
+ data->dlcs[SETUP_DLC] = NULL;
+
+ /* setup multiplexing */
+ setup_internal_mux(modem);
+
+ return;
+
+error:
+ shutdown_device(data);
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static void cfun_enable(GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct m95_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+
+ DBG("%p", modem);
+
+ g_at_result_iter_init(&iter, result);
+ if (!g_at_result_iter_next(&iter, enable_prefix[0]))
+ return;
+
+ /* remove the enable-completed listener */
+ if (data->cfun_enable) {
+ g_at_chat_unregister(data->dlcs[SETUP_DLC], data->cfun_enable);
+ data->cfun_enable = 0;
+ }
+
+ /* setup multiplexing */
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CMUX=0,0,5,127,10,3,30,10,2",
+ NULL, mux_setup_cb, modem, NULL);
+}
+
+static void cfun_enable_query(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ DBG("ok %d", ok);
+
+ if (ok)
+ cfun_enable(result, user_data);
+}
+
+static void cfun_reset(GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct m95_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+
+ DBG("%p", modem);
+
+ g_at_result_iter_init(&iter, result);
+ if (!g_at_result_iter_next(&iter, reset_prefix[0]))
+ return;
+
+ /* remove the reset-completed listener */
+ g_at_chat_unregister(data->dlcs[SETUP_DLC], data->cfun_reset);
+ data->cfun_reset = 0;
+
+ /* prepare to enable the modem */
+ g_at_chat_send(data->dlcs[SETUP_DLC], "ATE0", NULL, NULL, NULL, NULL);
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+IFC=2,2", NULL, NULL, NULL,
+ NULL);
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+GMM", NULL, NULL, NULL, NULL);
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT", NULL, NULL, NULL, NULL);
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+IPR=115200&w", NULL, NULL,
+ NULL, NULL);
+
+ /* setup a listener to delay multiplex-setup until modem is ready */
+ data->cfun_enable = g_at_chat_register(data->dlcs[SETUP_DLC],
+ "+CPIN:", cfun_enable, FALSE,
+ modem, NULL);
+
+ /* enable the modem */
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CFUN=1", enable_prefix,
+ cfun_enable_query, modem, NULL);
+}
+
+static void cfun_reset_query(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ DBG("ok %d", ok);
+
+ if (ok)
+ cfun_reset(result, user_data);
+}
+
+static int m95_enable(struct ofono_modem *modem)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ data->dlcs[SETUP_DLC] = open_device(modem, "Device", "Setup: ");
+ if (data->dlcs[SETUP_DLC] == NULL)
+ return -EINVAL;
+
+ /* when issuing the reset below, the modem is not ready until it
+ * responds with "+CFUN: 0", so set up a listener for this */
+ data->cfun_reset = g_at_chat_register(data->dlcs[SETUP_DLC], "+CFUN:",
+ cfun_reset, FALSE, modem, NULL);
+
+ /* bring the modem into a known state by issuing a reset */
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CFUN=4,1", reset_prefix,
+ cfun_reset_query, modem, NULL);
+
+ return -EINPROGRESS;
+}
+
+static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct m95_data *data = ofono_modem_get_data(modem);
+
+ /* device is now in non-functional mode, so shut down it down */
+ shutdown_device(data);
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static gboolean cfun_disable_timeout(gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct m95_data *data = ofono_modem_get_data(modem);
+
+ /* now put device in non-functional mode */
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CFUN=0,1", NULL, cfun_disable,
+ modem, NULL);
+
+ return FALSE;
+}
+
+static int m95_disable(struct ofono_modem *modem)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ /* shut down the device to tear down the muxing channels */
+ shutdown_device(data);
+
+ /* reopen device to get a plain AT control channel */
+ data->dlcs[SETUP_DLC] = open_device(modem, "Device", "Disable: ");
+ if (data->dlcs[SETUP_DLC] == NULL)
+ return -EINVAL;
+
+ /* add a timer to wait for device to drop GSM 07.10 multiplexing */
+ data->cfun_disable_timeout = g_timeout_add(500, cfun_disable_timeout,
+ modem);
+
+ return -EINPROGRESS;
+}
+
+static void m95_pre_sim(struct ofono_modem *modem)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+ struct ofono_sim *sim;
+
+ DBG("%p", modem);
+
+ ofono_devinfo_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ sim = ofono_sim_create(modem, OFONO_VENDOR_QUECTEL, "atmodem",
+ data->dlcs[VOICE_DLC]);
+
+ if (sim)
+ ofono_sim_inserted_notify(sim, TRUE);
+}
+
+static void m95_post_sim(struct ofono_modem *modem)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+ struct ofono_gprs *gprs;
+ struct ofono_gprs_context *gc;
+
+ DBG("%p", modem);
+
+ ofono_phonebook_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ ofono_sms_create(modem, OFONO_VENDOR_QUECTEL, "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_QUECTEL, "atmodem",
+ data->dlcs[GPRS_DLC]);
+ if (gc)
+ ofono_gprs_add_context(gprs, gc);
+}
+
+static void m95_post_online(struct ofono_modem *modem)
+{
+ struct m95_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ ofono_netreg_create(modem, OFONO_VENDOR_QUECTEL, "atmodem",
+ data->dlcs[NETREG_DLC]);
+ ofono_ussd_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ ofono_voicecall_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ ofono_call_volume_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+}
+
+static struct ofono_modem_driver m95_driver = {
+ .name = "m95",
+ .probe = m95_probe,
+ .remove = m95_remove,
+ .enable = m95_enable,
+ .disable = m95_disable,
+ .pre_sim = m95_pre_sim,
+ .post_sim = m95_post_sim,
+ .post_online = m95_post_online,
+};
+
+static int m95_init(void)
+{
+ return ofono_modem_driver_register(&m95_driver);
+}
+
+static void m95_exit(void)
+{
+ ofono_modem_driver_unregister(&m95_driver);
+}
+
+OFONO_PLUGIN_DEFINE(m95, "Quectel M95 modem driver", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, m95_init, m95_exit)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 71a70f0b..e58051d4 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1303,6 +1303,7 @@ static struct {
{ "wavecom", setup_wavecom },
{ "tc65", setup_tc65 },
{ "ehs6", setup_ehs6 },
+ { "m95", setup_serial_modem },
{ }
};
--
2.18.0
2 years, 6 months
[PATCH] udevng: fix removal of serial devices
by Martin Hundebøll
Since the merge of udev.c into udevng.c all cleanup function must handle
both usb devices and serial devices. Add this distinction to
check_remove(), so that is doesn't try to iterate the .serial member as
if it were a .devices list.
---
plugins/udevng.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 4b565070..71a70f0b 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1380,11 +1380,19 @@ static gboolean check_remove(gpointer key, gpointer value, gpointer user_data)
const char *devpath = user_data;
GSList *list;
- for (list = modem->devices; list; list = list->next) {
- struct device_info *info = list->data;
+ switch (modem->type) {
+ case MODEM_TYPE_USB:
+ for (list = modem->devices; list; list = list->next) {
+ struct device_info *info = list->data;
- if (g_strcmp0(info->devpath, devpath) == 0)
+ if (g_strcmp0(info->devpath, devpath) == 0)
+ return TRUE;
+ }
+ break;
+ case MODEM_TYPE_SERIAL:
+ if (g_strcmp0(modem->serial->devpath, devpath) == 0)
return TRUE;
+ break;
}
return FALSE;
--
2.18.0
2 years, 6 months
Ofono and Intel Clovertrail+
by Ilya Bizyaev
Hello everyone, I am currently working on a Halium port to an Intel Clovertrail+ phone, ASUS ZenFone 5 (A501CG). At the moment most vital device functions are supported, but it lacks the ability to make calls and send SMS. I have made some attempts to enable these features with Ofono but ran into issues. The device uses the XMM6360 modem and Intrinsyc Rapid-RIL M6.59, so I attempted to start the Ofono daemon like this: # OFONO_RIL_DEVICE=ril OFONO_RIL_TRACE=1 ofonod -d -n But it failed to detect the SIM card with various errors like E_RADIO_NOT_AVAILABLE: Ofono log: https://paste.kde.org/pjpiczknh RIL log: https://paste.kde.org/pmt7drhforo8 There is almost no publicly available information on the subject, so I would like to ask your opinion about my project, especially from the perspective of Ofono. Do you think it is possible to make this modem work with Ofono? Are there any tricky details or quirks I should know about? Any experience you can share is highly valuable to me. Best regards, Ilya Bizyaev.
2 years, 6 months