mirror of
https://github.com/sailfishos/ofono
synced 2025-11-24 19:39:44 +08:00
Compare commits
86 Commits
mer/1.18+g
...
mer/1.19+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adca340f4b | ||
|
|
709bb7e596 | ||
|
|
aef9bbd3e0 | ||
|
|
c6eb410f21 | ||
|
|
08b3ea3d0f | ||
|
|
2978862417 | ||
|
|
19228c9e67 | ||
|
|
9be791d531 | ||
|
|
6b9eb7bf8f | ||
|
|
01f8989aee | ||
|
|
2f5efaf591 | ||
|
|
ca1d06c37a | ||
|
|
5f45928a84 | ||
|
|
19f74e6c85 | ||
|
|
41d5cfcab2 | ||
|
|
357c5db580 | ||
|
|
8cea5b9f96 | ||
|
|
5fb35d5fb4 | ||
|
|
e8d57bb928 | ||
|
|
2bfde2418e | ||
|
|
c710ce76c1 | ||
|
|
78acd90464 | ||
|
|
e51b3ca0c8 | ||
|
|
b3c8813bd4 | ||
|
|
e2a3acd9d0 | ||
|
|
2054ca9570 | ||
|
|
48dbb7912a | ||
|
|
d7e7ad671d | ||
|
|
5b5a86dc80 | ||
|
|
c232524e99 | ||
|
|
bfd09a5c14 | ||
|
|
f8adcd2550 | ||
|
|
2a97567147 | ||
|
|
04d84b615e | ||
|
|
6e34792323 | ||
|
|
d6a59f5dc4 | ||
|
|
23e299055f | ||
|
|
a56ef3ba0f | ||
|
|
7294433906 | ||
|
|
d7263cd344 | ||
|
|
2f3b469fbb | ||
|
|
4187e7ee8f | ||
|
|
4d3f89bae0 | ||
|
|
cbd1c5d524 | ||
|
|
7976e44746 | ||
|
|
3d6e220686 | ||
|
|
919526d392 | ||
|
|
b7082146e8 | ||
|
|
094a296a14 | ||
|
|
5c259e751b | ||
|
|
69e5d5b356 | ||
|
|
56e7d0e8ea | ||
|
|
bb2ae6d1a1 | ||
|
|
cf7692db49 | ||
|
|
63f3311cd6 | ||
|
|
c5aae77d41 | ||
|
|
f8e21c8ad4 | ||
|
|
8e6dfe433b | ||
|
|
ae23bb552b | ||
|
|
2becd051d4 | ||
|
|
8cfb1d5ca3 | ||
|
|
50f35458f6 | ||
|
|
51843accf7 | ||
|
|
fb856dc7d6 | ||
|
|
1482748183 | ||
|
|
869ffda61e | ||
|
|
f875cbfda2 | ||
|
|
2a60eaa6e3 | ||
|
|
29b6c41d48 | ||
|
|
2f6491d005 | ||
|
|
1a25047e9d | ||
|
|
899e14bf17 | ||
|
|
2520664c63 | ||
|
|
445bbbd66f | ||
|
|
08fc4b0d03 | ||
|
|
c82e94ffb4 | ||
|
|
fd3712940b | ||
|
|
8410c985c9 | ||
|
|
0878decdc0 | ||
|
|
cb69984722 | ||
|
|
1fe8701f1a | ||
|
|
c5286fee70 | ||
|
|
3c5f6f84e1 | ||
|
|
8b87b55e8d | ||
|
|
bce34cbff3 | ||
|
|
f8351cacf1 |
1
ofono/.gitignore
vendored
1
ofono/.gitignore
vendored
@@ -44,6 +44,7 @@ unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
unit/test-rilmodem-sms
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
|
||||
@@ -113,3 +113,6 @@ Anirudh Gargi <anirudh.gargi@intel.com>
|
||||
Nishanth V <nishanth.v@intel.com>
|
||||
Antara Borwankar <antara.borwankar@gmail.com>
|
||||
Martin Chaplet <m.chaplet@kerlink.fr>
|
||||
Suman Mallela <suman.m@intel.com>
|
||||
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
|
||||
Antoine Aubert <a.aubert@overkiz.com>
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
ver 1.19:
|
||||
Fix issue with DHCP parsing and Huawei modems.
|
||||
Fix issue with detecting Huawei E3372 modem.
|
||||
Fix issue with handling serving cell info.
|
||||
Fix issue with handling SIM SC facility lock.
|
||||
Fix issue with Android RIL PIN retry logic.
|
||||
Fix issue with Android RIL and RAT handling.
|
||||
Add support for Android RIL cell broadcast.
|
||||
Add support for SoFIA 3GR thermal management.
|
||||
|
||||
ver 1.18:
|
||||
Fix issue with cell broadcast and use-after-fee.
|
||||
Fix issue with repeated held call indicator.
|
||||
|
||||
@@ -197,6 +197,7 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/call-barring.c \
|
||||
drivers/rilmodem/netmon.c \
|
||||
drivers/rilmodem/stk.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/infineonmodem/infineon_constants.h
|
||||
endif
|
||||
endif
|
||||
@@ -574,6 +575,11 @@ builtin_sources += plugins/bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez5
|
||||
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
|
||||
|
||||
if SAILFISHFOS
|
||||
builtin_modules += sfos_bt
|
||||
builtin_sources += plugins/sfos_bt.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if UPOWER
|
||||
@@ -758,6 +764,7 @@ test_scripts = test/backtrace \
|
||||
test/receive-sms \
|
||||
test/remove-contexts \
|
||||
test/send-sms \
|
||||
test/cancel-sms \
|
||||
test/set-mic-volume \
|
||||
test/set-speaker-volume \
|
||||
test/test-stk-menu \
|
||||
@@ -828,7 +835,9 @@ test_scripts = test/backtrace \
|
||||
test/set-sms-smsc \
|
||||
test/set-sms-bearer \
|
||||
test/get-serving-cell-info \
|
||||
test/list-allowed-access-points
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -854,7 +863,8 @@ if JOLLA_RILMODEM
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-sms \
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cb \
|
||||
unit/test-rilmodem-gprs
|
||||
|
||||
endif
|
||||
endif
|
||||
@@ -916,14 +926,14 @@ unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_provision_OBJECTS)
|
||||
|
||||
if RILMODEM
|
||||
if JOLLA_RILMODEM
|
||||
|
||||
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
|
||||
gatchat/ringbuffer.h gatchat/ringbuffer.c \
|
||||
unit/rilmodem-test-server.h \
|
||||
unit/rilmodem-test-server.c \
|
||||
src/simutil.c
|
||||
unit/rilmodem-test-engine.h \
|
||||
unit/rilmodem-test-engine.c \
|
||||
src/simutil.c \
|
||||
drivers/rilmodem/rilutil.c
|
||||
|
||||
unit_test_rilmodem_cs_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-cs.c \
|
||||
@@ -946,8 +956,12 @@ unit_test_rilmodem_cb_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_cb_OBJECTS)
|
||||
|
||||
endif
|
||||
endif
|
||||
unit_test_rilmodem_gprs_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-gprs.c \
|
||||
drivers/rilmodem/gprs.c
|
||||
unit_test_rilmodem_gprs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_gprs_OBJECTS)
|
||||
|
||||
TESTS = $(unit_tests)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.18)
|
||||
AC_INIT(ofono, 1.19)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -183,6 +183,13 @@ if (test "${enable_jolla_rilmodem}" = "yes"); then
|
||||
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
|
||||
[don't allow to add or remove connection context over D-Bus]), [
|
||||
if (test "${enableval}" = "no"); then
|
||||
CFLAGS="$CFLAGS -DDISABLE_ADD_REMOVE_CONTEXT"
|
||||
fi
|
||||
])
|
||||
|
||||
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
|
||||
[disable Qualcomm QMI modem support]),
|
||||
[enable_qmimodem=${enableval}])
|
||||
@@ -206,6 +213,10 @@ fi
|
||||
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
|
||||
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfishos, AC_HELP_STRING([--enable-sailfishos],
|
||||
[enable sailfishos plugin]), [enable_sailfishos=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISHFOS, test "${enable_sailfishos}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
|
||||
[disable Nettime plugin]),
|
||||
[enable_nettime=${enableval}])
|
||||
|
||||
@@ -80,7 +80,7 @@ static gboolean get_next_addr(GAtResultIter *iter, char **addr)
|
||||
if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
|
||||
return FALSE;
|
||||
|
||||
val = strtol(str, NULL, 16);
|
||||
val = strtoul(str, NULL, 16);
|
||||
|
||||
if (addr)
|
||||
*addr = g_strdup_printf("%u.%u.%u.%u",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,60 +16,155 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct ril_cbs {
|
||||
struct ofono_cbs *cbs;
|
||||
GRilIoChannel *io;
|
||||
guint timer_id;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
struct ril_cbs_cbd {
|
||||
struct ril_cbs *cd;
|
||||
ofono_cbs_set_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define RIL_CBS_CHECK_RETRY_MS 1000
|
||||
#define RIL_CBS_CHECK_RETRY_COUNT 30
|
||||
|
||||
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
|
||||
|
||||
#define ril_cbs_cbd_free g_free
|
||||
|
||||
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
|
||||
|
||||
cbd->cd = cd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_clear_topics(struct ofono_cbs *cbs,
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
GRilIoRequest* req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, activate ? 0 :1);
|
||||
|
||||
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||
GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
|
||||
int i, n = gutil_strv_length(list);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *entry = list[i];
|
||||
const char *delim = strchr(entry, '-');
|
||||
int from, to;
|
||||
if (delim) {
|
||||
char **range = g_strsplit(topics, "-", 0);
|
||||
from = atoi(range[0]);
|
||||
to = atoi(range[1]);
|
||||
g_strfreev(range);
|
||||
} else {
|
||||
from = to = atoi(entry);
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, from);
|
||||
grilio_request_append_int32(req, to);
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_append_int32(req, 0xff);
|
||||
grilio_request_append_int32(req, 1);
|
||||
}
|
||||
|
||||
DBG_(cd, "configuring CB");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
g_strfreev(list);
|
||||
}
|
||||
|
||||
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = user_data;
|
||||
|
||||
if (cbd->cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "%s", topics);
|
||||
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char* pdu;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
pdu = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", pdu);
|
||||
if (pdu) {
|
||||
ofono_cbs_notify(cd->cbs, (const guchar *)pdu, strlen(pdu));
|
||||
g_free(pdu);
|
||||
}
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
DBG_(cd, "%u bytes", len);
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_register(gpointer user_data)
|
||||
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(cd->timer_id);
|
||||
cd->timer_id = 0;
|
||||
ofono_cbs_register(cd->cbs);
|
||||
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||
cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
} else {
|
||||
DBG_(cd, "failed to query CB config");
|
||||
ofono_cbs_remove(cd->cbs);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
@@ -77,12 +172,27 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
DBG("");
|
||||
cd->cbs = cbs;
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->timer_id = g_idle_add(ril_cbs_register, cd);
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
cd->cbs = cbs;
|
||||
|
||||
DBG_(cd, "");
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
|
||||
/*
|
||||
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup.
|
||||
* We may have to retry a few times.
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
|
||||
ril_cbs_probe_done_cb, NULL, cd);
|
||||
grilio_request_unref(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -90,15 +200,13 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG("");
|
||||
DBG_(cd, "");
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
|
||||
if (cd->timer_id > 0) {
|
||||
g_source_remove(cd->timer_id);
|
||||
}
|
||||
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
grilio_queue_cancel_all(cd->q, FALSE);
|
||||
grilio_queue_unref(cd->q);
|
||||
g_free(cd->log_prefix);
|
||||
g_free(cd);
|
||||
}
|
||||
|
||||
@@ -106,8 +214,8 @@ const struct ofono_cbs_driver ril_cbs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_set_topics,
|
||||
.clear_topics = ril_clear_topics
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -15,6 +15,9 @@
|
||||
|
||||
#include "ril_config.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
@@ -106,6 +109,51 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
}
|
||||
}
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key)
|
||||
{
|
||||
char* value = ril_config_get_string(file, group, key);
|
||||
|
||||
if (value) {
|
||||
char **values = g_strsplit(value, ",", -1);
|
||||
char **ptr = values;
|
||||
GUtilIntArray* array = gutil_int_array_new();
|
||||
|
||||
while (*ptr) {
|
||||
const char *str = *ptr++;
|
||||
char *end = NULL;
|
||||
long ival = strtol(str, &end, 0);
|
||||
|
||||
if (str[0] && !end[0]) {
|
||||
gutil_int_array_append(array, ival);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
g_strfreev(values);
|
||||
return gutil_int_array_free_to_ints(array);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
{
|
||||
if (ints) {
|
||||
guint i, n;
|
||||
const int *data = gutil_ints_get_data(ints, &n);
|
||||
GString* buf = g_string_new(NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
if (buf->len > 0) {
|
||||
g_string_append_c(buf, separator);
|
||||
}
|
||||
g_string_append_printf(buf, "%d", data[i]);
|
||||
}
|
||||
return g_string_free(buf, FALSE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -22,13 +22,16 @@
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key);
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *value);
|
||||
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||
const char *key, gboolean *value);
|
||||
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags);
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||
|
||||
#endif /* RIL_CONFIG_H */
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* RIL constants adopted from AOSP's header:
|
||||
*
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2016 Jolla Ltd.
|
||||
* Copyright (C) 2013-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -118,45 +117,68 @@ enum ril_radio_tech {
|
||||
};
|
||||
|
||||
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
|
||||
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
|
||||
#define CALL_FAIL_NORMAL 16
|
||||
#define CALL_FAIL_BUSY 17
|
||||
#define CALL_FAIL_CONGESTION 34
|
||||
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
|
||||
#define CALL_FAIL_CALL_BARRED 240
|
||||
#define CALL_FAIL_FDN_BLOCKED 241
|
||||
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
|
||||
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
|
||||
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
|
||||
#define CALL_FAIL_CDMA_DROP 1001
|
||||
#define CALL_FAIL_CDMA_INTERCEPT 1002
|
||||
#define CALL_FAIL_CDMA_REORDER 1003
|
||||
#define CALL_FAIL_CDMA_SO_REJECT 1004
|
||||
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
|
||||
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
|
||||
#define CALL_FAIL_CDMA_PREEMPTED 1007
|
||||
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
|
||||
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
|
||||
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
|
||||
enum ril_call_fail_cause {
|
||||
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
|
||||
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
|
||||
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
|
||||
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
|
||||
CALL_FAIL_NORMAL = 16,
|
||||
CALL_FAIL_BUSY = 17,
|
||||
CALL_FAIL_NO_USER_RESPONDING = 18,
|
||||
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
|
||||
CALL_FAIL_CALL_REJECTED = 21,
|
||||
CALL_FAIL_NUMBER_CHANGED = 22,
|
||||
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
|
||||
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
|
||||
CALL_FAIL_FACILITY_REJECTED = 29,
|
||||
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
|
||||
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
|
||||
CALL_FAIL_CONGESTION = 34,
|
||||
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
|
||||
CALL_FAIL_TEMPORARY_FAILURE = 41,
|
||||
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
|
||||
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
|
||||
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
|
||||
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
|
||||
CALL_FAIL_QOS_UNAVAILABLE = 49,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
|
||||
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
|
||||
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
|
||||
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
|
||||
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
|
||||
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
|
||||
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
|
||||
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
|
||||
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
|
||||
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
|
||||
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
|
||||
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
|
||||
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
|
||||
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
|
||||
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
|
||||
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
|
||||
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
|
||||
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
|
||||
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
|
||||
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
|
||||
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
|
||||
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
|
||||
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
|
||||
CALL_FAIL_CALL_BARRED = 240,
|
||||
CALL_FAIL_FDN_BLOCKED = 241,
|
||||
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
|
||||
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
|
||||
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
|
||||
|
||||
/* Not defined in ril.h but valid 3GPP specific cause values
|
||||
* for call control. See 3GPP TS 24.008 Annex H. */
|
||||
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
|
||||
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
|
||||
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
|
||||
#define CALL_FAIL_NO_USER_RESPONDING 18
|
||||
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
|
||||
#define CALL_FAIL_CALL_REJECTED 21
|
||||
#define CALL_FAIL_NUMBER_CHANGED 22
|
||||
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
|
||||
#define CALL_FAIL_PRE_EMPTION 25
|
||||
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
|
||||
#define CALL_FAIL_INCOMPLETE_NUMBER 28
|
||||
#define CALL_FAIL_FACILITY_REJECTED 29
|
||||
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
|
||||
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
|
||||
CALL_FAIL_PRE_EMPTION = 25
|
||||
};
|
||||
|
||||
enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_NONE = 0,
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#define PROTO_IPV4V6_STR "IPV4V6"
|
||||
|
||||
enum ril_data_priv_flags {
|
||||
RIL_DATA_FLAG_NONE = 0x00,
|
||||
RIL_DATA_FLAG_ALLOWED = 0x01,
|
||||
RIL_DATA_FLAG_MAX_SPEED = 0x02,
|
||||
RIL_DATA_FLAG_ON = 0x04
|
||||
@@ -99,7 +100,8 @@ struct ril_data_priv {
|
||||
struct ril_data_request *req_queue;
|
||||
struct ril_data_request *pending_req;
|
||||
|
||||
enum ril_data_allow_data_opt allow_data;
|
||||
struct ril_data_options options;
|
||||
guint slot;
|
||||
char *log_prefix;
|
||||
guint query_id;
|
||||
gulong io_event_id;
|
||||
@@ -159,7 +161,8 @@ struct ril_data_request_setup {
|
||||
char *password;
|
||||
enum ofono_gprs_proto proto;
|
||||
enum ofono_gprs_auth_method auth_method;
|
||||
int retry_count;
|
||||
guint retry_count;
|
||||
guint retry_delay_id;
|
||||
};
|
||||
|
||||
struct ril_data_request_deact {
|
||||
@@ -172,7 +175,6 @@ struct ril_data_request_2g {
|
||||
gulong handler_id;
|
||||
};
|
||||
|
||||
static gboolean ril_data_manager_handover(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
|
||||
|
||||
@@ -272,7 +274,8 @@ static int ril_data_protocol_to_ofono(gchar *str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp)
|
||||
static struct ril_data_call *ril_data_call_parse(int version,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
int prot;
|
||||
char *prot_str;
|
||||
@@ -280,6 +283,7 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
|
||||
guint32 active = RIL_DATA_CALL_INACTIVE;
|
||||
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
|
||||
|
||||
/* RIL_Data_Call_Response_v6 (see ril.h) */
|
||||
grilio_parser_get_uint32(rilp, &status);
|
||||
grilio_parser_get_int32(rilp, &call->retry_time);
|
||||
grilio_parser_get_int32(rilp, &call->cid);
|
||||
@@ -299,15 +303,13 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
|
||||
call->status = status;
|
||||
call->active = active;
|
||||
|
||||
/* RIL_Data_Call_Response_v9 */
|
||||
if (version >= 9) {
|
||||
/* PCSCF */
|
||||
grilio_parser_skip_string(rilp);
|
||||
|
||||
/*
|
||||
* All known rils that report version 10 are using
|
||||
* RIL_Data_Call_Response_v11 (FairPhone 2, Nexus 4)
|
||||
*/
|
||||
if (version >= 10) {
|
||||
/* RIL_Data_Call_Response_v11 */
|
||||
if (version >= 11) {
|
||||
/* MTU */
|
||||
grilio_parser_get_int32(rilp, &call->mtu);
|
||||
}
|
||||
@@ -317,7 +319,8 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
|
||||
return call;
|
||||
}
|
||||
|
||||
struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
|
||||
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
guint len, enum ril_data_call_format format)
|
||||
{
|
||||
unsigned int version, n, i;
|
||||
GRilIoParser rilp;
|
||||
@@ -328,8 +331,13 @@ struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
|
||||
struct ril_data_call_list *list =
|
||||
g_new0(struct ril_data_call_list, 1);
|
||||
|
||||
DBG("version=%u,num=%u", version, n);
|
||||
list->version = version;
|
||||
if (format == RIL_DATA_CALL_FORMAT_AUTO || format == version) {
|
||||
DBG("version=%u,num=%u", version, n);
|
||||
list->version = version;
|
||||
} else {
|
||||
DBG("version=%u(%d),num=%u", version, format, n);
|
||||
list->version = format;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
|
||||
struct ril_data_call *call =
|
||||
@@ -499,7 +507,8 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
|
||||
priv->query_id = 0;
|
||||
}
|
||||
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format));
|
||||
}
|
||||
|
||||
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
@@ -511,7 +520,8 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,11 +596,11 @@ static gboolean ril_data_request_do_cancel(struct ril_data_request *req)
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
|
||||
DBG_(req->data, "canceling %s request %p", req->name, req);
|
||||
if (req->cancel) {
|
||||
req->cancel(req);
|
||||
}
|
||||
if (priv->pending_req == req) {
|
||||
/* Request has been submitted already */
|
||||
if (req->cancel) {
|
||||
req->cancel(req);
|
||||
}
|
||||
priv->pending_req = NULL;
|
||||
} else if (priv->req_queue == req) {
|
||||
/* It's the first one in the queue */
|
||||
@@ -673,15 +683,33 @@ static void ril_data_request_queue(struct ril_data_request *req)
|
||||
|
||||
static void ril_data_call_setup_cancel(struct ril_data_request *req)
|
||||
{
|
||||
if (req->pending_id) {
|
||||
grilio_queue_cancel_request(req->data->priv->q,
|
||||
req->pending_id, FALSE);
|
||||
req->pending_id = 0;
|
||||
if (req->cb.setup) {
|
||||
req->cb.setup(req->data, GRILIO_STATUS_CANCELLED,
|
||||
NULL, req->arg);
|
||||
}
|
||||
struct ril_data_request_setup *setup =
|
||||
G_CAST(req, struct ril_data_request_setup, req);
|
||||
|
||||
ril_data_request_cancel_io(req);
|
||||
if (setup->retry_delay_id) {
|
||||
g_source_remove(setup->retry_delay_id);
|
||||
setup->retry_delay_id = 0;
|
||||
}
|
||||
if (req->cb.setup) {
|
||||
ril_data_call_setup_cb_t cb = req->cb.setup;
|
||||
req->cb.setup = NULL;
|
||||
cb(req->data, GRILIO_STATUS_CANCELLED, NULL, req->arg);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_data_call_setup_retry(void *user_data)
|
||||
{
|
||||
struct ril_data_request_setup *setup = user_data;
|
||||
struct ril_data_request *req = &setup->req;
|
||||
|
||||
GASSERT(setup->retry_delay_id);
|
||||
setup->retry_delay_id = 0;
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
req->data->priv->options.data_call_retry_limit);
|
||||
req->submit(req);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
@@ -690,11 +718,13 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
struct ril_data_request_setup *setup = user_data;
|
||||
struct ril_data_request *req = &setup->req;
|
||||
struct ril_data *self = req->data;
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_data_call_list *list = NULL;
|
||||
struct ril_data_call *call = NULL;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
list = ril_data_call_list_parse(data, len);
|
||||
list = ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format);
|
||||
}
|
||||
|
||||
if (list) {
|
||||
@@ -707,15 +737,25 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
|
||||
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
|
||||
!setup->retry_count) {
|
||||
setup->retry_count < priv->options.data_call_retry_limit) {
|
||||
/*
|
||||
* Retry silently according to comment in ril.h
|
||||
* (no more than once though)
|
||||
* According to the comment from ril.h we should silently
|
||||
* retry. First time we retry immediately and if that doedsn't
|
||||
* work, then after certain delay.
|
||||
*/
|
||||
DBG("retrying silently");
|
||||
setup->retry_count++;
|
||||
req->pending_id = 0;
|
||||
req->submit(req);
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
priv->options.data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
guint ms = priv->options.data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
}
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
@@ -844,14 +884,11 @@ static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
|
||||
|
||||
static void ril_data_call_deact_cancel(struct ril_data_request *req)
|
||||
{
|
||||
if (req->pending_id) {
|
||||
grilio_queue_cancel_request(req->data->priv->q,
|
||||
req->pending_id, FALSE);
|
||||
req->pending_id = 0;
|
||||
if (req->cb.setup) {
|
||||
req->cb.deact(req->data, GRILIO_STATUS_CANCELLED,
|
||||
req->arg);
|
||||
}
|
||||
ril_data_request_cancel_io(req);
|
||||
if (req->cb.deact) {
|
||||
ril_data_call_deactivate_cb_t cb = req->cb.deact;
|
||||
req->cb.deact = NULL;
|
||||
cb(req->data, GRILIO_STATUS_CANCELLED, req->arg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1023,9 +1060,20 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
|
||||
ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
|
||||
}
|
||||
|
||||
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ril_data *d1 = a;
|
||||
const struct ril_data *d2 = b;
|
||||
const struct ril_data_priv *p1 = d1->priv;
|
||||
const struct ril_data_priv *p2 = d2->priv;
|
||||
|
||||
return p1->slot < p2->slot ? (-1) : p1->slot > p2->slot ? 1 : 0;
|
||||
}
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, enum ril_data_allow_data_opt opt)
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
GASSERT(dm);
|
||||
if (G_LIKELY(dm)) {
|
||||
@@ -1034,17 +1082,17 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_sim_settings *settings = network->settings;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
switch (opt) {
|
||||
priv->options = *options;
|
||||
switch (priv->options.allow_data) {
|
||||
case RIL_ALLOW_DATA_ON:
|
||||
case RIL_ALLOW_DATA_OFF:
|
||||
priv->allow_data = opt;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* When RIL_REQUEST_ALLOW_DATA first appeared in ril.h
|
||||
* RIL_VERSION was 10
|
||||
*/
|
||||
priv->allow_data = (io->ril_version > 10) ?
|
||||
priv->options.allow_data = (io->ril_version > 10) ?
|
||||
RIL_ALLOW_DATA_ON : RIL_ALLOW_DATA_OFF;
|
||||
break;
|
||||
}
|
||||
@@ -1052,6 +1100,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
priv->log_prefix = (name && name[0]) ?
|
||||
g_strconcat(name, " ", NULL) : g_strdup("");
|
||||
|
||||
priv->slot = config->slot;
|
||||
priv->q = grilio_queue_new(io);
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->dm = ril_data_manager_ref(dm);
|
||||
@@ -1076,7 +1125,10 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
dm->data_list = g_slist_append(dm->data_list, self);
|
||||
/* Order data contexts according to slot numbers */
|
||||
dm->data_list = g_slist_insert_sorted(dm->data_list, self,
|
||||
ril_data_compare_cb);
|
||||
ril_data_manager_check_network_mode(dm);
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
@@ -1379,6 +1431,16 @@ void ril_data_manager_unref(struct ril_data_manager *self)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
|
||||
{
|
||||
/*
|
||||
* The 3G/LTE handover thing only makes sense if we are managing
|
||||
* more than one SIM slot. Otherwise leave things where they are.
|
||||
*/
|
||||
return (self->data_list && self->data_list->next &&
|
||||
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
|
||||
}
|
||||
|
||||
static gboolean ril_data_manager_requests_pending(struct ril_data_manager *self)
|
||||
{
|
||||
GSList *l;
|
||||
@@ -1398,53 +1460,54 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
GSList *l;
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
gboolean need_fast_access = FALSE;
|
||||
struct ril_network *lte_network = NULL;
|
||||
int non_gsm_count = 0;
|
||||
|
||||
/*
|
||||
* Count number of SIMs for which GSM is selected
|
||||
* Count number of SIMs for which non-GSM mode is selected
|
||||
*/
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_data_priv *priv = data->priv;
|
||||
struct ril_sim_settings *sim = priv->network->settings;
|
||||
struct ril_network *network = priv->network;
|
||||
struct ril_sim_settings *sim = network->settings;
|
||||
|
||||
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM &&
|
||||
sim->imsi) {
|
||||
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) {
|
||||
non_gsm_count++;
|
||||
if (priv->flags & RIL_DATA_FLAG_MAX_SPEED) {
|
||||
need_fast_access = TRUE;
|
||||
if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) &&
|
||||
!lte_network) {
|
||||
lte_network = network;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the SIM selected for internet access has non-GSM mode
|
||||
* enabled and non-GSM mode is enabled for more than one SIM,
|
||||
* then we need to limit other SIMs to GSM. Otherwise, turn
|
||||
* all limits off.
|
||||
* If there's no SIM selected for internet access
|
||||
* then choose the first slot for LTE.
|
||||
*/
|
||||
if (need_fast_access && non_gsm_count > 1) {
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_data_priv *priv = data->priv;
|
||||
|
||||
ril_network_set_max_pref_mode(priv->network,
|
||||
(priv->flags & RIL_DATA_FLAG_MAX_SPEED) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
return;
|
||||
if (!lte_network) {
|
||||
struct ril_data *data = self->data_list->data;
|
||||
lte_network = data->priv->network;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise there's no reason to limit anything */
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
ril_network_set_max_pref_mode(data->priv->network,
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_network *network = data->priv->network;
|
||||
|
||||
ril_network_set_max_pref_mode(network,
|
||||
(network == lte_network) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Otherwise there's no reason to limit anything */
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
ril_network_set_max_pref_mode(data->priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1462,16 +1525,6 @@ static struct ril_data *ril_data_manager_allowed(struct ril_data_manager *self)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
|
||||
{
|
||||
/*
|
||||
* The 3G/LTE handover thing only makes sense if we are managing
|
||||
* more than one SIM slot. Otherwise leave things where they are.
|
||||
*/
|
||||
return (self->data_list && self->data_list->next &&
|
||||
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
|
||||
}
|
||||
|
||||
static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
struct ril_data *data)
|
||||
{
|
||||
@@ -1486,7 +1539,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
}
|
||||
|
||||
|
||||
if (priv->allow_data == RIL_ALLOW_DATA_ON) {
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ON) {
|
||||
ril_data_request_queue(ril_data_allow_new(data));
|
||||
} else {
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
|
||||
@@ -60,6 +60,20 @@ enum ril_data_allow_data_opt {
|
||||
RIL_ALLOW_DATA_OFF
|
||||
};
|
||||
|
||||
enum ril_data_call_format {
|
||||
RIL_DATA_CALL_FORMAT_AUTO,
|
||||
RIL_DATA_CALL_FORMAT_6 = 6,
|
||||
RIL_DATA_CALL_FORMAT_9 = 9,
|
||||
RIL_DATA_CALL_FORMAT_11 = 11
|
||||
};
|
||||
|
||||
struct ril_data_options {
|
||||
enum ril_data_allow_data_opt allow_data;
|
||||
enum ril_data_call_format data_call_format;
|
||||
unsigned int data_call_retry_limit;
|
||||
unsigned int data_call_retry_delay_ms;
|
||||
};
|
||||
|
||||
enum ril_data_role {
|
||||
RIL_DATA_ROLE_NONE, /* Data not allowed */
|
||||
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
|
||||
@@ -79,8 +93,9 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
||||
int ril_status, void *arg);
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, enum ril_data_allow_data_opt opt);
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config);
|
||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||
void ril_data_unref(struct ril_data *data);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
|
||||
@@ -448,14 +448,14 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Can't activate context %d (roaming)",
|
||||
ofono_info("Can't activate context %u (roaming)",
|
||||
ctx->cid);
|
||||
cb(ril_error_failure(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Activating context: %d", ctx->cid);
|
||||
ofono_info("Activating context: %u", ctx->cid);
|
||||
GASSERT(!gcd->activate.req);
|
||||
GASSERT(ctx->cid != CTX_ID_NONE);
|
||||
|
||||
@@ -509,7 +509,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivate primary");
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
gcd->deactivate.cb = cb;
|
||||
@@ -526,7 +526,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int id)
|
||||
{
|
||||
DBG("%d", id);
|
||||
DBG("%u", id);
|
||||
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,12 @@ struct ril_modem_online_request {
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_radio_settings *radio_settings;
|
||||
char *log_prefix;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gboolean pre_sim_done;
|
||||
gboolean allow_data;
|
||||
gulong sim_imsi_event_id;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
@@ -73,6 +74,8 @@ struct ril_modem_data {
|
||||
|
||||
#define RADIO_POWER_TAG(md) (md)
|
||||
|
||||
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
|
||||
|
||||
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||
{
|
||||
struct ril_modem_data *md = ofono_modem_get_data(o);
|
||||
@@ -115,6 +118,12 @@ struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
|
||||
}
|
||||
|
||||
static inline struct ofono_radio_settings *ril_modem_radio_settings(
|
||||
struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
|
||||
}
|
||||
|
||||
void ril_modem_delete(struct ril_modem *md)
|
||||
{
|
||||
if (md && md->ofono) {
|
||||
@@ -223,17 +232,23 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
if (md->modem.radio->state == RADIO_STATE_ON) {
|
||||
if (!md->radio_settings) {
|
||||
DBG("Initializing radio settings interface");
|
||||
md->radio_settings =
|
||||
ofono_radio_settings_create(md->modem.ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
struct ril_modem *m = &md->modem;
|
||||
if (m->radio->state == RADIO_STATE_ON && m->sim_settings->imsi) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!ril_modem_radio_settings(m)) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
ofono_radio_settings_create(m->ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
} else {
|
||||
/* ofono core may remove radio settings atom internally */
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
} else if (md->radio_settings) {
|
||||
DBG("Removing radio settings interface");
|
||||
ofono_radio_settings_remove(md->radio_settings);
|
||||
md->radio_settings = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +261,14 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
static void ril_modem_imsi_cb(struct ril_sim_settings *settings, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.sim_settings == settings);
|
||||
ril_modem_update_radio_settings(md);
|
||||
}
|
||||
|
||||
static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
@@ -255,7 +278,6 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ril_modem_update_radio_settings(md);
|
||||
if (!md->radio_state_event_id) {
|
||||
md->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||
@@ -289,6 +311,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||
}
|
||||
|
||||
@@ -385,6 +408,10 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_unref(modem->radio);
|
||||
|
||||
ril_sim_settings_remove_handler(modem->sim_settings,
|
||||
md->sim_imsi_event_id);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
}
|
||||
@@ -399,13 +426,13 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
ril_cell_info_unref(modem->cell_info);
|
||||
ril_data_unref(modem->data);
|
||||
grilio_channel_unref(modem->io);
|
||||
grilio_queue_cancel_all(md->q, FALSE);
|
||||
grilio_queue_unref(md->q);
|
||||
g_free(md->ecclist_file);
|
||||
g_free(md->log_prefix);
|
||||
g_free(md->imei);
|
||||
g_free(md);
|
||||
}
|
||||
@@ -436,6 +463,8 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
modem->log_prefix = log_prefix;
|
||||
modem->ecclist_file =
|
||||
md->ecclist_file = g_strdup(slot->ecclist_file);
|
||||
md->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
modem->ofono = ofono;
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
@@ -446,6 +475,16 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
|
||||
/*
|
||||
* modem->sim_settings->imsi follows IMSI known to the ofono
|
||||
* core, unlike ril_sim_info->imsi which may point to the
|
||||
* cached IMSI even before the PIN code is entered.
|
||||
*/
|
||||
md->sim_imsi_event_id =
|
||||
ril_sim_settings_add_imsi_changed_handler(settings,
|
||||
ril_modem_imsi_cb, md);
|
||||
|
||||
md->set_online.md = md;
|
||||
md->set_offline.md = md;
|
||||
ofono_modem_set_data(ofono, md);
|
||||
@@ -470,6 +509,8 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
*/
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
} else {
|
||||
ofono_error("Error %d registering %s",
|
||||
|
||||
@@ -436,9 +436,30 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
|
||||
{
|
||||
struct ril_sim_settings *settings = self->settings;
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = priv->max_pref_mode ?
|
||||
MIN(settings->pref_mode, priv->max_pref_mode) :
|
||||
settings->pref_mode;
|
||||
|
||||
/*
|
||||
* On dual-SIM phones such as Jolla C only one slot at a time
|
||||
* is allowed to use LTE. Even if the slot which has been using
|
||||
* LTE gets powered off, we still need to explicitely set its
|
||||
* preferred mode to GSM, to make LTE machinery available to
|
||||
* the other slot. This sort of behaviour might not be necessary
|
||||
* on some hardware and can (should) be made configurable when
|
||||
* it becomes necessary.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? priv->max_pref_mode :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
|
||||
/*
|
||||
* OFONO_RADIO_ACCESS_MODE_ANY is zero. If both pref_mode
|
||||
* and max_pref_mode are not ANY, we pick the smallest value.
|
||||
* Otherwise we take any non-zero value if there is one.
|
||||
*/
|
||||
const enum ofono_radio_access_mode pref_mode =
|
||||
(settings->pref_mode && max_pref_mode) ?
|
||||
MIN(settings->pref_mode, max_pref_mode) :
|
||||
settings->pref_mode ? settings->pref_mode :
|
||||
max_pref_mode;
|
||||
return ril_network_mode_to_rat(self, pref_mode);
|
||||
}
|
||||
|
||||
@@ -555,6 +576,31 @@ static int ril_network_parse_pref_resp(const void *data, guint len)
|
||||
return pref;
|
||||
}
|
||||
|
||||
static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
|
||||
int status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike ril_network_query_pref_mode_cb, this one always
|
||||
* checks the preferred mode.
|
||||
*/
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -661,8 +707,11 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
|
||||
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(RIL_NETWORK(data));
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,7 +802,9 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
* Query the initial state. Querying network state before the radio
|
||||
* has been turned on makes RIL unhappy.
|
||||
*/
|
||||
ril_network_query_pref_mode(self);
|
||||
grilio_queue_send_request_full(priv->q, NULL,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_startup_query_pref_mode_cb, NULL, self);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gdbus.h>
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_misc.h>
|
||||
#include <mce_display.h>
|
||||
@@ -54,6 +55,9 @@
|
||||
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
|
||||
#define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO
|
||||
#define RILMODEM_DEFAULT_DM_FLAGS RIL_DATA_MANAGER_3GLTE_HANDOVER
|
||||
#define RILMODEM_DEFAULT_DATA_CALL_FORMAT RIL_DATA_CALL_FORMAT_AUTO
|
||||
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4
|
||||
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY 200 /* ms */
|
||||
#define RILMODEM_DEFAULT_EMPTY_PIN_QUERY TRUE /* optimistic */
|
||||
|
||||
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
|
||||
@@ -71,6 +75,11 @@
|
||||
#define RILCONF_ECCLIST_FILE "ecclistFile"
|
||||
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
|
||||
#define RILCONF_EMPTY_PIN_QUERY "emptyPinQuery"
|
||||
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
|
||||
#define RILCONF_DATA_CALL_RETRY_LIMIT "dataCallRetryLimit"
|
||||
#define RILCONF_DATA_CALL_RETRY_DELAY "dataCallRetryDelay"
|
||||
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
|
||||
#define RILCONF_REMOTE_HANGUP_REASONS "remoteHangupReasons"
|
||||
|
||||
#define RIL_STORE "ril"
|
||||
#define RIL_STORE_GROUP "Settings"
|
||||
@@ -79,6 +88,12 @@
|
||||
#define RIL_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
|
||||
#define RIL_STORE_SLOTS_SEP ","
|
||||
|
||||
/* The file where error statistics is stored */
|
||||
#define RIL_ERROR_STORAGE "rilerror"
|
||||
|
||||
/* Modem error ids, must be static strings (only one is defined for now) */
|
||||
static const char RIL_ERROR_ID_RILD_RESTART[] = "rild-restart";
|
||||
|
||||
enum ril_plugin_io_events {
|
||||
IO_EVENT_CONNECTED,
|
||||
IO_EVENT_ERROR,
|
||||
@@ -122,7 +137,7 @@ struct ril_slot {
|
||||
int timeout; /* RIL timeout, in milliseconds */
|
||||
int index;
|
||||
int sim_flags;
|
||||
enum ril_data_allow_data_opt allow_data_opt;
|
||||
struct ril_data_options data_opt;
|
||||
struct ril_slot_config config;
|
||||
struct ril_plugin_priv *plugin;
|
||||
struct ril_modem *modem;
|
||||
@@ -202,6 +217,12 @@ static struct ofono_debug_desc ril_plugin_debug OFONO_DEBUG_ATTR = {
|
||||
.notify = ril_plugin_debug_notify
|
||||
};
|
||||
|
||||
static inline const char *ril_slot_debug_prefix(const struct ril_slot *slot)
|
||||
{
|
||||
/* slot->path always starts with a slash, skip it */
|
||||
return slot->path + 1;
|
||||
}
|
||||
|
||||
static struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
|
||||
{
|
||||
return G_CAST(pub, struct ril_plugin_priv, pub);
|
||||
@@ -605,7 +626,7 @@ static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
|
||||
struct ril_slot *slot = data;
|
||||
struct ril_plugin_priv *plugin = slot->plugin;
|
||||
|
||||
DBG("%s sim state %d", slot->path + 1, new_state);
|
||||
DBG("%s sim state %d", ril_slot_debug_prefix(slot), new_state);
|
||||
slot->sim_state = new_state;
|
||||
if (new_state == OFONO_SIM_STATE_READY) {
|
||||
struct ril_slot *voice_slot = plugin->voice_slot;
|
||||
@@ -661,10 +682,10 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
|
||||
struct ril_slot *slot = data;
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
|
||||
DBG("%s sim registered", slot->path + 1);
|
||||
DBG("%s sim registered", ril_slot_debug_prefix(slot));
|
||||
ril_plugin_register_sim(slot, __ofono_atom_get_data(atom));
|
||||
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
|
||||
DBG("%s sim unregistered", slot->path + 1);
|
||||
DBG("%s sim unregistered", ril_slot_debug_prefix(slot));
|
||||
slot->sim = NULL;
|
||||
}
|
||||
|
||||
@@ -672,8 +693,35 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
static void ril_plugin_handle_error(struct ril_slot *slot)
|
||||
static void ril_plugin_count_error(struct ril_slot *slot, const char *key,
|
||||
const char *message)
|
||||
{
|
||||
GHashTable *errors = slot->pub.errors;
|
||||
GKeyFile *storage = storage_open(NULL, RIL_ERROR_STORAGE);
|
||||
|
||||
/* Update life-time statistics */
|
||||
if (storage) {
|
||||
/* slot->path always starts with a slash, skip it */
|
||||
const char *group = slot->path + 1;
|
||||
g_key_file_set_integer(storage, group, key,
|
||||
g_key_file_get_integer(storage, group, key, NULL) + 1);
|
||||
storage_close(NULL, RIL_ERROR_STORAGE, storage, TRUE);
|
||||
}
|
||||
|
||||
/* Update run-time error counts. The key is the error id which
|
||||
* is always a static string */
|
||||
g_hash_table_insert(errors, (void*)key, GINT_TO_POINTER(
|
||||
GPOINTER_TO_INT(g_hash_table_lookup(errors, key)) + 1));
|
||||
|
||||
/* Issue the D-Bus signal */
|
||||
ril_plugin_dbus_signal_modem_error(slot->plugin->dbus,
|
||||
slot->index, key, message);
|
||||
}
|
||||
|
||||
static void ril_plugin_handle_error(struct ril_slot *slot, const char *msg)
|
||||
{
|
||||
ofono_error("%s %s", ril_slot_debug_prefix(slot), msg);
|
||||
ril_plugin_count_error(slot, RIL_ERROR_ID_RILD_RESTART, msg);
|
||||
ril_plugin_shutdown_slot(slot, TRUE);
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
ril_plugin_retry_init_io(slot);
|
||||
@@ -682,12 +730,12 @@ static void ril_plugin_handle_error(struct ril_slot *slot)
|
||||
static void ril_plugin_slot_error(GRilIoChannel *io, const GError *error,
|
||||
void *data)
|
||||
{
|
||||
ril_plugin_handle_error((struct ril_slot *)data);
|
||||
ril_plugin_handle_error((struct ril_slot *)data, GERRMSG(error));
|
||||
}
|
||||
|
||||
static void ril_plugin_slot_disconnected(GRilIoChannel *io, void *data)
|
||||
{
|
||||
ril_plugin_handle_error((struct ril_slot *)data);
|
||||
ril_plugin_handle_error((struct ril_slot *)data, "disconnected");
|
||||
}
|
||||
|
||||
static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
|
||||
@@ -695,7 +743,7 @@ static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
|
||||
{
|
||||
struct ril_slot *slot = data;
|
||||
|
||||
DBG("%s %d", slot->path + 1, online);
|
||||
DBG("%s %d", ril_slot_debug_prefix(slot), online);
|
||||
GASSERT(slot->modem);
|
||||
GASSERT(slot->modem == modem);
|
||||
|
||||
@@ -807,14 +855,15 @@ static void ril_debug_trace_update(struct ril_slot *slot)
|
||||
|
||||
static const char *ril_plugin_log_prefix(struct ril_slot *slot)
|
||||
{
|
||||
return ril_plugin_multisim(slot->plugin) ? (slot->path + 1) : "";
|
||||
return ril_plugin_multisim(slot->plugin) ?
|
||||
ril_slot_debug_prefix(slot) : "";
|
||||
}
|
||||
|
||||
static void ril_plugin_create_modem(struct ril_slot *slot)
|
||||
{
|
||||
struct ril_modem *modem;
|
||||
|
||||
DBG("%s", slot->path);
|
||||
DBG("%s", ril_slot_debug_prefix(slot));
|
||||
GASSERT(slot->io && slot->io->connected);
|
||||
GASSERT(!slot->modem);
|
||||
|
||||
@@ -969,7 +1018,8 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
|
||||
|
||||
GASSERT(!slot->data);
|
||||
slot->data = ril_data_new(slot->plugin->data_manager, log_prefix,
|
||||
slot->radio, slot->network, slot->io, slot->allow_data_opt);
|
||||
slot->radio, slot->network, slot->io, &slot->data_opt,
|
||||
&slot->config);
|
||||
|
||||
GASSERT(!slot->cell_info);
|
||||
if (slot->io->ril_version > 8) {
|
||||
@@ -1063,7 +1113,13 @@ static struct ril_slot *ril_plugin_slot_new(const char *sockpath,
|
||||
slot->config.empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
|
||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||
slot->allow_data_opt = RILMODEM_DEFAULT_DATA_OPT;
|
||||
slot->data_opt.allow_data = RILMODEM_DEFAULT_DATA_OPT;
|
||||
slot->data_opt.data_call_format = RILMODEM_DEFAULT_DATA_CALL_FORMAT;
|
||||
slot->data_opt.data_call_retry_limit =
|
||||
RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT;
|
||||
slot->data_opt.data_call_retry_delay_ms =
|
||||
RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY;
|
||||
slot->pub.errors = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
return slot;
|
||||
}
|
||||
|
||||
@@ -1153,17 +1209,67 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
strval = ril_config_get_string(file, group,
|
||||
RILCONF_ALLOW_DATA_REQ);
|
||||
if (strval) {
|
||||
slot->allow_data_opt =
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(strval, '#');
|
||||
if (comment) *comment = 0;
|
||||
g_strstrip(strval);
|
||||
slot->data_opt.allow_data =
|
||||
!strcasecmp(strval, "on") ? RIL_ALLOW_DATA_ON :
|
||||
!strcasecmp(strval, "off")? RIL_ALLOW_DATA_OFF :
|
||||
RIL_ALLOW_DATA_AUTO;
|
||||
DBG("%s: %s %s", group, RILCONF_ALLOW_DATA_REQ,
|
||||
slot->allow_data_opt==RIL_ALLOW_DATA_ON? "on":
|
||||
slot->allow_data_opt==RIL_ALLOW_DATA_OFF? "off":
|
||||
"auto");
|
||||
slot->data_opt.allow_data ==
|
||||
RIL_ALLOW_DATA_ON ? "on":
|
||||
slot->data_opt.allow_data ==
|
||||
RIL_ALLOW_DATA_OFF ? "off":
|
||||
"auto");
|
||||
g_free(strval);
|
||||
}
|
||||
|
||||
strval = ril_config_get_string(file, group,
|
||||
RILCONF_DATA_CALL_FORMAT);
|
||||
if (strval) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(strval, '#');
|
||||
if (comment) *comment = 0;
|
||||
g_strstrip(strval);
|
||||
slot->data_opt.data_call_format =
|
||||
!strcmp(strval, "6") ? RIL_DATA_CALL_FORMAT_6:
|
||||
!strcmp(strval, "9") ? RIL_DATA_CALL_FORMAT_9:
|
||||
!strcmp(strval, "11")? RIL_DATA_CALL_FORMAT_11:
|
||||
RIL_DATA_CALL_FORMAT_AUTO;
|
||||
if (slot->data_opt.data_call_format ==
|
||||
RIL_DATA_CALL_FORMAT_AUTO) {
|
||||
DBG("%s: %s auto", group,
|
||||
RILCONF_DATA_CALL_FORMAT);
|
||||
} else {
|
||||
DBG("%s: %s %d", group,
|
||||
RILCONF_DATA_CALL_FORMAT,
|
||||
slot->data_opt.data_call_format);
|
||||
}
|
||||
g_free(strval);
|
||||
}
|
||||
|
||||
if (ril_config_get_integer(file, group,
|
||||
RILCONF_DATA_CALL_RETRY_LIMIT, &value) && value >= 0) {
|
||||
DBG("%s: %s %d", group,
|
||||
RILCONF_DATA_CALL_RETRY_LIMIT, value);
|
||||
slot->data_opt.data_call_retry_limit = value;
|
||||
}
|
||||
|
||||
if (ril_config_get_integer(file, group,
|
||||
RILCONF_DATA_CALL_RETRY_DELAY, &value) && value >= 0) {
|
||||
DBG("%s: %s %d ms", group,
|
||||
RILCONF_DATA_CALL_RETRY_DELAY, value);
|
||||
slot->data_opt.data_call_retry_delay_ms = value;
|
||||
}
|
||||
|
||||
slot->ecclist_file = ril_config_get_string(file, group,
|
||||
RILCONF_ECCLIST_FILE);
|
||||
if (slot->ecclist_file && slot->ecclist_file[0]) {
|
||||
@@ -1174,6 +1280,27 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
g_free(slot->ecclist_file);
|
||||
slot->ecclist_file = NULL;
|
||||
}
|
||||
|
||||
slot->config.local_hangup_reasons = ril_config_get_ints(file,
|
||||
group, RILCONF_LOCAL_HANGUP_REASONS);
|
||||
strval = ril_config_ints_to_string(
|
||||
slot->config.local_hangup_reasons, ',');
|
||||
if (strval) {
|
||||
DBG("%s: %s %s", group, RILCONF_LOCAL_HANGUP_REASONS,
|
||||
strval);
|
||||
g_free(strval);
|
||||
}
|
||||
|
||||
slot->config.remote_hangup_reasons = ril_config_get_ints(file,
|
||||
group, RILCONF_REMOTE_HANGUP_REASONS);
|
||||
strval = ril_config_ints_to_string(
|
||||
slot->config.remote_hangup_reasons, ',');
|
||||
if (strval) {
|
||||
DBG("%s: %s %s", group, RILCONF_REMOTE_HANGUP_REASONS,
|
||||
strval);
|
||||
g_free(strval);
|
||||
}
|
||||
|
||||
} else {
|
||||
DBG("no socket path in %s", group);
|
||||
}
|
||||
@@ -1186,6 +1313,9 @@ static void ril_plugin_delete_slot(struct ril_slot *slot)
|
||||
ril_plugin_shutdown_slot(slot, TRUE);
|
||||
ril_sim_info_unref(slot->sim_info);
|
||||
ril_sim_settings_unref(slot->sim_settings);
|
||||
gutil_ints_unref(slot->config.local_hangup_reasons);
|
||||
gutil_ints_unref(slot->config.remote_hangup_reasons);
|
||||
g_hash_table_destroy(slot->pub.errors);
|
||||
g_free(slot->path);
|
||||
g_free(slot->imei);
|
||||
g_free(slot->name);
|
||||
@@ -1341,7 +1471,7 @@ static void ril_plugin_switch_user()
|
||||
static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
|
||||
{
|
||||
if (slot->pub.enabled) {
|
||||
DBG("%s enabled", slot->path + 1);
|
||||
DBG("%s enabled", ril_slot_debug_prefix(slot));
|
||||
ril_plugin_check_modem(slot);
|
||||
}
|
||||
}
|
||||
@@ -1349,7 +1479,7 @@ static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
|
||||
static void ril_plugin_update_disabled_slot(struct ril_slot *slot)
|
||||
{
|
||||
if (!slot->pub.enabled) {
|
||||
DBG("%s disabled", slot->path + 1);
|
||||
DBG("%s disabled", ril_slot_debug_prefix(slot));
|
||||
ril_plugin_shutdown_slot(slot, FALSE);
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -52,6 +52,7 @@ struct ril_slot_info {
|
||||
gboolean enabled;
|
||||
gboolean sim_present;
|
||||
const struct ril_slot_config *config;
|
||||
GHashTable *errors;
|
||||
};
|
||||
|
||||
struct ril_plugin {
|
||||
@@ -123,6 +124,8 @@ void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
|
||||
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
|
||||
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
|
||||
gboolean present);
|
||||
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
|
||||
int index, const char *id, const char *message);
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const struct ril_slot_info *slot, struct ril_radio *radio,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -46,7 +46,7 @@ struct ril_plugin_dbus {
|
||||
|
||||
#define RIL_DBUS_PATH "/"
|
||||
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
|
||||
#define RIL_DBUS_INTERFACE_VERSION (5)
|
||||
#define RIL_DBUS_INTERFACE_VERSION (6)
|
||||
|
||||
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
|
||||
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
|
||||
@@ -57,8 +57,11 @@ struct ril_plugin_dbus {
|
||||
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
|
||||
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
|
||||
#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
|
||||
#define RIL_DBUS_SIGNAL_MODEM_ERROR "ModemError"
|
||||
#define RIL_DBUS_IMSI_AUTO "auto"
|
||||
|
||||
#define RIL_DBUS_ERROR_SIGNATURE "si"
|
||||
|
||||
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
|
||||
{
|
||||
return slot->enabled;
|
||||
@@ -167,6 +170,48 @@ static void ril_plugin_dbus_message_append_path_array(DBusMessage *msg,
|
||||
ril_plugin_dbus_append_path_array(&iter, dbus, fn);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_modem_error(DBusMessageIter *it,
|
||||
const char *id, dbus_uint32_t count)
|
||||
{
|
||||
DBusMessageIter sub;
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub);
|
||||
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id);
|
||||
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &count);
|
||||
dbus_message_iter_close_container(it, &sub);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_modem_errors(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
DBusMessageIter slots;
|
||||
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
|
||||
"a(" RIL_DBUS_ERROR_SIGNATURE ")", &slots);
|
||||
|
||||
while (*ptr) {
|
||||
const struct ril_slot_info *slot = *ptr++;
|
||||
DBusMessageIter errors;
|
||||
|
||||
dbus_message_iter_open_container(&slots, DBUS_TYPE_ARRAY,
|
||||
"(" RIL_DBUS_ERROR_SIGNATURE ")", &errors);
|
||||
|
||||
if (g_hash_table_size(slot->errors)) {
|
||||
gpointer key, value;
|
||||
GHashTableIter iter;
|
||||
g_hash_table_iter_init(&iter, slot->errors);
|
||||
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||
ril_plugin_dbus_append_modem_error(&errors,
|
||||
key, GPOINTER_TO_INT(value));
|
||||
}
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(&slots, &errors);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(it, &slots);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
|
||||
const char *name, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
@@ -257,6 +302,19 @@ void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
|
||||
int index, const char *id, const char *message)
|
||||
{
|
||||
const char *path = dbus->plugin->slots[index]->path;
|
||||
if (!message) message = "";
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
RIL_DBUS_SIGNAL_MODEM_ERROR,
|
||||
DBUS_TYPE_OBJECT_PATH, &path,
|
||||
DBUS_TYPE_STRING, &id,
|
||||
DBUS_TYPE_STRING, &message,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
@@ -375,6 +433,13 @@ static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
|
||||
ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all6(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all5(it, dbus);
|
||||
ril_plugin_dbus_append_modem_errors(it, dbus);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -410,6 +475,13 @@ static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
|
||||
ril_plugin_dbus_append_all5);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all6(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all6);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -554,6 +626,13 @@ static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_modem_errors(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_modem_errors);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -697,28 +776,44 @@ static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
|
||||
* talking to.
|
||||
*/
|
||||
|
||||
#define RIL_DBUS_VERSION_ARG {"version", "i"}
|
||||
#define RIL_DBUS_AVAILABLE_MODEMS_ARG {"availableModems", "ao"}
|
||||
#define RIL_DBUS_ENABLED_MODEMS_ARG {"enabledModems", "ao" }
|
||||
#define RIL_DBUS_DEFAULT_DATA_SIM_ARG {"defaultDataSim", "s" }
|
||||
#define RIL_DBUS_DEFAULT_VOICE_SIM_ARG {"defaultVoiceSim", "s" }
|
||||
#define RIL_DBUS_DEFAULT_DATA_MODEM_ARG {"defaultDataModem", "s" }
|
||||
#define RIL_DBUS_DEFAULT_VOICE_MODEM_ARG {"defaultVoiceModem" , "s"}
|
||||
#define RIL_DBUS_PRESENT_SIMS_ARG {"presentSims" , "ab"}
|
||||
#define RIL_DBUS_IMEI_ARG {"imei" , "as"}
|
||||
#define RIL_DBUS_MMS_SIM_ARG {"mmsSim", "s"}
|
||||
#define RIL_DBUS_MMS_MODEM_ARG {"mmsModem" , "s"}
|
||||
#define RIL_DBUS_READY_ARG {"ready" , "b"}
|
||||
#define RIL_DBUS_MODEM_ERRORS_ARG {"errors" , \
|
||||
"aa(" RIL_DBUS_ERROR_SIGNATURE ")"}
|
||||
#define RIL_DBUS_GET_ALL_ARGS \
|
||||
{"version", "i" }, \
|
||||
{"availableModems", "ao" }, \
|
||||
{"enabledModems", "ao" }, \
|
||||
{"defaultDataSim", "s" }, \
|
||||
{"defaultVoiceSim", "s" }, \
|
||||
{"defaultDataModem", "s" }, \
|
||||
{"defaultVoiceModem" , "s"}
|
||||
RIL_DBUS_VERSION_ARG, \
|
||||
RIL_DBUS_AVAILABLE_MODEMS_ARG, \
|
||||
RIL_DBUS_ENABLED_MODEMS_ARG, \
|
||||
RIL_DBUS_DEFAULT_DATA_SIM_ARG, \
|
||||
RIL_DBUS_DEFAULT_VOICE_SIM_ARG, \
|
||||
RIL_DBUS_DEFAULT_DATA_MODEM_ARG, \
|
||||
RIL_DBUS_DEFAULT_VOICE_MODEM_ARG
|
||||
#define RIL_DBUS_GET_ALL2_ARGS \
|
||||
RIL_DBUS_GET_ALL_ARGS, \
|
||||
{"presentSims" , "ab"}
|
||||
RIL_DBUS_PRESENT_SIMS_ARG
|
||||
#define RIL_DBUS_GET_ALL3_ARGS \
|
||||
RIL_DBUS_GET_ALL2_ARGS, \
|
||||
{"imei" , "as"}
|
||||
RIL_DBUS_IMEI_ARG
|
||||
#define RIL_DBUS_GET_ALL4_ARGS \
|
||||
RIL_DBUS_GET_ALL3_ARGS, \
|
||||
{"mmsSim", "s" }, \
|
||||
{"mmsModem" , "s"}
|
||||
RIL_DBUS_MMS_SIM_ARG, \
|
||||
RIL_DBUS_MMS_MODEM_ARG
|
||||
#define RIL_DBUS_GET_ALL5_ARGS \
|
||||
RIL_DBUS_GET_ALL4_ARGS, \
|
||||
{"ready" , "b"}
|
||||
|
||||
RIL_DBUS_READY_ARG
|
||||
#define RIL_DBUS_GET_ALL6_ARGS \
|
||||
RIL_DBUS_GET_ALL5_ARGS, \
|
||||
RIL_DBUS_MODEM_ERRORS_ARG
|
||||
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
|
||||
@@ -735,42 +830,48 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
|
||||
{ GDBUS_ASYNC_METHOD("GetAll5",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
|
||||
ril_plugin_dbus_get_all5) },
|
||||
{ GDBUS_ASYNC_METHOD("GetAll6",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL6_ARGS),
|
||||
ril_plugin_dbus_get_all6) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion",
|
||||
NULL, GDBUS_ARGS({ "version", "i" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_VERSION_ARG),
|
||||
ril_plugin_dbus_get_interface_version) },
|
||||
{ GDBUS_METHOD("GetAvailableModems",
|
||||
NULL, GDBUS_ARGS({ "modems", "ao" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_AVAILABLE_MODEMS_ARG),
|
||||
ril_plugin_dbus_get_available_modems) },
|
||||
{ GDBUS_METHOD("GetEnabledModems",
|
||||
NULL, GDBUS_ARGS({ "modems", "ao" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG),
|
||||
ril_plugin_dbus_get_enabled_modems) },
|
||||
{ GDBUS_METHOD("GetPresentSims",
|
||||
NULL, GDBUS_ARGS({ "presentSims", "ab" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_PRESENT_SIMS_ARG),
|
||||
ril_plugin_dbus_get_present_sims) },
|
||||
{ GDBUS_ASYNC_METHOD("GetIMEI",
|
||||
NULL, GDBUS_ARGS({ "imei", "as" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_IMEI_ARG),
|
||||
ril_plugin_dbus_get_imei) },
|
||||
{ GDBUS_METHOD("GetDefaultDataSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG),
|
||||
ril_plugin_dbus_get_default_data_sim) },
|
||||
{ GDBUS_METHOD("GetDefaultVoiceSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG),
|
||||
ril_plugin_dbus_get_default_voice_sim) },
|
||||
{ GDBUS_METHOD("GetMmsSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG),
|
||||
ril_plugin_dbus_get_mms_sim) },
|
||||
{ GDBUS_METHOD("GetDefaultDataModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG),
|
||||
ril_plugin_dbus_get_default_data_modem) },
|
||||
{ GDBUS_METHOD("GetDefaultVoiceModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG),
|
||||
ril_plugin_dbus_get_default_voice_modem) },
|
||||
{ GDBUS_METHOD("GetMmsModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG),
|
||||
ril_plugin_dbus_get_mms_modem) },
|
||||
{ GDBUS_METHOD("GetReady",
|
||||
NULL, GDBUS_ARGS({ "ready", "b" }),
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_READY_ARG),
|
||||
ril_plugin_dbus_get_ready) },
|
||||
{ GDBUS_METHOD("GetModemErrors",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_MODEM_ERRORS_ARG),
|
||||
ril_plugin_dbus_get_modem_errors) },
|
||||
{ GDBUS_METHOD("SetEnabledModems",
|
||||
GDBUS_ARGS({ "modems", "ao" }), NULL,
|
||||
ril_plugin_dbus_set_enabled_modems) },
|
||||
@@ -788,24 +889,28 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
|
||||
|
||||
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
|
||||
GDBUS_ARGS({ "modems", "ao" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
|
||||
GDBUS_ARGS({"index", "i" },
|
||||
{"present" , "b"})) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
|
||||
GDBUS_ARGS({ "ready", "b" })) },
|
||||
GDBUS_ARGS(RIL_DBUS_READY_ARG)) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MODEM_ERROR,
|
||||
GDBUS_ARGS({"path","o"},
|
||||
{"error_id", "s"},
|
||||
{"message", "s"})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -85,6 +85,7 @@ struct ril_sim {
|
||||
ofono_sim_passwd_cb_t query_passwd_state_cb;
|
||||
void *query_passwd_state_cb_data;
|
||||
guint query_passwd_state_timeout_id;
|
||||
gulong query_passwd_state_sim_status_refresh_id;
|
||||
};
|
||||
|
||||
struct ril_sim_io_response {
|
||||
@@ -379,20 +380,11 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
|
||||
|
||||
DBG_(sd, "");
|
||||
|
||||
|
||||
/*
|
||||
* In case sim card has been removed prior to this callback has been
|
||||
* called we must not call the core call back method as otherwise the
|
||||
* core will crash.
|
||||
*/
|
||||
if (!sd->inserted) {
|
||||
ofono_error("No SIM card");
|
||||
return;
|
||||
}
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
if (!sd->inserted) {
|
||||
DBG_(sd, "No SIM card");
|
||||
} else if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
gboolean ok = FALSE;
|
||||
guchar access[3] = { 0x00, 0x00, 0x00 };
|
||||
guchar file_status = EF_STATUS_VALID;
|
||||
@@ -700,6 +692,12 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
|
||||
sd->query_passwd_state_timeout_id = 0;
|
||||
}
|
||||
|
||||
if (sd->query_passwd_state_sim_status_refresh_id) {
|
||||
ril_sim_card_remove_handler(sd->card,
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
sd->query_passwd_state_sim_status_refresh_id = 0;
|
||||
}
|
||||
|
||||
if (sd->query_passwd_state_cb) {
|
||||
ofono_sim_passwd_cb_t cb = sd->query_passwd_state_cb;
|
||||
void *data = sd->query_passwd_state_cb_data;
|
||||
@@ -893,6 +891,15 @@ static void ril_sim_query_pin_retries(struct ofono_sim *sim,
|
||||
cb(ril_error_ok(&error), sd->retries, data);
|
||||
}
|
||||
|
||||
static void ril_sim_query_passwd_state_complete_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_sim *sd = user_data;
|
||||
|
||||
GASSERT(sd->query_passwd_state_sim_status_refresh_id);
|
||||
ril_sim_finish_passwd_state_query(sd, ril_sim_passwd_state(sd));
|
||||
}
|
||||
|
||||
static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_sim *sd = user_data;
|
||||
@@ -908,29 +915,41 @@ static void ril_sim_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
enum ofono_sim_password_type passwd_state = ril_sim_passwd_state(sd);
|
||||
struct ofono_error error;
|
||||
|
||||
if (sd->query_passwd_state_timeout_id) {
|
||||
g_source_remove(sd->query_passwd_state_timeout_id);
|
||||
sd->query_passwd_state_timeout_id = 0;
|
||||
}
|
||||
|
||||
if (passwd_state != OFONO_SIM_PASSWORD_INVALID) {
|
||||
DBG_(sd, "%d", passwd_state);
|
||||
sd->query_passwd_state_cb = NULL;
|
||||
sd->query_passwd_state_cb_data = NULL;
|
||||
sd->ofono_passwd_state = passwd_state;
|
||||
cb(ril_error_ok(&error), passwd_state, data);
|
||||
if (!sd->query_passwd_state_sim_status_refresh_id) {
|
||||
ril_sim_card_remove_handler(sd->card,
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
sd->query_passwd_state_sim_status_refresh_id = 0;
|
||||
}
|
||||
|
||||
/* Always request fresh status, just in case. */
|
||||
ril_sim_card_request_status(sd->card);
|
||||
sd->query_passwd_state_cb = cb;
|
||||
sd->query_passwd_state_cb_data = data;
|
||||
|
||||
if (ril_sim_passwd_state(sd) != OFONO_SIM_PASSWORD_INVALID) {
|
||||
/* Just wait for GET_SIM_STATUS completion */
|
||||
DBG_(sd, "waiting for SIM status query to complete");
|
||||
sd->query_passwd_state_sim_status_refresh_id =
|
||||
ril_sim_card_add_status_received_handler(sd->card,
|
||||
ril_sim_query_passwd_state_complete_cb, sd);
|
||||
} else {
|
||||
/* Wait for the state to change */
|
||||
DBG_(sd, "waiting for the SIM state to change");
|
||||
sd->query_passwd_state_cb = cb;
|
||||
sd->query_passwd_state_cb_data = data;
|
||||
sd->query_passwd_state_timeout_id =
|
||||
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
|
||||
ril_sim_query_passwd_state_timeout_cb, sd);
|
||||
}
|
||||
|
||||
/*
|
||||
* We still need to complete the request somehow, even if
|
||||
* GET_STATUS never completes or SIM status never changes.
|
||||
*/
|
||||
sd->query_passwd_state_timeout_id =
|
||||
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
|
||||
ril_sim_query_passwd_state_timeout_cb, sd);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
|
||||
@@ -1289,6 +1308,11 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
g_source_remove(sd->query_passwd_state_timeout_id);
|
||||
}
|
||||
|
||||
if (sd->query_passwd_state_sim_status_refresh_id) {
|
||||
ril_sim_card_remove_handler(sd->card,
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
}
|
||||
|
||||
ril_sim_card_remove_handler(sd->card, sd->card_status_id);
|
||||
ril_sim_card_unref(sd->card);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -64,8 +64,6 @@ G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
|
||||
#define RIL_SIMCARD_STATE_CHANGED (0x01)
|
||||
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self);
|
||||
|
||||
static gboolean ril_sim_card_app_equal(const struct ril_sim_card_app *a1,
|
||||
const struct ril_sim_card_app *a2)
|
||||
{
|
||||
@@ -365,7 +363,7 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -55,6 +55,7 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_unref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_request_status(struct ril_sim_card *self);
|
||||
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
|
||||
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
|
||||
@@ -154,22 +154,18 @@ static void ril_sim_settings_imsi_watch_done(void *user_data)
|
||||
priv->imsi_watch_id = 0;
|
||||
}
|
||||
|
||||
static void ril_sim_settings_ready(struct ril_sim_settings *self)
|
||||
static void ril_sim_settings_state_check(struct ril_sim_settings *self,
|
||||
enum ofono_sim_state new_state)
|
||||
{
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
GASSERT(!priv->imsi_watch_id);
|
||||
priv->imsi_watch_id = ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_settings_imsi_watch_cb, self,
|
||||
ril_sim_settings_imsi_watch_done);
|
||||
if (new_state != OFONO_SIM_STATE_READY) {
|
||||
ril_sim_settings_set_imsi(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
|
||||
void *user_data)
|
||||
{
|
||||
if (new_state == OFONO_SIM_STATE_READY) {
|
||||
ril_sim_settings_ready(RIL_SIM_SETTINGS(user_data));
|
||||
}
|
||||
ril_sim_settings_state_check(RIL_SIM_SETTINGS(user_data), new_state);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_watch_done(void *user_data)
|
||||
@@ -191,13 +187,19 @@ void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
|
||||
if (priv->imsi_watch_id) {
|
||||
ofono_sim_remove_imsi_watch(priv->sim,
|
||||
priv->imsi_watch_id);
|
||||
/* ril_sim_settings_imsi_watch_done clears it */
|
||||
/*
|
||||
* ril_sim_settings_imsi_watch_done
|
||||
* clears it
|
||||
*/
|
||||
GASSERT(!priv->imsi_watch_id);
|
||||
}
|
||||
if (priv->state_watch_id) {
|
||||
ofono_sim_remove_state_watch(priv->sim,
|
||||
priv->state_watch_id);
|
||||
/* ril_sim_settings_state_watch_done clears it */
|
||||
/*
|
||||
* ril_sim_settings_state_watch_done
|
||||
* clears it
|
||||
*/
|
||||
GASSERT(!priv->state_watch_id);
|
||||
}
|
||||
priv->sim = sim;
|
||||
@@ -207,13 +209,25 @@ void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
|
||||
ril_sim_settings_state_watch, self,
|
||||
ril_sim_settings_state_watch_done);
|
||||
GASSERT(priv->state_watch_id);
|
||||
if (ofono_sim_get_state(sim) ==
|
||||
OFONO_SIM_STATE_READY) {
|
||||
ril_sim_settings_ready(self);
|
||||
}
|
||||
} else {
|
||||
ril_sim_settings_set_imsi(self, NULL);
|
||||
ril_sim_settings_state_check(self,
|
||||
ofono_sim_get_state(sim));
|
||||
/*
|
||||
* ofono_sim_add_imsi_watch immediately
|
||||
* calls the event callback if IMSI is
|
||||
* already known. It's useless though
|
||||
* because we still have to check the
|
||||
* current state in case if IMSI is not
|
||||
* available yet.
|
||||
*/
|
||||
priv->imsi_watch_id =
|
||||
ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_settings_imsi_watch_cb, self,
|
||||
ril_sim_settings_imsi_watch_done);
|
||||
GASSERT(priv->state_watch_id);
|
||||
}
|
||||
/* Luckily, ofono_sim_get_imsi handles NULL pointer */
|
||||
ril_sim_settings_set_imsi(self,
|
||||
ofono_sim_get_imsi(sim));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,3 +113,41 @@ socket=/dev/socket/rild
|
||||
# Default is true
|
||||
#
|
||||
#emptyPinQuery=true
|
||||
|
||||
# Different RILs use different data call structures which don't necessarily
|
||||
# match the format specified in the data list header. The header may have
|
||||
# version 9 but the list may contain RIL_Data_Call_Response_v6 structures,
|
||||
# list version 10 may contain RIL_Data_Call_Response_v11 and so on. By default
|
||||
# ofono assumes that the version from the list header matches the contents
|
||||
# but sometimes you have to explicitly tell ofono which one to use.
|
||||
# Possible values are 6, 9, 11 and auto.
|
||||
#
|
||||
# Default is auto
|
||||
#
|
||||
#dataCallFormat=auto
|
||||
|
||||
# Data call may fail with status 65535 which according to ril.h means that
|
||||
# we need to retry silently. The maximum number of retries is limited by
|
||||
# this parameter. Usually, one retry is enough. The first retry occurs
|
||||
# immediately, the subsequent ones after dataCallRetryDelay (see below)
|
||||
#
|
||||
# Default is 4
|
||||
#
|
||||
#dataCallRetryLimit=4
|
||||
|
||||
# Delay between data call retries, in milliseconds. Note that the first
|
||||
# retry occurs immediately after the first failure, the delays are only
|
||||
# applied if the first retry fails too.
|
||||
#
|
||||
# Default is 200 ms
|
||||
#
|
||||
#dataCallRetryDelay=200
|
||||
|
||||
# Additional local and remote hangup reasons. Remote reasons are checked
|
||||
# first. Normally, RIL plugin figures it out automatically. You would only
|
||||
# need to define these if your RIL does something unusual.
|
||||
#
|
||||
# No default
|
||||
#
|
||||
#remoteHangupReasons=20
|
||||
#localHangupReasons=23
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -53,6 +53,8 @@ struct ril_slot_config {
|
||||
guint slot;
|
||||
gboolean enable_4g;
|
||||
gboolean empty_pin_query;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
};
|
||||
|
||||
#endif /* RIL_TYPES_H */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_ring.h>
|
||||
|
||||
#define FLAG_NEED_CLIP 1
|
||||
@@ -43,7 +44,9 @@ struct ril_voicecall {
|
||||
ofono_voicecall_cb_t cb;
|
||||
void *data;
|
||||
guint timer_id;
|
||||
GUtilRing* dtmf_queue;
|
||||
GUtilRing *dtmf_queue;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
guint send_dtmf_id;
|
||||
guint clcc_poll_id;
|
||||
gulong event_id[VOICECALL_EVENT_COUNT];
|
||||
@@ -60,28 +63,13 @@ struct ril_voicecall_change_state_req {
|
||||
};
|
||||
|
||||
struct lastcause_req {
|
||||
struct ofono_voicecall *vc;
|
||||
struct ril_voicecall *vd;
|
||||
int id;
|
||||
};
|
||||
|
||||
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
|
||||
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
|
||||
|
||||
/*
|
||||
* structs ofono_voicecall and voicecall are fully defined
|
||||
* in src/voicecall.c; we need (read) access to the
|
||||
* call objects, so partially redefine them here.
|
||||
*/
|
||||
struct ofono_voicecall {
|
||||
GSList *call_list;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct voicecall {
|
||||
struct ofono_call *call;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
static inline struct ril_voicecall *ril_voicecall_get_data(
|
||||
struct ofono_voicecall *vc)
|
||||
{
|
||||
@@ -166,38 +154,76 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
|
||||
}
|
||||
|
||||
/* Valid call statuses have value >= 0 */
|
||||
static int call_status_with_id(struct ofono_voicecall *vc, int id)
|
||||
static int ril_voicecall_status_with_id(struct ofono_voicecall *vc,
|
||||
unsigned int id)
|
||||
{
|
||||
GSList *l;
|
||||
struct voicecall *v;
|
||||
struct ofono_call *call = ofono_voicecall_find_call(vc, id);
|
||||
|
||||
GASSERT(vc);
|
||||
return call ? call->status : -1;
|
||||
}
|
||||
|
||||
for (l = vc->call_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
if (v->call->id == id) {
|
||||
return v->call->status;
|
||||
/* Tries to parse the payload as a uint followed by a string */
|
||||
static int ril_voicecall_parse_lastcause_1(const void *data, guint len)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (len > 8) {
|
||||
int code;
|
||||
char *msg = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &code) && code >= 0 &&
|
||||
(msg = grilio_parser_get_utf8(&rilp)) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
DBG("%d \"%s\"", code, msg);
|
||||
result = code;
|
||||
}
|
||||
g_free(msg);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct lastcause_req *reqdata = user_data;
|
||||
struct ofono_voicecall *vc = reqdata->vc;
|
||||
int tmp;
|
||||
struct ril_voicecall *vd = reqdata->vd;
|
||||
struct ofono_voicecall *vc = vd->vc;
|
||||
int id = reqdata->id;
|
||||
int call_status;
|
||||
|
||||
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
|
||||
grilio_parser_get_int32(&rilp, &last_cause);
|
||||
int last_cause;
|
||||
|
||||
/*
|
||||
* According to ril.h:
|
||||
*
|
||||
* "response" is a "int *"
|
||||
* ((int *)response)[0] is RIL_LastCallFailCause. GSM failure
|
||||
* reasons are mapped to cause codes defined in TS 24.008 Annex H
|
||||
* where possible.
|
||||
*
|
||||
* However some RILs feel free to invent their own formats,
|
||||
* try those first.
|
||||
*/
|
||||
|
||||
last_cause = ril_voicecall_parse_lastcause_1(data, len);
|
||||
if (last_cause < 0) {
|
||||
GRilIoParser rilp;
|
||||
int num, code;
|
||||
|
||||
/* Default format described in ril.h */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &num) && num == 1 &&
|
||||
grilio_parser_get_int32(&rilp, &code) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
last_cause = code;
|
||||
} else {
|
||||
ofono_warn("Unable to parse last call fail cause");
|
||||
last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -208,7 +234,14 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
|
||||
* from a network failure.
|
||||
*/
|
||||
switch (last_cause) {
|
||||
if (gutil_ints_contains(vd->remote_hangup_reasons, last_cause)) {
|
||||
DBG("hangup cause %d => remote hangup", last_cause);
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
} else if (gutil_ints_contains(vd->local_hangup_reasons, last_cause)) {
|
||||
DBG("hangup cause %d => local hangup", last_cause);
|
||||
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
|
||||
} else {
|
||||
switch (last_cause) {
|
||||
case CALL_FAIL_UNOBTAINABLE_NUMBER:
|
||||
case CALL_FAIL_NORMAL:
|
||||
case CALL_FAIL_BUSY:
|
||||
@@ -216,19 +249,19 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
|
||||
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
|
||||
case CALL_FAIL_NO_USER_RESPONDING:
|
||||
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
|
||||
case CALL_FAIL_NO_ANSWER_FROM_USER:
|
||||
case CALL_FAIL_CALL_REJECTED:
|
||||
case CALL_FAIL_NUMBER_CHANGED:
|
||||
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
|
||||
case CALL_FAIL_PRE_EMPTION:
|
||||
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
|
||||
case CALL_FAIL_INCOMPLETE_NUMBER:
|
||||
case CALL_FAIL_INVALID_NUMBER_FORMAT:
|
||||
case CALL_FAIL_FACILITY_REJECTED:
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
break;
|
||||
|
||||
case CALL_FAIL_NORMAL_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
call_status = ril_voicecall_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_ACTIVE ||
|
||||
call_status == CALL_STATUS_HELD ||
|
||||
call_status == CALL_STATUS_DIALING ||
|
||||
@@ -240,7 +273,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
break;
|
||||
|
||||
case CALL_FAIL_ERROR_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
call_status = ril_voicecall_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
@@ -250,6 +283,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
default:
|
||||
reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
|
||||
@@ -295,7 +329,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
struct lastcause_req *reqdata =
|
||||
g_new0(struct lastcause_req, 1);
|
||||
|
||||
reqdata->vc = vd->vc;
|
||||
reqdata->vd = vd;
|
||||
reqdata->id = oc->id;
|
||||
grilio_queue_send_request_full(vd->q, NULL,
|
||||
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
|
||||
@@ -803,6 +837,7 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
const struct ril_slot_config *cfg = &modem->config;
|
||||
struct ril_voicecall *vd;
|
||||
|
||||
DBG("");
|
||||
@@ -810,6 +845,8 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
vd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
vd->q = grilio_queue_new(vd->io);
|
||||
vd->dtmf_queue = gutil_ring_new();
|
||||
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
|
||||
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
|
||||
vd->vc = vc;
|
||||
vd->timer_id = g_idle_add(ril_delayed_register, vd);
|
||||
if (modem->ecclist_file) {
|
||||
@@ -841,6 +878,8 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
gutil_ring_unref(vd->dtmf_queue);
|
||||
gutil_ints_unref(vd->local_hangup_reasons);
|
||||
gutil_ints_unref(vd->remote_hangup_reasons);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
|
||||
213
ofono/drivers/rilmodem/cbs.c
Normal file
213
ofono/drivers/rilmodem/cbs.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2016 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
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/cbs.h>
|
||||
#include "util.h"
|
||||
|
||||
#include <gril.h>
|
||||
#include <parcel.h>
|
||||
|
||||
#include "rilmodem.h"
|
||||
#include "vendor.h"
|
||||
|
||||
struct cbs_data {
|
||||
GRil *ril;
|
||||
unsigned int vendor;
|
||||
};
|
||||
|
||||
static void ril_cbs_set_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_cbs_set_cb_t cb = cbd->cb;
|
||||
struct cbs_data *cd = cbd->user;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
} else {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(cd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *user_data)
|
||||
{
|
||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, cd);
|
||||
int i = 0, from, to;
|
||||
const char *p, *pto;
|
||||
char **segments;
|
||||
struct parcel rilp;
|
||||
|
||||
segments = g_strsplit(topics, ",", 0);
|
||||
|
||||
while (segments[i])
|
||||
i++;
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, i);
|
||||
|
||||
i = 0;
|
||||
while (segments[i]) {
|
||||
p = segments[i++];
|
||||
from = atoi(p);
|
||||
to = from;
|
||||
|
||||
pto = strchr(p, '-');
|
||||
if (pto)
|
||||
to = atoi(pto + 1);
|
||||
|
||||
parcel_w_int32(&rilp, from);
|
||||
parcel_w_int32(&rilp, to);
|
||||
|
||||
parcel_w_int32(&rilp, 0);
|
||||
parcel_w_int32(&rilp, 0xFF);
|
||||
|
||||
parcel_w_int32(&rilp, 1);
|
||||
}
|
||||
|
||||
g_strfreev(segments);
|
||||
|
||||
if (g_ril_send(cd->ril, RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, &rilp,
|
||||
ril_cbs_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *user_data)
|
||||
{
|
||||
ril_cbs_set_topics(cbs, "", cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_cbs_received(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_cbs *cbs = user_data;
|
||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||
struct parcel rilp;
|
||||
int pdulen;
|
||||
unsigned char *pdu;
|
||||
|
||||
g_ril_print_unsol_no_args(cd->ril, message);
|
||||
|
||||
DBG("req: %d; data_len: %d", message->req, (int) message->buf_len);
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
pdu = parcel_r_raw(&rilp, &pdulen);
|
||||
|
||||
if (!pdu || pdulen != 88) {
|
||||
ofono_error("%s: it isn't a gsm cell broadcast msg", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_cbs_notify(cbs, pdu, pdulen);
|
||||
g_free(pdu);
|
||||
}
|
||||
|
||||
static void ril_cbs_register(const struct ofono_error *error, void *data)
|
||||
{
|
||||
struct ofono_cbs *cbs = data;
|
||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
g_ril_register(cd->ril, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||
ril_cbs_received, cbs);
|
||||
|
||||
ofono_cbs_register(cbs);
|
||||
}
|
||||
|
||||
static void get_cbs_config_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_cbs *cbs = user_data;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: RIL error %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
ofono_cbs_remove(cbs);
|
||||
return;
|
||||
}
|
||||
|
||||
ril_cbs_clear_topics(cbs, ril_cbs_register, cbs);
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
void *user)
|
||||
{
|
||||
GRil *ril = user;
|
||||
struct cbs_data *data;
|
||||
|
||||
data = g_new0(struct cbs_data, 1);
|
||||
data->ril = g_ril_clone(ril);
|
||||
data->vendor = vendor;
|
||||
|
||||
ofono_cbs_set_data(cbs, data);
|
||||
|
||||
if (g_ril_send(ril, RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, NULL,
|
||||
get_cbs_config_cb, cbs, NULL) == 0)
|
||||
ofono_error("%s: send failed", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct cbs_data *data = ofono_cbs_get_data(cbs);
|
||||
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
|
||||
g_ril_unref(data->ril);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static struct ofono_cbs_driver driver = {
|
||||
.name = RILMODEM,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics,
|
||||
};
|
||||
|
||||
void ril_cbs_init(void)
|
||||
{
|
||||
ofono_cbs_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ril_cbs_exit(void)
|
||||
{
|
||||
ofono_cbs_driver_unregister(&driver);
|
||||
}
|
||||
@@ -198,6 +198,7 @@ static void ril_rat_mode_cb(struct ril_msg *message, gpointer user_data)
|
||||
* capabilities, so it is sort of the default for MTK modems.
|
||||
*/
|
||||
switch (net_type) {
|
||||
case PREF_NET_TYPE_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA_AUTO:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
|
||||
@@ -53,6 +53,7 @@ static int rilmodem_init(void)
|
||||
ril_call_barring_init();
|
||||
ril_netmon_init();
|
||||
ril_stk_init();
|
||||
ril_cbs_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -76,6 +77,7 @@ static void rilmodem_exit(void)
|
||||
ril_call_barring_exit();
|
||||
ril_netmon_exit();
|
||||
ril_stk_exit();
|
||||
ril_cbs_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,
|
||||
|
||||
@@ -75,3 +75,6 @@ extern void ril_netmon_exit(void);
|
||||
|
||||
extern void ril_stk_init(void);
|
||||
extern void ril_stk_exit(void);
|
||||
|
||||
extern void ril_cbs_init(void);
|
||||
extern void ril_cbs_exit(void);
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
* The same applies to the app_type.
|
||||
*/
|
||||
|
||||
static void ril_pin_change_state(struct ofono_sim *sim,
|
||||
static void ril_set_facility_lock(struct ofono_sim *sim,
|
||||
enum ofono_sim_password_type passwd_type,
|
||||
int enable, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data);
|
||||
@@ -1083,7 +1083,7 @@ static void ril_query_passwd_state(struct ofono_sim *sim,
|
||||
CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
|
||||
}
|
||||
|
||||
static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
|
||||
static void ril_enter_sim_pin_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
@@ -1101,36 +1101,17 @@ static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
/* maguro/infineon: no data is returned */
|
||||
if (parcel_data_avail(&rilp) == 0)
|
||||
goto done;
|
||||
|
||||
parcel_r_int32(&rilp);
|
||||
|
||||
switch (g_ril_vendor(sd->ril)) {
|
||||
case OFONO_RIL_VENDOR_AOSP:
|
||||
case OFONO_RIL_VENDOR_QCOM_MSIM:
|
||||
/*
|
||||
* The number of retries is valid only when a wrong password has
|
||||
* been introduced in Nexus 4. TODO: check Nexus 5 behaviour.
|
||||
*/
|
||||
if (message->error == RIL_E_PASSWORD_INCORRECT)
|
||||
sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
sd->retries[sd->passwd_type] = -1;
|
||||
else
|
||||
sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%d}",
|
||||
sd->retries[sd->passwd_type]);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
g_ril_append_print_buf(sd->ril, "{%d}",
|
||||
sd->retries[sd->passwd_type]);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
break;
|
||||
/* Taken care of elsewhere */
|
||||
case OFONO_RIL_VENDOR_INFINEON:
|
||||
case OFONO_RIL_VENDOR_MTK:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
@@ -1167,30 +1148,13 @@ static void ril_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
g_ril_append_print_buf(sd->ril, "(%s,aid=%s)", passwd, sd->aid_str);
|
||||
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PIN, &rilp,
|
||||
ril_pin_change_state_cb, cbd, g_free) > 0)
|
||||
ril_enter_sim_pin_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void enter_pin_done(const struct ofono_error *error, void *data)
|
||||
{
|
||||
struct change_state_cbd *csd = data;
|
||||
struct sim_data *sd = ofono_sim_get_data(csd->sim);
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
ofono_error("%s: wrong password", __func__);
|
||||
sd->unlock_pending = FALSE;
|
||||
CALLBACK_WITH_FAILURE(csd->cb, csd->data);
|
||||
} else {
|
||||
ril_pin_change_state(csd->sim, csd->passwd_type, csd->enable,
|
||||
csd->passwd, csd->cb, csd->data);
|
||||
}
|
||||
|
||||
g_free(csd);
|
||||
}
|
||||
|
||||
static const char *const clck_cpwd_fac[] = {
|
||||
[OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
|
||||
[OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
|
||||
@@ -1204,7 +1168,45 @@ static const char *const clck_cpwd_fac[] = {
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
static void ril_pin_change_state(struct ofono_sim *sim,
|
||||
static void ril_set_facility_lock_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct parcel rilp;
|
||||
|
||||
/*
|
||||
* There is no reason to ask SIM status until
|
||||
* unsolicited sim status change indication
|
||||
* Looks like state does not change before that.
|
||||
*/
|
||||
DBG("Enter password: type %d, result %d",
|
||||
sd->passwd_type, message->error);
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
parcel_r_int32(&rilp);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
sd->retries[sd->passwd_type] = -1;
|
||||
else
|
||||
sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%d}",
|
||||
sd->retries[sd->passwd_type]);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_set_facility_lock(struct ofono_sim *sim,
|
||||
enum ofono_sim_password_type passwd_type,
|
||||
int enable, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
@@ -1213,29 +1215,8 @@ static void ril_pin_change_state(struct ofono_sim *sim,
|
||||
struct cb_data *cbd;
|
||||
struct parcel rilp;
|
||||
|
||||
/*
|
||||
* If we want to unlock a password that has not been entered yet,
|
||||
* we enter it before trying to unlock. We need sd->unlock_pending as
|
||||
* the password still has not yet been refreshed when this function is
|
||||
* called from enter_pin_done().
|
||||
*/
|
||||
if (ofono_sim_get_password_type(sim) == passwd_type
|
||||
&& enable == FALSE && sd->unlock_pending == FALSE) {
|
||||
struct change_state_cbd *csd = g_malloc0(sizeof(*csd));
|
||||
csd->sim = sim;
|
||||
csd->passwd_type = passwd_type;
|
||||
csd->enable = enable;
|
||||
csd->passwd = passwd;
|
||||
csd->cb = cb;
|
||||
csd->data = data;
|
||||
sd->unlock_pending = TRUE;
|
||||
|
||||
ril_pin_send(sim, passwd, enter_pin_done, csd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sd->unlock_pending = FALSE;
|
||||
sd->passwd_type = passwd_type;
|
||||
|
||||
if (passwd_type >= ARRAY_SIZE(clck_cpwd_fac) ||
|
||||
clck_cpwd_fac[passwd_type] == NULL)
|
||||
@@ -1257,7 +1238,7 @@ static void ril_pin_change_state(struct ofono_sim *sim,
|
||||
sd->aid_str);
|
||||
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_SET_FACILITY_LOCK, &rilp,
|
||||
ril_pin_change_state_cb, cbd, g_free) > 0)
|
||||
ril_set_facility_lock_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
@@ -1265,6 +1246,37 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ril_enter_sim_puk_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct parcel rilp;
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
parcel_r_int32(&rilp);
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = parcel_r_int32(&rilp);
|
||||
} else {
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = -1;
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = -1;
|
||||
}
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%d}",
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK]);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_pin_send_puk(struct ofono_sim *sim,
|
||||
const char *puk, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
@@ -1286,7 +1298,7 @@ static void ril_pin_send_puk(struct ofono_sim *sim,
|
||||
puk, passwd, sd->aid_str);
|
||||
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PUK, &rilp,
|
||||
ril_pin_change_state_cb, cbd, g_free) > 0)
|
||||
ril_enter_sim_puk_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
@@ -1324,7 +1336,7 @@ static void ril_change_passwd(struct ofono_sim *sim,
|
||||
g_ril_append_print_buf(sd->ril, "(old=%s,new=%s,aid=%s)",
|
||||
old_passwd, new_passwd, sd->aid_str);
|
||||
|
||||
if (g_ril_send(sd->ril, request, &rilp, ril_pin_change_state_cb,
|
||||
if (g_ril_send(sd->ril, request, &rilp, ril_enter_sim_pin_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
@@ -1413,12 +1425,17 @@ static void ril_query_facility_lock_cb(struct ril_msg *message,
|
||||
struct sim_data *sd = cbd->user;
|
||||
struct parcel rilp;
|
||||
ofono_bool_t status;
|
||||
int numparams;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
numparams = parcel_r_int32(&rilp);
|
||||
if (numparams < 1)
|
||||
goto error;
|
||||
|
||||
status = (ofono_bool_t) parcel_r_int32(&rilp);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%d}", status);
|
||||
@@ -1437,7 +1454,7 @@ static void ril_query_facility_lock(struct ofono_sim *sim,
|
||||
void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, sd);
|
||||
struct parcel rilp;
|
||||
|
||||
parcel_init(&rilp);
|
||||
@@ -1483,7 +1500,7 @@ static struct ofono_sim_driver driver = {
|
||||
.query_pin_retries = ril_query_pin_retries,
|
||||
.reset_passwd = ril_pin_send_puk,
|
||||
.change_passwd = ril_change_passwd,
|
||||
.lock = ril_pin_change_state,
|
||||
.lock = ril_set_facility_lock,
|
||||
.query_facility_lock = ril_query_facility_lock,
|
||||
};
|
||||
|
||||
|
||||
@@ -598,6 +598,13 @@ void g_at_mux_unref(GAtMux *mux)
|
||||
}
|
||||
}
|
||||
|
||||
static void read_watcher_destroy_notify(gpointer user_data)
|
||||
{
|
||||
GAtMux *mux = user_data;
|
||||
|
||||
mux->read_watch = 0;
|
||||
}
|
||||
|
||||
gboolean g_at_mux_start(GAtMux *mux)
|
||||
{
|
||||
if (mux->channel == NULL)
|
||||
@@ -611,7 +618,8 @@ gboolean g_at_mux_start(GAtMux *mux)
|
||||
|
||||
mux->read_watch = g_io_add_watch_full(mux->channel, G_PRIORITY_DEFAULT,
|
||||
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
|
||||
received_data, mux, NULL);
|
||||
received_data, mux,
|
||||
read_watcher_destroy_notify);
|
||||
|
||||
mux->shutdown = FALSE;
|
||||
|
||||
|
||||
@@ -374,6 +374,12 @@ static void handle_response(struct ril_s *p, struct ril_msg *message)
|
||||
if (req->callback)
|
||||
req->callback(message, req->user_data);
|
||||
|
||||
/* gril may have been destroyed in the request callback */
|
||||
if (p->destroyed) {
|
||||
ril_request_destroy(req);
|
||||
return;
|
||||
}
|
||||
|
||||
len = g_queue_get_length(p->out_queue);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
@@ -75,7 +75,8 @@ extern char print_buf[];
|
||||
#define g_ril_print_request(gril, token, req) \
|
||||
G_RIL_TRACE(gril, "[%d,%04d]> %s %s", \
|
||||
g_ril_get_slot(gril), token, \
|
||||
g_ril_request_id_to_string(gril, req), print_buf)
|
||||
g_ril_request_id_to_string(gril, req), print_buf); \
|
||||
print_buf[0] = '\0';
|
||||
#define g_ril_print_request_no_args(gril, token, req) \
|
||||
G_RIL_TRACE(gril, "[%d,%04d]> %s", \
|
||||
g_ril_get_slot(gril), token, \
|
||||
@@ -85,7 +86,8 @@ extern char print_buf[];
|
||||
g_ril_get_slot(gril), \
|
||||
message->serial_no, \
|
||||
g_ril_request_id_to_string(gril, message->req), \
|
||||
print_buf)
|
||||
print_buf); \
|
||||
print_buf[0] = '\0';
|
||||
#define g_ril_print_response_no_args(gril, message) \
|
||||
G_RIL_TRACE(gril, "[%d,%04d]< %s", \
|
||||
g_ril_get_slot(gril), message->serial_no, \
|
||||
|
||||
@@ -55,7 +55,6 @@ enum ofono_gprs_auth_method {
|
||||
|
||||
struct ofono_gprs_primary_context {
|
||||
unsigned int cid;
|
||||
int direction;
|
||||
char apn[OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||
|
||||
@@ -172,6 +172,8 @@ void ofono_voicecall_ssn_mt_notify(struct ofono_voicecall *vc, unsigned int id,
|
||||
int code, int index,
|
||||
const struct ofono_phone_number *ph);
|
||||
|
||||
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
|
||||
unsigned int id);
|
||||
void ofono_voicecall_ringback_tone_notify(struct ofono_voicecall *vc,
|
||||
const ofono_bool_t playTone);
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2012-2015 Jolla Ltd.
|
||||
* Copyright (C) 2012-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -12,11 +11,6 @@
|
||||
* 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
|
||||
@@ -35,9 +29,34 @@
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define NTD_WAIT_TIMEOUT (500) /* ms */
|
||||
|
||||
/*
|
||||
* There are 3 distinct states here:
|
||||
*
|
||||
* 1. !valid
|
||||
*
|
||||
* Initial state, no time/timezone information whatsoever.
|
||||
*
|
||||
* 2. valid && !mccmnc
|
||||
*
|
||||
* Time/timezone information has been received from the network,
|
||||
* but no MCC and MNC yet.
|
||||
*
|
||||
* 3. valid && mccmnc
|
||||
*
|
||||
* Time/timezone information is fully available.
|
||||
*
|
||||
*/
|
||||
struct nt_data {
|
||||
struct ofono_modem *modem;
|
||||
struct ofono_netreg *netreg;
|
||||
unsigned int netreg_watch_id;
|
||||
unsigned int netreg_status_watch_id;
|
||||
guint mccmnc_wait_id;
|
||||
|
||||
gboolean time_available;
|
||||
gboolean time_pending;
|
||||
gboolean valid;
|
||||
|
||||
time_t nw_time_utc;
|
||||
time_t received;
|
||||
@@ -47,27 +66,11 @@ struct nt_data {
|
||||
|
||||
char *mcc;
|
||||
char *mnc;
|
||||
char* path;
|
||||
DBusConnection *conn;
|
||||
};
|
||||
|
||||
static struct nt_data *nettime_new(const char *path)
|
||||
{
|
||||
struct nt_data *ntd = g_new0(struct nt_data, 1);
|
||||
|
||||
ntd->path = g_strdup(path);
|
||||
ntd->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
return ntd;
|
||||
}
|
||||
|
||||
static void nettime_free(struct nt_data *ntd)
|
||||
{
|
||||
dbus_connection_unref(ntd->conn);
|
||||
g_free(ntd->path);
|
||||
g_free(ntd->mcc);
|
||||
g_free(ntd->mnc);
|
||||
g_free(ntd);
|
||||
}
|
||||
#define DBG_(ntd,fmt,args...) \
|
||||
DBG("%s " fmt, ofono_modem_get_path((ntd)->modem), ##args)
|
||||
|
||||
static gboolean nettime_encode_time_format(struct tm *tm,
|
||||
const struct ofono_network_time *time)
|
||||
@@ -110,7 +113,7 @@ static int nettime_fill_time_notification(DBusMessage *msg, struct nt_data *ntd)
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
"{sv}",
|
||||
&iter_array);
|
||||
if (ntd->time_pending) {
|
||||
if (ntd->valid && ntd->mcc && ntd->mnc) {
|
||||
if (ntd->time_available) {
|
||||
utc_long = (dbus_int64_t) ntd->nw_time_utc;
|
||||
ofono_dbus_dict_append(&iter_array,
|
||||
@@ -145,7 +148,7 @@ static int nettime_fill_time_notification(DBusMessage *msg, struct nt_data *ntd)
|
||||
DBUS_TYPE_STRING,
|
||||
&ntd->mnc);
|
||||
} else {
|
||||
DBG("fill_time_notification: time not available");
|
||||
DBG_(ntd, "time not available");
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(&iter, &iter_array);
|
||||
@@ -177,23 +180,209 @@ static const GDBusSignalTable nettime_signals[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static void nettime_send_signal(struct nt_data *ntd)
|
||||
{
|
||||
DBusMessage *signal =
|
||||
dbus_message_new_signal(ofono_modem_get_path(ntd->modem),
|
||||
OFONO_NETWORK_TIME_INTERFACE, "NetworkTimeChanged");
|
||||
|
||||
DBG_(ntd, "");
|
||||
nettime_fill_time_notification(signal, ntd);
|
||||
g_dbus_send_message(ntd->conn, signal);
|
||||
}
|
||||
|
||||
static void nettime_set_mcc_mnc(struct nt_data *ntd, const char *mcc,
|
||||
const char *mnc)
|
||||
{
|
||||
if (g_strcmp0(ntd->mcc, mcc)) {
|
||||
g_free(ntd->mcc);
|
||||
ntd->mcc = g_strdup(mcc);
|
||||
}
|
||||
|
||||
if (g_strcmp0(ntd->mnc, mnc)) {
|
||||
g_free(ntd->mnc);
|
||||
ntd->mnc = g_strdup(mnc);
|
||||
}
|
||||
|
||||
if (ntd->mcc && ntd->mnc) {
|
||||
DBG_(ntd, "MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
|
||||
|
||||
if (ntd->mccmnc_wait_id) {
|
||||
/* We have been waiting for MCC and MNC */
|
||||
g_source_remove(ntd->mccmnc_wait_id);
|
||||
ntd->mccmnc_wait_id = 0;
|
||||
nettime_send_signal(ntd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void nettime_netreg_status_watch_cb(int status, int lac, int ci,
|
||||
int tech, const char *mcc, const char *mnc,
|
||||
void *userdata)
|
||||
{
|
||||
nettime_set_mcc_mnc(userdata, mcc, mnc);
|
||||
}
|
||||
|
||||
static void nettime_netreg_status_watch_done(void *userdata)
|
||||
{
|
||||
struct nt_data *ntd = userdata;
|
||||
|
||||
DBG_(ntd, "");
|
||||
ntd->netreg_status_watch_id = 0;
|
||||
}
|
||||
|
||||
static void nettime_set_netreg(struct nt_data *ntd,
|
||||
struct ofono_netreg *netreg)
|
||||
{
|
||||
if (ntd->netreg != netreg) {
|
||||
ntd->valid = FALSE;
|
||||
ntd->netreg = netreg;
|
||||
if (netreg) {
|
||||
nettime_set_mcc_mnc(ntd,
|
||||
ofono_netreg_get_mcc(netreg),
|
||||
ofono_netreg_get_mnc(netreg));
|
||||
ntd->netreg_status_watch_id =
|
||||
__ofono_netreg_add_status_watch(netreg,
|
||||
nettime_netreg_status_watch_cb, ntd,
|
||||
nettime_netreg_status_watch_done);
|
||||
} else {
|
||||
g_free(ntd->mcc);
|
||||
g_free(ntd->mnc);
|
||||
ntd->mcc = NULL;
|
||||
ntd->mnc = NULL;
|
||||
ntd->netreg_status_watch_id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void nettime_netreg_watch_cb(struct ofono_atom *atom,
|
||||
enum ofono_atom_watch_condition cond, void *userdata)
|
||||
{
|
||||
struct nt_data *ntd = userdata;
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
|
||||
DBG_(ntd, "registered");
|
||||
nettime_set_netreg(ntd, __ofono_atom_get_data(atom));
|
||||
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
|
||||
DBG_(ntd, "unregistered");
|
||||
nettime_set_netreg(ntd, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void nettime_netreg_watch_done(void *userdata)
|
||||
{
|
||||
struct nt_data *ntd = userdata;
|
||||
|
||||
DBG_(ntd, "");
|
||||
ntd->netreg_watch_id = 0;
|
||||
}
|
||||
|
||||
static gboolean nettime_timeout_cb(gpointer data)
|
||||
{
|
||||
struct nt_data *ntd = data;
|
||||
|
||||
DBG_(ntd, "timed out");
|
||||
ntd->mccmnc_wait_id = 0;
|
||||
ntd->valid = FALSE;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static struct nt_data *nettime_new(struct ofono_modem *modem)
|
||||
{
|
||||
struct nt_data *ntd = g_new0(struct nt_data, 1);
|
||||
struct ofono_atom *netreg_atom = __ofono_modem_find_atom(modem,
|
||||
OFONO_ATOM_TYPE_NETREG);
|
||||
|
||||
ntd->modem = modem;
|
||||
ntd->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
ntd->netreg_watch_id = __ofono_modem_add_atom_watch(modem,
|
||||
OFONO_ATOM_TYPE_NETREG, nettime_netreg_watch_cb,
|
||||
ntd, nettime_netreg_watch_done);
|
||||
|
||||
if (netreg_atom) {
|
||||
nettime_set_netreg(ntd, __ofono_atom_get_data(netreg_atom));
|
||||
}
|
||||
|
||||
return ntd;
|
||||
}
|
||||
|
||||
static void nettime_free(struct nt_data *ntd)
|
||||
{
|
||||
if (ntd->mccmnc_wait_id)
|
||||
g_source_remove(ntd->mccmnc_wait_id);
|
||||
|
||||
if (ntd->netreg_status_watch_id)
|
||||
__ofono_netreg_remove_status_watch(ntd->netreg,
|
||||
ntd->netreg_status_watch_id);
|
||||
|
||||
if (ntd->netreg_watch_id)
|
||||
__ofono_modem_remove_atom_watch(ntd->modem,
|
||||
ntd->netreg_watch_id);
|
||||
|
||||
dbus_connection_unref(ntd->conn);
|
||||
g_free(ntd->mcc);
|
||||
g_free(ntd->mnc);
|
||||
g_free(ntd);
|
||||
}
|
||||
|
||||
static void nettime_info_received(struct ofono_nettime_context *context,
|
||||
struct ofono_network_time *info)
|
||||
{
|
||||
struct nt_data *ntd = context->data;
|
||||
struct tm t;
|
||||
|
||||
if (!ntd)
|
||||
return;
|
||||
|
||||
ntd->received = nettime_get_monotonic_time();
|
||||
ntd->valid = TRUE;
|
||||
ntd->dst = info->dst;
|
||||
ntd->time_zone = info->utcoff;
|
||||
ntd->time_available = nettime_encode_time_format(&t, info);
|
||||
if (ntd->time_available) {
|
||||
ntd->nw_time_utc = timegm(&t);
|
||||
}
|
||||
|
||||
DBG_(ntd, "time: %04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d (DST=%d)",
|
||||
info->year, info->mon, info->mday, info->hour,
|
||||
info->min, info->sec, info->utcoff > 0 ? '+' : '-',
|
||||
abs(info->utcoff) / 3600, (abs(info->utcoff) % 3600) / 60,
|
||||
info->dst);
|
||||
DBG_(ntd, "UTC timestamp: %li, Received (monotonic time): %li",
|
||||
ntd->nw_time_utc, ntd->received);
|
||||
|
||||
if (ntd->mcc && ntd->mnc) {
|
||||
DBG_(ntd, "MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
|
||||
nettime_send_signal(ntd);
|
||||
} else {
|
||||
DBG_(ntd, "no MCC/MNC yet");
|
||||
|
||||
if (ntd->mccmnc_wait_id)
|
||||
g_source_remove(ntd->mccmnc_wait_id);
|
||||
|
||||
ntd->mccmnc_wait_id = g_timeout_add(NTD_WAIT_TIMEOUT,
|
||||
nettime_timeout_cb, ntd);
|
||||
}
|
||||
}
|
||||
|
||||
static int nettime_probe(struct ofono_nettime_context *context)
|
||||
{
|
||||
struct nt_data *ntd = nettime_new(ofono_modem_get_path(context->modem));
|
||||
struct nt_data *ntd = nettime_new(context->modem);
|
||||
const char *path = ofono_modem_get_path(context->modem);
|
||||
|
||||
DBG("Network time probe for modem: %p (%s)", context->modem, ntd->path);
|
||||
if (g_dbus_register_interface(ntd->conn, ntd->path,
|
||||
DBG("Network time probe for modem: %p (%s)", context->modem, path);
|
||||
if (g_dbus_register_interface(ntd->conn, path,
|
||||
OFONO_NETWORK_TIME_INTERFACE, nettime_methods,
|
||||
nettime_signals, NULL, ntd, NULL)) {
|
||||
context->data = ntd;
|
||||
ofono_info("Registered interface %s, path %s",
|
||||
OFONO_NETWORK_TIME_INTERFACE, ntd->path);
|
||||
OFONO_NETWORK_TIME_INTERFACE, path);
|
||||
ofono_modem_add_interface(context->modem,
|
||||
OFONO_NETWORK_TIME_INTERFACE);
|
||||
return 0;
|
||||
} else {
|
||||
ofono_error("Could not register interface %s, path %s",
|
||||
OFONO_NETWORK_TIME_INTERFACE, ntd->path);
|
||||
OFONO_NETWORK_TIME_INTERFACE, path);
|
||||
nettime_free(ntd);
|
||||
return 1;
|
||||
}
|
||||
@@ -202,77 +391,16 @@ static int nettime_probe(struct ofono_nettime_context *context)
|
||||
static void nettime_remove(struct ofono_nettime_context *context)
|
||||
{
|
||||
struct nt_data *ntd = context->data;
|
||||
const char *path = ofono_modem_get_path(context->modem);
|
||||
|
||||
DBG("Network time remove for modem: %p (%s)", context->modem,
|
||||
ofono_modem_get_path(context->modem));
|
||||
DBG("Network time remove for modem: %p (%s)", context->modem, path);
|
||||
ofono_modem_remove_interface(context->modem,
|
||||
OFONO_NETWORK_TIME_INTERFACE);
|
||||
if (!g_dbus_unregister_interface(ntd->conn, ntd->path,
|
||||
OFONO_NETWORK_TIME_INTERFACE)) {
|
||||
ofono_error("Network time: could not unregister interface %s"
|
||||
" for %s", OFONO_NETWORK_TIME_INTERFACE, ntd->path);
|
||||
}
|
||||
|
||||
g_dbus_unregister_interface(ntd->conn, path,
|
||||
OFONO_NETWORK_TIME_INTERFACE);
|
||||
nettime_free(ntd);
|
||||
}
|
||||
|
||||
static void nettime_send_signal(struct nt_data *ntd)
|
||||
{
|
||||
DBusMessage *signal = dbus_message_new_signal(ntd->path,
|
||||
OFONO_NETWORK_TIME_INTERFACE,
|
||||
"NetworkTimeChanged");
|
||||
|
||||
nettime_fill_time_notification(signal, ntd);
|
||||
g_dbus_send_message(ntd->conn, signal);
|
||||
}
|
||||
|
||||
static void nettime_info_received(struct ofono_nettime_context *context,
|
||||
struct ofono_network_time *info)
|
||||
{
|
||||
struct nt_data *ntd = context->data;
|
||||
struct ofono_netreg *netreg;
|
||||
const char *mcc;
|
||||
const char *mnc;
|
||||
struct tm t;
|
||||
|
||||
if (!ntd)
|
||||
return;
|
||||
|
||||
netreg = __ofono_atom_get_data(__ofono_modem_find_atom(
|
||||
context->modem, OFONO_ATOM_TYPE_NETREG));
|
||||
mcc = ofono_netreg_get_mcc(netreg);
|
||||
mnc = ofono_netreg_get_mnc(netreg);
|
||||
|
||||
if (!mcc || !mnc) {
|
||||
DBG("Incomplete network time received, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(ntd->mcc);
|
||||
g_free(ntd->mnc);
|
||||
ntd->mcc = g_strdup(mcc);
|
||||
ntd->mnc = g_strdup(mnc);
|
||||
ntd->received = nettime_get_monotonic_time();
|
||||
ntd->time_pending = TRUE;
|
||||
ntd->dst = info->dst;
|
||||
ntd->time_zone = info->utcoff;
|
||||
ntd->time_available = nettime_encode_time_format(&t, info);
|
||||
if (ntd->time_available) {
|
||||
ntd->nw_time_utc = timegm(&t);
|
||||
}
|
||||
|
||||
nettime_send_signal(ntd);
|
||||
DBG("modem: %p (%s)", context->modem, ntd->path);
|
||||
DBG("time: %04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d (DST=%d)",
|
||||
info->year, info->mon, info->mday, info->hour,
|
||||
info->min, info->sec, info->utcoff > 0 ? '+' : '-',
|
||||
abs(info->utcoff) / 3600, (abs(info->utcoff) % 3600) / 60,
|
||||
info->dst);
|
||||
DBG("UTC timestamp: %li, Received (monotonic time): %li",
|
||||
ntd->nw_time_utc, ntd->received);
|
||||
DBG("MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
|
||||
}
|
||||
|
||||
static struct ofono_nettime_driver driver = {
|
||||
.name = "Network Time",
|
||||
.probe = nettime_probe,
|
||||
|
||||
@@ -239,6 +239,7 @@ void ril_post_online(struct ofono_modem *modem)
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
ofono_cbs_create(modem, rd->vendor, RILMODEM, rd->ril);
|
||||
ofono_netreg_create(modem, rd->vendor, RILMODEM, rd->ril);
|
||||
ofono_ussd_create(modem, rd->vendor, RILMODEM, rd->ril);
|
||||
ofono_call_settings_create(modem, rd->vendor, RILMODEM, rd->ril);
|
||||
@@ -409,15 +410,30 @@ int ril_enable(struct ofono_modem *modem)
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void power_off_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ril_data *rd = cbd->user;
|
||||
struct ofono_modem *modem = cbd->data;
|
||||
|
||||
if (rd) {
|
||||
g_ril_unref(rd->ril);
|
||||
rd->ril = NULL;
|
||||
}
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
}
|
||||
|
||||
int ril_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
struct cb_data *cbd = cb_data_new(NULL, modem, rd);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ril_send_power(rd, FALSE, NULL, NULL);
|
||||
ril_send_power(rd, FALSE, power_off_cb, cbd);
|
||||
|
||||
return 0;
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver ril_driver = {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <glib.h>
|
||||
@@ -52,11 +53,22 @@
|
||||
|
||||
#include "drivers/rilmodem/rilmodem.h"
|
||||
#include "drivers/rilmodem/vendor.h"
|
||||
#include "gdbus.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define THERMAL_MANAGEMENT_INTERFACE OFONO_SERVICE ".sofia3gr.ThermalManagement"
|
||||
|
||||
struct ril_data {
|
||||
GRil *ril;
|
||||
};
|
||||
|
||||
struct ril_thermal_management {
|
||||
DBusMessage *pending;
|
||||
struct ofono_modem *modem;
|
||||
dbus_bool_t throttling;
|
||||
};
|
||||
|
||||
static int ril_send_power(GRil *ril, ofono_bool_t online,
|
||||
GRilResponseFunc func,
|
||||
gpointer user_data,
|
||||
@@ -129,7 +141,14 @@ static int ril_probe(struct ofono_modem *modem)
|
||||
|
||||
static void ril_remove(struct ofono_modem *modem)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
if (g_dbus_unregister_interface(conn, path,
|
||||
THERMAL_MANAGEMENT_INTERFACE))
|
||||
ofono_modem_remove_interface(modem,
|
||||
THERMAL_MANAGEMENT_INTERFACE);
|
||||
|
||||
ofono_modem_set_data(modem, NULL);
|
||||
|
||||
@@ -137,6 +156,270 @@ static void ril_remove(struct ofono_modem *modem)
|
||||
g_free(rd);
|
||||
}
|
||||
|
||||
static void set_rf_power_status_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ril_thermal_management *tm = user_data;
|
||||
struct ril_data *rd = ofono_modem_get_data(tm->modem);
|
||||
const char *path = ofono_modem_get_path(tm->modem);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(rd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
|
||||
__ofono_dbus_pending_reply(&tm->pending,
|
||||
__ofono_error_failed(tm->pending));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Change the throttling state */
|
||||
tm->throttling = tm->throttling ? false : true;
|
||||
|
||||
__ofono_dbus_pending_reply(&tm->pending,
|
||||
dbus_message_new_method_return(tm->pending));
|
||||
|
||||
ofono_dbus_signal_property_changed(conn, path,
|
||||
THERMAL_MANAGEMENT_INTERFACE,
|
||||
"TransmitPowerThrottling",
|
||||
DBUS_TYPE_BOOLEAN,
|
||||
&tm->throttling);
|
||||
}
|
||||
|
||||
static DBusMessage *set_rf_power_status(DBusMessage *msg,
|
||||
dbus_bool_t enable,
|
||||
void *data)
|
||||
{
|
||||
struct ril_thermal_management *tm = data;
|
||||
struct ril_data *rd = ofono_modem_get_data(tm->modem);
|
||||
struct parcel rilp;
|
||||
|
||||
int cmd_id;
|
||||
char buf[4];
|
||||
|
||||
DBG("");
|
||||
|
||||
if (tm->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 2);
|
||||
/* RIL_OEM_HOOK_STRING_SET_RF_POWER_STATUS = 0x000000AC */
|
||||
cmd_id = 0x000000AC;
|
||||
sprintf(buf, "%d", cmd_id);
|
||||
parcel_w_string(&rilp, buf);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
sprintf(buf, "%d", enable ? 1 : 0);
|
||||
parcel_w_string(&rilp, buf);
|
||||
|
||||
g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X,arg=%s}", cmd_id, buf);
|
||||
|
||||
if (g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
|
||||
set_rf_power_status_cb, tm, NULL) == 0)
|
||||
return __ofono_error_failed(msg);
|
||||
|
||||
tm->pending = dbus_message_ref(msg);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DBusMessage *thermal_management_set_property(DBusConnection *conn,
|
||||
DBusMessage *msg,
|
||||
void *data)
|
||||
{
|
||||
struct ril_thermal_management *tm = data;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter var;
|
||||
const char *name;
|
||||
dbus_bool_t throttling;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!ofono_modem_get_online(tm->modem))
|
||||
return __ofono_error_not_available(msg);
|
||||
|
||||
if (!dbus_message_iter_init(msg, &iter))
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &name);
|
||||
|
||||
if (!strcmp(name, "TransmitPowerThrottling")) {
|
||||
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, &throttling);
|
||||
|
||||
if (tm->throttling == throttling)
|
||||
/* Ignore set request if new state == current state */
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
return set_rf_power_status(msg, throttling, tm);
|
||||
}
|
||||
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
|
||||
static DBusMessage *thermal_management_get_properties(DBusConnection *conn,
|
||||
DBusMessage *msg,
|
||||
void *data)
|
||||
{
|
||||
struct ril_thermal_management *tm = data;
|
||||
DBusMessage *reply;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter dict;
|
||||
|
||||
DBG("");
|
||||
|
||||
reply = dbus_message_new_method_return(msg);
|
||||
if (reply == NULL)
|
||||
return NULL;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
OFONO_PROPERTIES_ARRAY_SIGNATURE,
|
||||
&dict);
|
||||
|
||||
ofono_dbus_dict_append(&dict, "TransmitPowerThrottling",
|
||||
DBUS_TYPE_BOOLEAN,
|
||||
&tm->throttling);
|
||||
|
||||
dbus_message_iter_close_container(&iter, &dict);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable thermal_management_methods[] = {
|
||||
{ GDBUS_METHOD("GetProperties",
|
||||
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
thermal_management_get_properties) },
|
||||
{ GDBUS_ASYNC_METHOD("SetProperty",
|
||||
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
|
||||
NULL, thermal_management_set_property) },
|
||||
{}
|
||||
};
|
||||
|
||||
static const GDBusSignalTable thermal_management_signals[] = {
|
||||
{ GDBUS_SIGNAL("PropertyChanged",
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void thermal_management_cleanup(void *data)
|
||||
{
|
||||
struct ril_thermal_management *tm = data;
|
||||
|
||||
if (tm->pending)
|
||||
__ofono_dbus_pending_reply(&tm->pending,
|
||||
__ofono_error_canceled(tm->pending));
|
||||
|
||||
g_free(tm);
|
||||
}
|
||||
|
||||
static void get_rf_power_status_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
struct ril_thermal_management *tm;
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct parcel rilp;
|
||||
gint numstr;
|
||||
gchar *power_status;
|
||||
char *endptr;
|
||||
int enabled;
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(rd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
return;
|
||||
}
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
numstr = parcel_r_int32(&rilp);
|
||||
if (numstr < 1) {
|
||||
ofono_error("RILD reply empty !");
|
||||
return;
|
||||
}
|
||||
|
||||
power_status = parcel_r_string(&rilp);
|
||||
if (power_status == NULL || power_status == '\0')
|
||||
return;
|
||||
|
||||
enabled = strtol(power_status, &endptr, 10);
|
||||
/*
|
||||
* power_status == endptr => conversion error
|
||||
* *endptr != '\0' => partial conversion
|
||||
*/
|
||||
if (power_status == endptr || *endptr != '\0')
|
||||
return;
|
||||
|
||||
tm = g_try_new0(struct ril_thermal_management, 1);
|
||||
if (tm == NULL)
|
||||
return;
|
||||
|
||||
tm->modem = modem;
|
||||
tm->throttling = (enabled > 0) ? true : false;
|
||||
|
||||
|
||||
if (!g_dbus_register_interface(conn, path, THERMAL_MANAGEMENT_INTERFACE,
|
||||
thermal_management_methods,
|
||||
thermal_management_signals,
|
||||
NULL, tm, thermal_management_cleanup)) {
|
||||
ofono_error("Could not register %s interface under %s",
|
||||
THERMAL_MANAGEMENT_INTERFACE, path);
|
||||
g_free(tm);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_modem_add_interface(modem, THERMAL_MANAGEMENT_INTERFACE);
|
||||
}
|
||||
|
||||
static int ril_thermal_management_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
struct parcel rilp;
|
||||
|
||||
int cmd_id;
|
||||
char buf[4];
|
||||
|
||||
DBG("");
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1);
|
||||
/* RIL_OEM_HOOK_STRING_GET_RF_POWER_STATUS = 0x000000AB */
|
||||
cmd_id = 0x000000AB;
|
||||
sprintf(buf, "%d", cmd_id);
|
||||
parcel_w_string(&rilp, buf);
|
||||
|
||||
g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X}", cmd_id);
|
||||
|
||||
if (g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
|
||||
get_rf_power_status_cb, modem, NULL) > 0)
|
||||
return 0;
|
||||
|
||||
/* Error path */
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void ril_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
@@ -145,6 +428,7 @@ static void ril_pre_sim(struct ofono_modem *modem)
|
||||
|
||||
ofono_devinfo_create(modem, 0, "rilmodem", rd->ril);
|
||||
ofono_sim_create(modem, 0, "rilmodem", rd->ril);
|
||||
ril_thermal_management_enable(modem);
|
||||
}
|
||||
|
||||
static void ril_post_sim(struct ofono_modem *modem)
|
||||
@@ -255,14 +539,45 @@ static int ril_enable(struct ofono_modem *modem)
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static int ril_disable(struct ofono_modem *modem)
|
||||
static void ril_send_power_off_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = (struct ofono_modem *) user_data;
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
ril_send_power(rd->ril, FALSE, NULL, NULL, NULL);
|
||||
g_ril_unref(rd->ril);
|
||||
|
||||
return 0;
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
}
|
||||
|
||||
static int ril_disable(struct ofono_modem *modem)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
struct parcel rilp;
|
||||
int cmd_id;
|
||||
char buf[4];
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (g_dbus_unregister_interface(conn, path,
|
||||
THERMAL_MANAGEMENT_INTERFACE))
|
||||
ofono_modem_remove_interface(modem,
|
||||
THERMAL_MANAGEMENT_INTERFACE);
|
||||
|
||||
/* RIL_OEM_HOOK_STRING_SET_MODEM_OFF = 0x000000CF */
|
||||
cmd_id = 0x000000CF;
|
||||
sprintf(buf, "%d", cmd_id);
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1);
|
||||
parcel_w_string(&rilp, buf);
|
||||
|
||||
g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X}", cmd_id);
|
||||
|
||||
g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
|
||||
ril_send_power_off_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver ril_driver = {
|
||||
|
||||
362
ofono/plugins/sfos_bt.c
Normal file
362
ofono/plugins/sfos_bt.c
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
#include <ofono.h>
|
||||
#include <gdbus.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#define SFOS_BT_DBUS_CV_INTERFACE "org.nemomobile.ofono.bluetooth.CallVolume"
|
||||
#define HFP_CALL_VOLUME_MAX 15
|
||||
|
||||
struct sfos_bt {
|
||||
unsigned int emu_watch;
|
||||
struct ofono_modem *modem;
|
||||
struct ofono_emulator *em;
|
||||
unsigned char speaker_volume;
|
||||
unsigned char microphone_volume;
|
||||
};
|
||||
|
||||
static GSList *modems;
|
||||
static guint modemwatch_id;
|
||||
|
||||
static void set_hfp_microphone_volume(struct sfos_bt *sfos_bt,
|
||||
unsigned char gain)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "+VGM:%d", (int) gain);
|
||||
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
|
||||
}
|
||||
|
||||
static void set_hfp_speaker_volume(struct sfos_bt *sfos_bt,
|
||||
unsigned char gain)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "+VGS:%d", (int) gain);
|
||||
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
|
||||
}
|
||||
|
||||
static DBusMessage *cv_set_property(DBusConnection *conn, DBusMessage *msg,
|
||||
void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter var;
|
||||
const char *property;
|
||||
|
||||
if (!dbus_message_iter_init(msg, &iter))
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &property);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_recurse(&iter, &var);
|
||||
|
||||
if (g_str_equal(property, "SpeakerVolume") == TRUE) {
|
||||
unsigned char gain;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&var, &gain);
|
||||
|
||||
if (gain > HFP_CALL_VOLUME_MAX)
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
if (gain == sfos_bt->speaker_volume)
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
DBG("SpeakerVolume:%d", gain);
|
||||
sfos_bt->speaker_volume = gain;
|
||||
set_hfp_speaker_volume(sfos_bt, gain);
|
||||
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
} else if (g_str_equal(property, "MicrophoneVolume") == TRUE) {
|
||||
unsigned char gain;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&var, &gain);
|
||||
|
||||
if (gain > HFP_CALL_VOLUME_MAX)
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
if (gain == sfos_bt->microphone_volume)
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
DBG("MicrophoneVolume:%d", gain);
|
||||
sfos_bt->microphone_volume = gain;
|
||||
set_hfp_microphone_volume(sfos_bt, gain);
|
||||
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
} else if (g_str_equal(property, "Muted") == TRUE) {
|
||||
unsigned char gain;
|
||||
dbus_bool_t muted;
|
||||
|
||||
/*Remove when supported*/
|
||||
return __ofono_error_not_implemented(msg);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&var, &muted);
|
||||
|
||||
if (muted)
|
||||
gain = 0;
|
||||
else
|
||||
gain = 7;/* rather gain = sfos->old_mic_vol */
|
||||
|
||||
if (gain == sfos_bt->microphone_volume)
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
sfos_bt->microphone_volume = gain;
|
||||
set_hfp_microphone_volume(sfos_bt, gain);
|
||||
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable cv_methods[] = {
|
||||
{ GDBUS_METHOD("SetProperty",
|
||||
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
|
||||
NULL, cv_set_property) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable cv_signals[] = {
|
||||
{ GDBUS_SIGNAL("PropertyChanged",
|
||||
GDBUS_ARGS({ "property", "s" }, { "value", "v" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
int sfos_bt_call_volume_set(struct ofono_modem *modem, unsigned char volume,
|
||||
const char *gain)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
return ofono_dbus_signal_property_changed(conn, path,
|
||||
SFOS_BT_DBUS_CV_INTERFACE,
|
||||
gain,
|
||||
DBUS_TYPE_BYTE, &volume);
|
||||
}
|
||||
|
||||
static void set_gain(struct ofono_emulator *em,
|
||||
struct ofono_emulator_request *req,
|
||||
void *userdata, const char *gain)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = userdata;
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
struct ofono_error result;
|
||||
unsigned char volume;
|
||||
int val;
|
||||
result.error = 0;
|
||||
|
||||
switch (ofono_emulator_request_get_type(req)) {
|
||||
case OFONO_EMULATOR_REQUEST_TYPE_SET:
|
||||
if (ofono_emulator_request_next_number(req, &val) == FALSE)
|
||||
goto fail;
|
||||
|
||||
if (val < 0 || val > 0xffff || val > HFP_CALL_VOLUME_MAX)
|
||||
goto fail;
|
||||
|
||||
DBG("gain:%d", val);
|
||||
|
||||
volume = (unsigned char) val;
|
||||
if (sfos_bt_call_volume_set(modem, volume, gain)<= 0)
|
||||
goto fail;
|
||||
|
||||
if (!g_strcmp0(gain, "SpeakerVolume"))
|
||||
sfos_bt->speaker_volume = volume;
|
||||
else
|
||||
sfos_bt->microphone_volume = volume;
|
||||
|
||||
result.type = OFONO_ERROR_TYPE_NO_ERROR;
|
||||
ofono_emulator_send_final(em, &result);
|
||||
break;
|
||||
|
||||
default:
|
||||
fail:
|
||||
result.type = OFONO_ERROR_TYPE_FAILURE;
|
||||
ofono_emulator_send_final(em, &result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sfos_bt_vgm_cb(struct ofono_emulator *em,
|
||||
struct ofono_emulator_request *req, void *userdata)
|
||||
{
|
||||
const char *gain = "MicrophoneVolume";
|
||||
set_gain(em, req, userdata, gain);
|
||||
}
|
||||
|
||||
static void sfos_bt_vgs_cb(struct ofono_emulator *em,
|
||||
struct ofono_emulator_request *req, void *userdata)
|
||||
{
|
||||
const char *gain = "SpeakerVolume";
|
||||
set_gain(em, req, userdata, gain);
|
||||
}
|
||||
|
||||
void sfos_bt_cv_dbus_new(struct sfos_bt *sfos_bt)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
if (g_dbus_register_interface(conn, path,
|
||||
SFOS_BT_DBUS_CV_INTERFACE, cv_methods,
|
||||
cv_signals, NULL, sfos_bt, NULL)){
|
||||
ofono_modem_add_interface(modem,SFOS_BT_DBUS_CV_INTERFACE);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_error("D-Bus register failed");
|
||||
}
|
||||
|
||||
static void sfos_bt_remove_handler(struct ofono_emulator *em)
|
||||
{
|
||||
ofono_emulator_remove_handler(em, "+VGS");
|
||||
ofono_emulator_remove_handler(em, "+VGM");
|
||||
}
|
||||
|
||||
void sfos_bt_cv_dbus_free(struct sfos_bt *sfos_bt)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
ofono_modem_remove_interface(modem, SFOS_BT_DBUS_CV_INTERFACE);
|
||||
g_dbus_unregister_interface(conn, path,
|
||||
SFOS_BT_DBUS_CV_INTERFACE);
|
||||
}
|
||||
|
||||
static void sfos_bt_emu_watch_cb(struct ofono_atom *atom,
|
||||
enum ofono_atom_watch_condition cond,
|
||||
void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED){
|
||||
sfos_bt->em = __ofono_atom_get_data(atom);
|
||||
sfos_bt_cv_dbus_new(sfos_bt);
|
||||
ofono_emulator_add_handler(sfos_bt->em, "+VGS",
|
||||
sfos_bt_vgs_cb, sfos_bt, NULL);
|
||||
ofono_emulator_add_handler(sfos_bt->em, "+VGM",
|
||||
sfos_bt_vgm_cb, sfos_bt, NULL);
|
||||
} else {
|
||||
sfos_bt_cv_dbus_free(sfos_bt);
|
||||
sfos_bt_remove_handler(sfos_bt->em);
|
||||
sfos_bt->em = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void sfos_bt_emu_watch_destroy(void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
|
||||
sfos_bt->emu_watch = 0;
|
||||
}
|
||||
|
||||
static void sfos_bt_free(void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
|
||||
if (sfos_bt->emu_watch)
|
||||
__ofono_modem_remove_atom_watch(sfos_bt->modem,
|
||||
sfos_bt->emu_watch);
|
||||
|
||||
if (sfos_bt->em) {
|
||||
sfos_bt_cv_dbus_free(sfos_bt);
|
||||
sfos_bt_remove_handler(sfos_bt->em);
|
||||
}
|
||||
|
||||
g_free(sfos_bt);
|
||||
}
|
||||
|
||||
static gint sfos_bt_find_modem(gconstpointer listdata, gconstpointer modem)
|
||||
{
|
||||
const struct sfos_bt *sfos_bt = listdata;
|
||||
|
||||
return (sfos_bt->modem != modem);
|
||||
}
|
||||
|
||||
static void modem_watch(struct ofono_modem *modem, gboolean added, void *user)
|
||||
{
|
||||
struct sfos_bt *sfos_bt;
|
||||
DBG("modem: %p, added: %d", modem, added);
|
||||
|
||||
if (added) {
|
||||
sfos_bt = g_new0(struct sfos_bt, 1);
|
||||
modems = g_slist_append(modems, sfos_bt);
|
||||
sfos_bt->emu_watch = __ofono_modem_add_atom_watch(modem,
|
||||
OFONO_ATOM_TYPE_EMULATOR_HFP, sfos_bt_emu_watch_cb,
|
||||
sfos_bt, sfos_bt_emu_watch_destroy);
|
||||
sfos_bt->modem = modem;
|
||||
} else {
|
||||
GSList *link = g_slist_find_custom(modems, modem,
|
||||
sfos_bt_find_modem);
|
||||
if (link) {
|
||||
sfos_bt_free(link->data);
|
||||
modems = g_slist_delete_link(modems, link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void call_modemwatch(struct ofono_modem *modem, void *user)
|
||||
{
|
||||
modem_watch(modem, TRUE, user);
|
||||
}
|
||||
|
||||
static int sfos_bt_init(void)
|
||||
{
|
||||
modemwatch_id = __ofono_modemwatch_add(modem_watch, NULL, NULL);
|
||||
__ofono_modem_foreach(call_modemwatch, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sfos_bt_exit(void)
|
||||
{
|
||||
DBG("");
|
||||
__ofono_modemwatch_remove(modemwatch_id);
|
||||
g_slist_free_full(modems, sfos_bt_free);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(sfos_bt, "Sailfish OS Bluetooth Plugin", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
sfos_bt_init, sfos_bt_exit)
|
||||
@@ -325,11 +325,14 @@ static gboolean setup_huawei(struct modem_info *modem)
|
||||
if (g_strcmp0(info->label, "modem") == 0 ||
|
||||
g_strcmp0(info->interface, "255/1/1") == 0 ||
|
||||
g_strcmp0(info->interface, "255/2/1") == 0 ||
|
||||
g_strcmp0(info->interface, "255/3/1") == 0 ||
|
||||
g_strcmp0(info->interface, "255/1/49") == 0) {
|
||||
mdm = info->devnode;
|
||||
} else if (g_strcmp0(info->label, "pcui") == 0 ||
|
||||
g_strcmp0(info->interface, "255/1/2") == 0 ||
|
||||
g_strcmp0(info->interface, "255/2/2") == 0 ||
|
||||
g_strcmp0(info->interface, "255/2/18") == 0 ||
|
||||
g_strcmp0(info->interface, "255/3/18") == 0 ||
|
||||
g_strcmp0(info->interface, "255/1/50") == 0) {
|
||||
pcui = info->devnode;
|
||||
} else if (g_strcmp0(info->label, "diag") == 0 ||
|
||||
|
||||
@@ -135,6 +135,7 @@ struct pri_context {
|
||||
struct ofono_gprs *gprs;
|
||||
};
|
||||
|
||||
static void gprs_attached_update(struct ofono_gprs *gprs);
|
||||
static void gprs_netreg_update(struct ofono_gprs *gprs);
|
||||
static void gprs_deactivate_next(struct ofono_gprs *gprs);
|
||||
static void write_context_settings(struct ofono_gprs *gprs,
|
||||
@@ -1148,6 +1149,16 @@ static void pri_deactivate_callback(const struct ofono_error *error, void *data)
|
||||
ofono_dbus_signal_property_changed(conn, ctx->path,
|
||||
OFONO_CONNECTION_CONTEXT_INTERFACE,
|
||||
"Active", DBUS_TYPE_BOOLEAN, &value);
|
||||
|
||||
/*
|
||||
* If "Attached" property was about to be signalled as TRUE but there
|
||||
* were still active contexts, try again to signal "Attached" property
|
||||
* to registered applications after active contexts have been released.
|
||||
*/
|
||||
if (ctx->gprs->flags & GPRS_FLAG_ATTACHED_UPDATE) {
|
||||
ctx->gprs->flags &= ~GPRS_FLAG_ATTACHED_UPDATE;
|
||||
gprs_attached_update(ctx->gprs);
|
||||
}
|
||||
}
|
||||
|
||||
static void pri_read_settings_callback(const struct ofono_error *error,
|
||||
@@ -2263,6 +2274,11 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
|
||||
const char *path;
|
||||
enum ofono_gprs_context_type type;
|
||||
|
||||
#ifdef DISABLE_ADD_REMOVE_CONTEXT
|
||||
ofono_error("AddContext not allowed");
|
||||
return __ofono_error_not_supported(msg);
|
||||
#endif
|
||||
|
||||
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
|
||||
DBUS_TYPE_INVALID))
|
||||
return __ofono_error_invalid_args(msg);
|
||||
@@ -2344,6 +2360,11 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
|
||||
const char *path;
|
||||
const char *atompath;
|
||||
|
||||
#ifdef DISABLE_ADD_REMOVE_CONTEXT
|
||||
ofono_error("RemoveContext not allowed");
|
||||
return __ofono_error_not_supported(msg);
|
||||
#endif
|
||||
|
||||
if (gprs->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
@@ -2358,13 +2379,13 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
|
||||
if (ctx == NULL)
|
||||
return __ofono_error_not_found(msg);
|
||||
|
||||
/* This context is already being messed with */
|
||||
if (ctx->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
if (ctx->active) {
|
||||
struct ofono_gprs_context *gc = ctx->context_driver;
|
||||
|
||||
/* This context is already being messed with */
|
||||
if (ctx->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
gprs->pending = dbus_message_ref(msg);
|
||||
gc->driver->deactivate_primary(gc, ctx->context.cid,
|
||||
gprs_deactivate_for_remove, ctx);
|
||||
|
||||
@@ -203,7 +203,7 @@ static gboolean sco_accept(GIOChannel *io, GIOCondition cond,
|
||||
send_new_connection(card->path, nsk, card->selected_codec);
|
||||
close(nsk);
|
||||
|
||||
if (card->driver->sco_connected_hint)
|
||||
if (card->driver && card->driver->sco_connected_hint)
|
||||
card->driver->sco_connected_hint(card);
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -2511,13 +2511,6 @@ static void sim_spn_close(struct ofono_sim *sim)
|
||||
|
||||
static void sim_free_main_state(struct ofono_sim *sim)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
sim->pin_retries[i] = -1;
|
||||
|
||||
memset(sim->locked_pins, 0, sizeof(sim->locked_pins));
|
||||
|
||||
if (sim->imsi) {
|
||||
g_free(sim->imsi);
|
||||
sim->imsi = NULL;
|
||||
@@ -2607,31 +2600,50 @@ static void sim_set_locked_pin(struct ofono_sim *sim,
|
||||
g_strfreev(locked_pins);
|
||||
}
|
||||
|
||||
static void sim_query_fac_imsilock_cb(const struct ofono_error *error,
|
||||
static void sim_query_fac_pinlock_cb(const struct ofono_error *error,
|
||||
ofono_bool_t status, void *data)
|
||||
{
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
|
||||
return;
|
||||
struct ofono_sim *sim = data;
|
||||
|
||||
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHSIM_PIN, status);
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
|
||||
goto done;
|
||||
|
||||
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_SIM_PIN, status);
|
||||
|
||||
done:
|
||||
sim_initialize(sim);
|
||||
}
|
||||
|
||||
static void sim_query_fac_networklock_cb(const struct ofono_error *error,
|
||||
ofono_bool_t status, void *data)
|
||||
{
|
||||
struct ofono_sim *sim = data;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
|
||||
return;
|
||||
goto done;
|
||||
|
||||
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHNET_PIN, status);
|
||||
|
||||
done:
|
||||
sim->driver->query_facility_lock(sim,
|
||||
OFONO_SIM_PASSWORD_SIM_PIN,
|
||||
sim_query_fac_pinlock_cb, sim);
|
||||
}
|
||||
|
||||
static void sim_query_fac_pinlock_cb(const struct ofono_error *error,
|
||||
static void sim_query_fac_imsilock_cb(const struct ofono_error *error,
|
||||
ofono_bool_t status, void *data)
|
||||
{
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
|
||||
return;
|
||||
struct ofono_sim *sim = data;
|
||||
|
||||
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_SIM_PIN, status);
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
|
||||
goto done;
|
||||
|
||||
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHSIM_PIN, status);
|
||||
|
||||
done:
|
||||
sim->driver->query_facility_lock(sim,
|
||||
OFONO_SIM_PASSWORD_PHNET_PIN,
|
||||
sim_query_fac_networklock_cb, sim);
|
||||
}
|
||||
|
||||
void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
|
||||
@@ -2665,18 +2677,28 @@ void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
|
||||
OFONO_SIM_PASSWORD_PHSIM_PIN,
|
||||
sim_query_fac_imsilock_cb, sim);
|
||||
|
||||
sim->driver->query_facility_lock(sim,
|
||||
OFONO_SIM_PASSWORD_PHNET_PIN,
|
||||
sim_query_fac_networklock_cb, sim);
|
||||
|
||||
sim->driver->query_facility_lock(sim,
|
||||
OFONO_SIM_PASSWORD_SIM_PIN,
|
||||
sim_query_fac_pinlock_cb, sim);
|
||||
} else {
|
||||
sim_initialize(sim);
|
||||
}
|
||||
} else {
|
||||
switch (sim->pin_type) {
|
||||
case OFONO_SIM_PASSWORD_SIM_PIN:
|
||||
case OFONO_SIM_PASSWORD_SIM_PUK:
|
||||
case OFONO_SIM_PASSWORD_SIM_PIN2:
|
||||
case OFONO_SIM_PASSWORD_SIM_PUK2:
|
||||
sim->pin_type = OFONO_SIM_PASSWORD_NONE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sim_initialize(sim);
|
||||
} else {
|
||||
sim->pin_type = OFONO_SIM_PASSWORD_NONE;
|
||||
sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] = FALSE;
|
||||
sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN2] = FALSE;
|
||||
|
||||
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN] = -1;
|
||||
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK] = -1;
|
||||
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN2] = -1;
|
||||
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK2] = -1;
|
||||
|
||||
sim_free_state(sim);
|
||||
}
|
||||
@@ -3282,8 +3304,6 @@ ofono_bool_t __ofono_is_valid_sim_pin(const char *pin,
|
||||
return is_valid_pin(pin, 8, 8);
|
||||
break;
|
||||
case OFONO_SIM_PASSWORD_NONE:
|
||||
return is_valid_pin(pin, 0, 8);
|
||||
break;
|
||||
case OFONO_SIM_PASSWORD_INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -226,6 +226,9 @@ void sim_fs_notify_file_watches(struct sim_fs *fs, int id)
|
||||
struct ofono_sim_context *context = l->data;
|
||||
GSList *k;
|
||||
|
||||
if (context->file_watches == NULL)
|
||||
continue;
|
||||
|
||||
for (k = context->file_watches->items; k; k = k->next) {
|
||||
struct file_watch *w = k->data;
|
||||
ofono_sim_file_changed_cb_t notify = w->item.notify;
|
||||
|
||||
@@ -2218,6 +2218,7 @@ char *sms_decode_text(GSList *sms_list)
|
||||
const struct sms *sms;
|
||||
int guess_size = g_slist_length(sms_list);
|
||||
char *utf8;
|
||||
GByteArray *utf16 = 0;
|
||||
|
||||
if (guess_size == 1)
|
||||
guess_size = 160;
|
||||
@@ -2289,8 +2290,12 @@ char *sms_decode_text(GSList *sms_list)
|
||||
NULL, NULL, 0,
|
||||
locking_shift,
|
||||
single_shift);
|
||||
if (converted) {
|
||||
g_string_append(str, converted);
|
||||
g_free(converted);
|
||||
}
|
||||
} else {
|
||||
const gchar *from = (const gchar *) (ud + taken);
|
||||
const guint8 *from = ud + taken;
|
||||
/*
|
||||
* According to the spec: A UCS2 character shall not be
|
||||
* split in the middle; if the length of the User Data
|
||||
@@ -2300,15 +2305,32 @@ char *sms_decode_text(GSList *sms_list)
|
||||
gssize num_ucs2_chars = (udl_in_bytes - taken) >> 1;
|
||||
num_ucs2_chars = num_ucs2_chars << 1;
|
||||
|
||||
converted = g_convert_with_fallback(from, num_ucs2_chars,
|
||||
"UTF-8//TRANSLIT", "UTF-16BE",
|
||||
NULL, NULL, NULL, NULL);
|
||||
/*
|
||||
* In theory SMS supports encoding using UCS2 which
|
||||
* is 16-bit, however in the real world messages
|
||||
* are encoded in UTF-16 which can be 4 bytes and
|
||||
* a multiple fragment message can split a 4-byte
|
||||
* character in the middle. So accumulate the
|
||||
* entire message before converting to UTF-8.
|
||||
*/
|
||||
if (!utf16)
|
||||
utf16 = g_byte_array_new();
|
||||
|
||||
g_byte_array_append(utf16, from, num_ucs2_chars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (utf16) {
|
||||
char *converted = g_convert_with_fallback((const gchar *)
|
||||
utf16->data, utf16->len,
|
||||
"UTF-8//TRANSLIT", "UTF-16BE",
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (converted) {
|
||||
g_string_append(str, converted);
|
||||
g_free(converted);
|
||||
}
|
||||
g_byte_array_free(utf16, TRUE);
|
||||
}
|
||||
|
||||
utf8 = g_string_free(str, FALSE);
|
||||
|
||||
@@ -3748,6 +3748,15 @@ int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc)
|
||||
return __ofono_modem_callid_next(modem);
|
||||
}
|
||||
|
||||
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
|
||||
unsigned int id)
|
||||
{
|
||||
GSList *l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(id),
|
||||
call_compare_by_id);
|
||||
|
||||
return l ? ((struct voicecall *)l->data)->call : NULL;
|
||||
}
|
||||
|
||||
ofono_bool_t __ofono_voicecall_is_busy(struct ofono_voicecall *vc,
|
||||
enum ofono_voicecall_interaction type)
|
||||
{
|
||||
|
||||
15
ofono/test/cancel-sms
Executable file
15
ofono/test/cancel-sms
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import dbus
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
|
||||
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
|
||||
'org.ofono.Manager')
|
||||
|
||||
path = sys.argv[1]
|
||||
message = dbus.Interface(bus.get_object('org.ofono', path),
|
||||
'org.ofono.Message')
|
||||
|
||||
message.Cancel()
|
||||
18
ofono/test/disable-throttling
Executable file
18
ofono/test/disable-throttling
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import dbus, sys
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
path = sys.argv[1]
|
||||
else:
|
||||
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
|
||||
'org.ofono.Manager')
|
||||
modems = manager.GetModems()
|
||||
path = modems[0][0]
|
||||
|
||||
print("Disabling transmit power throttling of modem %s ..." % path)
|
||||
thermal_management = dbus.Interface(bus.get_object('org.ofono', path),
|
||||
'org.ofono.sofia3gr.ThermalManagement')
|
||||
thermal_management.SetProperty("TransmitPowerThrottling", dbus.Boolean(0), timeout = 30)
|
||||
18
ofono/test/enable-throttling
Executable file
18
ofono/test/enable-throttling
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import dbus, sys
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
path = sys.argv[1]
|
||||
else:
|
||||
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
|
||||
'org.ofono.Manager')
|
||||
modems = manager.GetModems()
|
||||
path = modems[0][0]
|
||||
|
||||
print("Enabling transmit power throttling of modem %s ..." % path)
|
||||
thermal_management = dbus.Interface(bus.get_object('org.ofono', path),
|
||||
'org.ofono.sofia3gr.ThermalManagement')
|
||||
thermal_management.SetProperty("TransmitPowerThrottling", dbus.Boolean(1), timeout = 30)
|
||||
0
ofono/test/get-serving-cell-info
Normal file → Executable file
0
ofono/test/get-serving-cell-info
Normal file → Executable file
280
ofono/unit/rilmodem-test-engine.c
Normal file
280
ofono/unit/rilmodem-test-engine.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
#include <gril.h>
|
||||
|
||||
#include "rilmodem-test-engine.h"
|
||||
|
||||
#define MAX_REQUEST_SIZE 4096
|
||||
#define RIL_SERVER_SOCK_PATH "/tmp/unittestril"
|
||||
|
||||
static GMainLoop *mainloop;
|
||||
|
||||
struct engine_data {
|
||||
int server_sk;
|
||||
int connected_sk;
|
||||
guint connection_watch;
|
||||
rilmodem_test_engine_cb_t connect_func;
|
||||
GIOChannel *server_io;
|
||||
char *sock_name;
|
||||
struct rilmodem_test_data rtd;
|
||||
int step_i;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void send_parcel(struct engine_data *ed)
|
||||
{
|
||||
GIOStatus status;
|
||||
gsize wbytes;
|
||||
const struct rilmodem_test_step *step = &ed->rtd.steps[ed->step_i];
|
||||
|
||||
status = g_io_channel_write_chars(ed->server_io,
|
||||
step->parcel_data,
|
||||
step->parcel_size,
|
||||
&wbytes, NULL);
|
||||
|
||||
g_assert(wbytes == step->parcel_size);
|
||||
g_assert(status == G_IO_STATUS_NORMAL);
|
||||
|
||||
status = g_io_channel_flush(ed->server_io, NULL);
|
||||
g_assert(status == G_IO_STATUS_NORMAL);
|
||||
|
||||
rilmodem_test_engine_next_step(ed);
|
||||
}
|
||||
|
||||
static gboolean on_rx_data(GIOChannel *chan, GIOCondition cond, gpointer data)
|
||||
{
|
||||
struct engine_data *ed = data;
|
||||
GIOStatus status;
|
||||
gsize rbytes;
|
||||
gchar *buf;
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
/* We have closed the socket */
|
||||
if (cond == G_IO_NVAL)
|
||||
return FALSE;
|
||||
|
||||
buf = g_malloc0(MAX_REQUEST_SIZE);
|
||||
|
||||
status = g_io_channel_read_chars(ed->server_io, buf, MAX_REQUEST_SIZE,
|
||||
&rbytes, NULL);
|
||||
g_assert(status == G_IO_STATUS_NORMAL);
|
||||
|
||||
/* Check this is the expected step */
|
||||
step = &ed->rtd.steps[ed->step_i];
|
||||
g_assert(step->type == TST_EVENT_RECEIVE);
|
||||
|
||||
g_assert(rbytes == step->parcel_size);
|
||||
|
||||
/* validate received parcel */
|
||||
g_assert(!memcmp(buf, step->parcel_data, rbytes));
|
||||
|
||||
rilmodem_test_engine_next_step(ed);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
|
||||
gpointer data)
|
||||
{
|
||||
struct engine_data *ed = data;
|
||||
struct sockaddr saddr;
|
||||
unsigned int len = sizeof(saddr);
|
||||
GIOStatus status;
|
||||
|
||||
g_assert(cond == G_IO_IN);
|
||||
|
||||
ed->connected_sk = accept(ed->server_sk, &saddr, &len);
|
||||
g_assert(ed->connected_sk != -1);
|
||||
|
||||
ed->server_io = g_io_channel_unix_new(ed->connected_sk);
|
||||
g_assert(ed->server_io != NULL);
|
||||
|
||||
status = g_io_channel_set_encoding(ed->server_io, NULL, NULL);
|
||||
g_assert(status == G_IO_STATUS_NORMAL);
|
||||
|
||||
g_io_channel_set_buffered(ed->server_io, FALSE);
|
||||
g_io_channel_set_close_on_unref(ed->server_io, TRUE);
|
||||
|
||||
if (ed->connect_func)
|
||||
ed->connect_func(ed->user_data);
|
||||
|
||||
ed->connection_watch =
|
||||
g_io_add_watch_full(ed->server_io, G_PRIORITY_DEFAULT,
|
||||
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
|
||||
on_rx_data, ed, NULL);
|
||||
g_io_channel_unref(ed->server_io);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void rilmodem_test_engine_remove(struct engine_data *ed)
|
||||
{
|
||||
if (ed->connection_watch)
|
||||
g_source_remove(ed->connection_watch);
|
||||
|
||||
g_assert(ed->server_sk);
|
||||
close(ed->server_sk);
|
||||
remove(ed->sock_name);
|
||||
g_free(ed->sock_name);
|
||||
g_free(ed);
|
||||
}
|
||||
|
||||
struct engine_data *rilmodem_test_engine_create(
|
||||
rilmodem_test_engine_cb_t connect,
|
||||
const struct rilmodem_test_data *test_data,
|
||||
void *data)
|
||||
{
|
||||
GIOChannel *io;
|
||||
struct sockaddr_un addr;
|
||||
int retval;
|
||||
struct engine_data *ed;
|
||||
|
||||
ed = g_new0(struct engine_data, 1);
|
||||
|
||||
ed->connect_func = connect;
|
||||
ed->user_data = data;
|
||||
ed->rtd = *test_data;
|
||||
|
||||
ed->server_sk = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
g_assert(ed->server_sk);
|
||||
|
||||
ed->sock_name =
|
||||
g_strdup_printf(RIL_SERVER_SOCK_PATH"%u", (unsigned) getpid());
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, ed->sock_name, sizeof(addr.sun_path) - 1);
|
||||
|
||||
/* Unlink any existing socket for this session */
|
||||
unlink(addr.sun_path);
|
||||
|
||||
retval = bind(ed->server_sk, (struct sockaddr *) &addr, sizeof(addr));
|
||||
g_assert(retval >= 0);
|
||||
|
||||
retval = listen(ed->server_sk, 0);
|
||||
g_assert(retval >= 0);
|
||||
|
||||
io = g_io_channel_unix_new(ed->server_sk);
|
||||
g_assert(io != NULL);
|
||||
|
||||
g_io_channel_set_close_on_unref(io, TRUE);
|
||||
g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
|
||||
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
|
||||
on_socket_connected, ed, NULL);
|
||||
|
||||
g_io_channel_unref(io);
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
void rilmodem_test_engine_write_socket(struct engine_data *ed,
|
||||
const unsigned char *buf,
|
||||
const size_t buf_len)
|
||||
{
|
||||
GIOStatus status;
|
||||
gsize wbytes;
|
||||
|
||||
status = g_io_channel_write_chars(ed->server_io,
|
||||
(const char *) buf,
|
||||
buf_len,
|
||||
&wbytes, NULL);
|
||||
|
||||
g_assert(status == G_IO_STATUS_NORMAL);
|
||||
|
||||
status = g_io_channel_flush(ed->server_io, NULL);
|
||||
|
||||
g_assert(status == G_IO_STATUS_NORMAL);
|
||||
}
|
||||
|
||||
const char *rilmodem_test_engine_get_socket_name(struct engine_data *ed)
|
||||
{
|
||||
return ed->sock_name;
|
||||
}
|
||||
|
||||
static gboolean action_call(gpointer data)
|
||||
{
|
||||
struct engine_data *ed = data;
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = &ed->rtd.steps[ed->step_i];
|
||||
|
||||
step->call_action(ed->user_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void rilmodem_test_engine_next_step(struct engine_data *ed)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
ed->step_i++;
|
||||
|
||||
if (ed->step_i >= ed->rtd.num_steps) {
|
||||
/* Finish the test */
|
||||
g_main_loop_quit(mainloop);
|
||||
return;
|
||||
}
|
||||
|
||||
step = &ed->rtd.steps[ed->step_i];
|
||||
|
||||
/* If next step is an action, execute it */
|
||||
switch (step->type) {
|
||||
case TST_ACTION_SEND:
|
||||
send_parcel(ed);
|
||||
break;
|
||||
case TST_ACTION_CALL:
|
||||
g_idle_add(action_call, ed);
|
||||
break;
|
||||
case TST_EVENT_RECEIVE:
|
||||
case TST_EVENT_CALL:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
const struct rilmodem_test_step *rilmodem_test_engine_get_current_step(
|
||||
struct engine_data *ed)
|
||||
{
|
||||
const struct rilmodem_test_step *step = &ed->rtd.steps[ed->step_i];
|
||||
|
||||
return step;
|
||||
}
|
||||
|
||||
void rilmodem_test_engine_start(struct engine_data *ed)
|
||||
{
|
||||
mainloop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
g_main_loop_run(mainloop);
|
||||
g_main_loop_unref(mainloop);
|
||||
}
|
||||
74
ofono/unit/rilmodem-test-engine.h
Normal file
74
ofono/unit/rilmodem-test-engine.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
struct engine_data;
|
||||
|
||||
enum test_step_type {
|
||||
TST_ACTION_SEND,
|
||||
TST_ACTION_CALL,
|
||||
TST_EVENT_RECEIVE,
|
||||
TST_EVENT_CALL,
|
||||
};
|
||||
|
||||
typedef void (*rilmodem_test_engine_cb_t)(void *data);
|
||||
|
||||
struct rilmodem_test_step {
|
||||
enum test_step_type type;
|
||||
|
||||
union {
|
||||
/* For TST_ACTION_CALL */
|
||||
rilmodem_test_engine_cb_t call_action;
|
||||
/* For TST_ACTION_SEND or TST_EVENT_RECEIVE */
|
||||
struct {
|
||||
const char *parcel_data;
|
||||
const size_t parcel_size;
|
||||
};
|
||||
/* For TST_EVENT_CALL */
|
||||
struct {
|
||||
void (*call_func)(void);
|
||||
void (*check_func)(void);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct rilmodem_test_data {
|
||||
const struct rilmodem_test_step *steps;
|
||||
int num_steps;
|
||||
};
|
||||
|
||||
void rilmodem_test_engine_remove(struct engine_data *ed);
|
||||
|
||||
struct engine_data *rilmodem_test_engine_create(
|
||||
rilmodem_test_engine_cb_t connect,
|
||||
const struct rilmodem_test_data *test_data,
|
||||
void *data);
|
||||
|
||||
void rilmodem_test_engine_write_socket(struct engine_data *ed,
|
||||
const unsigned char *buf,
|
||||
const size_t buf_len);
|
||||
|
||||
const char *rilmodem_test_engine_get_socket_name(struct engine_data *ed);
|
||||
|
||||
void rilmodem_test_engine_next_step(struct engine_data *ed);
|
||||
const struct rilmodem_test_step *rilmodem_test_engine_get_current_step(
|
||||
struct engine_data *ed);
|
||||
|
||||
void rilmodem_test_engine_start(struct engine_data *ed);
|
||||
750
ofono/unit/test-rilmodem-gprs.c
Normal file
750
ofono/unit/test-rilmodem-gprs.c
Normal file
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <gril.h>
|
||||
#include <drivers/rilmodem/rilutil.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "ril_constants.h"
|
||||
#include "rilmodem-test-engine.h"
|
||||
|
||||
static const struct ofono_gprs_driver *gprs_drv;
|
||||
|
||||
/* Declarations && Re-implementations of core functions. */
|
||||
void ril_gprs_exit(void);
|
||||
void ril_gprs_init(void);
|
||||
|
||||
struct ofono_modem;
|
||||
|
||||
struct ofono_gprs {
|
||||
void *driver_data;
|
||||
GRil *ril;
|
||||
struct ofono_modem *modem;
|
||||
struct engine_data *engined;
|
||||
};
|
||||
|
||||
struct ofono_modem {
|
||||
struct ofono_gprs *gprs;
|
||||
};
|
||||
|
||||
int ofono_gprs_driver_register(const struct ofono_gprs_driver *d)
|
||||
{
|
||||
if (gprs_drv == NULL)
|
||||
gprs_drv = d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ofono_gprs_driver_unregister(const struct ofono_gprs_driver *d)
|
||||
{
|
||||
gprs_drv = NULL;
|
||||
}
|
||||
|
||||
void ofono_gprs_register(struct ofono_gprs *gprs)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func == (void (*)(void)) ofono_gprs_register);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
void ofono_gprs_set_data(struct ofono_gprs *gprs, void *data)
|
||||
{
|
||||
gprs->driver_data = data;
|
||||
}
|
||||
|
||||
void *ofono_gprs_get_data(struct ofono_gprs *gprs)
|
||||
{
|
||||
return gprs->driver_data;
|
||||
}
|
||||
|
||||
void ofono_gprs_status_notify(struct ofono_gprs *gprs, int status)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func == (void (*)(void)) ofono_gprs_status_notify);
|
||||
|
||||
if (step->check_func != NULL)
|
||||
((void (*)(struct ofono_gprs *, int)) step->check_func)(
|
||||
gprs, status);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
void ofono_gprs_detached_notify(struct ofono_gprs *gprs)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func ==
|
||||
(void (*)(void)) ofono_gprs_detached_notify);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
void ofono_gprs_bearer_notify(struct ofono_gprs *gprs, int bearer)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func == (void (*)(void)) ofono_gprs_bearer_notify);
|
||||
|
||||
if (step->check_func != NULL)
|
||||
((void (*)(struct ofono_gprs *, int)) step->check_func)(
|
||||
gprs, bearer);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
void ofono_gprs_set_cid_range(struct ofono_gprs *gprs,
|
||||
unsigned int min, unsigned int max)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func == (void (*)(void)) ofono_gprs_set_cid_range);
|
||||
|
||||
if (step->check_func != NULL)
|
||||
((void (*)(struct ofono_gprs *, unsigned int, unsigned int))
|
||||
step->check_func)(gprs, min, max);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs)
|
||||
{
|
||||
return gprs->modem;
|
||||
}
|
||||
|
||||
int ofono_modem_set_integer(struct ofono_modem *modem,
|
||||
const char *key, int value)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(modem->gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func == (void (*)(void)) ofono_modem_set_integer);
|
||||
|
||||
if (step->check_func != NULL)
|
||||
((void (*)(struct ofono_modem *, const char *, int))
|
||||
step->check_func)(modem, key, value);
|
||||
|
||||
rilmodem_test_engine_next_step(modem->gprs->engined);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ofono_gprs_remove(struct ofono_gprs *gprs)
|
||||
{
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func == (void (*)(void)) ofono_gprs_remove);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
/*
|
||||
* As all our architectures are little-endian except for
|
||||
* PowerPC, and the Binder wire-format differs slightly
|
||||
* depending on endian-ness, the following guards against test
|
||||
* failures when run on PowerPC.
|
||||
*/
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
|
||||
/* REQUEST_DATA_CALL_LIST, seq 1 */
|
||||
static const char parcel_req_data_call_list_1_1[] = {
|
||||
0x00, 0x00, 0x00, 0x08, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* --- TEST 1 ---
|
||||
* Step 1: Driver sends REQUEST_DATA_CALL_LIST
|
||||
*/
|
||||
static const struct rilmodem_test_step steps_test_1[] = {
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_call_list_1_1,
|
||||
.parcel_size = sizeof(parcel_req_data_call_list_1_1)
|
||||
}
|
||||
};
|
||||
|
||||
struct rilmodem_test_data test_1 = {
|
||||
.steps = steps_test_1,
|
||||
.num_steps = G_N_ELEMENTS(steps_test_1)
|
||||
};
|
||||
|
||||
/* REQUEST_DATA_CALL_LIST, seq 1 */
|
||||
static const char parcel_req_data_call_list_2_1[] = {
|
||||
0x00, 0x00, 0x00, 0x08, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* Response, no errors */
|
||||
static const char parcel_rsp_data_call_list_2_2[] = {
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* REQUEST_DATA_REGISTRATION_STATE, seq 2 */
|
||||
static const char parcel_req_data_registration_state_2_3[] = {
|
||||
0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* Responso, no error, {unregistered,0xb08,0x10e1,GPRS,(null),4} */
|
||||
static const char parcel_rsp_data_registration_state_2_4[] = {
|
||||
0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
|
||||
0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
|
||||
0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void set_cid_range_check_2_5(struct ofono_gprs *gprs,
|
||||
unsigned int min, unsigned int max)
|
||||
{
|
||||
g_assert(min == 1);
|
||||
g_assert(max == 2);
|
||||
}
|
||||
|
||||
static void gprs_cb_2_8(const struct ofono_error *error, void *data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
|
||||
g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
static void call_set_attached_2_7(gpointer data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
|
||||
gprs_drv->set_attached(gprs, 0, gprs_cb_2_8, gprs);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
/*
|
||||
* --- TEST 2 ---
|
||||
* Step 1: Driver sends REQUEST_DATA_CALL_LIST
|
||||
* Step 2: Harness answers with empty data call list
|
||||
* Step 3: Driver sends REQUEST_DATA_REGISTRATION_STATE
|
||||
* Step 4: Harness answers with status unregistered
|
||||
* Step 5: Driver calls ofono_gprs_set_cid_range
|
||||
* Step 6: Driver calls ofono_gprs_register
|
||||
* Step 7: Harness calls drv->set_attached(false)
|
||||
* Step 8: Driver calls the callback specified in step 7
|
||||
*/
|
||||
static const struct rilmodem_test_step steps_test_2[] = {
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_call_list_2_1,
|
||||
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_call_list_2_2,
|
||||
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_registration_state_2_3,
|
||||
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_registration_state_2_4,
|
||||
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
|
||||
.check_func = (void (*)(void)) set_cid_range_check_2_5
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_register,
|
||||
.check_func = NULL
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_CALL,
|
||||
.call_action = call_set_attached_2_7,
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) gprs_cb_2_8,
|
||||
.check_func = NULL
|
||||
},
|
||||
};
|
||||
|
||||
struct rilmodem_test_data test_2 = {
|
||||
.steps = steps_test_2,
|
||||
.num_steps = G_N_ELEMENTS(steps_test_2)
|
||||
};
|
||||
|
||||
static void gprs_cb_3_8(const struct ofono_error *error, void *data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
|
||||
g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
static void call_set_attached_3_7(gpointer data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
|
||||
gprs_drv->set_attached(gprs, 1, gprs_cb_3_8, gprs);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
/*
|
||||
* --- TEST 3 ---
|
||||
* Steps 1-6: Same as in test 2
|
||||
* Step 7: Harness calls drv->set_attached(true)
|
||||
* Step 8: Driver calls the callback specified in step 7
|
||||
*/
|
||||
static const struct rilmodem_test_step steps_test_3[] = {
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_call_list_2_1,
|
||||
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_call_list_2_2,
|
||||
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_registration_state_2_3,
|
||||
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_registration_state_2_4,
|
||||
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
|
||||
.check_func = (void (*)(void)) set_cid_range_check_2_5
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_register,
|
||||
.check_func = NULL
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_CALL,
|
||||
.call_action = call_set_attached_3_7,
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) gprs_cb_3_8,
|
||||
.check_func = NULL
|
||||
},
|
||||
};
|
||||
|
||||
struct rilmodem_test_data test_3 = {
|
||||
.steps = steps_test_3,
|
||||
.num_steps = G_N_ELEMENTS(steps_test_3)
|
||||
};
|
||||
|
||||
|
||||
/* REQUEST_DATA_REGISTRATION_STATE, seq 3 */
|
||||
static const char parcel_req_registration_state_4_8[] = {
|
||||
0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* Response, no error, {registered,0xb08,0x10e1,GPRS,(null),4} */
|
||||
static const char parcel_rsp_registration_state_4_9[] = {
|
||||
0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
|
||||
0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
|
||||
0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void reg_state_cb_4_12(const struct ofono_error *error,
|
||||
int status, void *data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
const struct rilmodem_test_step *step;
|
||||
|
||||
step = rilmodem_test_engine_get_current_step(gprs->engined);
|
||||
|
||||
g_assert(step->type == TST_EVENT_CALL);
|
||||
g_assert(step->call_func == (void (*)(void)) reg_state_cb_4_12);
|
||||
|
||||
g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
|
||||
/*
|
||||
* Driver returns unregistered even though network state is attached
|
||||
* because we did not set attach to true in this test case.
|
||||
*/
|
||||
g_assert(status == NETWORK_REGISTRATION_STATUS_NOT_REGISTERED);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
static void call_registration_status_4_7(gpointer data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
|
||||
gprs_drv->attached_status(gprs, reg_state_cb_4_12, gprs);
|
||||
|
||||
rilmodem_test_engine_next_step(gprs->engined);
|
||||
}
|
||||
|
||||
static void set_integer_check_4_10(struct ofono_modem *modem,
|
||||
const char *key, int value)
|
||||
{
|
||||
g_assert_cmpstr(key, ==, "RilDataRadioTechnology");
|
||||
g_assert(value == RADIO_TECH_GPRS);
|
||||
}
|
||||
|
||||
static void gprs_bearer_check_4_11(struct ofono_gprs *gprs, int bearer)
|
||||
{
|
||||
g_assert(bearer == PACKET_BEARER_GPRS);
|
||||
}
|
||||
|
||||
/*
|
||||
* --- TEST 4 ---
|
||||
* Steps 1-6: Same as in test 2
|
||||
* Step 7: Harness calls drv->registration_status
|
||||
* Step 8: Driver sends REQUEST_DATA_REGISTRATION_STATE
|
||||
* Step 9: Harness answers saying status is registered
|
||||
* Step 10: Driver calls ofono_modem_set_integer
|
||||
* Step 11: Driver calls ofono_gprs_bearer_notify(PACKET_BEARER_GPRS)
|
||||
* Step 12: Driver calls the callback specified in step 7
|
||||
*/
|
||||
static const struct rilmodem_test_step steps_test_4[] = {
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_call_list_2_1,
|
||||
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_call_list_2_2,
|
||||
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_registration_state_2_3,
|
||||
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_registration_state_2_4,
|
||||
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
|
||||
.check_func = (void (*)(void)) set_cid_range_check_2_5
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_register,
|
||||
.check_func = NULL
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_CALL,
|
||||
.call_action = call_registration_status_4_7,
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_registration_state_4_8,
|
||||
.parcel_size = sizeof(parcel_req_registration_state_4_8)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_registration_state_4_9,
|
||||
.parcel_size = sizeof(parcel_rsp_registration_state_4_9)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_modem_set_integer,
|
||||
.check_func = (void (*)(void)) set_integer_check_4_10
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_bearer_notify,
|
||||
.check_func = (void (*)(void)) gprs_bearer_check_4_11
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) reg_state_cb_4_12,
|
||||
.check_func = NULL
|
||||
},
|
||||
};
|
||||
|
||||
struct rilmodem_test_data test_4 = {
|
||||
.steps = steps_test_4,
|
||||
.num_steps = G_N_ELEMENTS(steps_test_4)
|
||||
};
|
||||
|
||||
/* UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED */
|
||||
static const char parcel_ev_network_state_changed_5_9[] = {
|
||||
0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0xEA, 0x03, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* REQUEST_DATA_REGISTRATION_STATE, seq 3 */
|
||||
static const char parcel_req_registration_state_5_10[] = {
|
||||
0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* Response, no error, {registered,0xb08,0x10e1,GPRS,(null),4} */
|
||||
static const char parcel_rsp_registration_state_5_11[] = {
|
||||
0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
|
||||
0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
|
||||
0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void gprs_status_check_5_12(struct ofono_gprs *gprs, int status)
|
||||
{
|
||||
g_assert(status == NETWORK_REGISTRATION_STATUS_REGISTERED);
|
||||
}
|
||||
|
||||
static void set_integer_check_5_13(struct ofono_modem *modem,
|
||||
const char *key, int value)
|
||||
{
|
||||
g_assert_cmpstr(key, ==, "RilDataRadioTechnology");
|
||||
g_assert(value == RADIO_TECH_GPRS);
|
||||
}
|
||||
|
||||
static void gprs_bearer_check_5_14(struct ofono_gprs *gprs, int bearer)
|
||||
{
|
||||
g_assert(bearer == PACKET_BEARER_GPRS);
|
||||
}
|
||||
|
||||
/*
|
||||
* --- TEST 5 ---
|
||||
* Steps 1-8: Same as test 3
|
||||
* Step 9: Harness sends UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
|
||||
* Step 10: Driver sends REQUEST_DATA_REGISTRATION_STATE
|
||||
* Step 11: Harness answers saying status is registered
|
||||
* Step 12: Driver calls ofono_gprs_status_notify(REGISTERED)
|
||||
* Step 13: Driver calls ofono_modem_set_integer
|
||||
* Step 14: Driver calls ofono_gprs_bearer_notify(PACKET_BEARER_GPRS)
|
||||
*/
|
||||
static const struct rilmodem_test_step steps_test_5[] = {
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_call_list_2_1,
|
||||
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_call_list_2_2,
|
||||
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_data_registration_state_2_3,
|
||||
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_data_registration_state_2_4,
|
||||
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
|
||||
.check_func = (void (*)(void)) set_cid_range_check_2_5
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_register,
|
||||
.check_func = NULL
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_CALL,
|
||||
.call_action = call_set_attached_3_7,
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) gprs_cb_3_8,
|
||||
.check_func = NULL
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_ev_network_state_changed_5_9,
|
||||
.parcel_size = sizeof(parcel_ev_network_state_changed_5_9)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_RECEIVE,
|
||||
.parcel_data = parcel_req_registration_state_5_10,
|
||||
.parcel_size = sizeof(parcel_req_registration_state_5_10)
|
||||
},
|
||||
{
|
||||
.type = TST_ACTION_SEND,
|
||||
.parcel_data = parcel_rsp_registration_state_5_11,
|
||||
.parcel_size = sizeof(parcel_rsp_registration_state_5_11)
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_status_notify,
|
||||
.check_func = (void (*)(void)) gprs_status_check_5_12
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_modem_set_integer,
|
||||
.check_func = (void (*)(void)) set_integer_check_5_13
|
||||
},
|
||||
{
|
||||
.type = TST_EVENT_CALL,
|
||||
.call_func = (void (*)(void)) ofono_gprs_bearer_notify,
|
||||
.check_func = (void (*)(void)) gprs_bearer_check_5_14
|
||||
},
|
||||
};
|
||||
|
||||
struct rilmodem_test_data test_5 = {
|
||||
.steps = steps_test_5,
|
||||
.num_steps = G_N_ELEMENTS(steps_test_5)
|
||||
};
|
||||
|
||||
static void server_connect_cb(gpointer data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* This triggers the first event from the gprs atom, which is a request
|
||||
* to retrieve currently active data calls. Test steps must start from
|
||||
* there.
|
||||
*/
|
||||
retval = gprs_drv->probe(gprs, OFONO_RIL_VENDOR_AOSP, gprs->ril);
|
||||
g_assert(retval == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This unit test:
|
||||
* - does some test data setup
|
||||
* - configures a dummy server socket
|
||||
* - creates a new gril client instance
|
||||
* - triggers a connect to the dummy
|
||||
* server socket
|
||||
* - starts the test engine
|
||||
*/
|
||||
static void test_function(gconstpointer data)
|
||||
{
|
||||
const struct rilmodem_test_data *test_data = data;
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_modem *modem;
|
||||
|
||||
ril_gprs_init();
|
||||
|
||||
gprs = g_malloc0(sizeof(*gprs));
|
||||
modem = g_malloc0(sizeof(*modem));
|
||||
|
||||
modem->gprs = gprs;
|
||||
gprs->modem = modem;
|
||||
|
||||
gprs->engined = rilmodem_test_engine_create(&server_connect_cb,
|
||||
test_data, gprs);
|
||||
|
||||
gprs->ril = g_ril_new(rilmodem_test_engine_get_socket_name(gprs->engined),
|
||||
OFONO_RIL_VENDOR_AOSP);
|
||||
g_assert(gprs->ril != NULL);
|
||||
|
||||
/* Perform test */
|
||||
rilmodem_test_engine_start(gprs->engined);
|
||||
|
||||
gprs_drv->remove(gprs);
|
||||
g_ril_unref(gprs->ril);
|
||||
g_free(modem);
|
||||
g_free(gprs);
|
||||
|
||||
rilmodem_test_engine_remove(gprs->engined);
|
||||
|
||||
ril_gprs_exit();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
/*
|
||||
* As all our architectures are little-endian except for
|
||||
* PowerPC, and the Binder wire-format differs slightly
|
||||
* depending on endian-ness, the following guards against test
|
||||
* failures when run on PowerPC.
|
||||
*/
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
g_test_add_data_func("/test-rilmodem-gprs/1", &test_1, test_function);
|
||||
g_test_add_data_func("/test-rilmodem-gprs/2", &test_2, test_function);
|
||||
g_test_add_data_func("/test-rilmodem-gprs/3", &test_3, test_function);
|
||||
g_test_add_data_func("/test-rilmodem-gprs/4", &test_4, test_function);
|
||||
g_test_add_data_func("/test-rilmodem-gprs/5", &test_5, test_function);
|
||||
#endif
|
||||
return g_test_run();
|
||||
}
|
||||
@@ -11,7 +11,7 @@ Requires: dbus
|
||||
Requires: systemd
|
||||
Requires: ofono-configs
|
||||
Requires: libgrilio >= 1.0.10
|
||||
Requires: libglibutil >= 1.0.10
|
||||
Requires: libglibutil >= 1.0.19
|
||||
Requires(preun): systemd
|
||||
Requires(post): systemd
|
||||
Requires(postun): systemd
|
||||
@@ -21,7 +21,7 @@ BuildRequires: pkgconfig(libudev) >= 145
|
||||
BuildRequires: pkgconfig(mobile-broadband-provider-info)
|
||||
BuildRequires: pkgconfig(libwspcodec) >= 2.0
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.10
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.10
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.19
|
||||
BuildRequires: pkgconfig(libdbuslogserver-dbus)
|
||||
BuildRequires: pkgconfig(libmce-glib)
|
||||
BuildRequires: libtool
|
||||
@@ -71,6 +71,10 @@ autoreconf --force --install
|
||||
--enable-test \
|
||||
--enable-debuglog \
|
||||
--enable-jolla-rilmodem \
|
||||
--enable-sailfishos \
|
||||
--disable-add-remove-context \
|
||||
--disable-isimodem \
|
||||
--disable-qmimodem \
|
||||
--with-systemdunitdir="/%{_lib}/systemd/system"
|
||||
|
||||
make %{?jobs:-j%jobs}
|
||||
|
||||
Reference in New Issue
Block a user