forked from sailfishos/ofono
Compare commits
113 Commits
mer/1.21+g
...
upgrade-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e6f7721a0 | ||
|
|
9c529dcdcc | ||
|
|
41814c6e6a | ||
|
|
cf99a5769f | ||
|
|
076e2f0ef1 | ||
|
|
fd76cb72ad | ||
|
|
554e4ab8e5 | ||
|
|
08f3da7577 | ||
|
|
2cbd3b6050 | ||
|
|
78d3d1892d | ||
|
|
1448bd2320 | ||
|
|
ea8dfb48ab | ||
|
|
80921e8b7e | ||
|
|
e4cc912719 | ||
|
|
c5f736d3c3 | ||
|
|
ddf4cec9b8 | ||
|
|
685d0b34d7 | ||
|
|
896f2f7a71 | ||
|
|
e96aacb9e7 | ||
|
|
91560afeec | ||
|
|
09fb8635c9 | ||
|
|
1cb80d7d2f | ||
|
|
7db5552e79 | ||
|
|
d87e40d0ff | ||
|
|
35131ff56b | ||
|
|
c5cc678b2b | ||
|
|
31be9a099b | ||
|
|
ccaf993977 | ||
|
|
74d633c58e | ||
|
|
f870880cf9 | ||
|
|
50c06afc73 | ||
|
|
e4e0ccd51d | ||
|
|
ee052af454 | ||
|
|
296b272274 | ||
|
|
9b9e5159f5 | ||
|
|
fa8002200c | ||
|
|
4cc71c78ec | ||
|
|
27b31e65bb | ||
|
|
e26d365a94 | ||
|
|
63f06cd11c | ||
|
|
96ca3aa907 | ||
|
|
11a84853fe | ||
|
|
a393cf0b11 | ||
|
|
6f263ee8d5 | ||
|
|
92a4760f46 | ||
|
|
c43d41829f | ||
|
|
25638a30c0 | ||
|
|
ed669bf66c | ||
|
|
e01dbd2b21 | ||
|
|
a8f0f26df8 | ||
|
|
56c84395ba | ||
|
|
3bf2b1df5c | ||
|
|
75041ccc37 | ||
|
|
e91ef8a701 | ||
|
|
620a20abdc | ||
|
|
d85fa8a64d | ||
|
|
d33b20889b | ||
|
|
cb8801752c | ||
|
|
a0722f8538 | ||
|
|
e016281b86 | ||
|
|
781a528625 | ||
|
|
5b1ab91b77 | ||
|
|
9604d9ef0a | ||
|
|
598acaa1a8 | ||
|
|
60193032f5 | ||
|
|
9faf27ec28 | ||
|
|
32c26c5a35 | ||
|
|
79fb591342 | ||
|
|
f6e46f78e3 | ||
|
|
7c587772d1 | ||
|
|
0d0728593b | ||
|
|
fd3916b2c7 | ||
|
|
c35557c2ed | ||
|
|
bb07543dd6 | ||
|
|
d346f1289c | ||
|
|
e170b6df4c | ||
|
|
761cd320bb | ||
|
|
60bc47aea2 | ||
|
|
183e4dab4b | ||
|
|
d6cdfc92ad | ||
|
|
b68752640c | ||
|
|
a53fc6ea7e | ||
|
|
63fe971077 | ||
|
|
011f3b74d1 | ||
|
|
4d2e314ad6 | ||
|
|
d846618057 | ||
|
|
38115199f7 | ||
|
|
f88c7ce919 | ||
|
|
9d6b3ec124 | ||
|
|
6dcf5cebc1 | ||
|
|
0e87392c90 | ||
|
|
dab76692db | ||
|
|
21bc90f638 | ||
|
|
d8707d52be | ||
|
|
fa0abf892d | ||
|
|
8a28d4eea8 | ||
|
|
4f0be99683 | ||
|
|
95933beb2d | ||
|
|
018a712e29 | ||
|
|
e6777f1ecc | ||
|
|
a58e1a5e9b | ||
|
|
61be41240f | ||
|
|
dbb40560c6 | ||
|
|
9bf50bb3e3 | ||
|
|
d2353c46a8 | ||
|
|
6701b53737 | ||
|
|
6612bfa1da | ||
|
|
c732d5192d | ||
|
|
6815772b17 | ||
|
|
e4766ef2c4 | ||
|
|
7aa396636b | ||
|
|
096cd04044 | ||
|
|
5eabe96602 |
61
.gitignore
vendored
61
.gitignore
vendored
@@ -1,61 +0,0 @@
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
||||
.dirstamp
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
compile
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
stamp-h1
|
||||
autom4te.cache
|
||||
test-driver
|
||||
test-suite.log
|
||||
|
||||
ofono.pc
|
||||
include/ofono
|
||||
include/version.h
|
||||
src/builtin.h
|
||||
src/ofonod
|
||||
src/ofono.service
|
||||
dundee/dundee
|
||||
dundee/dundee.service
|
||||
|
||||
unit/test-common
|
||||
unit/test-util
|
||||
unit/test-idmap
|
||||
unit/test-sms
|
||||
unit/test-sms-root
|
||||
unit/test-simutil
|
||||
unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
|
||||
tools/huawei-audio
|
||||
tools/auto-enable
|
||||
tools/get-location
|
||||
tools/lookup-apn
|
||||
tools/lookup-provider-name
|
||||
tools/tty-redirector
|
||||
tools/qmi
|
||||
tools/stktest
|
||||
|
||||
gatchat/gsmdial
|
||||
gatchat/test-server
|
||||
gatchat/test-qcdm
|
||||
7
.mailmap
7
.mailmap
@@ -1,7 +0,0 @@
|
||||
Luiz Augusto von Dentz <luiz.dentz-von@nokia.com> <luiz.dentz-von@nokia.com>
|
||||
Zhenhua Zhang <zhenhua.zhang@intel.com> <zhenhua.zhang@intel.com>
|
||||
Pekka Pessi <pekka.pessi@nokia.com> <Pekka.Pessi@nokia.com>
|
||||
Pekka Pessi <pekka.pessi@nokia.com> <ppessi@hamsa.research.nokia.com>
|
||||
Lasse Kunnasluoto <lasse.kunnasluoto@tieto.com> <Lasse.Kunnasluoto@tieto.com>
|
||||
Syam Sidhardhan <s.syam@samsung.com> <syamsidhardh@gmail.com>
|
||||
Michael Dietrich <mdt@emdete.de> <mdt@emdete.de>
|
||||
8
ofono/.gitignore
vendored
8
ofono/.gitignore
vendored
@@ -32,6 +32,8 @@ src/ofono.service
|
||||
dundee/dundee
|
||||
dundee/dundee.service
|
||||
|
||||
test-driver
|
||||
test-suite.log
|
||||
unit/test-common
|
||||
unit/test-util
|
||||
unit/test-idmap
|
||||
@@ -42,7 +44,11 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-dbus-queue
|
||||
unit/test-gprs-filter
|
||||
unit/test-ril_config
|
||||
unit/test-ril_util
|
||||
unit/test-ril-transport
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
@@ -52,7 +58,9 @@ unit/test-sailfish_cell_info_dbus
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sailfish_sim_info_dbus
|
||||
unit/test-sailfish_watch
|
||||
unit/test-sms-filter
|
||||
unit/test-voicecall-filter
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/cdma-provision.h include/handsfree.h \
|
||||
include/sim-mnclength.h \
|
||||
include/handsfree-audio.h include/siri.h \
|
||||
include/sms-filter.h \
|
||||
include/sms-filter.h include/gprs-filter.h \
|
||||
include/voicecall-filter.h \
|
||||
include/ril-constants.h include/ril-transport.h \
|
||||
include/netmon.h include/lte.h \
|
||||
include/storage.h \
|
||||
gdbus/gdbus.h
|
||||
@@ -736,7 +738,8 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/cdma-provision.c src/handsfree.c \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/sms-filter.c src/dbus-queue.c \
|
||||
src/sms-filter.c src/gprs-filter.c src/dbus-queue.c \
|
||||
src/voicecall-filter.c src/ril-transport.c \
|
||||
src/hfp.h src/siri.c \
|
||||
src/netmon.c src/lte.c \
|
||||
src/netmonagent.c src/netmonagent.h
|
||||
@@ -749,7 +752,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
|
||||
|
||||
BUILT_SOURCES = $(local_headers) src/builtin.h
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
|
||||
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
|
||||
|
||||
plugindir = $(pkglibdir)/plugins
|
||||
|
||||
@@ -919,8 +923,7 @@ unit_objects =
|
||||
|
||||
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
||||
unit/test-simutil unit/test-stkutil \
|
||||
unit/test-sms unit/test-cdmasms \
|
||||
unit/test-provision unit/test-sms-filter
|
||||
unit/test-sms unit/test-cdmasms
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
|
||||
@@ -980,11 +983,27 @@ unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_manager
|
||||
|
||||
unit_test_sailfish_watch_SOURCES = unit/test-sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_watch.c \
|
||||
src/log.c src/watch.c
|
||||
unit_test_sailfish_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
unit_test_sailfish_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_watch_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_watch
|
||||
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_config.c src/log.c
|
||||
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_config_OBJECTS)
|
||||
unit_tests += unit/test-ril_config
|
||||
|
||||
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
@@ -1061,6 +1080,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||
src/dbus-queue.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_queue_OBJECTS)
|
||||
unit_tests += unit/test-dbus-queue
|
||||
|
||||
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
plugins/provision.h plugins/mbpi.c \
|
||||
plugins/sailfish_provision.c \
|
||||
@@ -1068,12 +1095,36 @@ unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_provision_OBJECTS)
|
||||
unit_tests += unit/test-provision
|
||||
|
||||
unit_test_ril_transport_SOURCES = unit/test-ril-transport.c \
|
||||
src/ril-transport.c src/log.c
|
||||
unit_test_ril_transport_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_transport_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_transport_OBJECTS)
|
||||
unit_tests += unit/test-ril-transport
|
||||
|
||||
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
|
||||
src/sms-filter.c src/log.c
|
||||
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sms_filter_OBJECTS)
|
||||
unit_tests += unit/test-sms-filter
|
||||
|
||||
unit_test_gprs_filter_SOURCES = unit/test-gprs-filter.c \
|
||||
src/gprs-filter.c src/log.c
|
||||
unit_test_gprs_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_gprs_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_gprs_filter_OBJECTS)
|
||||
unit_tests += unit/test-gprs-filter
|
||||
|
||||
unit_test_voicecall_filter_SOURCES = unit/test-voicecall-filter.c \
|
||||
src/voicecall-filter.c src/log.c \
|
||||
src/common.c src/util.c
|
||||
unit_test_voicecall_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_voicecall_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_voicecall_filter_OBJECTS)
|
||||
unit_tests += unit/test-voicecall-filter
|
||||
|
||||
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
|
||||
gatchat/ringbuffer.h gatchat/ringbuffer.c \
|
||||
|
||||
@@ -184,10 +184,10 @@ AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||
|
||||
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.20, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.20 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.25, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.25 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.30, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.30 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -26,11 +27,11 @@
|
||||
* ril.h does not state that string count must be given, but that is
|
||||
* still expected by the modem
|
||||
*/
|
||||
#define RIL_QUERY_STRING_COUNT 4
|
||||
#define RIL_SET_STRING_COUNT 5
|
||||
#define RIL_SET_PW_STRING_COUNT 3
|
||||
|
||||
struct ril_call_barring {
|
||||
struct ril_sim_card *card;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
@@ -106,7 +107,7 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
GRilIoRequest *req;
|
||||
|
||||
DBG("lock: %s, services to query: %d", lock, cls);
|
||||
|
||||
@@ -123,15 +124,9 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
|
||||
/*
|
||||
* See 3GPP 27.007 7.4 for parameter descriptions.
|
||||
* According to ril.h password should be empty string "" when not
|
||||
* needed, but in reality we only need to give string length as 0
|
||||
*/
|
||||
grilio_request_append_int32(req, RIL_QUERY_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_int32(req, 0); /* Password length */
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
|
||||
req = grilio_request_array_utf8_new(4, lock, "", cls_textual,
|
||||
ril_sim_card_app_aid(bd->card));
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_call_barring_query_cb, cb, data);
|
||||
@@ -182,7 +177,7 @@ static void ril_call_barring_set(struct ofono_call_barring *b,
|
||||
RIL_FACILITY_UNLOCK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
grilio_request_append_utf8(req, ril_sim_card_app_aid(bd->card));
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
@@ -243,6 +238,7 @@ static int ril_call_barring_probe(struct ofono_call_barring *b,
|
||||
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
|
||||
|
||||
DBG("");
|
||||
bd->card = ril_sim_card_ref(modem->sim_card);
|
||||
bd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
bd->timer_id = g_idle_add(ril_call_barring_register, b);
|
||||
ofono_call_barring_set_data(b, bd);
|
||||
@@ -260,6 +256,7 @@ static void ril_call_barring_remove(struct ofono_call_barring *b)
|
||||
g_source_remove(bd->timer_id);
|
||||
}
|
||||
|
||||
ril_sim_card_unref(bd->card);
|
||||
grilio_queue_cancel_all(bd->q, FALSE);
|
||||
grilio_queue_unref(bd->q);
|
||||
g_free(bd);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_idlepool.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||
@@ -75,6 +76,20 @@ static void ril_cell_free1(gpointer cell)
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static const char *ril_cell_info_int_format(int value, const char *format)
|
||||
{
|
||||
if (value == SAILFISH_CELL_INVALID_VALUE) {
|
||||
return "";
|
||||
} else {
|
||||
static GUtilIdlePool *ril_cell_info_pool = NULL;
|
||||
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
|
||||
char *str = g_strdup_printf(format, value);
|
||||
|
||||
gutil_idle_pool_add(pool, str, g_free);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
@@ -106,10 +121,10 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = INT_MAX;
|
||||
gsm->bsic = INT_MAX;
|
||||
gsm->arfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
|
||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||
gsm->timingAdvance = INT_MAX;
|
||||
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
|
||||
/* RIL_CellIdentityGsm */
|
||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||
@@ -123,11 +138,17 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
|
||||
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
|
||||
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,arfcn=%d,"
|
||||
"bsic=%d,strength=%d,err=%d,t=%d", registered,
|
||||
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
|
||||
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
|
||||
gsm->timingAdvance);
|
||||
DBG("[gsm] reg=%d%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
|
||||
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
|
||||
ril_cell_info_int_format(gsm->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
|
||||
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -145,7 +166,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = INT_MAX;
|
||||
wcdma->uarfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
@@ -155,10 +176,16 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
|
||||
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
|
||||
"strength=%d,err=%d", registered, wcdma->mcc,
|
||||
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
|
||||
wcdma->signalStrength, wcdma->bitErrorRate);
|
||||
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
|
||||
ril_cell_info_int_format(wcdma->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(wcdma->bitErrorRate,
|
||||
",err=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -176,7 +203,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = INT_MAX;
|
||||
lte->earfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
@@ -190,11 +217,19 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, <e->rssnr) &&
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(lte->ci, ",ci=%d"),
|
||||
ril_cell_info_int_format(lte->pci, ",pci=%d"),
|
||||
ril_cell_info_int_format(lte->tac, ",tac=%d"),
|
||||
ril_cell_info_int_format(lte->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
|
||||
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
|
||||
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
|
||||
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
|
||||
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -19,6 +19,11 @@
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
@@ -186,14 +191,23 @@ GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
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();
|
||||
char **values, **ptr;
|
||||
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(value, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
values = g_strsplit(value, ",", -1);
|
||||
ptr = values;
|
||||
|
||||
while (*ptr) {
|
||||
int val;
|
||||
|
||||
if (ril_parse_int(*ptr++, 0, &val)) {
|
||||
if (gutil_parse_int(*ptr++, 0, &val)) {
|
||||
gutil_int_array_append(array, val);
|
||||
}
|
||||
}
|
||||
@@ -223,6 +237,337 @@ char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ril_config_merge_files() function does the following:
|
||||
*
|
||||
* 1. Loads the specified key file (say, "/etc/foo.conf")
|
||||
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
|
||||
* for the files with the same suffix as the main file (e.g. "*.conf")
|
||||
* 3. Sorts the files from the subdirectory (alphabetically)
|
||||
* 4. Merges the contents of the additional files with the main file
|
||||
* according to their sort order.
|
||||
*
|
||||
* When the entries are merged, keys and groups overwrite the exising
|
||||
* ones by default. Keys can be suffixed with special characters to
|
||||
* remove or modify the existing entries instead:
|
||||
*
|
||||
* ':' Sets the (default) value if the key is missing
|
||||
* '+' Appends values to the string list
|
||||
* '?' Appends only new (non-existent) values to the string list
|
||||
* '-' Removes the values from the string list
|
||||
*
|
||||
* Both keys and groups can be prefixed with '!' to remove the entire key
|
||||
* or group.
|
||||
*
|
||||
* For example if we merge these two files:
|
||||
*
|
||||
* /etc/foo.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=4
|
||||
* d=5
|
||||
* [bar]
|
||||
* e=5
|
||||
*
|
||||
* /etc/foo.d/bar.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a+=2
|
||||
* b-=2
|
||||
* c=5
|
||||
* !d
|
||||
* [!bar]
|
||||
*
|
||||
* we end up with this:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=5
|
||||
*
|
||||
* Not that the list separator is assumed to be ',' (rather than default ';').
|
||||
* The keyfile passed to ril_config_merge_files() should use the same list
|
||||
* separator, because the default values are copied from the config files
|
||||
* as is.
|
||||
*/
|
||||
|
||||
static gint ril_config_sort_files(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
/* The comparison function for g_ptr_array_sort() doesn't take
|
||||
* the pointers from the array as arguments, it takes pointers
|
||||
* to the pointers in the array. */
|
||||
return strcmp(*(char**)a, *(char**)b);
|
||||
}
|
||||
|
||||
static char **ril_config_collect_files(const char *path, const char *suffix)
|
||||
{
|
||||
/* Returns sorted list of regular files in the directory,
|
||||
* optionally having the specified suffix (e.g. ".conf").
|
||||
* Returns NULL if nothing appropriate has been found. */
|
||||
char **files = NULL;
|
||||
DIR *d = opendir(path);
|
||||
|
||||
if (d) {
|
||||
GPtrArray *list = g_ptr_array_new();
|
||||
const struct dirent *p;
|
||||
|
||||
while ((p = readdir(d)) != NULL) {
|
||||
/* No need to even stat . and .. */
|
||||
if (strcmp(p->d_name, ".") &&
|
||||
strcmp(p->d_name, "..") && (!suffix ||
|
||||
g_str_has_suffix(p->d_name, suffix))) {
|
||||
struct stat st;
|
||||
char *buf = g_strconcat(path, "/", p->d_name,
|
||||
NULL);
|
||||
|
||||
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
|
||||
g_ptr_array_add(list, buf);
|
||||
} else {
|
||||
g_free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list->len > 0) {
|
||||
g_ptr_array_sort(list, ril_config_sort_files);
|
||||
g_ptr_array_add(list, NULL);
|
||||
files = (char**)g_ptr_array_free(list, FALSE);
|
||||
} else {
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static int ril_config_list_find(char **list, gsize len, const char *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!strcmp(list[i], value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_config_list_append(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key,
|
||||
char **values, gsize n, gboolean unique)
|
||||
{
|
||||
/* Note: will steal strings from values */
|
||||
if (n > 0) {
|
||||
int i;
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
|
||||
|
||||
for (i = 0; i < (int)len; i++) {
|
||||
g_ptr_array_add(newlist, list[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)n; i++) {
|
||||
char *val = values[i];
|
||||
|
||||
if (!unique || ril_config_list_find((char**)
|
||||
newlist->pdata, newlist->len, val) < 0) {
|
||||
/* Move the string to the new list */
|
||||
g_ptr_array_add(newlist, val);
|
||||
memmove(values + i, values + i + 1,
|
||||
sizeof(char*) * (n - i));
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
if (newlist->len > len) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) newlist->pdata,
|
||||
newlist->len);
|
||||
}
|
||||
|
||||
/* Strings are deallocated by GPtrArray */
|
||||
g_ptr_array_free(newlist, TRUE);
|
||||
g_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_config_list_remove(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key, char **values, gsize n)
|
||||
{
|
||||
if (n > 0) {
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
|
||||
if (len > 0) {
|
||||
gsize i;
|
||||
const gsize oldlen = len;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int pos;
|
||||
|
||||
/* Remove all matching values */
|
||||
while ((pos = ril_config_list_find(list, len,
|
||||
values[i])) >= 0) {
|
||||
g_free(list[pos]);
|
||||
memmove(list + pos, list + pos + 1,
|
||||
sizeof(char*) * (len - pos));
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (len < oldlen) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) list, len);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_config_merge_group(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **keys = g_key_file_get_keys(k, group, &n, NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
char *key = keys[i];
|
||||
|
||||
if (key[0] == '!') {
|
||||
if (key[1]) {
|
||||
g_key_file_remove_key(conf, group, key+1, NULL);
|
||||
}
|
||||
} else {
|
||||
const gsize len = strlen(key);
|
||||
const char last = (len > 0) ? key[len-1] : 0;
|
||||
|
||||
if (last == '+' || last == '?') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
ril_config_list_append(conf, k, group, key,
|
||||
values, count, last == '?');
|
||||
g_strfreev(values);
|
||||
} else if (last == '-') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
ril_config_list_remove(conf, k, group, key,
|
||||
values, count);
|
||||
g_strfreev(values);
|
||||
} else {
|
||||
/* Overwrite the value (it must exist in k) */
|
||||
gchar *value = g_key_file_get_value(k, group,
|
||||
key, NULL);
|
||||
|
||||
if (last == ':') {
|
||||
/* Default value */
|
||||
key[len-1] = 0;
|
||||
if (!g_key_file_has_key(conf,
|
||||
group, key, NULL)) {
|
||||
g_key_file_set_value(conf,
|
||||
group, key, value);
|
||||
}
|
||||
} else {
|
||||
g_key_file_set_value(conf, group, key,
|
||||
value);
|
||||
}
|
||||
g_free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(keys);
|
||||
}
|
||||
|
||||
static void ril_config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
const char *group = groups[i];
|
||||
|
||||
if (group[0] == '!') {
|
||||
g_key_file_remove_group(conf, group + 1, NULL);
|
||||
} else {
|
||||
ril_config_merge_group(conf, k, group);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(groups);
|
||||
}
|
||||
|
||||
static void ril_config_merge_file(GKeyFile *conf, const char *file)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
|
||||
if (g_key_file_load_from_file(k, file, 0, NULL)) {
|
||||
ril_config_merge_keyfile(conf, k);
|
||||
}
|
||||
|
||||
g_key_file_unref(k);
|
||||
}
|
||||
|
||||
void ril_config_merge_files(GKeyFile *conf, const char *file)
|
||||
{
|
||||
if (conf && file && file[0]) {
|
||||
char *dot = strrchr(file, '.');
|
||||
const char *suffix;
|
||||
char *dir;
|
||||
char **files;
|
||||
|
||||
if (!dot) {
|
||||
dir = g_strconcat(file, ".d", NULL);
|
||||
suffix = NULL;
|
||||
} else if (!dot[1]) {
|
||||
dir = g_strconcat(file, "d", NULL);
|
||||
suffix = NULL;
|
||||
} else {
|
||||
/* 2 bytes for ".d" and 1 for NULL terminator */
|
||||
dir = g_malloc(dot - file + 3);
|
||||
strncpy(dir, file, dot - file);
|
||||
strcpy(dir + (dot - file), ".d");
|
||||
suffix = dot + 1;
|
||||
}
|
||||
|
||||
files = ril_config_collect_files(dir, suffix);
|
||||
g_free(dir);
|
||||
|
||||
/* Load the main config */
|
||||
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
|
||||
DBG("Loading %s", file);
|
||||
ril_config_merge_file(conf, file);
|
||||
}
|
||||
|
||||
if (files) {
|
||||
char **ptr;
|
||||
|
||||
for (ptr = files; *ptr; ptr++) {
|
||||
DBG("Merging %s", *ptr);
|
||||
ril_config_merge_file(conf, *ptr);
|
||||
}
|
||||
|
||||
g_strfreev(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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,6 +22,8 @@
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
void ril_config_merge_files(GKeyFile *conf, const char *file);
|
||||
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
/*
|
||||
* RIL constants adopted from AOSP's header:
|
||||
*
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2017 Jolla Ltd.
|
||||
* Copyright (C) 2013-2018 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
|
||||
@@ -19,81 +15,10 @@
|
||||
#ifndef __RIL_CONSTANTS_H
|
||||
#define __RIL_CONSTANTS_H 1
|
||||
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#define RIL_MAX_UUID_LENGTH 64
|
||||
|
||||
/* Error Codes */
|
||||
enum ril_status {
|
||||
RIL_E_SUCCESS = 0,
|
||||
RIL_E_RADIO_NOT_AVAILABLE = 1,
|
||||
RIL_E_GENERIC_FAILURE = 2,
|
||||
RIL_E_PASSWORD_INCORRECT = 3,
|
||||
RIL_E_SIM_PIN2 = 4,
|
||||
RIL_E_SIM_PUK2 = 5,
|
||||
RIL_E_REQUEST_NOT_SUPPORTED = 6,
|
||||
RIL_E_CANCELLED = 7,
|
||||
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
|
||||
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
|
||||
RIL_E_SMS_SEND_FAIL_RETRY = 10,
|
||||
RIL_E_SIM_ABSENT = 11,
|
||||
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
|
||||
RIL_E_MODE_NOT_SUPPORTED = 13,
|
||||
RIL_E_FDN_CHECK_FAILURE = 14,
|
||||
RIL_E_ILLEGAL_SIM_OR_ME = 15,
|
||||
RIL_E_MISSING_RESOURCE = 16,
|
||||
RIL_E_NO_SUCH_ELEMENT = 17,
|
||||
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
|
||||
RIL_E_DIAL_MODIFIED_TO_SS = 19,
|
||||
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
|
||||
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
|
||||
RIL_E_USSD_MODIFIED_TO_SS = 22,
|
||||
RIL_E_USSD_MODIFIED_TO_USSD = 23,
|
||||
RIL_E_SS_MODIFIED_TO_DIAL = 24,
|
||||
RIL_E_SS_MODIFIED_TO_USSD = 25,
|
||||
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
|
||||
RIL_E_SS_MODIFIED_TO_SS = 27,
|
||||
RIL_E_LCE_NOT_SUPPORTED = 36,
|
||||
RIL_E_NO_MEMORY = 37,
|
||||
RIL_E_INTERNAL_ERR = 38,
|
||||
RIL_E_SYSTEM_ERR = 39,
|
||||
RIL_E_MODEM_ERR = 40,
|
||||
RIL_E_INVALID_STATE = 41,
|
||||
RIL_E_NO_RESOURCES = 42,
|
||||
RIL_E_SIM_ERR = 43,
|
||||
RIL_E_INVALID_ARGUMENTS = 44,
|
||||
RIL_E_INVALID_SIM_STATE = 45,
|
||||
RIL_E_INVALID_MODEM_STATE = 46,
|
||||
RIL_E_INVALID_CALL_ID = 47,
|
||||
RIL_E_NO_SMS_TO_ACK = 48,
|
||||
RIL_E_NETWORK_ERR = 49,
|
||||
RIL_E_REQUEST_RATE_LIMITED = 50,
|
||||
RIL_E_SIM_BUSY = 51,
|
||||
RIL_E_SIM_FULL = 52,
|
||||
RIL_E_NETWORK_REJECT = 53,
|
||||
RIL_E_OPERATION_NOT_ALLOWED = 54,
|
||||
RIL_E_EMPTY_RECORD = 55,
|
||||
RIL_E_INVALID_SMS_FORMAT = 56,
|
||||
RIL_E_ENCODING_ERR = 57,
|
||||
RIL_E_INVALID_SMSC_ADDRESS = 58,
|
||||
RIL_E_NO_SUCH_ENTRY = 59,
|
||||
RIL_E_NETWORK_NOT_READY = 60,
|
||||
RIL_E_NOT_PROVISIONED = 61,
|
||||
RIL_E_NO_SUBSCRIPTION = 62,
|
||||
RIL_E_NO_NETWORK_FOUND = 63,
|
||||
RIL_E_DEVICE_IN_USE = 64,
|
||||
RIL_E_ABORTED = 65,
|
||||
RIL_E_INVALID_RESPONSE = 66
|
||||
};
|
||||
|
||||
/* call states */
|
||||
enum ril_call_state {
|
||||
RIL_CALL_ACTIVE = 0,
|
||||
RIL_CALL_HOLDING = 1,
|
||||
RIL_CALL_DIALING = 2,
|
||||
RIL_CALL_ALERTING = 3,
|
||||
RIL_CALL_INCOMING = 4,
|
||||
RIL_CALL_WAITING = 5
|
||||
};
|
||||
|
||||
/* Radio state */
|
||||
enum ril_radio_state {
|
||||
RADIO_STATE_OFF = 0,
|
||||
@@ -267,30 +192,30 @@ enum ril_call_fail_cause {
|
||||
};
|
||||
|
||||
enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_NONE = 0,
|
||||
PDP_FAIL_OPERATOR_BARRED = 0x08,
|
||||
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
|
||||
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
|
||||
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
|
||||
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
|
||||
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
|
||||
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
|
||||
PDP_FAIL_RADIO_POWER_OFF = -5,
|
||||
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
|
||||
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
|
||||
PDP_FAIL_NONE = 0,
|
||||
PDP_FAIL_OPERATOR_BARRED = 0x08,
|
||||
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
|
||||
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
|
||||
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
|
||||
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
|
||||
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
|
||||
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
|
||||
PDP_FAIL_RADIO_POWER_OFF = -5,
|
||||
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
|
||||
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
|
||||
@@ -395,191 +320,13 @@ enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
/* RIL Request Messages, ofono -> rild */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK 3
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN2 4
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK2 5
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN 6
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
|
||||
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
|
||||
#define RIL_REQUEST_GET_CURRENT_CALLS 9
|
||||
#define RIL_REQUEST_DIAL 10
|
||||
#define RIL_REQUEST_GET_IMSI 11
|
||||
#define RIL_REQUEST_HANGUP 12
|
||||
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
|
||||
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
|
||||
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
|
||||
#define RIL_REQUEST_CONFERENCE 16
|
||||
#define RIL_REQUEST_UDUB 17
|
||||
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
|
||||
#define RIL_REQUEST_SIGNAL_STRENGTH 19
|
||||
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
|
||||
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
|
||||
#define RIL_REQUEST_OPERATOR 22
|
||||
#define RIL_REQUEST_RADIO_POWER 23
|
||||
#define RIL_REQUEST_DTMF 24
|
||||
#define RIL_REQUEST_SEND_SMS 25
|
||||
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
|
||||
#define RIL_REQUEST_SETUP_DATA_CALL 27
|
||||
#define RIL_REQUEST_SIM_IO 28
|
||||
#define RIL_REQUEST_SEND_USSD 29
|
||||
#define RIL_REQUEST_CANCEL_USSD 30
|
||||
#define RIL_REQUEST_GET_CLIR 31
|
||||
#define RIL_REQUEST_SET_CLIR 32
|
||||
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
|
||||
#define RIL_REQUEST_SET_CALL_FORWARD 34
|
||||
#define RIL_REQUEST_QUERY_CALL_WAITING 35
|
||||
#define RIL_REQUEST_SET_CALL_WAITING 36
|
||||
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
|
||||
#define RIL_REQUEST_GET_IMEI 38
|
||||
#define RIL_REQUEST_GET_IMEISV 39
|
||||
#define RIL_REQUEST_ANSWER 40
|
||||
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
|
||||
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
|
||||
#define RIL_REQUEST_SET_FACILITY_LOCK 43
|
||||
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
|
||||
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
|
||||
#define RIL_REQUEST_DTMF_START 49
|
||||
#define RIL_REQUEST_DTMF_STOP 50
|
||||
#define RIL_REQUEST_BASEBAND_VERSION 51
|
||||
#define RIL_REQUEST_SEPARATE_CONNECTION 52
|
||||
#define RIL_REQUEST_SET_MUTE 53
|
||||
#define RIL_REQUEST_GET_MUTE 54
|
||||
#define RIL_REQUEST_QUERY_CLIP 55
|
||||
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
|
||||
#define RIL_REQUEST_DATA_CALL_LIST 57
|
||||
#define RIL_REQUEST_RESET_RADIO 58
|
||||
#define RIL_REQUEST_OEM_HOOK_RAW 59
|
||||
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
|
||||
#define RIL_REQUEST_SCREEN_STATE 61
|
||||
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
|
||||
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
|
||||
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
|
||||
#define RIL_REQUEST_SET_BAND_MODE 65
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
|
||||
#define RIL_REQUEST_STK_GET_PROFILE 67
|
||||
#define RIL_REQUEST_STK_SET_PROFILE 68
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
|
||||
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
|
||||
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
|
||||
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
|
||||
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
|
||||
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
|
||||
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
|
||||
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
|
||||
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
|
||||
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
|
||||
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
|
||||
#define RIL_REQUEST_SET_TTY_MODE 80
|
||||
#define RIL_REQUEST_QUERY_TTY_MODE 81
|
||||
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
|
||||
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
|
||||
#define RIL_REQUEST_CDMA_FLASH 84
|
||||
#define RIL_REQUEST_CDMA_BURST_DTMF 85
|
||||
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
|
||||
#define RIL_REQUEST_CDMA_SEND_SMS 87
|
||||
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
|
||||
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
|
||||
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
|
||||
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
|
||||
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
|
||||
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
|
||||
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
|
||||
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
|
||||
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
|
||||
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
|
||||
#define RIL_REQUEST_DEVICE_IDENTITY 98
|
||||
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
|
||||
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
|
||||
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
|
||||
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
|
||||
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
|
||||
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
|
||||
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
|
||||
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
|
||||
#define RIL_REQUEST_VOICE_RADIO_TECH 108
|
||||
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
|
||||
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
|
||||
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
|
||||
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
|
||||
#define RIL_REQUEST_IMS_SEND_SMS 113
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
|
||||
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
|
||||
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
|
||||
#define RIL_REQUEST_NV_READ_ITEM 118
|
||||
#define RIL_REQUEST_NV_WRITE_ITEM 119
|
||||
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
|
||||
#define RIL_REQUEST_NV_RESET_CONFIG 121
|
||||
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
|
||||
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
|
||||
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
|
||||
#define RIL_REQUEST_ALLOW_DATA 123
|
||||
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
|
||||
#define RIL_REQUEST_SIM_AUTHENTICATION 125
|
||||
#define RIL_REQUEST_GET_DC_RT_INFO 126
|
||||
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
|
||||
#define RIL_REQUEST_SET_DATA_PROFILE 128
|
||||
#define RIL_REQUEST_SHUTDOWN 129
|
||||
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
|
||||
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
|
||||
|
||||
/* RIL Unsolicited Messages, rild -> ofono */
|
||||
#define RIL_UNSOL_RESPONSE_BASE 1000
|
||||
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
|
||||
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
|
||||
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
|
||||
#define RIL_UNSOL_ON_USSD 1006
|
||||
#define RIL_UNSOL_ON_USSD_REQUEST 1007
|
||||
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
|
||||
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
|
||||
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
|
||||
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
|
||||
#define RIL_UNSOL_STK_SESSION_END 1012
|
||||
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
|
||||
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
|
||||
#define RIL_UNSOL_STK_CALL_SETUP 1015
|
||||
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
|
||||
#define RIL_UNSOL_SIM_REFRESH 1017
|
||||
#define RIL_UNSOL_CALL_RING 1018
|
||||
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
|
||||
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
|
||||
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
|
||||
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
|
||||
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
|
||||
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
|
||||
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
|
||||
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
|
||||
#define RIL_UNSOL_CDMA_INFO_REC 1027
|
||||
#define RIL_UNSOL_OEM_HOOK_RAW 1028
|
||||
#define RIL_UNSOL_RINGBACK_TONE 1029
|
||||
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
|
||||
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
|
||||
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
|
||||
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
|
||||
#define RIL_UNSOL_RIL_CONNECTED 1034
|
||||
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
|
||||
#define RIL_UNSOL_CELL_INFO_LIST 1036
|
||||
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
|
||||
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
|
||||
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
|
||||
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
|
||||
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
|
||||
#define RIL_UNSOL_RADIO_CAPABILITY 1042
|
||||
#define RIL_UNSOL_ON_SS 1043
|
||||
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
|
||||
|
||||
/* A special request, ofono -> rild */
|
||||
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
|
||||
enum ril_restricted_state {
|
||||
RIL_RESTRICTED_STATE_NONE = 0x00,
|
||||
RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
|
||||
RIL_RESTRICTED_STATE_CS_NORMAL = 0x02,
|
||||
RIL_RESTRICTED_STATE_CS_ALL = 0x04,
|
||||
RIL_RESTRICTED_STATE_PS_ALL = 0x10
|
||||
};
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 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
|
||||
@@ -76,6 +76,12 @@ enum ril_data_priv_flags {
|
||||
typedef GObjectClass RilDataClass;
|
||||
typedef struct ril_data RilData;
|
||||
|
||||
enum ril_data_io_event_id {
|
||||
IO_EVENT_DATA_CALL_LIST_CHANGED,
|
||||
IO_EVENT_RESTRICTED_STATE_CHANGED,
|
||||
IO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_data_settings_event_id {
|
||||
SETTINGS_EVENT_IMSI_CHANGED,
|
||||
SETTINGS_EVENT_PREF_MODE,
|
||||
@@ -94,9 +100,11 @@ struct ril_data_priv {
|
||||
struct ril_radio *radio;
|
||||
struct ril_network *network;
|
||||
struct ril_data_manager *dm;
|
||||
enum ril_data_priv_flags flags;
|
||||
struct ril_vendor_hook *vendor_hook;
|
||||
|
||||
enum ril_data_priv_flags flags;
|
||||
enum ril_restricted_state restricted_state;
|
||||
|
||||
struct ril_data_request *req_queue;
|
||||
struct ril_data_request *pending_req;
|
||||
|
||||
@@ -104,8 +112,9 @@ struct ril_data_priv {
|
||||
guint slot;
|
||||
char *log_prefix;
|
||||
guint query_id;
|
||||
gulong io_event_id;
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
gulong settings_event_id[SETTINGS_EVENT_COUNT];
|
||||
GHashTable* grab;
|
||||
};
|
||||
|
||||
enum ril_data_signal {
|
||||
@@ -177,7 +186,7 @@ struct ril_data_request_allow_data {
|
||||
|
||||
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);
|
||||
|
||||
static void ril_data_call_deact_cid(struct ril_data *data, int cid);
|
||||
static void ril_data_power_update(struct ril_data *self);
|
||||
static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
|
||||
{
|
||||
@@ -360,7 +369,8 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
|
||||
/* Try the default parser */
|
||||
ril_data_call_destroy(call);
|
||||
memset(call, 0, sizeof(*call));
|
||||
parsed = ril_data_call_parse_default(call, version, ©);
|
||||
*parser = copy;
|
||||
parsed = ril_data_call_parse_default(call, version, parser);
|
||||
}
|
||||
|
||||
if (parsed) {
|
||||
@@ -386,7 +396,7 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
guint len, struct ril_vendor_hook *hook,
|
||||
enum ril_data_call_format format)
|
||||
{
|
||||
guint32 version, n;
|
||||
guint32 version, n, i;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
@@ -403,22 +413,14 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
list->version = format;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
guint i, clen = grilio_parser_bytes_remaining(&rilp)/n;
|
||||
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
|
||||
struct ril_data_call *call = ril_data_call_parse(hook,
|
||||
list->version, &rilp);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
GRilIoParser callp;
|
||||
struct ril_data_call *call;
|
||||
|
||||
grilio_parser_get_data(&rilp, &callp, clen);
|
||||
call = ril_data_call_parse(hook, list->version,
|
||||
&callp);
|
||||
if (call) {
|
||||
list->num++;
|
||||
list->calls = g_slist_insert_sorted
|
||||
(list->calls, call,
|
||||
ril_data_call_compare);
|
||||
}
|
||||
if (call) {
|
||||
list->num++;
|
||||
list->calls = g_slist_insert_sorted(list->calls,
|
||||
call, ril_data_call_compare);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,6 +546,10 @@ struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
static void ril_data_set_calls(struct ril_data *self,
|
||||
struct ril_data_call_list *list)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
GHashTableIter it;
|
||||
gpointer key;
|
||||
|
||||
if (!ril_data_call_list_equal(self->data_calls, list)) {
|
||||
DBG("data calls changed");
|
||||
ril_data_call_list_free(self->data_calls);
|
||||
@@ -552,6 +558,63 @@ static void ril_data_set_calls(struct ril_data *self,
|
||||
} else {
|
||||
ril_data_call_list_free(list);
|
||||
}
|
||||
|
||||
/* Clean up the grab table */
|
||||
g_hash_table_iter_init(&it, priv->grab);
|
||||
while (g_hash_table_iter_next(&it, &key, NULL)) {
|
||||
const int cid = GPOINTER_TO_INT(key);
|
||||
|
||||
if (!ril_data_call_find(self->data_calls, cid)) {
|
||||
g_hash_table_iter_remove(&it);
|
||||
}
|
||||
}
|
||||
|
||||
if (self->data_calls) {
|
||||
GSList *l;
|
||||
|
||||
/* Disconnect stray calls (one at a time) */
|
||||
for (l = self->data_calls->calls; l; l = l->next) {
|
||||
struct ril_data_call *dc = l->data;
|
||||
|
||||
key = GINT_TO_POINTER(dc->cid);
|
||||
if (!g_hash_table_contains(priv->grab, key)) {
|
||||
DBG_(self, "stray call %u", dc->cid);
|
||||
ril_data_call_deact_cid(self, dc->cid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_check_allowed(struct ril_data *self, gboolean was_allowed)
|
||||
{
|
||||
if (ril_data_allowed(self) != was_allowed) {
|
||||
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_restricted_state_changed_cb(GRilIoChannel *io, guint event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_data *self = RIL_DATA(user_data);
|
||||
GRilIoParser rilp;
|
||||
guint32 count, state;
|
||||
|
||||
GASSERT(event == RIL_UNSOL_RESTRICTED_STATE_CHANGED);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &count) && count == 1 &&
|
||||
grilio_parser_get_uint32(&rilp, &state) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (priv->restricted_state != state) {
|
||||
const gboolean was_allowed = ril_data_allowed(self);
|
||||
|
||||
DBG_(self, "restricted state 0x%02x", state);
|
||||
priv->restricted_state = state;
|
||||
ril_data_check_allowed(self, was_allowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
|
||||
@@ -1051,6 +1114,11 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_data_call_deact_cid(struct ril_data *data, int cid)
|
||||
{
|
||||
ril_data_request_queue(ril_data_call_deact_new(data, cid, NULL, NULL));
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ril_data_allow_request
|
||||
*==========================================================================*/
|
||||
@@ -1077,9 +1145,7 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
DBG_(data, "data off");
|
||||
}
|
||||
|
||||
if (ril_data_allowed(data) != was_allowed) {
|
||||
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
ril_data_check_allowed(data, was_allowed);
|
||||
}
|
||||
|
||||
ril_data_request_finish(req);
|
||||
@@ -1195,9 +1261,15 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->network = ril_network_ref(network);
|
||||
priv->vendor_hook = ril_vendor_hook_ref(vendor_hook);
|
||||
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
|
||||
|
||||
priv->io_event_id[IO_EVENT_DATA_CALL_LIST_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_data_call_list_changed_cb,
|
||||
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
|
||||
priv->io_event_id[IO_EVENT_RESTRICTED_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_data_restricted_state_changed_cb,
|
||||
RIL_UNSOL_RESTRICTED_STATE_CHANGED, self);
|
||||
|
||||
priv->settings_event_id[SETTINGS_EVENT_IMSI_CHANGED] =
|
||||
ril_sim_settings_add_imsi_changed_handler(settings,
|
||||
@@ -1271,6 +1343,8 @@ void ril_data_unref(struct ril_data *self)
|
||||
gboolean ril_data_allowed(struct ril_data *self)
|
||||
{
|
||||
return G_LIKELY(self) &&
|
||||
(self->priv->restricted_state &
|
||||
RIL_RESTRICTED_STATE_PS_ALL) == 0 &&
|
||||
(self->priv->flags &
|
||||
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON)) ==
|
||||
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
|
||||
@@ -1285,9 +1359,7 @@ static void ril_data_deactivate_all(struct ril_data *self)
|
||||
struct ril_data_call *call = l->data;
|
||||
if (call->status == PDP_FAIL_NONE) {
|
||||
DBG_(self, "deactivating call %u", call->cid);
|
||||
ril_data_request_queue(
|
||||
ril_data_call_deact_new(self,
|
||||
call->cid, NULL, NULL));
|
||||
ril_data_call_deact_cid(self, call->cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1355,9 +1427,7 @@ static void ril_data_disallow(struct ril_data *self)
|
||||
ril_data_power_update(self);
|
||||
}
|
||||
|
||||
if (ril_data_allowed(self) != was_allowed) {
|
||||
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
ril_data_check_allowed(self, was_allowed);
|
||||
}
|
||||
|
||||
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
|
||||
@@ -1456,12 +1526,39 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *self,
|
||||
return req;
|
||||
}
|
||||
|
||||
gboolean ril_data_call_grab(struct ril_data *self, int cid, void *cookie)
|
||||
{
|
||||
if (self && cookie && ril_data_call_find(self->data_calls, cid)) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(cid);
|
||||
void *prev = g_hash_table_lookup(priv->grab, key);
|
||||
|
||||
if (!prev) {
|
||||
g_hash_table_insert(priv->grab, key, cookie);
|
||||
return TRUE;
|
||||
} else {
|
||||
return (prev == cookie);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ril_data_call_release(struct ril_data *self, int cid, void *cookie)
|
||||
{
|
||||
if (self && cookie) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
g_hash_table_remove(priv->grab, GUINT_TO_POINTER(cid));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_init(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_DATA_TYPE, struct ril_data_priv);
|
||||
|
||||
self->priv = priv;
|
||||
priv->grab = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void ril_data_dispose(GObject *object)
|
||||
@@ -1475,7 +1572,7 @@ static void ril_data_dispose(GObject *object)
|
||||
|
||||
ril_sim_settings_remove_handlers(settings, priv->settings_event_id,
|
||||
G_N_ELEMENTS(priv->settings_event_id));
|
||||
grilio_channel_remove_handlers(priv->io, &priv->io_event_id, 1);
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
priv->query_id = 0;
|
||||
|
||||
@@ -1489,6 +1586,7 @@ static void ril_data_dispose(GObject *object)
|
||||
|
||||
dm->data_list = g_slist_remove(dm->data_list, self);
|
||||
ril_data_manager_check_data(dm);
|
||||
g_hash_table_destroy(priv->grab);
|
||||
G_OBJECT_CLASS(ril_data_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 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
|
||||
@@ -17,8 +17,11 @@
|
||||
#define RIL_DATA_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
enum ril_data_call_active {
|
||||
RIL_DATA_CALL_INACTIVE = 0,
|
||||
RIL_DATA_CALL_LINK_DOWN = 1,
|
||||
@@ -120,6 +123,9 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
|
||||
void ril_data_request_detach(struct ril_data_request *req);
|
||||
void ril_data_request_cancel(struct ril_data_request *req);
|
||||
|
||||
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
|
||||
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
|
||||
|
||||
void ril_data_call_free(struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 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
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_ecclist_priv;
|
||||
|
||||
struct ril_ecclist {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -88,6 +88,7 @@ static int ril_gprs_context_address_family(const char *addr)
|
||||
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = NULL;
|
||||
}
|
||||
@@ -111,6 +112,7 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||
}
|
||||
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
ril_data_call_grab(gcd->data, call->cid, gcd);
|
||||
} else {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
}
|
||||
@@ -378,7 +380,7 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
|
||||
@@ -396,6 +398,8 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("GPRS context: Reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
} else if (!call) {
|
||||
ofono_error("Unexpected data call failure");
|
||||
} else if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_error("Unexpected data call status %d", call->status);
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -285,8 +285,10 @@ 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));
|
||||
if (md->modem.config.enable_cbs) {
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
@@ -452,8 +454,10 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
ofono_modem_set_data(ofono, md);
|
||||
err = ofono_modem_register(ofono);
|
||||
if (!err) {
|
||||
ril_radio_power_cycle(modem->radio);
|
||||
GASSERT(io->connected);
|
||||
if (config->radio_power_cycle) {
|
||||
ril_radio_power_cycle(modem->radio);
|
||||
}
|
||||
|
||||
/*
|
||||
* ofono_modem_reset sets Powered to TRUE without
|
||||
@@ -466,11 +470,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
/*
|
||||
* With some RIL implementations, querying available
|
||||
* band modes causes some magic Android properties to
|
||||
* appear. Otherwise this request is pretty harmless
|
||||
* and useless.
|
||||
* appear.
|
||||
*/
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
if (config->query_available_band_mode) {
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
}
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -61,6 +61,8 @@ struct ril_netreg_cbd {
|
||||
|
||||
#define ril_netreg_cbd_free g_free
|
||||
|
||||
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
|
||||
|
||||
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
|
||||
{
|
||||
return ofono ? ofono_netreg_get_data(ofono) : NULL;
|
||||
@@ -109,7 +111,7 @@ static gboolean ril_netreg_status_notify_cb(gpointer user_data)
|
||||
struct ril_netreg *nd = user_data;
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
DBG_(nd, "");
|
||||
GASSERT(nd->notify_id);
|
||||
nd->notify_id = 0;
|
||||
ofono_netreg_status_notify(nd->netreg,
|
||||
@@ -124,9 +126,9 @@ static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
|
||||
|
||||
/* Coalesce multiple notifications into one */
|
||||
if (nd->notify_id) {
|
||||
DBG("%snotification aready queued", nd->log_prefix);
|
||||
DBG_(nd, "notification aready queued");
|
||||
} else {
|
||||
DBG("%squeuing notification", nd->log_prefix);
|
||||
DBG_(nd, "queuing notification");
|
||||
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
|
||||
}
|
||||
}
|
||||
@@ -138,7 +140,7 @@ static void ril_netreg_registration_status(struct ofono_netreg *netreg,
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
DBG_(nd, "");
|
||||
cb(ril_error_ok(&error),
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech, data);
|
||||
@@ -151,7 +153,7 @@ static gboolean ril_netreg_current_operator_cb(void *user_data)
|
||||
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
DBG_(nd, "");
|
||||
GASSERT(nd->current_operator_id);
|
||||
nd->current_operator_id = 0;
|
||||
|
||||
@@ -322,6 +324,7 @@ static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||
int rsrp = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
@@ -341,23 +344,41 @@ static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, <e_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rsrp */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* cqi */
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
/* The rest is ignored */
|
||||
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
|
||||
evdo_dbm, lte_signal);
|
||||
if (rsrp == INT_MAX) {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal,
|
||||
cdma_dbm, evdo_dbm, lte_signal);
|
||||
} else {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d", gw_signal,
|
||||
cdma_dbm, evdo_dbm, lte_signal, rsrp);
|
||||
}
|
||||
|
||||
/* Return the first valid one */
|
||||
if (gw_signal != 99 && gw_signal != -1) {
|
||||
|
||||
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
|
||||
* RSRP value. If we've got zero, don't report it just yet. */
|
||||
if (gw_signal >= 1 && gw_signal <= 31) {
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
return (gw_signal * 100) / 31;
|
||||
}
|
||||
|
||||
if (lte_signal != 99 && lte_signal != -1) {
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
if (lte_signal >= 0 && lte_signal <= 31) {
|
||||
return (lte_signal * 100) / 31;
|
||||
}
|
||||
|
||||
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
|
||||
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
return 140 - rsrp;
|
||||
}
|
||||
|
||||
/* If we've got zero strength and no valid RSRP, then so be it */
|
||||
if (gw_signal == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In case of dbm, return the value directly */
|
||||
if (cdma_dbm != -1) {
|
||||
return MIN(cdma_dbm, 100);
|
||||
@@ -378,7 +399,7 @@ static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
|
||||
strength = ril_netreg_get_signal_strength(data, len);
|
||||
DBG("%d", strength);
|
||||
DBG_(nd, "%d", strength);
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
}
|
||||
|
||||
@@ -417,9 +438,8 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
GRilIoParser rilp;
|
||||
struct ofono_network_time time;
|
||||
int year, mon, mday, hour, min, sec, dst, tzi;
|
||||
char tzs, tz[4];
|
||||
int year, mon, mday, hour, min, sec, tzi, dst = 0;
|
||||
char tzs;
|
||||
gchar *nitz;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
||||
@@ -427,21 +447,33 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
nitz = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
DBG("%s", nitz);
|
||||
sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday,
|
||||
&hour, &min, &sec, &tzs, &tzi, &dst);
|
||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||
DBG_(nd, "%s", nitz);
|
||||
|
||||
time.utcoff = atoi(tz) * 15 * 60;
|
||||
time.dst = dst;
|
||||
time.sec = sec;
|
||||
time.min = min;
|
||||
time.hour = hour;
|
||||
time.mday = mday;
|
||||
time.mon = mon;
|
||||
time.year = 2000 + year;
|
||||
/*
|
||||
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
|
||||
* The ds part is considered optional, initialized to zero.
|
||||
*/
|
||||
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
|
||||
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
|
||||
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
|
||||
struct ofono_network_time time;
|
||||
char tz[4];
|
||||
|
||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||
time.utcoff = atoi(tz) * 15 * 60;
|
||||
time.dst = dst;
|
||||
time.sec = sec;
|
||||
time.min = min;
|
||||
time.hour = hour;
|
||||
time.mday = mday;
|
||||
time.mon = mon;
|
||||
time.year = 2000 + year;
|
||||
|
||||
ofono_netreg_time_notify(nd->netreg, &time);
|
||||
} else {
|
||||
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
|
||||
}
|
||||
|
||||
ofono_netreg_time_notify(nd->netreg, &time);
|
||||
g_free(nitz);
|
||||
}
|
||||
|
||||
@@ -482,10 +514,11 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
|
||||
guint slot = ril_modem_slot(modem);
|
||||
|
||||
DBG("[%u] %p", slot, netreg);
|
||||
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
|
||||
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
DBG_(nd, "%p", netreg);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
@@ -499,9 +532,8 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
unsigned int i;
|
||||
|
||||
DBG("%p", netreg);
|
||||
DBG_(nd, "%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
ofono_netreg_set_data(netreg, NULL);
|
||||
|
||||
@@ -517,14 +549,10 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
|
||||
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
|
||||
}
|
||||
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
|
||||
ril_network_unref(nd->network);
|
||||
|
||||
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
|
||||
G_N_ELEMENTS(nd->ril_event_id));
|
||||
|
||||
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
|
||||
grilio_channel_unref(nd->io);
|
||||
grilio_queue_unref(nd->q);
|
||||
g_free(nd->log_prefix);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -47,6 +47,12 @@ enum ril_network_radio_event {
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_sim_events {
|
||||
SIM_EVENT_STATUS_CHANGED,
|
||||
SIM_EVENT_IO_ACTIVE_CHANGED,
|
||||
SIM_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_unsol_event {
|
||||
UNSOL_EVENT_NETWORK_STATE,
|
||||
UNSOL_EVENT_RADIO_CAPABILITY,
|
||||
@@ -57,8 +63,10 @@ struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_card *simcard;
|
||||
int rat;
|
||||
int lte_network_mode;
|
||||
int network_mode_timeout;
|
||||
char *log_prefix;
|
||||
guint operator_poll_id;
|
||||
guint voice_poll_id;
|
||||
@@ -68,8 +76,8 @@ struct ril_network_priv {
|
||||
gulong set_rat_id;
|
||||
gulong unsol_event_id[UNSOL_EVENT_COUNT];
|
||||
gulong settings_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
gulong simcard_event_id[SIM_EVENT_COUNT];
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
};
|
||||
@@ -111,7 +119,8 @@ G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self);
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat);
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean immediate);
|
||||
|
||||
static void ril_network_emit(struct ril_network *self,
|
||||
enum ril_network_signal sig)
|
||||
@@ -208,11 +217,11 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(slac, 16, ®->lac)) {
|
||||
if (!gutil_parse_int(slac, 16, ®->lac)) {
|
||||
reg->lac = -1;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(sci, 16, ®->ci)) {
|
||||
if (!gutil_parse_int(sci, 16, ®->ci)) {
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
@@ -400,12 +409,25 @@ static void ril_network_poll_state(struct ril_network *self)
|
||||
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
||||
ril_network_poll_operator_cb);
|
||||
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||
ril_network_poll_voice_state_cb);
|
||||
priv->data_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_network_poll_data_state_cb);
|
||||
|
||||
ril_network_query_registration_state(self);
|
||||
}
|
||||
|
||||
void ril_network_query_registration_state(struct ril_network *self)
|
||||
{
|
||||
if (self) {
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->voice_poll_id,
|
||||
RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||
ril_network_poll_voice_state_cb);
|
||||
priv->data_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->data_poll_id,
|
||||
RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_network_poll_data_state_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
|
||||
@@ -435,7 +457,7 @@ static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
return PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
return self->priv->lte_network_mode;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
@@ -484,37 +506,28 @@ static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
|
||||
/*
|
||||
* With some modems an attempt to set rat significantly slows
|
||||
* down SIM I/O, let's avoid that.
|
||||
*/
|
||||
return priv->radio->online && ril_sim_card_ready(priv->simcard) &&
|
||||
!priv->simcard->sim_io_active &&
|
||||
!priv->timer[TIMER_SET_RAT_HOLDOFF] ;
|
||||
}
|
||||
|
||||
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
|
||||
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
|
||||
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
|
||||
|
||||
/*
|
||||
* Don't retry the request if modem is offline or SIM card isn't
|
||||
* ready, to avoid spamming system log with error messages. Radio
|
||||
* and SIM card state change callbacks will schedule a new check
|
||||
* when it's appropriate.
|
||||
*/
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
DBG_(self, "giving up");
|
||||
}
|
||||
}
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
static void ril_network_set_rat_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
@@ -529,33 +542,53 @@ static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
ril_network_query_pref_mode(self);
|
||||
}
|
||||
|
||||
static void ril_network_set_rat(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (!priv->set_rat_id && priv->radio->online &&
|
||||
ril_sim_card_ready(priv->simcard) &&
|
||||
/*
|
||||
* With some modems an attempt to set rat significantly
|
||||
* slows down SIM I/O, let's avoid that.
|
||||
*/
|
||||
!priv->simcard->sim_io_active &&
|
||||
!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG_(self, "setting rat mode %d", rat);
|
||||
grilio_request_append_int32(req, 1); /* count */
|
||||
grilio_request_append_int32(req, rat);
|
||||
|
||||
grilio_request_set_timeout(req, priv->network_mode_timeout);
|
||||
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_set_rat_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* And don't do it too often */
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
|
||||
ril_network_set_rat_holdoff_cb, self);
|
||||
} else {
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG_(self, "setting rat mode %d", rat);
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, rat);
|
||||
|
||||
grilio_queue_cancel_request(priv->q, priv->set_rat_id, FALSE);
|
||||
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_set_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* Don't do it too often */
|
||||
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
|
||||
ril_network_set_rat_holdoff_cb, self);
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
ril_network_set_rat(self, rat);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean force)
|
||||
gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
@@ -567,10 +600,14 @@ static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
force = TRUE;
|
||||
immediate = TRUE;
|
||||
}
|
||||
|
||||
if (priv->rat == rat || force) {
|
||||
if (priv->rat != rat) {
|
||||
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
@@ -813,8 +850,9 @@ static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
|
||||
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings)
|
||||
struct ril_sim_card *simcard,
|
||||
struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
@@ -823,10 +861,16 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->simcard = ril_sim_card_ref(simcard);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
|
||||
/* Copy relevant config values */
|
||||
priv->lte_network_mode = config->lte_network_mode;
|
||||
priv->network_mode_timeout = config->network_mode_timeout;
|
||||
|
||||
/* Register listeners */
|
||||
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_state_changed_cb,
|
||||
@@ -841,12 +885,15 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
|
||||
ril_radio_add_online_changed_handler(priv->radio,
|
||||
ril_network_radio_online_cb, self);
|
||||
priv->simcard_event_id[SIM_EVENT_STATUS_CHANGED] =
|
||||
ril_sim_card_add_status_changed_handler(priv->simcard,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
priv->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
|
||||
ril_sim_card_add_sim_io_active_changed_handler(priv->simcard,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
priv->settings_event_id =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(settings,
|
||||
ril_network_pref_mode_changed_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
|
||||
/*
|
||||
* Query the initial state. Querying network state before the radio
|
||||
@@ -903,16 +950,13 @@ static void ril_network_finalize(GObject *object)
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
|
||||
G_N_ELEMENTS(priv->unsol_event_id));
|
||||
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->unsol_event_id);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_handler(priv->sim_card,
|
||||
priv->sim_status_event_id);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id);
|
||||
ril_sim_card_unref(priv->simcard);
|
||||
ril_sim_settings_remove_handler(self->settings,
|
||||
priv->settings_event_id);
|
||||
ril_sim_settings_unref(self->settings);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
@@ -46,7 +48,8 @@ typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings);
|
||||
struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *ril_slot_config);
|
||||
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
|
||||
@@ -54,6 +57,7 @@ void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||
enum ofono_radio_access_mode max_pref_mode,
|
||||
gboolean force_check);
|
||||
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
||||
void ril_network_query_registration_state(struct ril_network *net);
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||
@@ -67,6 +71,9 @@ gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
|
||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||
|
||||
#define ril_network_remove_all_handlers(net, ids) \
|
||||
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_NETWORK_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,8 +30,11 @@
|
||||
#include <sailfish_manager.h>
|
||||
#include <sailfish_watch.h>
|
||||
|
||||
#include <grilio_transport.h>
|
||||
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <mce_display.h>
|
||||
#include <mce_log.h>
|
||||
@@ -48,6 +51,7 @@
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/storage.h>
|
||||
#include <ofono/ril-transport.h>
|
||||
|
||||
#define OFONO_RADIO_ACCESS_MODE_ALL (OFONO_RADIO_ACCESS_MODE_GSM |\
|
||||
OFONO_RADIO_ACCESS_MODE_UMTS |\
|
||||
@@ -63,7 +67,10 @@
|
||||
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
|
||||
#define RILMODEM_DEFAULT_SUB "SUB1"
|
||||
#define RILMODEM_DEFAULT_TECHS OFONO_RADIO_ACCESS_MODE_ALL
|
||||
#define RILMODEM_DEFAULT_LTE_MODE PREF_NET_TYPE_LTE_GSM_WCDMA
|
||||
#define RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT (20*1000) /* ms */
|
||||
#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
|
||||
#define RILMODEM_DEFAULT_ENABLE_CBS TRUE
|
||||
#define RILMODEM_DEFAULT_SLOT 0xffffffff
|
||||
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
|
||||
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
|
||||
@@ -74,7 +81,15 @@
|
||||
#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 RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE TRUE /* Qualcomm */
|
||||
#define RILMODEM_DEFAULT_LEGACY_IMEI_QUERY FALSE
|
||||
#define RILMODEM_DEFAULT_RADIO_POWER_CYCLE TRUE
|
||||
#define RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON TRUE
|
||||
|
||||
/* RIL socket transport name and parameters */
|
||||
#define RIL_TRANSPORT_SOCKET "socket"
|
||||
#define RIL_TRANSPORT_SOCKET_PATH "path"
|
||||
#define RIL_TRANSPORT_SOCKET_SUB "sub"
|
||||
|
||||
/*
|
||||
* The convention is that the keys which can only appear in the [Settings]
|
||||
@@ -82,37 +97,43 @@
|
||||
* modem section (OR in the [Settings] if they apply to all modems) start
|
||||
* with lower case.
|
||||
*/
|
||||
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
|
||||
#define RILCONF_SETTINGS_IDENTITY "Identity"
|
||||
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
|
||||
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
|
||||
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
|
||||
#define RILCONF_SETTINGS_IDENTITY "Identity"
|
||||
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
|
||||
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
|
||||
|
||||
#define RILCONF_DEV_PREFIX "ril_"
|
||||
#define RILCONF_PATH_PREFIX "/" RILCONF_DEV_PREFIX
|
||||
#define RILCONF_NAME "name"
|
||||
#define RILCONF_SOCKET "socket"
|
||||
#define RILCONF_SLOT "slot"
|
||||
#define RILCONF_SUB "sub"
|
||||
#define RILCONF_START_TIMEOUT "startTimeout"
|
||||
#define RILCONF_TIMEOUT "timeout"
|
||||
#define RILCONF_4G "enable4G" /* Deprecated */
|
||||
#define RILCONF_ENABLE_VOICECALL "enableVoicecall"
|
||||
#define RILCONF_TECHNOLOGIES "technologies"
|
||||
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
|
||||
#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_VENDOR_DRIVER "vendorDriver"
|
||||
#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 RILCONF_DEFAULT_LEGACY_IMEI_QUERY "legacyImeiQuery"
|
||||
#define RILCONF_MODEM_PREFIX "ril_"
|
||||
#define RILCONF_PATH_PREFIX "/" RILCONF_MODEM_PREFIX
|
||||
#define RILCONF_TRANSPORT "transport"
|
||||
#define RILCONF_NAME "name"
|
||||
#define RILCONF_SOCKET "socket"
|
||||
#define RILCONF_SLOT "slot"
|
||||
#define RILCONF_SUB "sub"
|
||||
#define RILCONF_START_TIMEOUT "startTimeout"
|
||||
#define RILCONF_TIMEOUT "timeout"
|
||||
#define RILCONF_4G "enable4G" /* Deprecated */
|
||||
#define RILCONF_ENABLE_VOICECALL "enableVoicecall"
|
||||
#define RILCONF_ENABLE_CBS "enableCellBroadcast"
|
||||
#define RILCONF_TECHNOLOGIES "technologies"
|
||||
#define RILCONF_LTE_MODE "lteNetworkMode"
|
||||
#define RILCONF_NETWORK_MODE_TIMEOUT "networkModeTimeout"
|
||||
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
|
||||
#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_VENDOR_DRIVER "vendorDriver"
|
||||
#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 RILCONF_LEGACY_IMEI_QUERY "legacyImeiQuery"
|
||||
#define RILCONF_RADIO_POWER_CYCLE "radioPowerCycle"
|
||||
#define RILCONF_CONFIRM_RADIO_POWER_ON "confirmRadioPowerOn"
|
||||
|
||||
/* Modem error ids */
|
||||
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
|
||||
#define RIL_ERROR_ID_CAPS_SWITCH_ABORTED "ril-caps-switch-aborted"
|
||||
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
|
||||
#define RIL_ERROR_ID_CAPS_SWITCH_ABORTED "ril-caps-switch-aborted"
|
||||
|
||||
enum ril_plugin_io_events {
|
||||
IO_EVENT_CONNECTED,
|
||||
@@ -171,8 +192,8 @@ typedef struct sailfish_slot_impl {
|
||||
char *imei;
|
||||
char *imeisv;
|
||||
char *name;
|
||||
char *sockpath;
|
||||
char *sub;
|
||||
char *transport_name;
|
||||
GHashTable *transport_params;
|
||||
char *ecclist_file;
|
||||
int timeout; /* RIL timeout, in milliseconds */
|
||||
int index;
|
||||
@@ -957,18 +978,16 @@ static void ril_plugin_slot_connected(ril_slot *slot)
|
||||
*/
|
||||
ril_plugin_start_imei_query(slot, TRUE, -1);
|
||||
|
||||
GASSERT(!slot->vendor_hook);
|
||||
slot->vendor_hook = ril_vendor_create_hook(slot->vendor, slot->io,
|
||||
slot->path, &slot->config);
|
||||
|
||||
GASSERT(!slot->radio);
|
||||
slot->radio = ril_radio_new(slot->io);
|
||||
|
||||
GASSERT(!slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED]);
|
||||
slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(slot->io,
|
||||
if (slot->config.confirm_radio_power_on) {
|
||||
slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(slot->io,
|
||||
ril_plugin_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, slot);
|
||||
}
|
||||
|
||||
GASSERT(!slot->sim_card);
|
||||
slot->sim_card = ril_sim_card_new(slot->io, slot->config.slot,
|
||||
@@ -982,7 +1001,12 @@ static void ril_plugin_slot_connected(ril_slot *slot)
|
||||
|
||||
GASSERT(!slot->network);
|
||||
slot->network = ril_network_new(slot->path, slot->io, log_prefix,
|
||||
slot->radio, slot->sim_card, slot->sim_settings);
|
||||
slot->radio, slot->sim_card, slot->sim_settings,
|
||||
&slot->config);
|
||||
|
||||
GASSERT(!slot->vendor_hook);
|
||||
slot->vendor_hook = ril_vendor_create_hook(slot->vendor, slot->io,
|
||||
slot->path, &slot->config, slot->network);
|
||||
|
||||
GASSERT(!slot->data);
|
||||
slot->data = ril_data_new(plugin->data_manager, log_prefix,
|
||||
@@ -1040,8 +1064,8 @@ static void ril_plugin_slot_connected_cb(GRilIoChannel *io, void *user_data)
|
||||
static void ril_plugin_init_io(ril_slot *slot)
|
||||
{
|
||||
if (!slot->io) {
|
||||
DBG("%s %s", slot->sockpath, slot->sub);
|
||||
slot->io = grilio_channel_new_socket(slot->sockpath, slot->sub);
|
||||
slot->io = grilio_channel_new(ofono_ril_transport_connect
|
||||
(slot->transport_name, slot->transport_params));
|
||||
if (slot->io) {
|
||||
ril_debug_trace_update(slot);
|
||||
ril_debug_dump_update(slot);
|
||||
@@ -1097,7 +1121,7 @@ static void ril_plugin_retry_init_io(ril_slot *slot)
|
||||
g_source_remove(slot->retry_id);
|
||||
}
|
||||
|
||||
DBG("%s %s", slot->sockpath, slot->sub);
|
||||
DBG("%s", slot->path);
|
||||
slot->retry_id = g_timeout_add_seconds(RIL_RETRY_SECS,
|
||||
ril_plugin_retry_init_io_cb, slot);
|
||||
}
|
||||
@@ -1125,7 +1149,7 @@ static void ril_slot_free(ril_slot *slot)
|
||||
{
|
||||
ril_plugin* plugin = slot->plugin;
|
||||
|
||||
DBG("%s", slot->sockpath);
|
||||
DBG("%s", slot->path);
|
||||
ril_plugin_shutdown_slot(slot, TRUE);
|
||||
plugin->slots = g_slist_remove(plugin->slots, slot);
|
||||
mce_display_remove_all_handlers(slot->display, slot->display_event_id);
|
||||
@@ -1139,8 +1163,8 @@ static void ril_slot_free(ril_slot *slot)
|
||||
g_free(slot->imei);
|
||||
g_free(slot->imeisv);
|
||||
g_free(slot->name);
|
||||
g_free(slot->sockpath);
|
||||
g_free(slot->sub);
|
||||
g_free(slot->transport_name);
|
||||
g_hash_table_destroy(slot->transport_params);
|
||||
g_free(slot->ecclist_file);
|
||||
g_free(slot);
|
||||
}
|
||||
@@ -1150,7 +1174,7 @@ static gboolean ril_plugin_slot_start_timeout(gpointer user_data)
|
||||
ril_slot *slot = user_data;
|
||||
ril_plugin* plugin = slot->plugin;
|
||||
|
||||
DBG("%s", slot->sockpath);
|
||||
DBG("%s", slot->path);
|
||||
plugin->slots = g_slist_remove(plugin->slots, slot);
|
||||
slot->start_timeout_id = 0;
|
||||
ril_slot_free(slot);
|
||||
@@ -1158,18 +1182,28 @@ static gboolean ril_plugin_slot_start_timeout(gpointer user_data)
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
|
||||
char *name, guint slot_index)
|
||||
static ril_slot *ril_plugin_slot_new_take(char *transport,
|
||||
GHashTable *transport_params, char *dbus_path,
|
||||
char *name, guint slot_index)
|
||||
{
|
||||
ril_slot *slot = g_new0(ril_slot, 1);
|
||||
struct ril_slot_config *config = &slot->config;
|
||||
|
||||
slot->sockpath = sockpath;
|
||||
slot->path = path;
|
||||
slot->transport_name = transport;
|
||||
slot->transport_params = transport_params;
|
||||
slot->path = dbus_path;
|
||||
slot->name = name;
|
||||
slot->config.slot = slot_index;
|
||||
slot->config.techs = RILMODEM_DEFAULT_TECHS;
|
||||
slot->config.empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
|
||||
slot->config.enable_voicecall = RILMODEM_DEFAULT_ENABLE_VOICECALL;
|
||||
config->slot = slot_index;
|
||||
config->techs = RILMODEM_DEFAULT_TECHS;
|
||||
config->lte_network_mode = RILMODEM_DEFAULT_LTE_MODE;
|
||||
config->empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
|
||||
config->radio_power_cycle = RILMODEM_DEFAULT_RADIO_POWER_CYCLE;
|
||||
config->confirm_radio_power_on =
|
||||
RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON;
|
||||
config->enable_voicecall = RILMODEM_DEFAULT_ENABLE_VOICECALL;
|
||||
config->enable_cbs = RILMODEM_DEFAULT_ENABLE_CBS;
|
||||
config->query_available_band_mode =
|
||||
RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE;
|
||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||
slot->legacy_imei_query = RILMODEM_DEFAULT_LEGACY_IMEI_QUERY;
|
||||
@@ -1190,7 +1224,7 @@ static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
|
||||
mce_display_add_state_changed_handler(slot->display,
|
||||
ril_plugin_display_cb, slot);
|
||||
|
||||
slot->watch = sailfish_watch_new(path);
|
||||
slot->watch = sailfish_watch_new(dbus_path);
|
||||
slot->watch_event_id[WATCH_EVENT_MODEM] =
|
||||
sailfish_watch_add_modem_changed_handler(slot->watch,
|
||||
ril_plugin_slot_modem_changed, slot);
|
||||
@@ -1205,20 +1239,38 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
|
||||
|
||||
/* Let the vendor extension to adjust (some) defaults */
|
||||
memset(&defaults, 0, sizeof(defaults));
|
||||
defaults.empty_pin_query = config->empty_pin_query;
|
||||
defaults.legacy_imei_query = slot->legacy_imei_query;
|
||||
defaults.enable_cbs = config->enable_cbs;
|
||||
defaults.empty_pin_query = config->empty_pin_query;
|
||||
defaults.query_available_band_mode =
|
||||
config->query_available_band_mode;
|
||||
|
||||
ril_vendor_get_defaults(slot->vendor, &defaults);
|
||||
config->empty_pin_query = defaults.empty_pin_query;
|
||||
slot->legacy_imei_query = defaults.legacy_imei_query;
|
||||
config->enable_cbs = defaults.enable_cbs;
|
||||
config->empty_pin_query = defaults.empty_pin_query;
|
||||
config->query_available_band_mode =
|
||||
defaults.query_available_band_mode;
|
||||
}
|
||||
}
|
||||
|
||||
static ril_slot *ril_plugin_slot_new(const char *sockpath, const char *path,
|
||||
static ril_slot *ril_plugin_slot_new_socket(const char *sockpath,
|
||||
const char *sub, const char *dbus_path,
|
||||
const char *name, guint slot_index)
|
||||
{
|
||||
return ril_plugin_slot_new_take(g_strdup(sockpath), g_strdup(path),
|
||||
g_strdup(name), slot_index);
|
||||
/* RIL socket configuration */
|
||||
GHashTable *params = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
|
||||
g_hash_table_insert(params, g_strdup(RIL_TRANSPORT_SOCKET_PATH),
|
||||
g_strdup(sockpath));
|
||||
if (sub) {
|
||||
g_hash_table_insert(params, g_strdup(RIL_TRANSPORT_SOCKET_SUB),
|
||||
g_strdup(sub));
|
||||
}
|
||||
|
||||
return ril_plugin_slot_new_take(g_strdup(RIL_TRANSPORT_SOCKET), params,
|
||||
g_strdup(dbus_path), g_strdup(name), slot_index);
|
||||
}
|
||||
|
||||
static GSList *ril_plugin_create_default_config()
|
||||
@@ -1227,24 +1279,75 @@ static GSList *ril_plugin_create_default_config()
|
||||
|
||||
if (g_file_test(RILMODEM_DEFAULT_SOCK2, G_FILE_TEST_EXISTS)) {
|
||||
DBG("Falling back to default dual SIM config");
|
||||
list = g_slist_append(list,
|
||||
ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK,
|
||||
list = g_slist_append(list, ril_plugin_slot_new_socket
|
||||
(RILMODEM_DEFAULT_SOCK, NULL,
|
||||
RILCONF_PATH_PREFIX "0", "RIL1", 0));
|
||||
list = g_slist_append(list,
|
||||
ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK2,
|
||||
list = g_slist_append(list, ril_plugin_slot_new_socket
|
||||
(RILMODEM_DEFAULT_SOCK2, NULL,
|
||||
RILCONF_PATH_PREFIX "1", "RIL2", 1));
|
||||
} else {
|
||||
ril_slot *slot = ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK,
|
||||
RILCONF_PATH_PREFIX "0", "RIL", 0);
|
||||
|
||||
DBG("Falling back to default single SIM config");
|
||||
slot->sub = g_strdup(RILMODEM_DEFAULT_SUB);
|
||||
list = g_slist_append(list, slot);
|
||||
list = g_slist_append(list, ril_plugin_slot_new_socket
|
||||
(RILMODEM_DEFAULT_SOCK, RILMODEM_DEFAULT_SUB,
|
||||
RILCONF_PATH_PREFIX "0", "RIL", 0));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the spec according to the following grammar:
|
||||
*
|
||||
* spec: transport | transport ':' parameters
|
||||
* params: param | params ';' param
|
||||
* param: name '=' value
|
||||
* transport: STRING
|
||||
* name: STRING
|
||||
* value: STRING
|
||||
*
|
||||
* For example, a RIL socket spec may look like this:
|
||||
*
|
||||
* socket:path=/dev/socket/rild;sub=SUB1
|
||||
*/
|
||||
static char *ril_plugin_parse_transport_spec(const char *spec,
|
||||
GHashTable *params)
|
||||
{
|
||||
char *transport = NULL;
|
||||
char *sep = strchr(spec, ':');
|
||||
|
||||
if (sep) {
|
||||
transport = g_strstrip(g_strndup(spec, sep - spec));
|
||||
if (transport[0]) {
|
||||
char **list = g_strsplit(sep + 1, ";", 0);
|
||||
char **ptr;
|
||||
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
const char *p = *ptr;
|
||||
|
||||
sep = strchr(p, '=');
|
||||
if (sep) {
|
||||
char *name = g_strndup(p, sep - p);
|
||||
char* value = g_strdup(sep + 1);
|
||||
|
||||
g_hash_table_insert(params,
|
||||
g_strstrip(name),
|
||||
g_strstrip(value));
|
||||
}
|
||||
}
|
||||
g_strfreev(list);
|
||||
return transport;
|
||||
}
|
||||
} else {
|
||||
/* Use default transport attributes */
|
||||
transport = g_strstrip(g_strdup(spec));
|
||||
if (transport[0]) {
|
||||
return transport;
|
||||
}
|
||||
}
|
||||
g_free(transport);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
const char *group)
|
||||
{
|
||||
@@ -1253,29 +1356,57 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
int ival;
|
||||
char *sval;
|
||||
char **strv;
|
||||
char *sock = g_key_file_get_string(file, group, RILCONF_SOCKET, NULL);
|
||||
GHashTable *transport_params = g_hash_table_new_full(g_str_hash,
|
||||
g_str_equal, g_free, g_free);
|
||||
char *transport = NULL;
|
||||
char *transport_spec = g_key_file_get_string(file, group,
|
||||
RILCONF_TRANSPORT, NULL);
|
||||
|
||||
if (!sock) {
|
||||
ofono_warn("no socket path for %s", group);
|
||||
if (transport_spec) {
|
||||
transport = ril_plugin_parse_transport_spec(transport_spec,
|
||||
transport_params);
|
||||
if (transport) {
|
||||
DBG("%s: %s:%s", group, transport,
|
||||
strchr(transport_spec, ':') + 1);
|
||||
}
|
||||
g_free(transport_spec);
|
||||
} else {
|
||||
/* Fall back to socket transport */
|
||||
char *sockpath = g_key_file_get_string(file, group,
|
||||
RILCONF_SOCKET, NULL);
|
||||
|
||||
if (sockpath) {
|
||||
char *sub = g_key_file_get_string(file, group,
|
||||
RILCONF_SUB, NULL);
|
||||
|
||||
transport = g_strdup(RIL_TRANSPORT_SOCKET);
|
||||
g_hash_table_insert(transport_params,
|
||||
g_strdup(RIL_TRANSPORT_SOCKET_PATH),
|
||||
sockpath);
|
||||
if (sub && strlen(sub) == RIL_SUB_SIZE) {
|
||||
DBG("%s: %s:%s", group, sockpath, sub);
|
||||
g_hash_table_insert(transport_params,
|
||||
g_strdup(RIL_TRANSPORT_SOCKET_SUB),
|
||||
sub);
|
||||
} else {
|
||||
DBG("%s: %s", group, sockpath);
|
||||
g_free(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!transport) {
|
||||
ofono_warn("No usable RIL transport defined for %s", group);
|
||||
g_hash_table_destroy(transport_params);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
slot = ril_plugin_slot_new_take(sock,
|
||||
slot = ril_plugin_slot_new_take(transport, transport_params,
|
||||
g_strconcat("/", group, NULL),
|
||||
ril_config_get_string(file, group, RILCONF_NAME),
|
||||
RILMODEM_DEFAULT_SLOT);
|
||||
config = &slot->config;
|
||||
|
||||
/* sub */
|
||||
sval = ril_config_get_string(file, group, RILCONF_SUB);
|
||||
if (sval && strlen(sval) == RIL_SUB_SIZE) {
|
||||
DBG("%s: %s:%s", group, sock, sval);
|
||||
slot->sub = sval;
|
||||
} else {
|
||||
DBG("%s: %s", group, sock);
|
||||
g_free(sval);
|
||||
}
|
||||
|
||||
/* slot */
|
||||
if (ril_config_get_integer(file, group, RILCONF_SLOT, &ival) &&
|
||||
ival >= 0) {
|
||||
@@ -1322,6 +1453,13 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
config->enable_voicecall ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* enableCellBroadcast */
|
||||
if (ril_config_get_boolean(file, group, RILCONF_ENABLE_CBS,
|
||||
&config->enable_cbs)) {
|
||||
DBG("%s: " RILCONF_ENABLE_CBS " %s", group,
|
||||
config->enable_cbs ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* technologies */
|
||||
strv = ril_config_get_strings(file, group, RILCONF_TECHNOLOGIES, ',');
|
||||
if (strv) {
|
||||
@@ -1357,6 +1495,20 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
}
|
||||
g_strfreev(strv);
|
||||
}
|
||||
|
||||
/* lteNetworkMode */
|
||||
if (ril_config_get_integer(file, group, RILCONF_LTE_MODE,
|
||||
&config->lte_network_mode)) {
|
||||
DBG("%s: " RILCONF_LTE_MODE " %d", group,
|
||||
config->lte_network_mode);
|
||||
}
|
||||
|
||||
/* networkModeTimeout */
|
||||
if (ril_config_get_integer(file, group, RILCONF_NETWORK_MODE_TIMEOUT,
|
||||
&config->network_mode_timeout)) {
|
||||
DBG("%s: " RILCONF_NETWORK_MODE_TIMEOUT " %d", group,
|
||||
config->network_mode_timeout);
|
||||
}
|
||||
|
||||
/* enable4G (deprecated but still supported) */
|
||||
ival = config->techs;
|
||||
@@ -1374,6 +1526,20 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
config->empty_pin_query ? "on" : "off");
|
||||
}
|
||||
|
||||
/* radioPowerCycle */
|
||||
if (ril_config_get_boolean(file, group, RILCONF_RADIO_POWER_CYCLE,
|
||||
&config->radio_power_cycle)) {
|
||||
DBG("%s: " RILCONF_RADIO_POWER_CYCLE " %s", group,
|
||||
config->radio_power_cycle ? "on" : "off");
|
||||
}
|
||||
|
||||
/* confirmRadioPowerOn */
|
||||
if (ril_config_get_boolean(file, group, RILCONF_CONFIRM_RADIO_POWER_ON,
|
||||
&config->confirm_radio_power_on)) {
|
||||
DBG("%s: " RILCONF_CONFIRM_RADIO_POWER_ON " %s", group,
|
||||
config->confirm_radio_power_on ? "on" : "off");
|
||||
}
|
||||
|
||||
/* uiccWorkaround */
|
||||
if (ril_config_get_flag(file, group, RILCONF_UICC_WORKAROUND,
|
||||
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND,
|
||||
@@ -1454,10 +1620,9 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
}
|
||||
|
||||
/* legacyImeiQuery */
|
||||
if (ril_config_get_boolean(file, group,
|
||||
RILCONF_DEFAULT_LEGACY_IMEI_QUERY,
|
||||
if (ril_config_get_boolean(file, group, RILCONF_LEGACY_IMEI_QUERY,
|
||||
&slot->legacy_imei_query)) {
|
||||
DBG("%s: " RILCONF_DEFAULT_LEGACY_IMEI_QUERY " %s", group,
|
||||
DBG("%s: " RILCONF_LEGACY_IMEI_QUERY " %s", group,
|
||||
slot->legacy_imei_query ? "on" : "off");
|
||||
}
|
||||
|
||||
@@ -1535,7 +1700,7 @@ static void ril_plugin_parse_identity(struct ril_plugin_identity *identity,
|
||||
int n;
|
||||
|
||||
/* Try numeric */
|
||||
if (ril_parse_int(group, 0, &n)) {
|
||||
if (gutil_parse_int(group, 0, &n)) {
|
||||
gr = getgrgid(n);
|
||||
}
|
||||
}
|
||||
@@ -1547,7 +1712,7 @@ static void ril_plugin_parse_identity(struct ril_plugin_identity *identity,
|
||||
int n;
|
||||
|
||||
/* Try numeric */
|
||||
if (ril_parse_int(user, 0, &n)) {
|
||||
if (gutil_parse_int(user, 0, &n)) {
|
||||
pw = getpwuid(n);
|
||||
}
|
||||
}
|
||||
@@ -1578,7 +1743,7 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
const char *group = groups[i];
|
||||
if (g_str_has_prefix(group, RILCONF_DEV_PREFIX)) {
|
||||
if (g_str_has_prefix(group, RILCONF_MODEM_PREFIX)) {
|
||||
/* Modem configuration */
|
||||
ril_slot *slot = ril_plugin_parse_config_group(file,
|
||||
group);
|
||||
@@ -1632,22 +1797,16 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
||||
static GSList *ril_plugin_load_config(const char *path,
|
||||
struct ril_plugin_settings *ps)
|
||||
{
|
||||
GError *err = NULL;
|
||||
GSList *l, *list = NULL;
|
||||
GKeyFile *file = g_key_file_new();
|
||||
gboolean empty = FALSE;
|
||||
|
||||
if (g_key_file_load_from_file(file, path, 0, &err)) {
|
||||
DBG("Loading %s", path);
|
||||
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
|
||||
ril_config_merge_files(file, path);
|
||||
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
|
||||
RILCONF_SETTINGS_EMPTY, &empty) && empty) {
|
||||
DBG("Empty config");
|
||||
} else {
|
||||
list = ril_plugin_parse_config_file(file, ps);
|
||||
}
|
||||
DBG("Empty config");
|
||||
} else {
|
||||
DBG("conf load error: %s", err->message);
|
||||
g_error_free(err);
|
||||
list = ril_plugin_parse_config_file(file, ps);
|
||||
}
|
||||
|
||||
if (!list && !empty) {
|
||||
@@ -1908,10 +2067,31 @@ static void ril_slot_enabled_changed(struct sailfish_slot_impl *s)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RIL socket transport factory
|
||||
*/
|
||||
static struct grilio_transport *ril_socket_transport_connect(GHashTable *args)
|
||||
{
|
||||
const char* path = g_hash_table_lookup(args, RIL_TRANSPORT_SOCKET_PATH);
|
||||
const char* sub = g_hash_table_lookup(args, RIL_TRANSPORT_SOCKET_SUB);
|
||||
|
||||
GASSERT(path);
|
||||
if (path) {
|
||||
DBG("%s %s", path, sub);
|
||||
return grilio_transport_socket_new_path(path, sub);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Global part (that requires access to global variables) */
|
||||
|
||||
static struct sailfish_slot_driver_reg *ril_driver = NULL;
|
||||
static guint ril_driver_init_id = 0;
|
||||
static const struct ofono_ril_transport ril_socket_transport = {
|
||||
.name = RIL_TRANSPORT_SOCKET,
|
||||
.api_version = OFONO_RIL_TRANSPORT_API_VERSION,
|
||||
.connect = ril_socket_transport_connect
|
||||
};
|
||||
|
||||
static void ril_debug_trace_notify(struct ofono_debug_desc *desc)
|
||||
{
|
||||
@@ -1957,6 +2137,9 @@ static gboolean ril_plugin_start(gpointer user_data)
|
||||
DBG("");
|
||||
ril_driver_init_id = 0;
|
||||
|
||||
/* Socket transport can be registered right away */
|
||||
ofono_ril_transport_register(&ril_socket_transport);
|
||||
|
||||
/* Register the driver */
|
||||
ril_driver = sailfish_slot_driver_register(&ril_slot_driver);
|
||||
return G_SOURCE_REMOVE;
|
||||
@@ -1992,6 +2175,7 @@ static void ril_plugin_exit(void)
|
||||
DBG("");
|
||||
GASSERT(ril_driver);
|
||||
|
||||
ofono_ril_transport_unregister(&ril_socket_transport);
|
||||
ofono_modem_driver_unregister(&ril_modem_driver);
|
||||
ofono_sim_driver_unregister(&ril_sim_driver);
|
||||
ofono_sms_driver_unregister(&ril_sms_driver);
|
||||
|
||||
@@ -71,14 +71,16 @@ G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
|
||||
#define RIL_RADIO_TYPE (ril_radio_get_type())
|
||||
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
|
||||
|
||||
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
return self->online && !priv->power_cycle &&
|
||||
g_hash_table_size(priv->req_table) > 0;
|
||||
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
|
||||
!priv->power_cycle;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
@@ -102,7 +104,7 @@ static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self,
|
||||
@@ -116,7 +118,7 @@ static void ril_radio_cancel_retry(struct ril_radio *self)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->retry_id) {
|
||||
DBG("%sretry cancelled", priv->log_prefix);
|
||||
DBG_(self, "retry cancelled");
|
||||
g_source_remove(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
}
|
||||
@@ -129,8 +131,8 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
if (!priv->pending_id) {
|
||||
gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
if (ril_radio_state_on(self->priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
if (ril_radio_state_on(priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
/* All is good, cancel pending retry if there is one */
|
||||
ril_radio_cancel_retry(self);
|
||||
} else if (priv->state_changed_while_request_pending) {
|
||||
@@ -138,7 +140,7 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
ril_radio_submit_power_request(self, should_be_on);
|
||||
} else if (!priv->retry_id) {
|
||||
/* There has been no reaction so far, wait a bit */
|
||||
DBG("%sretry scheduled", priv->log_prefix);
|
||||
DBG_(self, "retry scheduled");
|
||||
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
|
||||
ril_radio_power_request_retry_cb, self);
|
||||
}
|
||||
@@ -147,33 +149,38 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
/* Don't update public state while something is pending */
|
||||
if (!priv->pending_id && !priv->retry_id &&
|
||||
self->state != priv->last_known_state) {
|
||||
DBG("%s%s -> %s", priv->log_prefix,
|
||||
ril_radio_state_to_string(self->state),
|
||||
DBG_(self, "%s -> %s", ril_radio_state_to_string(self->state),
|
||||
ril_radio_state_to_string(priv->last_known_state));
|
||||
self->state = priv->last_known_state;
|
||||
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_done(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
priv->pending_id = 0;
|
||||
|
||||
if (priv->next_state_valid) {
|
||||
ril_radio_submit_power_request(self, priv->next_state);
|
||||
} else {
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
priv->pending_id = 0;
|
||||
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("Power request failed: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
if (priv->next_state_valid) {
|
||||
ril_radio_submit_power_request(self, priv->next_state);
|
||||
} else {
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
ril_radio_power_request_done(self);
|
||||
}
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
@@ -214,13 +221,18 @@ static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = on;
|
||||
DBG("%s%s (queued)", priv->log_prefix, on_off);
|
||||
DBG_(self, "%s (queued)", on_off);
|
||||
} else {
|
||||
DBG("%s%s (ignored)", priv->log_prefix, on_off);
|
||||
DBG_(self, "%s (ignored)", on_off);
|
||||
}
|
||||
} else {
|
||||
DBG("%s%s", priv->log_prefix, on_off);
|
||||
ril_radio_submit_power_request(self, on);
|
||||
if (ril_radio_state_on(priv->last_known_state) == on) {
|
||||
DBG_(self, "%s (already)", on_off);
|
||||
ril_radio_check_state(self);
|
||||
} else {
|
||||
DBG_(self, "%s", on_off);
|
||||
ril_radio_submit_power_request(self, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,12 +249,12 @@ void ril_radio_power_cycle(struct ril_radio *self)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (ril_radio_state_off(priv->last_known_state)) {
|
||||
DBG("%spower is already off", priv->log_prefix);
|
||||
DBG_(self, "power is already off");
|
||||
GASSERT(!priv->power_cycle);
|
||||
} else if (priv->power_cycle) {
|
||||
DBG("%salready in progress", priv->log_prefix);
|
||||
DBG_(self, "already in progress");
|
||||
} else {
|
||||
DBG("%sinitiated", priv->log_prefix);
|
||||
DBG_(self, "initiated");
|
||||
priv->power_cycle = TRUE;
|
||||
if (!priv->pending_id) {
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
@@ -259,7 +271,7 @@ void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||
if (!g_hash_table_contains(priv->req_table, tag)) {
|
||||
gboolean was_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
DBG_(self, "%p", tag);
|
||||
g_hash_table_insert(priv->req_table, tag, tag);
|
||||
if (!was_on && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, FALSE);
|
||||
@@ -274,7 +286,7 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (g_hash_table_remove(priv->req_table, tag)) {
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
DBG_(self, "%p", tag);
|
||||
if (!ril_radio_power_should_be_on(self)) {
|
||||
/* The last one turns the lights off */
|
||||
ril_radio_power_request(self, FALSE, FALSE);
|
||||
@@ -346,20 +358,41 @@ static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
if (radio_state != RADIO_STATE_UNAVAILABLE) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s%s", priv->log_prefix,
|
||||
ril_radio_state_to_string(radio_state));
|
||||
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
|
||||
GASSERT(!priv->pending_id || !priv->retry_id);
|
||||
|
||||
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
|
||||
DBG("%sswitched off for power cycle", priv->log_prefix);
|
||||
DBG_(self, "switched off for power cycle");
|
||||
priv->power_cycle = FALSE;
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
|
||||
if (priv->pending_id) {
|
||||
priv->state_changed_while_request_pending++;
|
||||
if (ril_radio_state_on(radio_state) ==
|
||||
ril_radio_power_should_be_on(self)) {
|
||||
DBG_(self, "dropping pending request");
|
||||
/*
|
||||
* All right, the modem has switched to the
|
||||
* desired state, drop the request.
|
||||
*/
|
||||
grilio_queue_cancel_request(priv->q,
|
||||
priv->pending_id, FALSE);
|
||||
|
||||
/*
|
||||
* This will zero pending_id and call
|
||||
* ril_radio_check_state() if necesary:
|
||||
*/
|
||||
ril_radio_power_request_done(self);
|
||||
|
||||
/* We are done */
|
||||
return;
|
||||
} else {
|
||||
/* Something weird is going on */
|
||||
priv->state_changed_while_request_pending++;
|
||||
}
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
@@ -374,7 +407,7 @@ struct ril_radio *ril_radio_new(GRilIoChannel *io)
|
||||
priv->log_prefix =
|
||||
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
|
||||
g_strconcat(io->name, " ", NULL) : g_strdup("");
|
||||
DBG("%s", priv->log_prefix);
|
||||
DBG_(self, "");
|
||||
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
|
||||
@@ -431,7 +464,7 @@ static void ril_radio_finalize(GObject *object)
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_radio {
|
||||
GObject object;
|
||||
struct ril_radio_priv *priv;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
* Copyright (C) 2017-2018 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
|
||||
@@ -71,6 +71,7 @@ struct ril_radio_caps {
|
||||
gulong max_pref_mode_event_id;
|
||||
gulong radio_event_id;
|
||||
int tx_id;
|
||||
int tx_pending;
|
||||
struct ril_data *data;
|
||||
struct ril_radio *radio;
|
||||
struct ril_network *network;
|
||||
@@ -85,7 +86,6 @@ typedef struct ril_radio_caps_manager {
|
||||
GObject object;
|
||||
GPtrArray *caps_list;
|
||||
guint check_id;
|
||||
int tx_pending;
|
||||
int tx_id;
|
||||
int tx_phase_index;
|
||||
gboolean tx_failed;
|
||||
@@ -453,7 +453,7 @@ struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
struct ril_radio_caps *self =
|
||||
g_slice_new0(struct ril_radio_caps);
|
||||
|
||||
self->ref_count = 1;
|
||||
g_atomic_int_set(&self->ref_count, 1);
|
||||
self->slot = config->slot;
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
@@ -471,13 +471,16 @@ struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
self->simcard_event_id[SIM_EVENT_STATE_CHANGED] =
|
||||
ril_sim_card_add_state_changed_handler(sim,
|
||||
ril_radio_caps_simcard_event, self);
|
||||
self->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
|
||||
ril_sim_card_add_sim_io_active_changed_handler(sim,
|
||||
ril_radio_caps_simcard_event, self);
|
||||
|
||||
self->network = ril_network_ref(net);
|
||||
self->settings_event_id[SETTINGS_EVENT_PREF_MODE] =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(
|
||||
settings, ril_radio_caps_settings_event, self);
|
||||
self->settings_event_id[SETTINGS_EVENT_IMSI] =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(
|
||||
ril_sim_settings_add_imsi_changed_handler(
|
||||
settings, ril_radio_caps_settings_event, self);
|
||||
|
||||
self->max_pref_mode_event_id =
|
||||
@@ -560,6 +563,24 @@ static void ril_radio_caps_manager_foreach_tx
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_radio_caps_manager_tx_pending
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
guint i;
|
||||
const GPtrArray *list = self->caps_list;
|
||||
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const struct ril_radio_caps *caps = list->pdata[i];
|
||||
|
||||
/* Ignore the modems not associated with this transaction */
|
||||
if (caps->tx_id == self->tx_id && caps->tx_pending > 0) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all radio caps have been initialized (i.e. all the initial
|
||||
* GET_RADIO_CAPABILITY requests have completed) and there's no transaction
|
||||
@@ -568,7 +589,7 @@ static void ril_radio_caps_manager_foreach_tx
|
||||
static gboolean ril_radio_caps_manager_can_check
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
if (self->caps_list && !self->tx_pending) {
|
||||
if (self->caps_list && !ril_radio_caps_manager_tx_pending(self)) {
|
||||
const GPtrArray *list = self->caps_list;
|
||||
const struct ril_radio_caps *prev_caps = NULL;
|
||||
gboolean all_modes_equal = TRUE;
|
||||
@@ -753,6 +774,10 @@ static void ril_radio_caps_manager_issue_requests
|
||||
phase->send_new_cap ? &caps->new_cap :
|
||||
&caps->old_cap;
|
||||
|
||||
/* Count it */
|
||||
caps->tx_pending++;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
|
||||
/* Encode and send the request */
|
||||
grilio_request_append_int32(req,
|
||||
RIL_RADIO_CAPABILITY_VERSION);
|
||||
@@ -766,9 +791,6 @@ static void ril_radio_caps_manager_issue_requests
|
||||
RIL_REQUEST_SET_RADIO_CAPABILITY,
|
||||
handler, NULL, caps);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Count it */
|
||||
self->tx_pending++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -791,7 +813,6 @@ static void ril_radio_caps_manager_next_transaction
|
||||
{
|
||||
ril_radio_caps_manager_foreach(self,
|
||||
ril_radio_caps_manager_next_transaction_cb);
|
||||
self->tx_pending = 0;
|
||||
self->tx_failed = FALSE;
|
||||
self->tx_phase_index = -1;
|
||||
self->tx_id++;
|
||||
@@ -829,8 +850,10 @@ static void ril_radio_caps_manager_abort_cb(GRilIoChannel *io,
|
||||
struct ril_radio_caps *caps = user_data;
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
|
||||
GASSERT(self->tx_pending > 0);
|
||||
if (!(--self->tx_pending)) {
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
DBG("transaction aborted");
|
||||
ril_radio_caps_manager_transaction_done(self);
|
||||
}
|
||||
@@ -875,7 +898,7 @@ static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
gboolean ok = FALSE;
|
||||
|
||||
GASSERT(self->tx_pending > 0);
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
struct ril_radio_capability cap;
|
||||
if (ril_radio_caps_parse(caps->log_prefix, data, len, &cap) &&
|
||||
@@ -892,7 +915,9 @@ static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(--self->tx_pending)) {
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->tx_failed) {
|
||||
ril_radio_caps_manager_abort_transaction(self);
|
||||
} else {
|
||||
@@ -907,7 +932,7 @@ static void ril_radio_caps_manager_next_phase
|
||||
/* Note: -1 > 2 if 2 is unsigned (which turns -1 into 4294967295) */
|
||||
const int max_index = G_N_ELEMENTS(ril_radio_caps_tx_phase) - 1;
|
||||
|
||||
GASSERT(!self->tx_pending);
|
||||
GASSERT(!ril_radio_caps_manager_tx_pending(self));
|
||||
if (self->tx_phase_index >= max_index) {
|
||||
DBG("transaction %d is done", self->tx_id);
|
||||
ril_radio_caps_manager_transaction_done(self);
|
||||
@@ -924,14 +949,16 @@ static void ril_radio_caps_manager_next_phase
|
||||
static void ril_radio_caps_manager_data_off_done(GRilIoChannel *io,
|
||||
int status, const void *req_data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio_caps_manager *self = RADIO_CAPS_MANAGER(user_data);
|
||||
struct ril_radio_caps *caps = user_data;
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
|
||||
DBG("%d", self->tx_pending);
|
||||
GASSERT(self->tx_pending > 0);
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
if (status != GRILIO_STATUS_OK) {
|
||||
self->tx_failed = TRUE;
|
||||
}
|
||||
if (!(--self->tx_pending)) {
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->tx_failed) {
|
||||
DBG("failed to start the transaction");
|
||||
ril_data_manager_assert_data_on(self->data_manager);
|
||||
@@ -951,13 +978,13 @@ static void ril_radio_caps_manager_data_off
|
||||
{
|
||||
GRilIoRequest *req = ril_request_allow_data_new(FALSE);
|
||||
|
||||
self->tx_pending++;
|
||||
DBG_(caps, "disallowing data");
|
||||
caps->tx_pending++;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
grilio_request_set_timeout(req, DATA_OFF_TIMEOUT_MS);
|
||||
grilio_queue_send_request_full(caps->q, req,
|
||||
RIL_REQUEST_ALLOW_DATA,
|
||||
ril_radio_caps_manager_data_off_done,
|
||||
NULL, self);
|
||||
NULL, caps);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -967,14 +994,16 @@ static void ril_radio_caps_manager_deactivate_data_call_done(GRilIoChannel *io,
|
||||
struct ril_radio_caps *caps = user_data;
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
|
||||
GASSERT(self->tx_pending > 0);
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
if (status != GRILIO_STATUS_OK) {
|
||||
self->tx_failed = TRUE;
|
||||
/* Something seems to be slightly broken, try requesting the
|
||||
* current state (later, after we release the transaction). */
|
||||
ril_data_poll_call_state(caps->data);
|
||||
}
|
||||
if (!(--self->tx_pending)) {
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->tx_failed) {
|
||||
DBG("failed to start the transaction");
|
||||
ril_radio_caps_manager_recheck_later(self);
|
||||
@@ -992,8 +1021,8 @@ static void ril_radio_caps_deactivate_data_call(struct ril_radio_caps *caps,
|
||||
{
|
||||
GRilIoRequest *req = ril_request_deactivate_data_call_new(cid);
|
||||
|
||||
caps->mgr->tx_pending++;
|
||||
DBG_(caps, "deactivating call %u", cid);
|
||||
caps->tx_pending++;
|
||||
DBG_(caps, "cid=%u, tx_pending=%d", cid, caps->tx_pending);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_request_set_timeout(req, DEACTIVATE_TIMEOUT_MS);
|
||||
grilio_queue_send_request_full(caps->q, req,
|
||||
@@ -1028,11 +1057,11 @@ static void ril_radio_caps_manager_deactivate_all
|
||||
{
|
||||
ril_radio_caps_manager_foreach_tx(self,
|
||||
ril_radio_caps_manager_deactivate_all_cb);
|
||||
if (!self->tx_pending) {
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
/* No data calls, submit ALLOW_DATA requests right away */
|
||||
ril_radio_caps_manager_foreach_tx(self,
|
||||
ril_radio_caps_manager_data_off);
|
||||
GASSERT(self->tx_pending);
|
||||
GASSERT(ril_radio_caps_manager_tx_pending(self));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,6 +1284,24 @@ static GSList *ril_radio_caps_manager_empty_slots
|
||||
return found;
|
||||
}
|
||||
|
||||
static guint ril_radio_caps_manager_sim_count
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
const GPtrArray *list = self->caps_list;
|
||||
guint i, count = 0;
|
||||
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const struct ril_radio_caps *caps = list->pdata[i];
|
||||
|
||||
if (caps->simcard->status->card_state ==
|
||||
RIL_CARDSTATE_PRESENT) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* There could be no capability mismatch but LTE could be enabled for
|
||||
* the slot that has no SIM card in it. That's a waste, fix it.
|
||||
@@ -1298,7 +1345,7 @@ static void ril_radio_caps_manager_check(struct ril_radio_caps_manager *self)
|
||||
if (ril_radio_caps_manager_can_check(self)) {
|
||||
const int first = ril_radio_caps_manager_first_mismatch(self);
|
||||
|
||||
if (first >= 0) {
|
||||
if (first >= 0 && ril_radio_caps_manager_sim_count(self) > 1) {
|
||||
if (ril_radio_caps_manager_update_caps(self, first)) {
|
||||
ril_radio_caps_manager_start_transaction(self);
|
||||
}
|
||||
@@ -1321,7 +1368,7 @@ static gboolean ril_radio_caps_manager_check_cb(gpointer data)
|
||||
static void ril_radio_caps_manager_recheck_later
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
if (!self->tx_pending) {
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->check_id) {
|
||||
g_source_remove(self->check_id);
|
||||
self->check_id = 0;
|
||||
@@ -1334,7 +1381,7 @@ static void ril_radio_caps_manager_recheck_later
|
||||
static void ril_radio_caps_manager_schedule_check
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
if (!self->check_id && !self->tx_pending) {
|
||||
if (!self->check_id && !ril_radio_caps_manager_tx_pending(self)) {
|
||||
self->check_id = g_idle_add(ril_radio_caps_manager_check_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,11 @@ enum ril_sim_card_event {
|
||||
SIM_CARD_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_sim_io_event {
|
||||
IO_EVENT_SIM_REFRESH,
|
||||
IO_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
@@ -81,6 +86,7 @@ struct ril_sim {
|
||||
gboolean inserted;
|
||||
guint idle_id; /* Used by register and SIM reset callbacks */
|
||||
gulong card_event_id[SIM_CARD_EVENT_COUNT];
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
guint query_pin_retries_id;
|
||||
|
||||
const char *log_prefix;
|
||||
@@ -102,8 +108,9 @@ struct ril_sim_io_response {
|
||||
guint data_len;
|
||||
};
|
||||
|
||||
struct ril_sim_cbd {
|
||||
struct ril_sim_cbd_io {
|
||||
struct ril_sim *sd;
|
||||
struct ril_sim_card *card;
|
||||
union _ofono_sim_cb {
|
||||
ofono_sim_file_info_cb_t file_info;
|
||||
ofono_sim_read_cb_t read;
|
||||
@@ -173,24 +180,43 @@ static const struct ril_sim_retry_query ril_sim_retry_query_types[] = {
|
||||
|
||||
#define DBG_(sd,fmt,args...) DBG("%s" fmt, (sd)->log_prefix, ##args)
|
||||
|
||||
#define ril_sim_cbd_free g_free
|
||||
|
||||
static inline struct ril_sim *ril_sim_get_data(struct ofono_sim *sim)
|
||||
{
|
||||
return ofono_sim_get_data(sim);
|
||||
}
|
||||
|
||||
static struct ril_sim_cbd *ril_sim_cbd_new(struct ril_sim *sd, void *cb,
|
||||
static struct ril_sim_cbd_io *ril_sim_cbd_io_new(struct ril_sim *sd, void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = g_new0(struct ril_sim_cbd, 1);
|
||||
struct ril_sim_cbd_io *cbd = g_new0(struct ril_sim_cbd_io, 1);
|
||||
|
||||
cbd->sd = sd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
cbd->card = ril_sim_card_ref(sd->card);
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_sim_cbd_io_free(void *data)
|
||||
{
|
||||
|
||||
struct ril_sim_cbd_io *cbd = data;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->card, cbd->req_id);
|
||||
ril_sim_card_unref(cbd->card);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_sim_cbd_io_start(struct ril_sim_cbd_io *cbd, GRilIoRequest* req,
|
||||
guint code, GRilIoChannelResponseFunc cb)
|
||||
{
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req, code,
|
||||
cb, ril_sim_cbd_io_free, cbd);
|
||||
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
|
||||
}
|
||||
|
||||
static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
@@ -249,11 +275,6 @@ static void ril_sim_pin_req_done(gpointer ptr)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_sim_app_id(struct ril_sim *sd)
|
||||
{
|
||||
return sd->card->app ? sd->card->app->aid : NULL;
|
||||
}
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
@@ -423,14 +444,13 @@ static void ril_sim_io_response_free(struct ril_sim_io_response *res)
|
||||
static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_file_info_cb_t cb = cbd->cb.file_info;
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
struct ril_sim_io_response *res = NULL;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(sd, "");
|
||||
ril_sim_card_sim_io_finished(sd->card, cbd->req_id);
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
@@ -474,12 +494,13 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
|
||||
static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
|
||||
guint p1, guint p2, guint p3, const char *hex_data,
|
||||
const guchar *path, guint path_len,
|
||||
GRilIoChannelResponseFunc cb, struct ril_sim_cbd *cbd)
|
||||
GRilIoChannelResponseFunc cb, struct ril_sim_cbd_io *cbd)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG_(sd, "cmd=0x%.2X,efid=0x%.4X,%d,%d,%d,%s,pin2=(null),aid=%s",
|
||||
cmd, fileid, p1, p2, p3, hex_data, ril_sim_app_id(sd));
|
||||
cmd, fileid, p1, p2, p3, hex_data,
|
||||
ril_sim_card_app_aid(sd->card));
|
||||
|
||||
grilio_request_append_int32(req, cmd);
|
||||
grilio_request_append_int32(req, fileid);
|
||||
@@ -489,13 +510,11 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
|
||||
grilio_request_append_int32(req, p3); /* P3 */
|
||||
grilio_request_append_utf8(req, hex_data); /* data; only for writes */
|
||||
grilio_request_append_utf8(req, NULL); /* pin2; only for writes */
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
grilio_request_append_utf8(req, ril_sim_card_app_aid(sd->card));
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_IO, cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -505,19 +524,19 @@ static void ril_sim_ofono_read_file_info(struct ofono_sim *sim, int fileid,
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
ril_sim_request_io(sd, CMD_GET_RESPONSE, fileid, 0, 0, 15, NULL,
|
||||
path, len, ril_sim_file_info_cb, ril_sim_cbd_new(sd, cb, data));
|
||||
path, len, ril_sim_file_info_cb,
|
||||
ril_sim_cbd_io_new(sd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_sim_read_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_read_cb_t cb = cbd->cb.read;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error err;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
@@ -536,7 +555,7 @@ static void ril_sim_read(struct ofono_sim *sim, guint cmd, int fileid,
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
ril_sim_request_io(sd, cmd, fileid, p1, p2, p3, NULL, path, path_len,
|
||||
ril_sim_read_cb, ril_sim_cbd_new(sd, cb, data));
|
||||
ril_sim_read_cb, ril_sim_cbd_io_new(sd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_sim_ofono_read_file_transparent(struct ofono_sim *sim,
|
||||
@@ -566,13 +585,12 @@ static void ril_sim_ofono_read_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
static void ril_sim_write_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_write_cb_t cb = cbd->cb.write;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error err;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
@@ -593,7 +611,7 @@ static void ril_sim_write(struct ofono_sim *sim, guint cmd, int fileid,
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
char *hex_data = encode_hex(value, length, 0);
|
||||
ril_sim_request_io(sd, cmd, fileid, p1, p2, length, hex_data, path,
|
||||
path_len, ril_sim_write_cb, ril_sim_cbd_new(sd, cb, data));
|
||||
path_len, ril_sim_write_cb, ril_sim_cbd_io_new(sd, cb, data));
|
||||
g_free(hex_data);
|
||||
}
|
||||
|
||||
@@ -630,12 +648,10 @@ static void ril_sim_write_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
static void ril_sim_get_imsi_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_imsi_cb_t cb = cbd->cb.imsi;
|
||||
struct ofono_error error;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
gchar *imsi;
|
||||
GRilIoParser rilp;
|
||||
@@ -660,8 +676,8 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(1, app_id);
|
||||
|
||||
DBG_(sd, "%s", app_id);
|
||||
@@ -673,10 +689,8 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_GET_IMSI, ril_sim_get_imsi_cb,
|
||||
ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_GET_IMSI,
|
||||
ril_sim_get_imsi_cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -858,31 +872,15 @@ static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_reinsert_cb(gpointer data)
|
||||
{
|
||||
struct ril_sim *sd = data;
|
||||
const enum ofono_sim_state state = ofono_sim_get_state(sd->watch->sim);
|
||||
|
||||
GASSERT(sd->idle_id);
|
||||
sd->idle_id = 0;
|
||||
|
||||
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
|
||||
DBG_(sd, "reinserting SIM");
|
||||
ofono_sim_inserted_notify(sd->sim, TRUE);
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_sim_state_changed_cb(struct sailfish_watch *watch, void *data)
|
||||
{
|
||||
struct ril_sim *sd = data;
|
||||
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
|
||||
|
||||
DBG_(sd, "%d %d", state, sd->inserted);
|
||||
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted &&
|
||||
!sd->idle_id) {
|
||||
sd->idle_id = g_idle_add(ril_sim_reinsert_cb, sd);
|
||||
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
|
||||
/* That will simulate SIM card removal: */
|
||||
ril_sim_card_reset(sd->card);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -900,25 +898,22 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
|
||||
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
|
||||
const char *pin)
|
||||
{
|
||||
if (sd->card->app) {
|
||||
/*
|
||||
* If there's no AID then so be it... Some
|
||||
* adaptations (namely, MTK) don't provide it
|
||||
* but don't seem to require it either.
|
||||
*/
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(2,
|
||||
pin, sd->card->app->aid);
|
||||
/*
|
||||
* If there's no AID then so be it... Some
|
||||
* adaptations (namely, MTK) don't provide it
|
||||
* but don't seem to require it either.
|
||||
*/
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(2, pin,
|
||||
ril_sim_card_app_aid(sd->card));
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
return req;
|
||||
}
|
||||
return NULL;
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
return req;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_sim_enter_sim_puk_req(struct ril_sim *sd,
|
||||
const char *puk, const char *pin)
|
||||
{
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
if (app_id) {
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(3,
|
||||
puk, pin, app_id);
|
||||
@@ -1220,7 +1215,7 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
GRilIoRequest *req = ril_sim_enter_sim_pin_req(sd, passwd);
|
||||
|
||||
if (req) {
|
||||
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
|
||||
DBG_(sd, "%s,aid=%s", passwd, ril_sim_card_app_aid(sd->card));
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PIN, ril_sim_pin_change_state_cb,
|
||||
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
|
||||
@@ -1247,10 +1242,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
|
||||
case OFONO_SIM_PASSWORD_PHNET_PIN:
|
||||
if (!enable) {
|
||||
code = RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION;
|
||||
req = grilio_request_sized_new(12);
|
||||
grilio_request_append_int32(req,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
req = grilio_request_array_utf8_new(1, passwd);
|
||||
} else {
|
||||
DBG_(sd, "Not supported, enable=%d", enable);
|
||||
}
|
||||
@@ -1263,7 +1255,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
|
||||
if (req) {
|
||||
id = grilio_queue_send_request_full(sd->q, req, code,
|
||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -1299,7 +1291,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
|
||||
const char *passwd, ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
const char *type_str = ril_sim_facility_code(passwd_type);
|
||||
struct ofono_error error;
|
||||
guint id = 0;
|
||||
@@ -1319,7 +1311,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
|
||||
id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -1337,7 +1329,7 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
|
||||
|
||||
if (req) {
|
||||
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd,
|
||||
ril_sim_app_id(sd));
|
||||
ril_sim_card_app_aid(sd->card));
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PUK, ril_sim_pin_change_state_cb,
|
||||
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
|
||||
@@ -1357,7 +1349,7 @@ static void ril_sim_change_passwd(struct ofono_sim *sim,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(3,
|
||||
old_passwd, new_passwd, app_id);
|
||||
|
||||
@@ -1375,11 +1367,9 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_query_facility_lock_cb_t cb = cbd->cb.query_facility_lock;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int locked = 0;
|
||||
GRilIoParser rilp;
|
||||
@@ -1409,9 +1399,9 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *type_str = ril_sim_facility_code(type);
|
||||
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(4,
|
||||
type_str, "", "0" /* class */, ril_sim_app_id(sd));
|
||||
type_str, "", "0" /* class */, ril_sim_card_app_aid(sd->card));
|
||||
|
||||
/* Make sure that this request gets completed sooner or later */
|
||||
grilio_request_set_timeout(req, FAC_LOCK_QUERY_TIMEOUT_SECS * 1000);
|
||||
@@ -1419,13 +1409,24 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
grilio_request_set_retry_func(req, ril_sim_query_facility_lock_retry);
|
||||
|
||||
DBG_(sd, "%s", type_str);
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
|
||||
ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_sim_query_facility_lock_cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim *sd = user_data;
|
||||
|
||||
/*
|
||||
* RIL_UNSOL_SIM_REFRESH may contain the EFID of the updated file,
|
||||
* so we could be more descrete here. However I have't actually
|
||||
* seen that in real life, let's just refresh everything for now.
|
||||
*/
|
||||
__ofono_sim_refresh(sd->sim, NULL, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_register(gpointer user)
|
||||
{
|
||||
struct ril_sim *sd = user;
|
||||
@@ -1447,6 +1448,11 @@ static gboolean ril_sim_register(gpointer user)
|
||||
sailfish_watch_add_sim_state_changed_handler(sd->watch,
|
||||
ril_sim_state_changed_cb, sd);
|
||||
|
||||
/* And RIL events */
|
||||
sd->io_event_id[IO_EVENT_SIM_REFRESH] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_sim_refresh_cb, RIL_UNSOL_SIM_REFRESH, sd);
|
||||
|
||||
/* Check the current state */
|
||||
ril_sim_status_changed_cb(sd->card, sd);
|
||||
return FALSE;
|
||||
@@ -1485,6 +1491,7 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
|
||||
DBG_(sd, "");
|
||||
g_list_free_full(sd->pin_cbd_list, ril_sim_pin_cbd_list_free_cb);
|
||||
grilio_channel_remove_all_handlers(sd->io, sd->io_event_id);
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -24,6 +24,17 @@
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
/*
|
||||
* First we wait for USIM app to get activated by itself. If that
|
||||
* doesn't happen within UICC_SUBSCRIPTION_START_MS we poke the SIM
|
||||
* with SET_UICC_SUBSCRIPTION request, resubmitting it if it times out.
|
||||
* If nothing happens within UICC_SUBSCRIPTION_TIMEOUT_MS we give up.
|
||||
*
|
||||
* Submitting SET_UICC_SUBSCRIPTION request when rild doesn't expect
|
||||
* it sometimes breaks pretty much everything. Unfortunately, there no
|
||||
* reliable way to find out when rild expects it and when it doesn't :/
|
||||
*/
|
||||
#define UICC_SUBSCRIPTION_START_MS (5000)
|
||||
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
|
||||
|
||||
/* SIM I/O idle timeout is measured in the number of idle loops.
|
||||
@@ -48,6 +59,7 @@ struct ril_sim_card_priv {
|
||||
int flags;
|
||||
guint status_req_id;
|
||||
guint sub_req_id;
|
||||
guint sub_start_timer;
|
||||
gulong event_id[EVENT_COUNT];
|
||||
guint sim_io_idle_id;
|
||||
guint sim_io_idle_count;
|
||||
@@ -157,10 +169,55 @@ static void ril_sim_card_status_free(struct ril_sim_card_status *status)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_tx_start(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRILIO_TRANSACTION_STATE tx_state =
|
||||
grilio_queue_transaction_state(priv->q);
|
||||
|
||||
if (tx_state == GRILIO_TRANSACTION_NONE) {
|
||||
tx_state = grilio_queue_transaction_start(priv->q);
|
||||
DBG("status tx for slot %u %s", self->slot,
|
||||
(tx_state == GRILIO_TRANSACTION_STARTED) ?
|
||||
"started" : "starting");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_tx_check(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (grilio_queue_transaction_state(priv->q) !=
|
||||
GRILIO_TRANSACTION_NONE) {
|
||||
const struct ril_sim_card_status *status = self->status;
|
||||
|
||||
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
/* Transaction (if there is any) is finished when
|
||||
* both GET_SIM_STATUS and SET_UICC_SUBSCRIPTION
|
||||
* complete or get dropped */
|
||||
if (!priv->status_req_id && !priv->sub_req_id &&
|
||||
status->gsm_umts_index >= 0 &&
|
||||
status->gsm_umts_index < status->num_apps) {
|
||||
DBG("status tx for slot %u finished",
|
||||
self->slot);
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
} else {
|
||||
DBG("status tx for slot %u cancelled", self->slot);
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->sub_start_timer) {
|
||||
/* Don't need this timer anymore */
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
priv->sub_start_timer = 0;
|
||||
}
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
@@ -168,7 +225,7 @@ static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
}
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
ril_sim_card_tx_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||
@@ -184,19 +241,18 @@ static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
||||
enum ril_uicc_subscription_action sub_action)
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||
const guint sub_id = self->slot;
|
||||
guint code;
|
||||
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
|
||||
DBG("%u,%d,%u", self->slot, app_index, sub_id);
|
||||
grilio_request_append_int32(req, self->slot);
|
||||
grilio_request_append_int32(req, app_index);
|
||||
grilio_request_append_int32(req, sub_id);
|
||||
grilio_request_append_int32(req, sub_action);
|
||||
grilio_request_append_int32(req, RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||
|
||||
grilio_request_set_retry(req, 0, -1);
|
||||
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
|
||||
@@ -213,7 +269,7 @@ static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
||||
|
||||
/* Don't allow any requests other that GET_SIM_STATUS until
|
||||
* we are done with the subscription */
|
||||
grilio_queue_transaction_start(priv->q);
|
||||
ril_sim_card_tx_start(self);
|
||||
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
|
||||
req, code, ril_sim_card_subscribe_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -250,9 +306,8 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
ril_sim_card_subscription_done(self);
|
||||
} else {
|
||||
app_index = ril_sim_card_select_app(status);
|
||||
if (app_index >= 0) {
|
||||
ril_sim_card_subscribe(self, app_index,
|
||||
RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||
if (app_index >= 0 && !self->priv->sub_start_timer) {
|
||||
ril_sim_card_subscribe(self, app_index);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -273,6 +328,18 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_card_sub_start_timeout(gpointer user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
DBG("%u", self->slot);
|
||||
GASSERT(priv->sub_start_timer);
|
||||
priv->sub_start_timer = 0;
|
||||
ril_sim_card_update_app(self);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
struct ril_sim_card_status *status)
|
||||
{
|
||||
@@ -282,6 +349,23 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
struct ril_sim_card_status *old_status = self->status;
|
||||
|
||||
self->status = status;
|
||||
if (diff & RIL_SIMCARD_STATE_CHANGED &&
|
||||
status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* SIM card has just appeared, give it some time to
|
||||
* activate the USIM app
|
||||
*/
|
||||
if (priv->sub_start_timer) {
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
}
|
||||
DBG("started subscription timeout for slot %u",
|
||||
self->slot);
|
||||
priv->sub_start_timer =
|
||||
g_timeout_add(UICC_SUBSCRIPTION_START_MS,
|
||||
ril_sim_card_sub_start_timeout, self);
|
||||
}
|
||||
ril_sim_card_update_app(self);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
@@ -297,6 +381,7 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
}
|
||||
ril_sim_card_status_free(old_status);
|
||||
} else {
|
||||
ril_sim_card_update_app(self);
|
||||
ril_sim_card_status_free(status);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
@@ -430,6 +515,24 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
ril_sim_card_update_status(self, status);
|
||||
}
|
||||
}
|
||||
|
||||
ril_sim_card_tx_check(self);
|
||||
}
|
||||
|
||||
void ril_sim_card_reset(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_card_status *status =
|
||||
g_new0(struct ril_sim_card_status, 1);
|
||||
|
||||
/* Simulate removal and re-submit the SIM status query */
|
||||
status->card_state = RIL_CARDSTATE_ABSENT;
|
||||
status->gsm_umts_index = -1;
|
||||
status->cdma_index = -1;
|
||||
status->ims_index = -1;
|
||||
ril_sim_card_update_status(self, status);
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
@@ -445,6 +548,9 @@ void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
/* Start the transaction to not allow any other
|
||||
* requests to interfere with SIM status query */
|
||||
ril_sim_card_tx_start(self);
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->status_req_id =
|
||||
grilio_queue_send_request_full(priv->q,
|
||||
@@ -664,6 +770,9 @@ static void ril_sim_card_finalize(GObject *object)
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
}
|
||||
if (priv->sub_start_timer) {
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
}
|
||||
g_hash_table_destroy(priv->sim_io_pending);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_sim_card_app {
|
||||
enum ril_app_type app_type;
|
||||
enum ril_app_state app_state;
|
||||
@@ -56,6 +58,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_reset(struct ril_sim_card *sc);
|
||||
void ril_sim_card_request_status(struct ril_sim_card *sc);
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
|
||||
@@ -74,9 +77,13 @@ void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
|
||||
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
|
||||
|
||||
/* Inline wrappers */
|
||||
static inline enum ril_app_type
|
||||
ril_sim_card_app_type(struct ril_sim_card *sc)
|
||||
static inline enum ril_app_type ril_sim_card_app_type(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
|
||||
static inline const char *ril_sim_card_app_aid(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->aid : NULL; }
|
||||
|
||||
#define ril_sim_card_remove_all_handlers(net, ids) \
|
||||
ril_sim_card_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_SIM_CARD_H */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 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
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_sim_settings_priv;
|
||||
|
||||
struct ril_sim_settings {
|
||||
|
||||
@@ -184,6 +184,13 @@ socket=/dev/socket/rild
|
||||
#
|
||||
#enableVoicecall=true
|
||||
|
||||
# Support for Cell Broadcast System (CBS). By default, its enabled but if
|
||||
# your rild and/or modem is not happy about it, you can turn it off.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableCellBroadcast=true
|
||||
|
||||
# Timeout for the modem to show up, in milliseconds. Those that don't
|
||||
# show up before this timeout expires, will be dropped (ignored).
|
||||
#
|
||||
@@ -202,3 +209,34 @@ socket=/dev/socket/rild
|
||||
# Default is false (use RIL_REQUEST_DEVICE_IDENTITY)
|
||||
#
|
||||
#legacyImeiQuery=false
|
||||
|
||||
# Some devices don't support LTE RAT mode PREF_NET_TYPE_LTE_GSM_WCDMA.
|
||||
# This option allows to set a custom LTE mode.
|
||||
#
|
||||
# The default is 9 (PREF_NET_TYPE_LTE_GSM_WCDMA)
|
||||
#
|
||||
#lteNetworkMode=9
|
||||
|
||||
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
|
||||
#
|
||||
# The default is 20000 (20 seconds)
|
||||
#
|
||||
#networkModeTimeout=20000
|
||||
|
||||
# Cycle radio power at startup.
|
||||
#
|
||||
# The default is true (cycle the power)
|
||||
#
|
||||
#radioPowerCycle=true
|
||||
|
||||
# With some RILs it seems to be necessary to kick (RIL_REQUEST_RADIO_POWER)
|
||||
# the modems with power on after one of the modems has been powered off.
|
||||
# Otherwise bad things may happen (like the modem never registering
|
||||
# on the network).
|
||||
#
|
||||
# On the other hand, with some RILs it's causing some trouble (like this
|
||||
# extra RIL_REQUEST_RADIO_POWER getting stuck indefinitely).
|
||||
#
|
||||
# The default is true for historical reasons
|
||||
#
|
||||
#confirmRadioPowerOn=true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -51,8 +51,14 @@ struct ril_vendor_hook;
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
enum ofono_radio_access_mode techs;
|
||||
int lte_network_mode;
|
||||
int network_mode_timeout;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean empty_pin_query;
|
||||
gboolean radio_power_cycle;
|
||||
gboolean confirm_radio_power_on;
|
||||
gboolean enable_voicecall;
|
||||
gboolean enable_cbs;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
|
||||
#define USSD_CANCEL_TIMEOUT_SEC (20)
|
||||
|
||||
struct ril_ussd {
|
||||
struct ofono_ussd *ussd;
|
||||
GRilIoChannel *io;
|
||||
@@ -114,11 +116,14 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
|
||||
grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000);
|
||||
grilio_queue_send_request_full(ud->q, req, RIL_REQUEST_CANCEL_USSD,
|
||||
ril_ussd_cancel_cb, ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
#include <grilio_channel.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "netreg.h"
|
||||
@@ -326,7 +326,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
int access_tech = -1;
|
||||
int tech = -1;
|
||||
if (ril_parse_int(stech, 0, &tech)) {
|
||||
if (gutil_parse_int(stech, 0, &tech)) {
|
||||
switch (tech) {
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
@@ -411,26 +411,6 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_parse_int(const char *str, int base, int *value)
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (str && str[0]) {
|
||||
char *str2 = g_strstrip(g_strdup(str));
|
||||
char *end = str2;
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(str2, &end, base);
|
||||
ok = !*end && errno != ERANGE && l >= INT_MIN && l <= INT_MAX;
|
||||
if (ok && value) {
|
||||
*value = (int)l;
|
||||
}
|
||||
g_free(str2);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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,7 +26,6 @@ const char *ril_unsol_event_to_string(guint event);
|
||||
const char *ril_radio_state_to_string(int radio_state);
|
||||
int ril_parse_tech(const char *stech, int *ril_tech);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
gboolean ril_parse_int(const char *str, int base, int *value);
|
||||
|
||||
#define ril_error_init_ok(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 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
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_create_hook
|
||||
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||
const char *path, const struct ril_slot_config *config)
|
||||
const char *path, const struct ril_slot_config *config,
|
||||
struct ril_network *network)
|
||||
{
|
||||
if (vendor) {
|
||||
const void *data = vendor->driver_data;
|
||||
@@ -31,16 +32,19 @@ struct ril_vendor_hook *ril_vendor_create_hook
|
||||
vendor = vendor->base;
|
||||
}
|
||||
if (vendor->create_hook) {
|
||||
return vendor->create_hook(data, io, path, config);
|
||||
return vendor->create_hook(data, io, path, config,
|
||||
network);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *self,
|
||||
const struct ril_vendor_hook_proc *proc)
|
||||
const struct ril_vendor_hook_proc *proc,
|
||||
ril_vendor_hook_free_proc free)
|
||||
{
|
||||
self->proc = proc;
|
||||
self->free = free;
|
||||
g_atomic_int_set(&self->ref_count, 1);
|
||||
return self;
|
||||
}
|
||||
@@ -56,13 +60,8 @@ struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *self)
|
||||
|
||||
static void ril_vendor_hook_free(struct ril_vendor_hook *self)
|
||||
{
|
||||
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||
|
||||
while (!proc->free && proc->base) {
|
||||
proc = proc->base;
|
||||
}
|
||||
if (proc->free) {
|
||||
proc->free(self);
|
||||
if (self->free) {
|
||||
self->free(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 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,8 @@
|
||||
struct ril_vendor_defaults {
|
||||
gboolean empty_pin_query;
|
||||
gboolean legacy_imei_query;
|
||||
gboolean enable_cbs;
|
||||
gboolean query_available_band_mode;
|
||||
};
|
||||
|
||||
struct ril_vendor_driver {
|
||||
@@ -30,12 +32,12 @@ struct ril_vendor_driver {
|
||||
void (*get_defaults)(struct ril_vendor_defaults *defaults);
|
||||
struct ril_vendor_hook *(*create_hook)(const void *driver_data,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *cfg);
|
||||
const struct ril_slot_config *cfg,
|
||||
struct ril_network *network);
|
||||
};
|
||||
|
||||
struct ril_vendor_hook_proc {
|
||||
const struct ril_vendor_hook_proc *base;
|
||||
void (*free)(struct ril_vendor_hook *hook);
|
||||
const char *(*request_to_string)(struct ril_vendor_hook *hook,
|
||||
guint request);
|
||||
const char *(*event_to_string)(struct ril_vendor_hook *hook,
|
||||
@@ -49,19 +51,23 @@ struct ril_vendor_hook_proc {
|
||||
GRilIoParser *rilp);
|
||||
};
|
||||
|
||||
typedef void (*ril_vendor_hook_free_proc)(struct ril_vendor_hook *hook);
|
||||
struct ril_vendor_hook {
|
||||
const struct ril_vendor_hook_proc *proc;
|
||||
ril_vendor_hook_free_proc free;
|
||||
gint ref_count;
|
||||
};
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_create_hook
|
||||
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||
const char *path, const struct ril_slot_config *cfg);
|
||||
const char *path, const struct ril_slot_config *cfg,
|
||||
struct ril_network *network);
|
||||
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
|
||||
struct ril_vendor_defaults *defaults);
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *hook,
|
||||
const struct ril_vendor_hook_proc *proc);
|
||||
const struct ril_vendor_hook_proc *proc,
|
||||
ril_vendor_hook_free_proc free);
|
||||
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *hook);
|
||||
void ril_vendor_hook_unref(struct ril_vendor_hook *hook);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 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,7 @@
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -26,17 +27,27 @@
|
||||
#include <grilio_queue.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define SET_INITIAL_ATTACH_APN_TIMEOUT (20*1000)
|
||||
|
||||
enum ril_mtk_watch_events {
|
||||
WATCH_EVENT_SIM_CHANGED,
|
||||
WATCH_EVENT_IMSI_CHANGED,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_mtk_network_events {
|
||||
NETWORK_EVENT_PREF_MODE_CHANGED,
|
||||
NETWORK_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_mtk_events {
|
||||
MTK_EVENT_REGISTRATION_SUSPENDED,
|
||||
MTK_EVENT_SET_ATTACH_APN,
|
||||
MTK_EVENT_PS_NETWORK_STATE_CHANGED,
|
||||
MTK_EVENT_INCOMING_CALL_INDICATION,
|
||||
MTK_EVENT_COUNT
|
||||
};
|
||||
|
||||
@@ -45,7 +56,12 @@ struct ril_vendor_hook_mtk {
|
||||
const struct ril_mtk_msg *msg;
|
||||
GRilIoQueue *q;
|
||||
GRilIoChannel *io;
|
||||
struct ril_network *network;
|
||||
struct sailfish_watch *watch;
|
||||
guint set_initial_attach_apn_id;
|
||||
gboolean initial_attach_apn_ok;
|
||||
gulong network_event_id[NETWORK_EVENT_COUNT];
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
gulong ril_event_id[MTK_EVENT_COUNT];
|
||||
guint slot;
|
||||
};
|
||||
@@ -57,39 +73,47 @@ struct ril_vendor_mtk_driver_data {
|
||||
const struct ril_vendor_hook_proc *proc;
|
||||
};
|
||||
|
||||
/* Hook with auto-detection */
|
||||
struct ril_vendor_hook_mtk_auto {
|
||||
struct ril_vendor_hook_mtk mtk;
|
||||
const struct ril_vendor_mtk_driver_data *type;
|
||||
gulong detect_id;
|
||||
};
|
||||
|
||||
/* MTK specific RIL messages (actual codes differ from model to model!) */
|
||||
struct ril_mtk_msg {
|
||||
gboolean attach_apn_has_roaming_protocol;
|
||||
guint request_resume_registration;
|
||||
guint unsol_network_info;
|
||||
guint request_set_call_indication;
|
||||
|
||||
/* See ril_vendor_mtk_auto_detect_event */
|
||||
#define unsol_msgs unsol_ps_network_state_changed
|
||||
#define MTK_UNSOL_MSGS (4)
|
||||
|
||||
guint unsol_ps_network_state_changed;
|
||||
guint unsol_registration_suspended;
|
||||
guint unsol_ims_registration_info;
|
||||
guint unsol_volte_eps_network_feature_support;
|
||||
guint unsol_emergency_bearer_support_notify;
|
||||
guint unsol_incoming_call_indication;
|
||||
guint unsol_set_attach_apn;
|
||||
};
|
||||
|
||||
/* Fly FS522 Cirrus 14 */
|
||||
static const struct ril_mtk_msg mtk_msg_mt6737 = {
|
||||
static const struct ril_mtk_msg msg_mtk1 = {
|
||||
.attach_apn_has_roaming_protocol = TRUE,
|
||||
.request_resume_registration = 2050,
|
||||
.unsol_network_info = 3001,
|
||||
.request_set_call_indication = 2065,
|
||||
.unsol_ps_network_state_changed = 3012,
|
||||
.unsol_registration_suspended = 3021,
|
||||
.unsol_ims_registration_info = 3029,
|
||||
.unsol_volte_eps_network_feature_support = 3042,
|
||||
.unsol_emergency_bearer_support_notify = 3052,
|
||||
.unsol_incoming_call_indication = 3037,
|
||||
.unsol_set_attach_apn = 3065
|
||||
};
|
||||
|
||||
/* MT8735 Tablet */
|
||||
static const struct ril_mtk_msg mtk_msg_mt8735 = {
|
||||
static const struct ril_mtk_msg msg_mtk2 = {
|
||||
.attach_apn_has_roaming_protocol = FALSE,
|
||||
.request_resume_registration = 2065,
|
||||
.unsol_network_info = 3001,
|
||||
.request_set_call_indication = 2086,
|
||||
.unsol_ps_network_state_changed = 3015,
|
||||
.unsol_ims_registration_info = 3033,
|
||||
.unsol_volte_eps_network_feature_support = 3048,
|
||||
.unsol_emergency_bearer_support_notify = 3059,
|
||||
.unsol_registration_suspended = 3024
|
||||
.unsol_registration_suspended = 3024,
|
||||
.unsol_incoming_call_indication = 3042,
|
||||
.unsol_set_attach_apn = 3073
|
||||
};
|
||||
|
||||
static inline struct ril_vendor_hook_mtk *ril_vendor_hook_mtk_cast
|
||||
@@ -98,6 +122,12 @@ static inline struct ril_vendor_hook_mtk *ril_vendor_hook_mtk_cast
|
||||
return G_CAST(hook, struct ril_vendor_hook_mtk, hook);
|
||||
}
|
||||
|
||||
static inline struct ril_vendor_hook_mtk_auto *ril_vendor_hook_mtk_auto_cast
|
||||
(struct ril_vendor_hook *hook)
|
||||
{
|
||||
return G_CAST(hook, struct ril_vendor_hook_mtk_auto, mtk.hook);
|
||||
}
|
||||
|
||||
static const char *ril_vendor_mtk_request_to_string
|
||||
(struct ril_vendor_hook *hook, guint request)
|
||||
{
|
||||
@@ -106,6 +136,24 @@ static const char *ril_vendor_mtk_request_to_string
|
||||
|
||||
if (request == msg->request_resume_registration) {
|
||||
return "MTK_RESUME_REGISTRATION";
|
||||
} else if (request == msg->request_set_call_indication) {
|
||||
return "MTK_SET_CALL_INDICATION";
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_vendor_mtk_unsol_msg_name(const struct ril_mtk_msg *msg,
|
||||
guint event)
|
||||
{
|
||||
if (event == msg->unsol_ps_network_state_changed) {
|
||||
return "MTK_PS_NETWORK_STATE_CHANGED";
|
||||
} else if (event == msg->unsol_registration_suspended) {
|
||||
return "MTK_REGISTRATION_SUSPENDED";
|
||||
} else if (event == msg->unsol_set_attach_apn) {
|
||||
return "MTK_SET_ATTACH_APN";
|
||||
} else if (event == msg->unsol_incoming_call_indication) {
|
||||
return "MTK_INCOMING_CALL_INDICATION";
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
@@ -115,25 +163,8 @@ static const char *ril_vendor_mtk_event_to_string(struct ril_vendor_hook *hook,
|
||||
guint event)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||
const struct ril_mtk_msg *msg = self->msg;
|
||||
|
||||
if (event == msg->unsol_network_info) {
|
||||
return "MTK_NETWORK_INFO";
|
||||
} else if (event == msg->unsol_ps_network_state_changed) {
|
||||
return "MTK_PS_NETWORK_STATE_CHANGED";
|
||||
} else if (event == msg->unsol_registration_suspended) {
|
||||
return "MTK_REGISTRATION_SUSPENDED";
|
||||
} else if (event == msg->unsol_ims_registration_info) {
|
||||
return "MTK_IMS_REGISTRATION_INFO";
|
||||
} else if (event == msg->unsol_volte_eps_network_feature_support) {
|
||||
return "MTK_VOLTE_EPS_NETWORK_FEATURE_SUPPORT";
|
||||
} else if (event == msg->unsol_emergency_bearer_support_notify) {
|
||||
return "MTK_EMERGENCY_BEARER_SUPPORT_NOTIFY";
|
||||
} else if (event == msg->unsol_set_attach_apn) {
|
||||
return "MTK_SET_ATTACH_APN";
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return ril_vendor_mtk_unsol_msg_name(self->msg, event);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
|
||||
@@ -148,7 +179,7 @@ static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, NULL) &&
|
||||
grilio_parser_get_int32(&rilp, &session_id)) {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
DBG("slot=%u,session_id=%d", self->slot, session_id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, session_id);
|
||||
@@ -158,70 +189,215 @@ static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *user_data)
|
||||
static GRilIoRequest *ril_vendor_mtk_build_set_attach_apn_req
|
||||
(const struct ofono_gprs_primary_context *pc,
|
||||
gboolean roamingProtocol)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
const char *proto = ril_data_ofono_protocol_to_ril(pc->proto);
|
||||
|
||||
DBG("%s %d", pc->apn, roamingProtocol);
|
||||
grilio_request_append_utf8(req, pc->apn); /* apn */
|
||||
grilio_request_append_utf8(req, proto); /* protocol */
|
||||
if (roamingProtocol) {
|
||||
grilio_request_append_utf8(req, proto); /* roamingProtocol */
|
||||
}
|
||||
|
||||
if (pc->username[0]) {
|
||||
int auth;
|
||||
|
||||
switch (pc->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
auth = RIL_AUTH_BOTH;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
auth = RIL_AUTH_NONE;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = RIL_AUTH_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = RIL_AUTH_PAP;
|
||||
break;
|
||||
default:
|
||||
auth = RIL_AUTH_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, auth);
|
||||
grilio_request_append_utf8(req, pc->username);
|
||||
grilio_request_append_utf8(req, pc->password);
|
||||
} else {
|
||||
grilio_request_append_int32(req, RIL_AUTH_NONE);
|
||||
grilio_request_append_utf8(req, "");
|
||||
grilio_request_append_utf8(req, "");
|
||||
}
|
||||
|
||||
grilio_request_append_utf8(req, ""); /* operatorNumeric */
|
||||
grilio_request_append_int32(req, FALSE); /* canHandleIms */
|
||||
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static const struct ofono_gprs_primary_context *ril_vendor_mtk_internet_context
|
||||
(struct ril_vendor_hook_mtk *self)
|
||||
{
|
||||
struct sailfish_watch *watch = self->watch;
|
||||
|
||||
if (watch->imsi) {
|
||||
struct ofono_atom *atom = __ofono_modem_find_atom(watch->modem,
|
||||
OFONO_ATOM_TYPE_GPRS);
|
||||
|
||||
if (atom) {
|
||||
return __ofono_gprs_context_settings_by_type
|
||||
(__ofono_atom_get_data(atom),
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_initial_attach_apn_resp(GRilIoChannel *io,
|
||||
int ril_status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = user_data;
|
||||
struct sailfish_watch *watch = self->watch;
|
||||
struct ofono_atom * gprs_atom = __ofono_modem_find_atom(watch->modem,
|
||||
OFONO_ATOM_TYPE_GPRS);
|
||||
struct ofono_gprs *gprs = gprs_atom ?
|
||||
__ofono_atom_get_data(gprs_atom) : NULL;
|
||||
const struct ofono_gprs_primary_context *pc =
|
||||
(gprs && watch->imsi) ?
|
||||
__ofono_gprs_context_settings_by_type(gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET) : NULL;
|
||||
|
||||
/* authtype, username, password */
|
||||
if (pc) {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
const char *proto = ril_data_ofono_protocol_to_ril(pc->proto);
|
||||
|
||||
DBG("%s",pc->apn);
|
||||
grilio_request_append_utf8(req, pc->apn); /* apn */
|
||||
grilio_request_append_utf8(req, proto); /* protocol */
|
||||
grilio_request_append_utf8(req, proto); /* roamingProtocol */
|
||||
|
||||
if (pc->username[0]) {
|
||||
int auth;
|
||||
|
||||
switch (pc->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
auth = RIL_AUTH_BOTH;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
auth = RIL_AUTH_NONE;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = RIL_AUTH_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = RIL_AUTH_PAP;
|
||||
break;
|
||||
default:
|
||||
auth = RIL_AUTH_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, auth);
|
||||
grilio_request_append_utf8(req, pc->username);
|
||||
grilio_request_append_utf8(req, pc->password);
|
||||
} else {
|
||||
grilio_request_append_int32(req, RIL_AUTH_NONE);
|
||||
grilio_request_append_utf8(req, "");
|
||||
grilio_request_append_utf8(req, "");
|
||||
}
|
||||
|
||||
grilio_request_append_utf8(req, ""); /* operatorNumeric */
|
||||
grilio_request_append_int32(req, FALSE); /* canHandleIms */
|
||||
grilio_request_append_int32(req, 0); /* Some sort of count */
|
||||
grilio_queue_send_request(self->q, req,
|
||||
RIL_REQUEST_SET_INITIAL_ATTACH_APN);
|
||||
grilio_request_unref(req);
|
||||
GASSERT(self->set_initial_attach_apn_id);
|
||||
self->set_initial_attach_apn_id = 0;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBG("ok");
|
||||
self->initial_attach_apn_ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static GRilIoRequest* ril_vendor_mtk_data_call_req
|
||||
static void ril_vendor_mtk_initial_attach_apn_check
|
||||
(struct ril_vendor_hook_mtk *self)
|
||||
{
|
||||
|
||||
if (!self->set_initial_attach_apn_id && !self->initial_attach_apn_ok) {
|
||||
const struct ofono_gprs_primary_context *pc =
|
||||
ril_vendor_mtk_internet_context(self);
|
||||
|
||||
if (pc) {
|
||||
GRilIoRequest *req =
|
||||
ril_vendor_mtk_build_set_attach_apn_req(pc,
|
||||
self->msg->attach_apn_has_roaming_protocol);
|
||||
|
||||
grilio_request_set_timeout(req,
|
||||
SET_INITIAL_ATTACH_APN_TIMEOUT);
|
||||
self->set_initial_attach_apn_id =
|
||||
grilio_queue_send_request_full(self->q, req,
|
||||
RIL_REQUEST_SET_INITIAL_ATTACH_APN,
|
||||
ril_vendor_mtk_initial_attach_apn_resp,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_initial_attach_apn_reset
|
||||
(struct ril_vendor_hook_mtk *self)
|
||||
{
|
||||
self->initial_attach_apn_ok = FALSE;
|
||||
if (self->set_initial_attach_apn_id) {
|
||||
grilio_queue_cancel_request(self->q,
|
||||
self->set_initial_attach_apn_id, FALSE);
|
||||
self->set_initial_attach_apn_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_watch_imsi_changed(struct sailfish_watch *watch,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = user_data;
|
||||
|
||||
if (watch->imsi) {
|
||||
ril_vendor_mtk_initial_attach_apn_check(self);
|
||||
} else {
|
||||
ril_vendor_mtk_initial_attach_apn_reset(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_network_pref_mode_changed(struct ril_network *net,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = user_data;
|
||||
|
||||
if (net->pref_mode >= OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
ril_vendor_mtk_initial_attach_apn_check(self);
|
||||
} else {
|
||||
ril_vendor_mtk_initial_attach_apn_reset(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *self)
|
||||
{
|
||||
ril_vendor_mtk_initial_attach_apn_check(self);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_ps_network_state_changed(GRilIoChannel *io,
|
||||
guint id, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = user_data;
|
||||
|
||||
ril_network_query_registration_state(self->network);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_incoming_call_indication(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = user_data;
|
||||
const struct ril_mtk_msg *msg = self->msg;
|
||||
GRilIoRequest* req = NULL;
|
||||
|
||||
GASSERT(id == msg->unsol_incoming_call_indication);
|
||||
|
||||
if (msg->request_set_call_indication) {
|
||||
int nparams, cid, seq;
|
||||
gchar *call_id = NULL, *seq_no = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
if (grilio_parser_get_int32(&rilp, &nparams) && nparams >= 5 &&
|
||||
(call_id = grilio_parser_get_utf8(&rilp)) != NULL &&
|
||||
grilio_parser_skip_string(&rilp) /* number */ &&
|
||||
grilio_parser_skip_string(&rilp) /* type */ &&
|
||||
grilio_parser_skip_string(&rilp) /* call_mode */ &&
|
||||
(seq_no = grilio_parser_get_utf8(&rilp)) != NULL &&
|
||||
gutil_parse_int(call_id, 10, &cid) &&
|
||||
gutil_parse_int(seq_no, 10, &seq)) {
|
||||
|
||||
DBG("slot=%u,cid=%d,seq=%d", self->slot, cid, seq);
|
||||
req = grilio_request_new();
|
||||
grilio_request_append_int32(req, 3); /* Param count */
|
||||
/* mode - IMS_ALLOW_INCOMING_CALL_INDICATION: */
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_append_int32(req, cid);
|
||||
grilio_request_append_int32(req, seq);
|
||||
} else {
|
||||
DBG("failed to parse INCOMING_CALL_INDICATION");
|
||||
}
|
||||
|
||||
g_free(call_id);
|
||||
g_free(seq_no);
|
||||
}
|
||||
|
||||
if (req) {
|
||||
grilio_queue_send_request(self->q, req,
|
||||
msg->request_set_call_indication);
|
||||
grilio_request_unref(req);
|
||||
} else {
|
||||
/* Let ril_voicecall.c know that something happened */
|
||||
grilio_channel_inject_unsol_event(io,
|
||||
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_vendor_mtk_data_call_req
|
||||
(struct ril_vendor_hook *hook, int tech, const char *profile,
|
||||
const char *apn, const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
@@ -279,24 +455,24 @@ static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_vendor_hook *hook,
|
||||
|
||||
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
|
||||
{
|
||||
/*
|
||||
* With most Qualcomm RIL implementations, querying available band
|
||||
* modes causes some magic Android properties to appear. Otherwise
|
||||
* this request is pretty harmless and useless.
|
||||
*
|
||||
* Most MediaTek RIL implementations don't support this request and
|
||||
* don't even bother to reply which slows things down because we wait
|
||||
* for this request to complete at startup.
|
||||
*/
|
||||
defaults->query_available_band_mode = FALSE;
|
||||
defaults->empty_pin_query = FALSE;
|
||||
defaults->legacy_imei_query = TRUE;
|
||||
}
|
||||
|
||||
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
|
||||
(const void *driver_data, GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config)
|
||||
static void ril_vendor_mtk_hook_subscribe(struct ril_vendor_hook_mtk *self)
|
||||
{
|
||||
const struct ril_vendor_mtk_driver_data *mtk_driver_data = driver_data;
|
||||
const struct ril_mtk_msg *msg = mtk_driver_data->msg;
|
||||
struct ril_vendor_hook_mtk *self =
|
||||
g_new0(struct ril_vendor_hook_mtk, 1);
|
||||
const struct ril_mtk_msg *msg = self->msg;
|
||||
|
||||
self->msg = msg;
|
||||
self->q = grilio_queue_new(io);
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->watch = sailfish_watch_new(path);
|
||||
self->slot = config->slot;
|
||||
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
|
||||
grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_vendor_mtk_registration_suspended,
|
||||
@@ -307,8 +483,51 @@ static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
|
||||
ril_vendor_mtk_set_attach_apn,
|
||||
msg->unsol_set_attach_apn, self);
|
||||
}
|
||||
DBG("%s slot %u", mtk_driver_data->name, self->slot);
|
||||
return ril_vendor_hook_init(&self->hook, mtk_driver_data->proc);
|
||||
if (msg->unsol_ps_network_state_changed) {
|
||||
self->ril_event_id[MTK_EVENT_PS_NETWORK_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_vendor_mtk_ps_network_state_changed,
|
||||
msg->unsol_ps_network_state_changed, self);
|
||||
}
|
||||
if (msg->unsol_incoming_call_indication) {
|
||||
self->ril_event_id[MTK_EVENT_INCOMING_CALL_INDICATION] =
|
||||
grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_vendor_mtk_incoming_call_indication,
|
||||
msg->unsol_incoming_call_indication, self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_hook_init(struct ril_vendor_hook_mtk *self,
|
||||
const struct ril_vendor_mtk_driver_data *mtk_driver_data,
|
||||
ril_vendor_hook_free_proc free, GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config, struct ril_network *network)
|
||||
{
|
||||
self->msg = mtk_driver_data->msg;
|
||||
self->q = grilio_queue_new(io);
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->watch = sailfish_watch_new(path);
|
||||
self->slot = config->slot;
|
||||
self->network = ril_network_ref(network);
|
||||
self->watch_event_id[WATCH_EVENT_IMSI_CHANGED] =
|
||||
sailfish_watch_add_imsi_changed_handler(self->watch,
|
||||
ril_vendor_mtk_watch_imsi_changed, self);
|
||||
self->network_event_id[NETWORK_EVENT_PREF_MODE_CHANGED] =
|
||||
ril_network_add_pref_mode_changed_handler(self->network,
|
||||
ril_vendor_mtk_network_pref_mode_changed, self);
|
||||
ril_vendor_mtk_hook_subscribe(self);
|
||||
ril_vendor_hook_init(&self->hook, mtk_driver_data->proc, free);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_destroy(struct ril_vendor_hook_mtk *self)
|
||||
{
|
||||
grilio_queue_cancel_all(self->q, FALSE);
|
||||
grilio_channel_remove_all_handlers(self->io, self->ril_event_id);
|
||||
grilio_queue_unref(self->q);
|
||||
grilio_channel_unref(self->io);
|
||||
sailfish_watch_remove_all_handlers(self->watch, self->watch_event_id);
|
||||
sailfish_watch_unref(self->watch);
|
||||
ril_network_remove_all_handlers(self->network, self->network_event_id);
|
||||
ril_network_unref(self->network);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_free(struct ril_vendor_hook *hook)
|
||||
@@ -316,16 +535,26 @@ static void ril_vendor_mtk_free(struct ril_vendor_hook *hook)
|
||||
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||
|
||||
DBG("slot %u", self->slot);
|
||||
grilio_queue_cancel_all(self->q, FALSE);
|
||||
grilio_channel_remove_all_handlers(self->io, self->ril_event_id);
|
||||
grilio_queue_unref(self->q);
|
||||
grilio_channel_unref(self->io);
|
||||
sailfish_watch_unref(self->watch);
|
||||
ril_vendor_mtk_destroy(self);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
|
||||
(const void *driver_data, GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_network *network)
|
||||
{
|
||||
const struct ril_vendor_mtk_driver_data *mtk_driver_data = driver_data;
|
||||
struct ril_vendor_hook_mtk *self =
|
||||
g_new0(struct ril_vendor_hook_mtk, 1);
|
||||
|
||||
ril_vendor_mtk_hook_init(self, mtk_driver_data, ril_vendor_mtk_free,
|
||||
io, path, config, network);
|
||||
DBG("%s slot %u", mtk_driver_data->name, self->slot);
|
||||
return &self->hook;
|
||||
}
|
||||
|
||||
static const struct ril_vendor_hook_proc ril_vendor_mtk_hook_base_proc = {
|
||||
.free = ril_vendor_mtk_free,
|
||||
.request_to_string = ril_vendor_mtk_request_to_string,
|
||||
.event_to_string = ril_vendor_mtk_event_to_string,
|
||||
.data_call_req = ril_vendor_mtk_data_call_req
|
||||
@@ -336,141 +565,127 @@ static const struct ril_vendor_driver ril_vendor_mtk_base = {
|
||||
.create_hook = ril_vendor_mtk_create_hook_from_data
|
||||
};
|
||||
|
||||
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk_mt6737_data = {
|
||||
.name = "MT6737",
|
||||
.msg = &mtk_msg_mt6737,
|
||||
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk1_data = {
|
||||
.name = "mtk1",
|
||||
.msg = &msg_mtk1,
|
||||
.proc = &ril_vendor_mtk_hook_base_proc
|
||||
};
|
||||
|
||||
static struct ril_vendor_hook_proc ril_vendor_mtk_mt8735_proc = {
|
||||
static struct ril_vendor_hook_proc ril_vendor_mtk2_proc = {
|
||||
.base = &ril_vendor_mtk_hook_base_proc,
|
||||
.data_call_parse = ril_vendor_mtk_data_call_parse_v6
|
||||
};
|
||||
|
||||
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk_mt8735_data = {
|
||||
.name = "MT8735",
|
||||
.msg = &mtk_msg_mt8735,
|
||||
.proc = &ril_vendor_mtk_mt8735_proc
|
||||
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk2_data = {
|
||||
.name = "mtk2",
|
||||
.msg = &msg_mtk2,
|
||||
.proc = &ril_vendor_mtk2_proc
|
||||
};
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mt6737) {
|
||||
.name = "mt6737t",
|
||||
.driver_data = &ril_vendor_mtk_mt6737_data,
|
||||
#define DEFAULT_MTK_TYPE (&ril_vendor_mtk1_data)
|
||||
|
||||
static const struct ril_vendor_mtk_driver_data *mtk_types [] = {
|
||||
&ril_vendor_mtk1_data,
|
||||
&ril_vendor_mtk2_data
|
||||
};
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk1) {
|
||||
.name = "mtk1",
|
||||
.driver_data = &ril_vendor_mtk1_data,
|
||||
.base = &ril_vendor_mtk_base
|
||||
};
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mt8735) {
|
||||
.name = "mt8735",
|
||||
.driver_data = &ril_vendor_mtk_mt8735_data,
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk2) {
|
||||
.name = "mtk2",
|
||||
.driver_data = &ril_vendor_mtk2_data,
|
||||
.base = &ril_vendor_mtk_base
|
||||
};
|
||||
|
||||
#define DEFAULT_MTK_DRIVER (&ril_vendor_driver_mt6737)
|
||||
/* Auto-selection */
|
||||
|
||||
static const struct ril_vendor_driver *mtk_hw_drivers [] = {
|
||||
&ril_vendor_driver_mt6737,
|
||||
&ril_vendor_driver_mt8735
|
||||
};
|
||||
|
||||
/* Automatic driver selection based on /proc/cpuinfo */
|
||||
|
||||
static GString *ril_vendor_mtk_read_line(GString *buf, FILE *f)
|
||||
static gboolean ril_vendor_mtk_auto_set_type
|
||||
(struct ril_vendor_hook_mtk_auto *self,
|
||||
const struct ril_vendor_mtk_driver_data *type)
|
||||
{
|
||||
int c = fgetc(f);
|
||||
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_string_truncate(buf, 0);
|
||||
if (c != EOF) {
|
||||
/* Read the line char by char until we hit EOF or EOL */
|
||||
while (c != EOF && c != '\r' && c != '\n') {
|
||||
g_string_append_c(buf, c);
|
||||
c = fgetc(f);
|
||||
}
|
||||
/* Skip EOL characters */
|
||||
while (c != EOF && (c == '\r' || c == '\n')) {
|
||||
c = fgetc(f);
|
||||
}
|
||||
/* Unget the last char (the first char of the next line) */
|
||||
if (c != EOF) {
|
||||
ungetc(c, f);
|
||||
}
|
||||
return buf;
|
||||
if (self->type != type) {
|
||||
DBG("switching type %s -> %s", self->type->name, type->name);
|
||||
self->type = type;
|
||||
mtk->msg = type->msg;
|
||||
mtk->hook.proc = type->proc;
|
||||
grilio_channel_remove_all_handlers(mtk->io, mtk->ril_event_id);
|
||||
ril_vendor_mtk_hook_subscribe(mtk);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
grilio_channel_remove_handler(mtk->io, self->detect_id);
|
||||
self->detect_id = 0;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static char *ril_vendor_mtk_hardware()
|
||||
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *self)
|
||||
{
|
||||
FILE *f = fopen("/proc/cpuinfo", "r");
|
||||
char *hardware = NULL;
|
||||
guint i;
|
||||
|
||||
if (f) {
|
||||
const char prefix[] = "Hardware\t:";
|
||||
const gsize prefix_len = sizeof(prefix) - 1;
|
||||
GString *buf = g_string_new("");
|
||||
for (i = 0; i < G_N_ELEMENTS(mtk_types); i++) {
|
||||
const struct ril_vendor_mtk_driver_data *type = mtk_types[i];
|
||||
const struct ril_mtk_msg *msg = type->msg;
|
||||
const guint *ids = &msg->unsol_msgs;
|
||||
guint j;
|
||||
|
||||
/* Find the "Hardware:" line */
|
||||
while (ril_vendor_mtk_read_line(buf, f) &&
|
||||
strncmp(buf->str, prefix, prefix_len));
|
||||
|
||||
if (buf->len > prefix_len) {
|
||||
/* Erase the prefix */
|
||||
g_string_erase(buf, 0, prefix_len);
|
||||
|
||||
/* Remove trailing whitespaces */
|
||||
while (buf->len > 0 &&
|
||||
g_ascii_isspace(buf->str[buf->len - 1])) {
|
||||
g_string_truncate(buf, buf->len - 1);
|
||||
}
|
||||
|
||||
/* Extract the last word */
|
||||
if (buf->len > 0) {
|
||||
gsize pos = buf->len;
|
||||
|
||||
while (pos > 0 &&
|
||||
!g_ascii_isspace(buf->str[pos - 1])) {
|
||||
pos--;
|
||||
}
|
||||
|
||||
if (buf->str[pos]) {
|
||||
hardware = g_strdup(buf->str + pos);
|
||||
DBG("Hardware: %s", hardware);
|
||||
for (j = 0; j < MTK_UNSOL_MSGS; j++) {
|
||||
if (ids[j] == id) {
|
||||
DBG("event %u is %s %s", id, type->name,
|
||||
ril_vendor_mtk_unsol_msg_name(msg,id));
|
||||
if (ril_vendor_mtk_auto_set_type(self, type)) {
|
||||
/* And repeat the event to invoke
|
||||
* the handler */
|
||||
grilio_channel_inject_unsol_event(io,
|
||||
id, data, len);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_string_free(buf, TRUE);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return hardware;
|
||||
}
|
||||
|
||||
static const struct ril_vendor_driver *ril_vendor_mtk_detect()
|
||||
static void ril_vendor_mtk_auto_free(struct ril_vendor_hook *hook)
|
||||
{
|
||||
const struct ril_vendor_driver *driver = DEFAULT_MTK_DRIVER;
|
||||
char *hw = ril_vendor_mtk_hardware();
|
||||
struct ril_vendor_hook_mtk_auto *self =
|
||||
ril_vendor_hook_mtk_auto_cast(hook);
|
||||
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||
|
||||
if (hw) {
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(mtk_hw_drivers); i++) {
|
||||
if (!strcasecmp(mtk_hw_drivers[i]->name, hw)) {
|
||||
driver = mtk_hw_drivers[i];
|
||||
DBG("Driver: %s", driver->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_free(hw);
|
||||
}
|
||||
return driver;
|
||||
DBG("slot %u", mtk->slot);
|
||||
grilio_channel_remove_handler(mtk->io, self->detect_id);
|
||||
ril_vendor_mtk_destroy(mtk);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_auto
|
||||
(const void *driver_data, GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *cfg)
|
||||
(const void *driver_data, GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *cfg, struct ril_network *network)
|
||||
{
|
||||
return ril_vendor_create_hook(ril_vendor_mtk_detect(), io, path, cfg);
|
||||
struct ril_vendor_hook_mtk_auto *self =
|
||||
g_new0(struct ril_vendor_hook_mtk_auto, 1);
|
||||
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||
|
||||
/* Pick the default */
|
||||
self->type = DEFAULT_MTK_TYPE;
|
||||
ril_vendor_mtk_hook_init(mtk, self->type, ril_vendor_mtk_auto_free,
|
||||
io, path, cfg, network);
|
||||
DBG("%s slot %u", self->type->name, mtk->slot);
|
||||
|
||||
/*
|
||||
* Subscribe for (all) unsolicited events. Keep on listening until
|
||||
* we receive an MTK specific event that tells us which particular
|
||||
* kind of MTK adaptation we are using.
|
||||
*/
|
||||
self->detect_id = grilio_channel_add_unsol_event_handler(mtk->io,
|
||||
ril_vendor_mtk_auto_detect_event, 0, self);
|
||||
return &mtk->hook;
|
||||
}
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 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
|
||||
@@ -587,39 +587,75 @@ static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
|
||||
grilio_request_unref(ioreq);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
|
||||
static void ril_voicecall_hangup(struct ofono_voicecall *vc,
|
||||
gboolean (*filter)(struct ofono_call *call),
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall_request_data *req = NULL;
|
||||
GSList *l;
|
||||
|
||||
if (vd->calls) {
|
||||
GSList *l;
|
||||
struct ril_voicecall_request_data *req =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
/*
|
||||
* Here the idea is that we submit (potentially) multiple
|
||||
* hangup requests to RIL and invoke the callback after
|
||||
* the last request has completed (pending call count
|
||||
* becomes zero).
|
||||
*/
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
|
||||
/*
|
||||
* Here the idea is that we submit (potentially) multiple
|
||||
* hangup requests to RIL and invoke the callback after
|
||||
* the last request has completed (pending call count
|
||||
* becomes zero).
|
||||
*/
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
if (!filter || filter(call)) {
|
||||
if (!req) {
|
||||
req = ril_voicecall_request_data_new(vc, cb,
|
||||
data);
|
||||
}
|
||||
|
||||
/* Send request to RIL */
|
||||
DBG("Hanging up call with id %d", call->id);
|
||||
ril_voicecall_submit_hangup_req(vc, call->id, req);
|
||||
} else {
|
||||
DBG("Skipping call with id %d", call->id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Release our reference */
|
||||
if (req) {
|
||||
/* Release our reference (if any) */
|
||||
ril_voicecall_request_data_unref(req);
|
||||
} else {
|
||||
/* No calls */
|
||||
/* No requests were submitted */
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_voicecall_hangup_active_filter(struct ofono_call *call)
|
||||
{
|
||||
switch (call->status) {
|
||||
case CALL_STATUS_ACTIVE:
|
||||
case CALL_STATUS_DIALING:
|
||||
case CALL_STATUS_ALERTING:
|
||||
case CALL_STATUS_INCOMING:
|
||||
return TRUE;
|
||||
case CALL_STATUS_HELD:
|
||||
case CALL_STATUS_WAITING:
|
||||
case CALL_STATUS_DISCONNECTED:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_hangup(vc, ril_voicecall_hangup_active_filter, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_hangup(vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
|
||||
int id, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
@@ -657,7 +693,7 @@ static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
|
||||
grilio_parser_get_int32(&rilp, &type);
|
||||
grilio_parser_get_int32(&rilp, &code);
|
||||
grilio_parser_get_int32(&rilp, &index);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &phone.type);
|
||||
tmp = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
if (tmp) {
|
||||
@@ -811,8 +847,7 @@ static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, NULL, cb, data);
|
||||
ril_voicecall_request(RIL_REQUEST_UDUB, vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
|
||||
@@ -946,6 +981,7 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
|
||||
.remove = ril_voicecall_remove,
|
||||
.dial = ril_voicecall_dial,
|
||||
.answer = ril_voicecall_answer,
|
||||
.hangup_active = ril_voicecall_hangup_active,
|
||||
.hangup_all = ril_voicecall_hangup_all,
|
||||
.release_specific = ril_voicecall_release_specific,
|
||||
.send_tones = ril_voicecall_send_dtmf,
|
||||
|
||||
84
ofono/include/gprs-filter.h
Normal file
84
ofono/include/gprs-filter.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_GPRS_FILTER_H
|
||||
#define __OFONO_GPRS_FILTER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_gprs;
|
||||
struct ofono_gprs_context;
|
||||
struct ofono_gprs_primary_context;
|
||||
|
||||
/* If ctx is NULL then activation gets cancelled */
|
||||
typedef void (*ofono_gprs_filter_activate_cb_t)
|
||||
(const struct ofono_gprs_primary_context *ctx, void *data);
|
||||
typedef void (*ofono_gprs_filter_check_cb_t)(ofono_bool_t allow, void *data);
|
||||
|
||||
#define OFONO_GPRS_FILTER_PRIORITY_LOW (-100)
|
||||
#define OFONO_GPRS_FILTER_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_GPRS_FILTER_PRIORITY_HIGH (100)
|
||||
|
||||
/*
|
||||
* The api_version field makes it possible to keep using old plugins
|
||||
* even if struct ofono_gprs_filter gets extended with new callbacks.
|
||||
*/
|
||||
|
||||
#define OFONO_GPRS_FILTER_API_VERSION (1)
|
||||
|
||||
/*
|
||||
* The filter callbacks either invoke the completion callback directly
|
||||
* or return the id of the cancellable asynchronous operation (but never
|
||||
* both). If non-zero value is returned, the completion callback has to
|
||||
* be invoked later on a fresh stack. Once the asynchronous filtering
|
||||
* operation is cancelled, the associated completion callback must not
|
||||
* be invoked.
|
||||
*
|
||||
* Please avoid making blocking D-Bus calls from the filter callbacks.
|
||||
*/
|
||||
struct ofono_gprs_filter {
|
||||
const char *name;
|
||||
int api_version; /* OFONO_GPRS_FILTER_API_VERSION */
|
||||
int priority;
|
||||
void (*cancel)(unsigned int id);
|
||||
unsigned int (*filter_activate)(struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ofono_gprs_filter_activate_cb_t cb,
|
||||
void *data);
|
||||
/* API version 1 */
|
||||
unsigned int (*filter_check)(struct ofono_gprs *gprs,
|
||||
ofono_gprs_filter_check_cb_t cb, void *data);
|
||||
};
|
||||
|
||||
int ofono_gprs_filter_register(const struct ofono_gprs_filter *filter);
|
||||
void ofono_gprs_filter_unregister(const struct ofono_gprs_filter *filter);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_GPRS_FILTER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -83,6 +83,8 @@ void ofono_gprs_add_context(struct ofono_gprs *gprs,
|
||||
void ofono_gprs_cid_activated(struct ofono_gprs *gprs, unsigned int cid,
|
||||
const char *apn);
|
||||
|
||||
void ofono_gprs_attached_update(struct ofono_gprs *gprs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -29,7 +29,9 @@ extern "C" {
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_gprs;
|
||||
struct ofono_sim;
|
||||
struct ofono_voicecall;
|
||||
|
||||
enum ofono_modem_type {
|
||||
OFONO_MODEM_TYPE_HARDWARE = 0,
|
||||
@@ -82,6 +84,8 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
|
||||
|
||||
const char *ofono_modem_get_path(struct ofono_modem *modem);
|
||||
struct ofono_sim *ofono_modem_get_sim(struct ofono_modem *modem);
|
||||
struct ofono_gprs *ofono_modem_get_gprs(struct ofono_modem *modem);
|
||||
struct ofono_voicecall *ofono_modem_get_voicecall(struct ofono_modem *modem);
|
||||
|
||||
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
|
||||
void *ofono_modem_get_data(struct ofono_modem *modem);
|
||||
|
||||
284
ofono/include/ril-constants.h
Normal file
284
ofono/include/ril-constants.h
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_RIL_CONSTANTS_H
|
||||
#define __OFONO_RIL_CONSTANTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Error Codes */
|
||||
enum ril_status {
|
||||
RIL_E_SUCCESS = 0,
|
||||
RIL_E_RADIO_NOT_AVAILABLE = 1,
|
||||
RIL_E_GENERIC_FAILURE = 2,
|
||||
RIL_E_PASSWORD_INCORRECT = 3,
|
||||
RIL_E_SIM_PIN2 = 4,
|
||||
RIL_E_SIM_PUK2 = 5,
|
||||
RIL_E_REQUEST_NOT_SUPPORTED = 6,
|
||||
RIL_E_CANCELLED = 7,
|
||||
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
|
||||
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
|
||||
RIL_E_SMS_SEND_FAIL_RETRY = 10,
|
||||
RIL_E_SIM_ABSENT = 11,
|
||||
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
|
||||
RIL_E_MODE_NOT_SUPPORTED = 13,
|
||||
RIL_E_FDN_CHECK_FAILURE = 14,
|
||||
RIL_E_ILLEGAL_SIM_OR_ME = 15,
|
||||
RIL_E_MISSING_RESOURCE = 16,
|
||||
RIL_E_NO_SUCH_ELEMENT = 17,
|
||||
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
|
||||
RIL_E_DIAL_MODIFIED_TO_SS = 19,
|
||||
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
|
||||
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
|
||||
RIL_E_USSD_MODIFIED_TO_SS = 22,
|
||||
RIL_E_USSD_MODIFIED_TO_USSD = 23,
|
||||
RIL_E_SS_MODIFIED_TO_DIAL = 24,
|
||||
RIL_E_SS_MODIFIED_TO_USSD = 25,
|
||||
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
|
||||
RIL_E_SS_MODIFIED_TO_SS = 27,
|
||||
RIL_E_LCE_NOT_SUPPORTED = 36,
|
||||
RIL_E_NO_MEMORY = 37,
|
||||
RIL_E_INTERNAL_ERR = 38,
|
||||
RIL_E_SYSTEM_ERR = 39,
|
||||
RIL_E_MODEM_ERR = 40,
|
||||
RIL_E_INVALID_STATE = 41,
|
||||
RIL_E_NO_RESOURCES = 42,
|
||||
RIL_E_SIM_ERR = 43,
|
||||
RIL_E_INVALID_ARGUMENTS = 44,
|
||||
RIL_E_INVALID_SIM_STATE = 45,
|
||||
RIL_E_INVALID_MODEM_STATE = 46,
|
||||
RIL_E_INVALID_CALL_ID = 47,
|
||||
RIL_E_NO_SMS_TO_ACK = 48,
|
||||
RIL_E_NETWORK_ERR = 49,
|
||||
RIL_E_REQUEST_RATE_LIMITED = 50,
|
||||
RIL_E_SIM_BUSY = 51,
|
||||
RIL_E_SIM_FULL = 52,
|
||||
RIL_E_NETWORK_REJECT = 53,
|
||||
RIL_E_OPERATION_NOT_ALLOWED = 54,
|
||||
RIL_E_EMPTY_RECORD = 55,
|
||||
RIL_E_INVALID_SMS_FORMAT = 56,
|
||||
RIL_E_ENCODING_ERR = 57,
|
||||
RIL_E_INVALID_SMSC_ADDRESS = 58,
|
||||
RIL_E_NO_SUCH_ENTRY = 59,
|
||||
RIL_E_NETWORK_NOT_READY = 60,
|
||||
RIL_E_NOT_PROVISIONED = 61,
|
||||
RIL_E_NO_SUBSCRIPTION = 62,
|
||||
RIL_E_NO_NETWORK_FOUND = 63,
|
||||
RIL_E_DEVICE_IN_USE = 64,
|
||||
RIL_E_ABORTED = 65,
|
||||
RIL_E_INVALID_RESPONSE = 66
|
||||
};
|
||||
|
||||
/* RIL Request Messages, ofono -> rild */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK 3
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN2 4
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK2 5
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN 6
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
|
||||
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
|
||||
#define RIL_REQUEST_GET_CURRENT_CALLS 9
|
||||
#define RIL_REQUEST_DIAL 10
|
||||
#define RIL_REQUEST_GET_IMSI 11
|
||||
#define RIL_REQUEST_HANGUP 12
|
||||
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
|
||||
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
|
||||
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
|
||||
#define RIL_REQUEST_CONFERENCE 16
|
||||
#define RIL_REQUEST_UDUB 17
|
||||
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
|
||||
#define RIL_REQUEST_SIGNAL_STRENGTH 19
|
||||
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
|
||||
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
|
||||
#define RIL_REQUEST_OPERATOR 22
|
||||
#define RIL_REQUEST_RADIO_POWER 23
|
||||
#define RIL_REQUEST_DTMF 24
|
||||
#define RIL_REQUEST_SEND_SMS 25
|
||||
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
|
||||
#define RIL_REQUEST_SETUP_DATA_CALL 27
|
||||
#define RIL_REQUEST_SIM_IO 28
|
||||
#define RIL_REQUEST_SEND_USSD 29
|
||||
#define RIL_REQUEST_CANCEL_USSD 30
|
||||
#define RIL_REQUEST_GET_CLIR 31
|
||||
#define RIL_REQUEST_SET_CLIR 32
|
||||
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
|
||||
#define RIL_REQUEST_SET_CALL_FORWARD 34
|
||||
#define RIL_REQUEST_QUERY_CALL_WAITING 35
|
||||
#define RIL_REQUEST_SET_CALL_WAITING 36
|
||||
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
|
||||
#define RIL_REQUEST_GET_IMEI 38
|
||||
#define RIL_REQUEST_GET_IMEISV 39
|
||||
#define RIL_REQUEST_ANSWER 40
|
||||
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
|
||||
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
|
||||
#define RIL_REQUEST_SET_FACILITY_LOCK 43
|
||||
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
|
||||
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
|
||||
#define RIL_REQUEST_DTMF_START 49
|
||||
#define RIL_REQUEST_DTMF_STOP 50
|
||||
#define RIL_REQUEST_BASEBAND_VERSION 51
|
||||
#define RIL_REQUEST_SEPARATE_CONNECTION 52
|
||||
#define RIL_REQUEST_SET_MUTE 53
|
||||
#define RIL_REQUEST_GET_MUTE 54
|
||||
#define RIL_REQUEST_QUERY_CLIP 55
|
||||
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
|
||||
#define RIL_REQUEST_DATA_CALL_LIST 57
|
||||
#define RIL_REQUEST_RESET_RADIO 58
|
||||
#define RIL_REQUEST_OEM_HOOK_RAW 59
|
||||
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
|
||||
#define RIL_REQUEST_SCREEN_STATE 61
|
||||
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
|
||||
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
|
||||
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
|
||||
#define RIL_REQUEST_SET_BAND_MODE 65
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
|
||||
#define RIL_REQUEST_STK_GET_PROFILE 67
|
||||
#define RIL_REQUEST_STK_SET_PROFILE 68
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
|
||||
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
|
||||
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
|
||||
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
|
||||
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
|
||||
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
|
||||
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
|
||||
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
|
||||
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
|
||||
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
|
||||
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
|
||||
#define RIL_REQUEST_SET_TTY_MODE 80
|
||||
#define RIL_REQUEST_QUERY_TTY_MODE 81
|
||||
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
|
||||
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
|
||||
#define RIL_REQUEST_CDMA_FLASH 84
|
||||
#define RIL_REQUEST_CDMA_BURST_DTMF 85
|
||||
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
|
||||
#define RIL_REQUEST_CDMA_SEND_SMS 87
|
||||
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
|
||||
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
|
||||
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
|
||||
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
|
||||
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
|
||||
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
|
||||
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
|
||||
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
|
||||
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
|
||||
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
|
||||
#define RIL_REQUEST_DEVICE_IDENTITY 98
|
||||
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
|
||||
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
|
||||
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
|
||||
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
|
||||
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
|
||||
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
|
||||
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
|
||||
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
|
||||
#define RIL_REQUEST_VOICE_RADIO_TECH 108
|
||||
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
|
||||
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
|
||||
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
|
||||
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
|
||||
#define RIL_REQUEST_IMS_SEND_SMS 113
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
|
||||
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
|
||||
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
|
||||
#define RIL_REQUEST_NV_READ_ITEM 118
|
||||
#define RIL_REQUEST_NV_WRITE_ITEM 119
|
||||
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
|
||||
#define RIL_REQUEST_NV_RESET_CONFIG 121
|
||||
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
|
||||
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
|
||||
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
|
||||
#define RIL_REQUEST_ALLOW_DATA 123
|
||||
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
|
||||
#define RIL_REQUEST_SIM_AUTHENTICATION 125
|
||||
#define RIL_REQUEST_GET_DC_RT_INFO 126
|
||||
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
|
||||
#define RIL_REQUEST_SET_DATA_PROFILE 128
|
||||
#define RIL_REQUEST_SHUTDOWN 129
|
||||
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
|
||||
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
|
||||
|
||||
/* RIL Unsolicited Messages, rild -> ofono */
|
||||
#define RIL_UNSOL_RESPONSE_BASE 1000
|
||||
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
|
||||
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
|
||||
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
|
||||
#define RIL_UNSOL_ON_USSD 1006
|
||||
#define RIL_UNSOL_ON_USSD_REQUEST 1007
|
||||
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
|
||||
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
|
||||
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
|
||||
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
|
||||
#define RIL_UNSOL_STK_SESSION_END 1012
|
||||
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
|
||||
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
|
||||
#define RIL_UNSOL_STK_CALL_SETUP 1015
|
||||
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
|
||||
#define RIL_UNSOL_SIM_REFRESH 1017
|
||||
#define RIL_UNSOL_CALL_RING 1018
|
||||
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
|
||||
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
|
||||
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
|
||||
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
|
||||
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
|
||||
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
|
||||
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
|
||||
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
|
||||
#define RIL_UNSOL_CDMA_INFO_REC 1027
|
||||
#define RIL_UNSOL_OEM_HOOK_RAW 1028
|
||||
#define RIL_UNSOL_RINGBACK_TONE 1029
|
||||
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
|
||||
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
|
||||
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
|
||||
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
|
||||
#define RIL_UNSOL_RIL_CONNECTED 1034
|
||||
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
|
||||
#define RIL_UNSOL_CELL_INFO_LIST 1036
|
||||
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
|
||||
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
|
||||
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
|
||||
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
|
||||
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
|
||||
#define RIL_UNSOL_RADIO_CAPABILITY 1042
|
||||
#define RIL_UNSOL_ON_SS 1043
|
||||
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
|
||||
|
||||
/* A special request, ofono -> rild */
|
||||
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_RIL_CONSTANTS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
64
ofono/include/ril-transport.h
Normal file
64
ofono/include/ril-transport.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_RIL_TRANSPORT_H
|
||||
#define __OFONO_RIL_TRANSPORT_H
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct grilio_transport;
|
||||
|
||||
/*
|
||||
* The api_version field makes it possible to keep using old plugins
|
||||
* even if struct ofono_ril_transport gets extended with new callbacks.
|
||||
*/
|
||||
|
||||
#define OFONO_RIL_TRANSPORT_API_VERSION (0)
|
||||
|
||||
/*
|
||||
* The connect callback takes a (char*) -> (char*) hashtable containing
|
||||
* transport-specific connection parameters. The caller receives a reference
|
||||
* i.e. it has to unref the returned object.
|
||||
*/
|
||||
struct ofono_ril_transport {
|
||||
const char *name;
|
||||
int api_version; /* OFONO_RIL_TRANSPORT_API_VERSION */
|
||||
struct grilio_transport *(*connect)(GHashTable *params);
|
||||
};
|
||||
|
||||
int ofono_ril_transport_register(const struct ofono_ril_transport *t);
|
||||
void ofono_ril_transport_unregister(const struct ofono_ril_transport *t);
|
||||
|
||||
struct grilio_transport *ofono_ril_transport_connect(const char *name,
|
||||
GHashTable *params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_RIL_TRANSPORT_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -56,6 +56,7 @@ enum ofono_error_type {
|
||||
OFONO_ERROR_TYPE_CEER,
|
||||
OFONO_ERROR_TYPE_SIM,
|
||||
OFONO_ERROR_TYPE_FAILURE,
|
||||
OFONO_ERROR_TYPE_ERRNO
|
||||
};
|
||||
|
||||
enum ofono_disconnect_reason {
|
||||
@@ -70,16 +71,6 @@ struct ofono_error {
|
||||
int error;
|
||||
};
|
||||
|
||||
#define OFONO_EINVAL(error) do { \
|
||||
error->type = OFONO_ERROR_TYPE_FAILURE; \
|
||||
error->error = -EINVAL; \
|
||||
} while (0)
|
||||
|
||||
#define OFONO_NO_ERROR(error) do { \
|
||||
error->type = OFONO_ERROR_TYPE_NO_ERROR; \
|
||||
error->error = 0; \
|
||||
} while (0)
|
||||
|
||||
#define OFONO_MAX_PHONE_NUMBER_LENGTH 80
|
||||
#define OFONO_MAX_CALLER_NAME_LENGTH 80
|
||||
|
||||
|
||||
128
ofono/include/voicecall-filter.h
Normal file
128
ofono/include/voicecall-filter.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_VOICECALL_FILTER_H
|
||||
#define __OFONO_VOICECALL_FILTER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <ofono/voicecall.h>
|
||||
|
||||
/* 27.007 Section 7.6 */
|
||||
enum ofono_clip_validity {
|
||||
OFONO_CLIP_VALIDITY_VALID = 0,
|
||||
OFONO_CLIP_VALIDITY_WITHHELD,
|
||||
OFONO_CLIP_VALIDITY_NOT_AVAILABLE
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.18 */
|
||||
enum ofono_call_status {
|
||||
OFONO_CALL_STATUS_ACTIVE = 0,
|
||||
OFONO_CALL_STATUS_HELD,
|
||||
OFONO_CALL_STATUS_DIALING,
|
||||
OFONO_CALL_STATUS_ALERTING,
|
||||
OFONO_CALL_STATUS_INCOMING,
|
||||
OFONO_CALL_STATUS_WAITING,
|
||||
OFONO_CALL_STATUS_DISCONNECTED
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.18 */
|
||||
enum ofono_call_direction {
|
||||
OFONO_CALL_DIRECTION_MOBILE_ORIGINATED = 0,
|
||||
OFONO_CALL_DIRECTION_MOBILE_TERMINATED
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.30 */
|
||||
enum ofono_cnap_validity {
|
||||
OFONO_CNAP_VALIDITY_VALID = 0,
|
||||
OFONO_CNAP_VALIDITY_WITHHELD,
|
||||
OFONO_CNAP_VALIDITY_NOT_AVAILABLE
|
||||
};
|
||||
|
||||
enum ofono_voicecall_filter_dial_result {
|
||||
OFONO_VOICECALL_FILTER_DIAL_CONTINUE, /* Run the next filter */
|
||||
OFONO_VOICECALL_FILTER_DIAL_BLOCK /* Don't dial*/
|
||||
};
|
||||
|
||||
enum ofono_voicecall_filter_incoming_result {
|
||||
OFONO_VOICECALL_FILTER_INCOMING_CONTINUE, /* Run the next filter */
|
||||
OFONO_VOICECALL_FILTER_INCOMING_HANGUP, /* Hangup incoming call */
|
||||
OFONO_VOICECALL_FILTER_INCOMING_IGNORE /* Ignore incoming call */
|
||||
};
|
||||
|
||||
typedef void (*ofono_voicecall_filter_dial_cb_t)
|
||||
(enum ofono_voicecall_filter_dial_result result,
|
||||
void *data);
|
||||
|
||||
typedef void (*ofono_voicecall_filter_incoming_cb_t)
|
||||
(enum ofono_voicecall_filter_incoming_result result,
|
||||
void *data);
|
||||
|
||||
#define OFONO_VOICECALL_FILTER_PRIORITY_LOW (-100)
|
||||
#define OFONO_VOICECALL_FILTER_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_VOICECALL_FILTER_PRIORITY_HIGH (100)
|
||||
|
||||
/*
|
||||
* The api_version field makes it possible to keep using old plugins
|
||||
* even if struct ofono_voicecall_filter gets extended with new callbacks.
|
||||
*/
|
||||
|
||||
#define OFONO_VOICECALL_FILTER_API_VERSION (0)
|
||||
|
||||
/*
|
||||
* The filter callbacks either invoke the completion callback directly
|
||||
* or return the id of the cancellable asynchronous operation (but never
|
||||
* both). If non-zero value is returned, the completion callback has to
|
||||
* be invoked later on a fresh stack. Once the asynchronous filtering
|
||||
* operation is cancelled, the associated completion callback must not
|
||||
* be invoked.
|
||||
*
|
||||
* Please avoid making blocking D-Bus calls from the filter callbacks.
|
||||
*/
|
||||
struct ofono_voicecall_filter {
|
||||
const char *name;
|
||||
int api_version; /* OFONO_VOICECALL_FILTER_API_VERSION */
|
||||
int priority;
|
||||
void (*filter_cancel)(unsigned int id);
|
||||
unsigned int (*filter_dial)(struct ofono_voicecall *vc,
|
||||
const struct ofono_phone_number *number,
|
||||
enum ofono_clir_option clir,
|
||||
ofono_voicecall_filter_dial_cb_t cb,
|
||||
void *data);
|
||||
unsigned int (*filter_incoming)(struct ofono_voicecall *vc,
|
||||
const struct ofono_call *call,
|
||||
ofono_voicecall_filter_incoming_cb_t cb,
|
||||
void *data);
|
||||
};
|
||||
|
||||
void ofono_voicecall_filter_notify(struct ofono_voicecall *vc);
|
||||
int ofono_voicecall_filter_register(const struct ofono_voicecall_filter *f);
|
||||
void ofono_voicecall_filter_unregister(const struct ofono_voicecall_filter *f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_VOICECALL_FILTER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -153,6 +153,8 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id,
|
||||
*/
|
||||
void ofono_voicecall_mpty_hint(struct ofono_voicecall *vc, unsigned int ids);
|
||||
|
||||
struct ofono_modem *ofono_voicecall_get_modem(struct ofono_voicecall *vc);
|
||||
|
||||
int ofono_voicecall_driver_register(const struct ofono_voicecall_driver *d);
|
||||
void ofono_voicecall_driver_unregister(const struct ofono_voicecall_driver *d);
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ static DBusMessage *push_notification_register_agent(DBusConnection *conn,
|
||||
DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (!__ofono_dbus_valid_object_path(agent_path))
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
pn->agent = sms_agent_new(AGENT_INTERFACE,
|
||||
|
||||
@@ -461,6 +461,8 @@ static void sailfish_watch_set_modem(struct sailfish_watch *self,
|
||||
if (modem) {
|
||||
sailfish_watch_setup_modem(self);
|
||||
}
|
||||
sailfish_watch_online_update(self,
|
||||
ofono_modem_get_online(self->modem));
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ static DBusMessage *smart_messaging_register_agent(DBusConnection *conn,
|
||||
DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (!__ofono_dbus_valid_object_path(agent_path))
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
sm->agent = sms_agent_new(AGENT_INTERFACE,
|
||||
|
||||
@@ -56,7 +56,7 @@ static void __ofono_dbus_queue_req_complete
|
||||
(struct ofono_dbus_queue_request *req,
|
||||
ofono_dbus_cb_t fn, void *param)
|
||||
{
|
||||
DBusMessage *reply = fn(req->msg, param);
|
||||
DBusMessage *reply = fn ? fn(req->msg, param) : NULL;
|
||||
|
||||
if (!reply)
|
||||
reply = __ofono_error_failed(req->msg);
|
||||
@@ -129,11 +129,13 @@ void __ofono_dbus_queue_reply_msg(struct ofono_dbus_queue *q,
|
||||
|
||||
if (!q || !q->requests) {
|
||||
/* This should never happen */
|
||||
dbus_message_unref(reply);
|
||||
if (reply) {
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* De-queue the request */
|
||||
/* De-queue one request */
|
||||
done = q->requests;
|
||||
next = done->next;
|
||||
q->requests = next;
|
||||
@@ -148,8 +150,19 @@ void __ofono_dbus_queue_reply_msg(struct ofono_dbus_queue *q,
|
||||
__ofono_dbus_queue_req_free(done);
|
||||
|
||||
/* Submit the next request if there is any */
|
||||
if (next) {
|
||||
next->fn(next->msg, next->data);
|
||||
while (next && reply) {
|
||||
reply = next->fn(next->msg, next->data);
|
||||
if (reply) {
|
||||
/* The request has completed synchronously */
|
||||
done = next;
|
||||
next = done->next;
|
||||
q->requests = next;
|
||||
done->next = NULL;
|
||||
|
||||
/* Send the reply */
|
||||
__ofono_dbus_pending_reply(&done->msg, reply);
|
||||
__ofono_dbus_queue_req_free(done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +203,8 @@ void __ofono_dbus_queue_reply_all_fn(struct ofono_dbus_queue *q,
|
||||
ofono_dbus_reply_cb_t fn)
|
||||
{
|
||||
__ofono_dbus_queue_reply_all_fn_param(q,
|
||||
__ofono_dbus_queue_reply_all_wrapper, fn);
|
||||
__ofono_dbus_queue_reply_all_wrapper,
|
||||
fn ? fn : __ofono_error_failed);
|
||||
}
|
||||
|
||||
void __ofono_dbus_queue_reply_all_fn_param(struct ofono_dbus_queue *q,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <errno.h>
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
@@ -37,7 +38,7 @@ struct error_mapping_entry {
|
||||
DBusMessage *(*ofono_error_func)(DBusMessage *);
|
||||
};
|
||||
|
||||
struct error_mapping_entry cme_errors_mapping[] = {
|
||||
static const struct error_mapping_entry cme_errors_mapping[] = {
|
||||
{ 3, __ofono_error_not_allowed },
|
||||
{ 4, __ofono_error_not_supported },
|
||||
{ 16, __ofono_error_incorrect_password },
|
||||
@@ -45,6 +46,16 @@ struct error_mapping_entry cme_errors_mapping[] = {
|
||||
{ 31, __ofono_error_timed_out },
|
||||
{ 32, __ofono_error_access_denied },
|
||||
{ 50, __ofono_error_invalid_args },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct error_mapping_entry errno_errors_mapping[] = {
|
||||
{ EACCES, __ofono_error_access_denied },
|
||||
{ EOPNOTSUPP, __ofono_error_not_supported },
|
||||
{ ENOSYS, __ofono_error_not_implemented },
|
||||
{ ETIMEDOUT, __ofono_error_timed_out },
|
||||
{ EINPROGRESS, __ofono_error_busy },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void append_variant(DBusMessageIter *iter,
|
||||
@@ -419,26 +430,31 @@ DBusMessage *__ofono_error_network_terminated(DBusMessage *msg)
|
||||
" network");
|
||||
}
|
||||
|
||||
static DBusMessage *__ofono_map_error(const struct error_mapping_entry *map,
|
||||
int error, DBusMessage *msg)
|
||||
{
|
||||
const struct error_mapping_entry *e;
|
||||
|
||||
for (e = map; e->ofono_error_func; e++)
|
||||
if (e->error == error)
|
||||
return e->ofono_error_func(msg);
|
||||
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
DBusMessage *__ofono_error_from_error(const struct ofono_error *error,
|
||||
DBusMessage *msg)
|
||||
{
|
||||
struct error_mapping_entry *e;
|
||||
int maxentries;
|
||||
int i;
|
||||
|
||||
switch (error->type) {
|
||||
case OFONO_ERROR_TYPE_CME:
|
||||
e = cme_errors_mapping;
|
||||
maxentries = sizeof(cme_errors_mapping) /
|
||||
sizeof(struct error_mapping_entry);
|
||||
for (i = 0; i < maxentries; i++)
|
||||
if (e[i].error == error->error)
|
||||
return e[i].ofono_error_func(msg);
|
||||
break;
|
||||
return __ofono_map_error(cme_errors_mapping, error->error, msg);
|
||||
case OFONO_ERROR_TYPE_CMS:
|
||||
return __ofono_error_failed(msg);
|
||||
case OFONO_ERROR_TYPE_CEER:
|
||||
return __ofono_error_failed(msg);
|
||||
case OFONO_ERROR_TYPE_ERRNO:
|
||||
return __ofono_map_error(errno_errors_mapping,
|
||||
ABS(error->error), msg);
|
||||
default:
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
@@ -456,50 +472,6 @@ void __ofono_dbus_pending_reply(DBusMessage **msg, DBusMessage *reply)
|
||||
*msg = NULL;
|
||||
}
|
||||
|
||||
gboolean __ofono_dbus_valid_object_path(const char *path)
|
||||
{
|
||||
unsigned int i;
|
||||
char c = '\0';
|
||||
|
||||
if (path == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (path[0] == '\0')
|
||||
return FALSE;
|
||||
|
||||
if (path[0] && !path[1] && path[0] == '/')
|
||||
return TRUE;
|
||||
|
||||
if (path[0] != '/')
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; path[i]; i++) {
|
||||
if (path[i] == '/' && c == '/')
|
||||
return FALSE;
|
||||
|
||||
c = path[i];
|
||||
|
||||
if (path[i] >= 'a' && path[i] <= 'z')
|
||||
continue;
|
||||
|
||||
if (path[i] >= 'A' && path[i] <= 'Z')
|
||||
continue;
|
||||
|
||||
if (path[i] >= '0' && path[i] <= '9')
|
||||
continue;
|
||||
|
||||
if (path[i] == '_' || path[i] == '/')
|
||||
continue;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (path[i-1] == '/')
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DBusConnection *ofono_dbus_get_connection(void)
|
||||
{
|
||||
return g_connection;
|
||||
|
||||
@@ -1347,6 +1347,7 @@ void ofono_emulator_send_final(struct ofono_emulator *em,
|
||||
case OFONO_ERROR_TYPE_CEER:
|
||||
case OFONO_ERROR_TYPE_SIM:
|
||||
case OFONO_ERROR_TYPE_FAILURE:
|
||||
case OFONO_ERROR_TYPE_ERRNO:
|
||||
failure:
|
||||
g_at_server_send_final(em->server, G_AT_SERVER_RESULT_ERROR);
|
||||
break;
|
||||
|
||||
@@ -135,7 +135,7 @@ static DBusMessage *gnss_register_agent(DBusConnection *conn,
|
||||
&agent_path, DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (!__ofono_dbus_valid_object_path(agent_path))
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
gnss->posr_agent = gnss_agent_new(agent_path,
|
||||
|
||||
548
ofono/src/gprs-filter.c
Normal file
548
ofono/src/gprs-filter.c
Normal file
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
struct gprs_filter_request;
|
||||
struct gprs_filter_request_fn {
|
||||
const char *name;
|
||||
gboolean (*can_process)(const struct ofono_gprs_filter *filter);
|
||||
guint (*process)(const struct ofono_gprs_filter *filter,
|
||||
struct gprs_filter_request *req);
|
||||
void (*complete)(struct gprs_filter_request *req, gboolean allow);
|
||||
void (*free)(struct gprs_filter_request *req);
|
||||
};
|
||||
|
||||
struct gprs_filter_request {
|
||||
int refcount;
|
||||
struct gprs_filter_chain *chain;
|
||||
struct ofono_gprs_context *gc;
|
||||
const struct gprs_filter_request_fn *fn;
|
||||
GSList *filter_link;
|
||||
guint pending_id;
|
||||
guint next_id;
|
||||
ofono_destroy_func destroy;
|
||||
void* user_data;
|
||||
};
|
||||
|
||||
struct gprs_filter_request_activate {
|
||||
struct gprs_filter_request req;
|
||||
struct ofono_gprs_primary_context ctx;
|
||||
gprs_filter_activate_cb_t cb;
|
||||
};
|
||||
|
||||
struct gprs_filter_request_check {
|
||||
struct gprs_filter_request req;
|
||||
ofono_gprs_filter_check_cb_t cb;
|
||||
};
|
||||
|
||||
struct gprs_filter_chain {
|
||||
struct ofono_gprs *gprs;
|
||||
GSList *req_list;
|
||||
};
|
||||
|
||||
static GSList *gprs_filter_list = NULL;
|
||||
|
||||
static void gprs_filter_request_init(struct gprs_filter_request *req,
|
||||
const struct gprs_filter_request_fn *fn,
|
||||
struct gprs_filter_chain *chain, struct ofono_gprs_context *gc,
|
||||
ofono_destroy_func destroy, void *user_data)
|
||||
{
|
||||
req->chain = chain;
|
||||
req->fn = fn;
|
||||
req->gc = gc;
|
||||
req->filter_link = gprs_filter_list;
|
||||
req->destroy = destroy;
|
||||
req->user_data = user_data;
|
||||
|
||||
/*
|
||||
* The list holds an implicit reference to the message. The reference
|
||||
* is released by gprs_filter_request_free when the message is removed
|
||||
* from the list.
|
||||
*/
|
||||
req->refcount = 1;
|
||||
chain->req_list = g_slist_append(chain->req_list, req);
|
||||
}
|
||||
|
||||
static void gprs_filter_request_cancel(struct gprs_filter_request *req)
|
||||
{
|
||||
if (req->pending_id) {
|
||||
const struct ofono_gprs_filter *f = req->filter_link->data;
|
||||
|
||||
/*
|
||||
* If the filter returns id of the pending operation,
|
||||
* then it must provide the cancel callback
|
||||
*/
|
||||
f->cancel(req->pending_id);
|
||||
req->pending_id = 0;
|
||||
}
|
||||
if (req->next_id) {
|
||||
g_source_remove(req->next_id);
|
||||
req->next_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void gprs_filter_request_dispose(struct gprs_filter_request *req)
|
||||
{
|
||||
/* May be invoked several times per request */
|
||||
if (req->destroy) {
|
||||
ofono_destroy_func destroy = req->destroy;
|
||||
|
||||
req->destroy = NULL;
|
||||
destroy(req->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void gprs_filter_request_free(struct gprs_filter_request *req)
|
||||
{
|
||||
gprs_filter_request_dispose(req);
|
||||
req->fn->free(req);
|
||||
}
|
||||
|
||||
#define gprs_filter_request_ref(req) ((req)->refcount++, req)
|
||||
|
||||
static int gprs_filter_request_unref(struct gprs_filter_request *req)
|
||||
{
|
||||
const int refcount = --(req->refcount);
|
||||
|
||||
if (!refcount) {
|
||||
gprs_filter_request_free(req);
|
||||
}
|
||||
return refcount;
|
||||
}
|
||||
|
||||
static void gprs_filter_request_free1(gpointer data)
|
||||
{
|
||||
struct gprs_filter_request *req = data;
|
||||
|
||||
/*
|
||||
* This is a g_slist_free_full() callback for use by
|
||||
* __ofono_gprs_filter_chain_free(), meaning that the
|
||||
* chain is no more. Zero the pointer to it in case if
|
||||
* this is not the last reference.
|
||||
*/
|
||||
req->chain = NULL;
|
||||
gprs_filter_request_unref(req);
|
||||
}
|
||||
|
||||
static void gprs_filter_request_dequeue(struct gprs_filter_request *req)
|
||||
{
|
||||
struct gprs_filter_chain *chain = req->chain;
|
||||
GSList *l;
|
||||
|
||||
/*
|
||||
* Single-linked list is not particularly good at searching
|
||||
* and removing the elements but since it should be pretty
|
||||
* short (typically just one request), it's not worth optimization.
|
||||
*/
|
||||
if (chain && (l = g_slist_find(chain->req_list, req)) != NULL) {
|
||||
gprs_filter_request_free1(l->data);
|
||||
chain->req_list = g_slist_delete_link(chain->req_list, l);
|
||||
}
|
||||
}
|
||||
|
||||
static void gprs_filter_request_complete(struct gprs_filter_request *req,
|
||||
gboolean allow)
|
||||
{
|
||||
gprs_filter_request_ref(req);
|
||||
req->fn->complete(req, allow);
|
||||
gprs_filter_request_dispose(req);
|
||||
gprs_filter_request_dequeue(req);
|
||||
gprs_filter_request_unref(req);
|
||||
}
|
||||
|
||||
static void gprs_filter_request_process(struct gprs_filter_request *req)
|
||||
{
|
||||
GSList *l = req->filter_link;
|
||||
const struct ofono_gprs_filter *f = l->data;
|
||||
const struct gprs_filter_request_fn *fn = req->fn;
|
||||
|
||||
while (f && !fn->can_process(f)) {
|
||||
l = l->next;
|
||||
f = l ? l->data : NULL;
|
||||
}
|
||||
|
||||
gprs_filter_request_ref(req);
|
||||
if (f) {
|
||||
req->filter_link = l;
|
||||
req->pending_id = fn->process(f, req);
|
||||
} else {
|
||||
gprs_filter_request_complete(req, TRUE);
|
||||
}
|
||||
gprs_filter_request_unref(req);
|
||||
}
|
||||
|
||||
static void gprs_filter_request_next(struct gprs_filter_request *req,
|
||||
GSourceFunc fn)
|
||||
{
|
||||
req->pending_id = 0;
|
||||
req->next_id = g_idle_add(fn, req);
|
||||
}
|
||||
|
||||
static gboolean gprs_filter_request_continue_cb(gpointer data)
|
||||
{
|
||||
struct gprs_filter_request *req = data;
|
||||
|
||||
req->next_id = 0;
|
||||
req->filter_link = req->filter_link->next;
|
||||
if (req->filter_link) {
|
||||
gprs_filter_request_process(req);
|
||||
} else {
|
||||
gprs_filter_request_complete(req, TRUE);
|
||||
}
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean gprs_filter_request_disallow_cb(gpointer data)
|
||||
{
|
||||
struct gprs_filter_request *req = data;
|
||||
|
||||
req->next_id = 0;
|
||||
gprs_filter_request_complete(req, FALSE);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* gprs_filter_request_activate
|
||||
*==========================================================================*/
|
||||
|
||||
static void gprs_filter_copy_context(struct ofono_gprs_primary_context *dest,
|
||||
const struct ofono_gprs_primary_context *src)
|
||||
{
|
||||
dest->cid = src->cid;
|
||||
dest->proto = src->proto;
|
||||
dest->auth_method = src->auth_method;
|
||||
strncpy(dest->apn, src->apn, OFONO_GPRS_MAX_APN_LENGTH);
|
||||
strncpy(dest->username, src->username, OFONO_GPRS_MAX_USERNAME_LENGTH);
|
||||
strncpy(dest->password, src->password, OFONO_GPRS_MAX_PASSWORD_LENGTH);
|
||||
dest->apn[OFONO_GPRS_MAX_APN_LENGTH] = 0;
|
||||
dest->username[OFONO_GPRS_MAX_USERNAME_LENGTH] = 0;
|
||||
dest->password[OFONO_GPRS_MAX_PASSWORD_LENGTH] = 0;
|
||||
}
|
||||
|
||||
static struct gprs_filter_request_activate *gprs_filter_request_activate_cast
|
||||
(struct gprs_filter_request *req)
|
||||
{
|
||||
return (struct gprs_filter_request_activate *)req;
|
||||
}
|
||||
|
||||
static gboolean gprs_filter_request_activate_can_process
|
||||
(const struct ofono_gprs_filter *f)
|
||||
{
|
||||
return f->filter_activate != NULL;
|
||||
}
|
||||
|
||||
static void gprs_filter_request_activate_cb
|
||||
(const struct ofono_gprs_primary_context *ctx, void *data)
|
||||
{
|
||||
struct gprs_filter_request_activate *act = data;
|
||||
struct gprs_filter_request *req = &act->req;
|
||||
const struct ofono_gprs_filter *filter = req->filter_link->data;
|
||||
|
||||
if (ctx) {
|
||||
if (ctx != &act->ctx) {
|
||||
/* The filter may have updated context settings */
|
||||
gprs_filter_copy_context(&act->ctx, ctx);
|
||||
}
|
||||
gprs_filter_request_next(req, gprs_filter_request_continue_cb);
|
||||
} else {
|
||||
DBG("%s not allowing to activate mobile data", filter->name);
|
||||
gprs_filter_request_next(req, gprs_filter_request_disallow_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static guint gprs_filter_request_activate_process
|
||||
(const struct ofono_gprs_filter *f,
|
||||
struct gprs_filter_request *req)
|
||||
{
|
||||
struct gprs_filter_request_activate *act =
|
||||
gprs_filter_request_activate_cast(req);
|
||||
|
||||
return f->filter_activate(req->gc, &act->ctx,
|
||||
gprs_filter_request_activate_cb, act);
|
||||
}
|
||||
|
||||
static void gprs_filter_request_activate_complete
|
||||
(struct gprs_filter_request *req, gboolean allow)
|
||||
{
|
||||
struct gprs_filter_request_activate *act =
|
||||
gprs_filter_request_activate_cast(req);
|
||||
|
||||
act->cb(allow ? &act->ctx : NULL, req->user_data);
|
||||
}
|
||||
|
||||
static void gprs_filter_request_activate_free(struct gprs_filter_request *req)
|
||||
{
|
||||
g_slice_free1(sizeof(struct gprs_filter_request_activate), req);
|
||||
}
|
||||
|
||||
static struct gprs_filter_request *gprs_filter_request_activate_new
|
||||
(struct gprs_filter_chain *chain, struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
gprs_filter_activate_cb_t cb, ofono_destroy_func destroy,
|
||||
void *data)
|
||||
{
|
||||
static const struct gprs_filter_request_fn activate_fn = {
|
||||
.name = "activate",
|
||||
.can_process = gprs_filter_request_activate_can_process,
|
||||
.process = gprs_filter_request_activate_process,
|
||||
.complete = gprs_filter_request_activate_complete,
|
||||
.free = gprs_filter_request_activate_free
|
||||
};
|
||||
|
||||
struct gprs_filter_request_activate *act =
|
||||
g_slice_new0(struct gprs_filter_request_activate);
|
||||
struct gprs_filter_request *req = &act->req;
|
||||
|
||||
gprs_filter_request_init(req, &activate_fn, chain, gc, destroy, data);
|
||||
gprs_filter_copy_context(&act->ctx, ctx);
|
||||
act->cb = cb;
|
||||
return req;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* gprs_filter_request_check
|
||||
*==========================================================================*/
|
||||
|
||||
static struct gprs_filter_request_check *gprs_filter_request_check_cast
|
||||
(struct gprs_filter_request *req)
|
||||
{
|
||||
return (struct gprs_filter_request_check *)req;
|
||||
}
|
||||
|
||||
static gboolean gprs_filter_request_check_can_process
|
||||
(const struct ofono_gprs_filter *f)
|
||||
{
|
||||
return f->api_version >= 1 && f->filter_check != NULL;
|
||||
}
|
||||
|
||||
static void gprs_filter_request_check_cb(ofono_bool_t allow, void *data)
|
||||
{
|
||||
struct gprs_filter_request_check *check = data;
|
||||
struct gprs_filter_request *req = &check->req;
|
||||
const struct ofono_gprs_filter *filter = req->filter_link->data;
|
||||
|
||||
if (allow) {
|
||||
gprs_filter_request_next(req, gprs_filter_request_continue_cb);
|
||||
} else {
|
||||
DBG("%s not allowing mobile data", filter->name);
|
||||
gprs_filter_request_next(req, gprs_filter_request_disallow_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static guint gprs_filter_request_check_process
|
||||
(const struct ofono_gprs_filter *f,
|
||||
struct gprs_filter_request *req)
|
||||
{
|
||||
return f->filter_check(req->chain->gprs, gprs_filter_request_check_cb,
|
||||
gprs_filter_request_check_cast(req));
|
||||
}
|
||||
|
||||
static void gprs_filter_request_check_complete
|
||||
(struct gprs_filter_request *req, gboolean allow)
|
||||
{
|
||||
gprs_filter_request_check_cast(req)->cb(allow, req->user_data);
|
||||
}
|
||||
|
||||
static void gprs_filter_request_check_free(struct gprs_filter_request *req)
|
||||
{
|
||||
g_slice_free1(sizeof(struct gprs_filter_request_check), req);
|
||||
}
|
||||
|
||||
static struct gprs_filter_request *gprs_filter_request_check_new
|
||||
(struct gprs_filter_chain *chain, gprs_filter_check_cb_t cb,
|
||||
ofono_destroy_func destroy, void *data)
|
||||
{
|
||||
static const struct gprs_filter_request_fn check_fn = {
|
||||
.name = "check",
|
||||
.can_process = gprs_filter_request_check_can_process,
|
||||
.process = gprs_filter_request_check_process,
|
||||
.complete = gprs_filter_request_check_complete,
|
||||
.free = gprs_filter_request_check_free
|
||||
};
|
||||
|
||||
struct gprs_filter_request_check *check =
|
||||
g_slice_new0(struct gprs_filter_request_check);
|
||||
struct gprs_filter_request *req = &check->req;
|
||||
|
||||
gprs_filter_request_init(req, &check_fn, chain, NULL, destroy, data);
|
||||
check->cb = cb;
|
||||
return req;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* gprs_filter_chain
|
||||
*==========================================================================*/
|
||||
|
||||
struct gprs_filter_chain *__ofono_gprs_filter_chain_new(struct ofono_gprs *gp)
|
||||
{
|
||||
struct gprs_filter_chain *chain = NULL;
|
||||
|
||||
if (gp) {
|
||||
chain = g_new0(struct gprs_filter_chain, 1);
|
||||
chain->gprs = gp;
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
void __ofono_gprs_filter_chain_free(struct gprs_filter_chain *chain)
|
||||
{
|
||||
if (chain) {
|
||||
__ofono_gprs_filter_chain_cancel(chain, NULL);
|
||||
g_free(chain);
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain,
|
||||
struct ofono_gprs_context *gc)
|
||||
{
|
||||
if (chain) {
|
||||
GSList *l, *canceled;
|
||||
|
||||
/* Move canceled requests to a separate list */
|
||||
if (gc) {
|
||||
GSList *prev = NULL;
|
||||
|
||||
canceled = NULL;
|
||||
l = chain->req_list;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct gprs_filter_request *req = l->data;
|
||||
|
||||
if (req->gc == gc) {
|
||||
/* This one will get canceled */
|
||||
l->next = canceled;
|
||||
canceled = l;
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
} else {
|
||||
chain->req_list = next;
|
||||
}
|
||||
} else {
|
||||
/* This one survives */
|
||||
prev = l;
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
} else {
|
||||
/* Everything is getting canceled */
|
||||
canceled = chain->req_list;
|
||||
chain->req_list = NULL;
|
||||
}
|
||||
|
||||
/* Actually cancel each request */
|
||||
for (l = canceled; l; l = l->next) {
|
||||
gprs_filter_request_cancel(l->data);
|
||||
}
|
||||
|
||||
/* And deallocate them */
|
||||
g_slist_free_full(canceled, gprs_filter_request_free1);
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_gprs_filter_chain_activate(struct gprs_filter_chain *chain,
|
||||
struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
gprs_filter_activate_cb_t cb, ofono_destroy_func destroy,
|
||||
void *user_data)
|
||||
{
|
||||
if (chain && gprs_filter_list && ctx && cb) {
|
||||
gprs_filter_request_process
|
||||
(gprs_filter_request_activate_new(chain, gc, ctx,
|
||||
cb, destroy, user_data));
|
||||
} else {
|
||||
if (cb) {
|
||||
cb(ctx, user_data);
|
||||
}
|
||||
if (destroy) {
|
||||
destroy(user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_gprs_filter_chain_check(struct gprs_filter_chain *chain,
|
||||
gprs_filter_check_cb_t cb, ofono_destroy_func destroy,
|
||||
void *user_data)
|
||||
{
|
||||
if (chain && gprs_filter_list && cb) {
|
||||
gprs_filter_request_process
|
||||
(gprs_filter_request_check_new(chain, cb, destroy,
|
||||
user_data));
|
||||
} else {
|
||||
if (cb) {
|
||||
cb(TRUE, user_data);
|
||||
}
|
||||
if (destroy) {
|
||||
destroy(user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ofono_gprs_filter
|
||||
*==========================================================================*/
|
||||
|
||||
/**
|
||||
* Returns 0 if both are equal;
|
||||
* <0 if a comes before b;
|
||||
* >0 if a comes after b.
|
||||
*/
|
||||
static gint gprs_filter_sort(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ofono_gprs_filter *a_filter = a;
|
||||
const struct ofono_gprs_filter *b_filter = b;
|
||||
|
||||
if (a_filter->priority > b_filter->priority) {
|
||||
/* a comes before b */
|
||||
return -1;
|
||||
} else if (a_filter->priority < b_filter->priority) {
|
||||
/* a comes after b */
|
||||
return 1;
|
||||
} else {
|
||||
/* Whatever, as long as the sort is stable */
|
||||
return strcmp(a_filter->name, b_filter->name);
|
||||
}
|
||||
}
|
||||
|
||||
int ofono_gprs_filter_register(const struct ofono_gprs_filter *filter)
|
||||
{
|
||||
if (!filter || !filter->name) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DBG("%s", filter->name);
|
||||
gprs_filter_list = g_slist_insert_sorted(gprs_filter_list,
|
||||
(void*)filter, gprs_filter_sort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ofono_gprs_filter_unregister(const struct ofono_gprs_filter *filter)
|
||||
{
|
||||
if (filter) {
|
||||
DBG("%s", filter->name);
|
||||
gprs_filter_list = g_slist_remove(gprs_filter_list, filter);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
123
ofono/src/gprs.c
123
ofono/src/gprs.c
@@ -85,6 +85,7 @@ struct ofono_gprs {
|
||||
void *driver_data;
|
||||
struct ofono_atom *atom;
|
||||
unsigned int spn_watch;
|
||||
struct gprs_filter_chain *filters;
|
||||
};
|
||||
|
||||
struct ipv4_settings {
|
||||
@@ -136,7 +137,13 @@ struct pri_context {
|
||||
struct ofono_gprs *gprs;
|
||||
};
|
||||
|
||||
static void gprs_attached_update(struct ofono_gprs *gprs);
|
||||
/*
|
||||
* In Sailfish OS fork gprs_attached_update() is exported to plugins
|
||||
* as ofono_gprs_attached_update(). Exported functions must start
|
||||
* with ofono_ prefix.
|
||||
*/
|
||||
#define gprs_attached_update(gprs) ofono_gprs_attached_update(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,
|
||||
@@ -368,6 +375,9 @@ static void release_context(struct pri_context *ctx)
|
||||
if (ctx == NULL || ctx->gprs == NULL || ctx->context_driver == NULL)
|
||||
return;
|
||||
|
||||
__ofono_gprs_filter_chain_cancel(ctx->gprs->filters,
|
||||
ctx->context_driver);
|
||||
|
||||
gprs_cid_release(ctx->gprs, ctx->context.cid);
|
||||
ctx->context.cid = 0;
|
||||
ctx->context_driver->inuse = FALSE;
|
||||
@@ -1047,16 +1057,17 @@ static DBusMessage *pri_provision_context(DBusConnection *conn,
|
||||
for (i = 0; i < count; i++) {
|
||||
const struct ofono_gprs_provision_data *ap = settings + i;
|
||||
if (ap->type == ctx->type && ap_valid(ap)) {
|
||||
if ((!ctx->active &&
|
||||
!ctx->pending && !ctx->gprs->pending) ||
|
||||
!pri_deactivation_required(ctx, ap)) {
|
||||
if (ctx->pending || ctx->gprs->pending) {
|
||||
/* Context is being messed with */
|
||||
reply = __ofono_error_busy(msg);
|
||||
} else if (ctx->active &&
|
||||
pri_deactivation_required(ctx, ap)) {
|
||||
/* Context needs to be deactivated first */
|
||||
reply = __ofono_error_busy(msg);
|
||||
} else {
|
||||
/* Re-provision the context */
|
||||
pri_reset_context_properties(ctx, ap);
|
||||
reply = dbus_message_new_method_return(msg);
|
||||
} else {
|
||||
/* Context should be inactive */
|
||||
if (ctx->gprs->pending || ctx->pending)
|
||||
reply = __ofono_error_busy(msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1546,6 +1557,51 @@ static DBusMessage *pri_set_auth_method(struct pri_context *ctx,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pri_request_data {
|
||||
struct pri_context *pri;
|
||||
DBusMessage *msg;
|
||||
};
|
||||
|
||||
static struct pri_request_data *pri_request_new(struct pri_context *pri)
|
||||
{
|
||||
struct pri_request_data *data = g_new0(struct pri_request_data, 1);
|
||||
|
||||
data->pri = pri;
|
||||
data->msg = pri->pending;
|
||||
return data;
|
||||
}
|
||||
|
||||
static void pri_request_free(void *user_data)
|
||||
{
|
||||
struct pri_request_data *data = user_data;
|
||||
struct pri_context *pri = data->pri;
|
||||
|
||||
if (pri->pending && pri->pending == data->msg) {
|
||||
__ofono_dbus_pending_reply(&pri->pending,
|
||||
__ofono_error_canceled(pri->pending));
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void pri_activate_filt(const struct ofono_gprs_primary_context *ctx,
|
||||
void *user_data)
|
||||
{
|
||||
struct pri_request_data *data = user_data;
|
||||
struct pri_context *pri = data->pri;
|
||||
|
||||
data->msg = NULL;
|
||||
if (ctx) {
|
||||
struct ofono_gprs_context *gc = pri->context_driver;
|
||||
|
||||
gc->driver->activate_primary(gc, ctx, pri_activate_callback,
|
||||
pri);
|
||||
} else if (pri->pending != NULL) {
|
||||
__ofono_dbus_pending_reply(&pri->pending,
|
||||
__ofono_error_access_denied(pri->pending));
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *pri_set_property(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -1601,8 +1657,9 @@ static DBusMessage *pri_set_property(DBusConnection *conn,
|
||||
ctx->pending = dbus_message_ref(msg);
|
||||
|
||||
if (value)
|
||||
gc->driver->activate_primary(gc, &ctx->context,
|
||||
pri_activate_callback, ctx);
|
||||
__ofono_gprs_filter_chain_activate(gc->gprs->filters,
|
||||
gc, &ctx->context, pri_activate_filt,
|
||||
pri_request_free, pri_request_new(ctx));
|
||||
else
|
||||
gc->driver->deactivate_primary(gc, ctx->context.cid,
|
||||
pri_deactivate_callback, ctx);
|
||||
@@ -1886,14 +1943,8 @@ static void release_active_contexts(struct ofono_gprs *gprs)
|
||||
}
|
||||
}
|
||||
|
||||
static void gprs_attached_update(struct ofono_gprs *gprs)
|
||||
static void gprs_set_attached(struct ofono_gprs *gprs, ofono_bool_t attached)
|
||||
{
|
||||
ofono_bool_t attached;
|
||||
|
||||
attached = gprs->driver_attached &&
|
||||
(gprs->status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
|
||||
gprs->status == NETWORK_REGISTRATION_STATUS_ROAMING);
|
||||
|
||||
if (attached == gprs->attached)
|
||||
return;
|
||||
|
||||
@@ -1920,6 +1971,32 @@ static void gprs_attached_update(struct ofono_gprs *gprs)
|
||||
gprs_set_attached_property(gprs, attached);
|
||||
}
|
||||
|
||||
static void gprs_attached_check_cb(ofono_bool_t allow, void *user_data)
|
||||
{
|
||||
gprs_set_attached((struct ofono_gprs *)user_data, allow);
|
||||
}
|
||||
|
||||
void gprs_attached_update(struct ofono_gprs *gprs)
|
||||
{
|
||||
ofono_bool_t attached = gprs->driver_attached &&
|
||||
(gprs->status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
|
||||
gprs->status == NETWORK_REGISTRATION_STATUS_ROAMING);
|
||||
|
||||
if (!attached) {
|
||||
/* Cancel all other checks - nothing is allowed if we are
|
||||
* not attached */
|
||||
__ofono_gprs_filter_chain_cancel(gprs->filters, NULL);
|
||||
|
||||
/* We are done synchronously */
|
||||
gprs_set_attached(gprs, FALSE);
|
||||
} else {
|
||||
/* This implicitely cancels the previous check if it's still
|
||||
* running, so that we never have two simultanous checks. */
|
||||
__ofono_gprs_filter_chain_check(gprs->filters,
|
||||
gprs_attached_check_cb, NULL, gprs);
|
||||
}
|
||||
}
|
||||
|
||||
static void registration_status_cb(const struct ofono_error *error,
|
||||
int status, void *data)
|
||||
{
|
||||
@@ -1988,6 +2065,12 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
|
||||
|
||||
DBG("attach: %u, driver_attached: %u", attach, gprs->driver_attached);
|
||||
|
||||
/*
|
||||
* In Sailfish OS the Attached flag is used by connman to check
|
||||
* whether context activation is possible. There won't be any
|
||||
* context activation if Attached stays FALSE.
|
||||
*/
|
||||
#if 0
|
||||
if (ofono_netreg_get_technology(gprs->netreg) ==
|
||||
ACCESS_TECHNOLOGY_EUTRAN)
|
||||
/*
|
||||
@@ -1995,6 +2078,7 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
|
||||
* context activation.
|
||||
*/
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (gprs->driver_attached == attach)
|
||||
return;
|
||||
@@ -3068,6 +3152,9 @@ static void gprs_context_remove(struct ofono_atom *atom)
|
||||
if (gc->driver && gc->driver->remove)
|
||||
gc->driver->remove(gc);
|
||||
|
||||
if (gc->gprs)
|
||||
__ofono_gprs_filter_chain_cancel(gc->gprs->filters, gc);
|
||||
|
||||
g_free(gc);
|
||||
}
|
||||
|
||||
@@ -3383,6 +3470,7 @@ static void gprs_remove(struct ofono_atom *atom)
|
||||
if (gprs->driver && gprs->driver->remove)
|
||||
gprs->driver->remove(gprs);
|
||||
|
||||
__ofono_gprs_filter_chain_free(gprs->filters);
|
||||
g_free(gprs);
|
||||
}
|
||||
|
||||
@@ -3419,6 +3507,7 @@ struct ofono_gprs *ofono_gprs_create(struct ofono_modem *modem,
|
||||
gprs->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
gprs->netreg_status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
gprs->pid_map = idmap_new(MAX_CONTEXTS);
|
||||
gprs->filters = __ofono_gprs_filter_chain_new(gprs);
|
||||
|
||||
return gprs;
|
||||
}
|
||||
|
||||
@@ -190,6 +190,16 @@ struct ofono_sim *ofono_modem_get_sim(struct ofono_modem *modem)
|
||||
return __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
|
||||
}
|
||||
|
||||
struct ofono_gprs *ofono_modem_get_gprs(struct ofono_modem *modem)
|
||||
{
|
||||
return __ofono_atom_find(OFONO_ATOM_TYPE_GPRS, modem);
|
||||
}
|
||||
|
||||
struct ofono_voicecall *ofono_modem_get_voicecall(struct ofono_modem *modem)
|
||||
{
|
||||
return __ofono_atom_find(OFONO_ATOM_TYPE_VOICECALL, modem);
|
||||
}
|
||||
|
||||
struct ofono_atom *__ofono_modem_add_atom(struct ofono_modem *modem,
|
||||
enum ofono_atom_type type,
|
||||
void (*destruct)(struct ofono_atom *),
|
||||
@@ -1882,7 +1892,7 @@ struct ofono_modem *ofono_modem_create(const char *name, const char *type)
|
||||
else
|
||||
snprintf(path, sizeof(path), "/%s", name);
|
||||
|
||||
if (__ofono_dbus_valid_object_path(path) == FALSE)
|
||||
if (!dbus_validate_path(path, NULL))
|
||||
return NULL;
|
||||
|
||||
modem = g_try_new0(struct ofono_modem, 1);
|
||||
|
||||
@@ -353,7 +353,7 @@ static DBusMessage *netmon_register_agent(DBusConnection *conn,
|
||||
DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (!__ofono_dbus_valid_object_path(agent_path))
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
if (!period)
|
||||
|
||||
@@ -77,8 +77,6 @@ DBusMessage *__ofono_error_from_error(const struct ofono_error *error,
|
||||
|
||||
void __ofono_dbus_pending_reply(DBusMessage **msg, DBusMessage *reply);
|
||||
|
||||
gboolean __ofono_dbus_valid_object_path(const char *path);
|
||||
|
||||
struct ofono_watchlist_item {
|
||||
unsigned int id;
|
||||
void *notify;
|
||||
@@ -592,6 +590,51 @@ void __ofono_sms_filter_chain_recv_text(struct sms_filter_chain *chain,
|
||||
const struct sms_scts *scts,
|
||||
sms_dispatch_recv_text_cb_t default_handler);
|
||||
|
||||
#include <ofono/gprs-filter.h>
|
||||
|
||||
struct gprs_filter_chain;
|
||||
|
||||
typedef void (*gprs_filter_activate_cb_t)
|
||||
(const struct ofono_gprs_primary_context *ctx, void *user_data);
|
||||
typedef void (*gprs_filter_check_cb_t)(ofono_bool_t allow, void *user_data);
|
||||
struct gprs_filter_chain *__ofono_gprs_filter_chain_new(struct ofono_gprs *gp);
|
||||
void __ofono_gprs_filter_chain_free(struct gprs_filter_chain *chain);
|
||||
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain,
|
||||
struct ofono_gprs_context *gc);
|
||||
void __ofono_gprs_filter_chain_activate(struct gprs_filter_chain *chain,
|
||||
struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
gprs_filter_activate_cb_t act, ofono_destroy_func destroy,
|
||||
void *user_data);
|
||||
void __ofono_gprs_filter_chain_check(struct gprs_filter_chain *chain,
|
||||
gprs_filter_check_cb_t cb, ofono_destroy_func destroy,
|
||||
void *user_data);
|
||||
|
||||
#include <ofono/voicecall-filter.h>
|
||||
|
||||
struct voicecall_filter_chain;
|
||||
|
||||
struct voicecall_filter_chain *__ofono_voicecall_filter_chain_new
|
||||
(struct ofono_voicecall *vc);
|
||||
void __ofono_voicecall_filter_chain_cancel(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call);
|
||||
void __ofono_voicecall_filter_chain_restart(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call);
|
||||
void __ofono_voicecall_filter_chain_free(struct voicecall_filter_chain *c);
|
||||
void __ofono_voicecall_filter_chain_dial(struct voicecall_filter_chain *c,
|
||||
const struct ofono_phone_number *number,
|
||||
enum ofono_clir_option clir,
|
||||
ofono_voicecall_filter_dial_cb_t cb,
|
||||
ofono_destroy_func destroy, void *user_data);
|
||||
void __ofono_voicecall_filter_chain_dial_check(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call,
|
||||
ofono_voicecall_filter_dial_cb_t cb,
|
||||
ofono_destroy_func destroy, void *user_data);
|
||||
void __ofono_voicecall_filter_chain_incoming(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call,
|
||||
ofono_voicecall_filter_incoming_cb_t cb,
|
||||
ofono_destroy_func destroy, void *user_data);
|
||||
|
||||
#include <ofono/sim-mnclength.h>
|
||||
|
||||
int __ofono_sim_mnclength_get_mnclength(const char *imsi);
|
||||
|
||||
@@ -428,7 +428,6 @@ static void export_phonebook_cb(const struct ofono_error *error, void *data)
|
||||
g_slist_foreach(phonebook->merge_list, print_merged_entry,
|
||||
phonebook->vcards);
|
||||
g_slist_free_full(phonebook->merge_list, destroy_merged_entry);
|
||||
g_slist_free(phonebook->merge_list);
|
||||
phonebook->merge_list = NULL;
|
||||
|
||||
phonebook->storage_index++;
|
||||
|
||||
@@ -211,17 +211,26 @@ void __ofono_plugin_cleanup(void)
|
||||
|
||||
DBG("");
|
||||
|
||||
/*
|
||||
* Terminate the plugins but don't unload the libraries yet.
|
||||
* Plugins may reference data structures allocated by each other.
|
||||
*/
|
||||
for (list = plugins; list; list = list->next) {
|
||||
struct ofono_plugin *plugin = list->data;
|
||||
|
||||
if (plugin->active == TRUE && plugin->desc->exit)
|
||||
plugin->desc->exit();
|
||||
}
|
||||
|
||||
/* Second pass - unload the libraries */
|
||||
for (list = plugins; list; list = list->next) {
|
||||
struct ofono_plugin *plugin = list->data;
|
||||
|
||||
if (plugin->handle)
|
||||
dlclose(plugin->handle);
|
||||
|
||||
g_free(plugin);
|
||||
}
|
||||
|
||||
g_slist_free(plugins);
|
||||
/* Finally, free the memory */
|
||||
g_slist_free_full(plugins, g_free);
|
||||
plugins = NULL;
|
||||
}
|
||||
|
||||
78
ofono/src/ril-transport.c
Normal file
78
ofono/src/ril-transport.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ofono/ril-transport.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
static GSList *ril_transports = NULL;
|
||||
|
||||
struct grilio_transport *ofono_ril_transport_connect(const char *name,
|
||||
GHashTable *params)
|
||||
{
|
||||
if (name) {
|
||||
GSList *l;
|
||||
|
||||
for (l = ril_transports; l; l = l->next) {
|
||||
const struct ofono_ril_transport *t = l->data;
|
||||
|
||||
if (!strcmp(name, t->name)) {
|
||||
return t->connect ? t->connect(params) : NULL;
|
||||
}
|
||||
}
|
||||
ofono_error("Unknown RIL transport: %s", name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ofono_ril_transport_register(const struct ofono_ril_transport *t)
|
||||
{
|
||||
if (!t || !t->name) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
GSList *l;
|
||||
|
||||
for (l = ril_transports; l; l = l->next) {
|
||||
const struct ofono_ril_transport *t1 = l->data;
|
||||
|
||||
if (!strcmp(t->name, t1->name)) {
|
||||
DBG("%s already registered", t->name);
|
||||
return -EALREADY;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("%s", t->name);
|
||||
ril_transports = g_slist_append(ril_transports, (void*)t);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ofono_ril_transport_unregister(const struct ofono_ril_transport *t)
|
||||
{
|
||||
if (t && t->name) {
|
||||
DBG("%s", t->name);
|
||||
ril_transports = g_slist_remove(ril_transports, t);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -722,7 +722,7 @@ static DBusMessage *stk_register_agent(DBusConnection *conn,
|
||||
DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (!__ofono_dbus_valid_object_path(agent_path))
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
stk->default_agent = stk_agent_new(agent_path,
|
||||
@@ -839,7 +839,7 @@ static DBusMessage *stk_select_item(DBusConnection *conn,
|
||||
DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (!__ofono_dbus_valid_object_path(agent_path))
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
for (i = 0; i < selection && menu->items[i].text; i++);
|
||||
|
||||
@@ -417,13 +417,18 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
|
||||
}
|
||||
|
||||
if (status == OFONO_USSD_STATUS_TERMINATED) {
|
||||
ussd_change_state(ussd, USSD_STATE_IDLE);
|
||||
if (ussd->state == USSD_STATE_ACTIVE && data && data_len > 0) {
|
||||
/* Interpret that as a Notify */
|
||||
status = OFONO_USSD_STATUS_NOTIFY;
|
||||
} else {
|
||||
ussd_change_state(ussd, USSD_STATE_IDLE);
|
||||
|
||||
if (ussd->pending == NULL)
|
||||
return;
|
||||
if (ussd->pending == NULL)
|
||||
return;
|
||||
|
||||
reply = __ofono_error_network_terminated(ussd->pending);
|
||||
goto out;
|
||||
reply = __ofono_error_network_terminated(ussd->pending);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == OFONO_USSD_STATUS_NOT_SUPPORTED) {
|
||||
@@ -808,6 +813,22 @@ static void ussd_unregister(struct ofono_atom *atom)
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(atom);
|
||||
const char *path = __ofono_atom_get_path(atom);
|
||||
DBusMessage *reply;
|
||||
|
||||
if (ussd->pending) {
|
||||
reply = __ofono_error_canceled(ussd->pending);
|
||||
__ofono_dbus_pending_reply(&ussd->pending, reply);
|
||||
}
|
||||
|
||||
if (ussd->cancel) {
|
||||
reply = dbus_message_new_method_return(ussd->cancel);
|
||||
__ofono_dbus_pending_reply(&ussd->cancel, reply);
|
||||
}
|
||||
|
||||
if (ussd->req)
|
||||
ussd_request_finish(ussd, -ECANCELED, 0, NULL, 0);
|
||||
|
||||
ussd_change_state(ussd, USSD_STATE_IDLE);
|
||||
|
||||
g_slist_free_full(ussd->ss_control_list, ssc_entry_destroy);
|
||||
ussd->ss_control_list = NULL;
|
||||
|
||||
662
ofono/src/voicecall-filter.c
Normal file
662
ofono/src/voicecall-filter.c
Normal file
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
struct voicecall_filter_request;
|
||||
struct voicecall_filter_request_fn {
|
||||
const char *name;
|
||||
gboolean (*can_process)(const struct ofono_voicecall_filter *filter);
|
||||
guint (*process)(const struct ofono_voicecall_filter *filter,
|
||||
struct voicecall_filter_request *req);
|
||||
void (*allow)(struct voicecall_filter_request *req);
|
||||
void (*free)(struct voicecall_filter_request *req);
|
||||
};
|
||||
|
||||
struct voicecall_filter_request {
|
||||
int refcount;
|
||||
const struct voicecall_filter_request_fn *fn;
|
||||
const struct ofono_call *call;
|
||||
struct voicecall_filter_chain *chain;
|
||||
GSList *filter_link;
|
||||
guint pending_id;
|
||||
guint next_id;
|
||||
ofono_destroy_func destroy;
|
||||
void* user_data;
|
||||
};
|
||||
|
||||
struct voicecall_filter_request_dial {
|
||||
struct voicecall_filter_request req;
|
||||
const struct ofono_phone_number *number;
|
||||
enum ofono_clir_option clir;
|
||||
ofono_voicecall_filter_dial_cb_t cb;
|
||||
};
|
||||
|
||||
struct voicecall_filter_request_incoming {
|
||||
struct voicecall_filter_request req;
|
||||
ofono_voicecall_filter_incoming_cb_t cb;
|
||||
};
|
||||
|
||||
struct voicecall_filter_chain {
|
||||
struct ofono_voicecall *vc;
|
||||
GSList *req_list;
|
||||
};
|
||||
|
||||
static GSList *voicecall_filters = NULL;
|
||||
|
||||
static void voicecall_filter_request_init(struct voicecall_filter_request *req,
|
||||
const struct voicecall_filter_request_fn *fn,
|
||||
struct voicecall_filter_chain *chain, const struct ofono_call *call,
|
||||
ofono_destroy_func destroy, void *user_data)
|
||||
{
|
||||
req->fn = fn;
|
||||
req->chain = chain;
|
||||
req->call = call;
|
||||
req->filter_link = voicecall_filters;
|
||||
req->destroy = destroy;
|
||||
req->user_data = user_data;
|
||||
|
||||
/*
|
||||
* The list holds an implicit reference to the message. The reference
|
||||
* is released by voicecall_filter_request_free when the message is
|
||||
* removed from the list.
|
||||
*/
|
||||
req->refcount = 1;
|
||||
chain->req_list = g_slist_append(chain->req_list, req);
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_cancel
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
if (req->pending_id) {
|
||||
const struct ofono_voicecall_filter *f = req->filter_link->data;
|
||||
|
||||
/*
|
||||
* If the filter returns id of the pending operation,
|
||||
* then it must provide the cancel callback
|
||||
*/
|
||||
f->filter_cancel(req->pending_id);
|
||||
req->pending_id = 0;
|
||||
}
|
||||
if (req->next_id) {
|
||||
g_source_remove(req->next_id);
|
||||
req->next_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_dispose
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
/* May be invoked several times per request */
|
||||
if (req->destroy) {
|
||||
ofono_destroy_func destroy = req->destroy;
|
||||
|
||||
req->destroy = NULL;
|
||||
destroy(req->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_free(struct voicecall_filter_request *req)
|
||||
{
|
||||
voicecall_filter_request_dispose(req);
|
||||
req->fn->free(req);
|
||||
}
|
||||
|
||||
#define voicecall_filter_request_ref(req) ((req)->refcount++, req)
|
||||
|
||||
static int voicecall_filter_request_unref(struct voicecall_filter_request *req)
|
||||
{
|
||||
const int refcount = --(req->refcount);
|
||||
|
||||
if (!refcount) {
|
||||
voicecall_filter_request_free(req);
|
||||
}
|
||||
return refcount;
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_done(struct voicecall_filter_request *req)
|
||||
{
|
||||
/* Zero the pointer to it in case if this is not the last reference. */
|
||||
req->chain = NULL;
|
||||
voicecall_filter_request_unref(req);
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_dequeue
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
struct voicecall_filter_chain *chain = req->chain;
|
||||
GSList *l;
|
||||
|
||||
/*
|
||||
* Single-linked list is not particularly good at searching
|
||||
* and removing the elements but since it should be pretty
|
||||
* short (typically just one request), it's not worth optimization.
|
||||
*/
|
||||
if (chain && (l = g_slist_find(chain->req_list, req)) != NULL) {
|
||||
voicecall_filter_request_done(l->data);
|
||||
chain->req_list = g_slist_delete_link(chain->req_list, l);
|
||||
}
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_complete
|
||||
(struct voicecall_filter_request *req,
|
||||
void (*complete)(struct voicecall_filter_request *req))
|
||||
{
|
||||
voicecall_filter_request_ref(req);
|
||||
complete(req);
|
||||
voicecall_filter_request_dispose(req);
|
||||
voicecall_filter_request_dequeue(req);
|
||||
voicecall_filter_request_unref(req);
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_process
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
GSList *l = req->filter_link;
|
||||
const struct ofono_voicecall_filter *f = l->data;
|
||||
const struct voicecall_filter_request_fn *fn = req->fn;
|
||||
|
||||
while (f && !fn->can_process(f)) {
|
||||
l = l->next;
|
||||
f = l ? l->data : NULL;
|
||||
}
|
||||
|
||||
voicecall_filter_request_ref(req);
|
||||
if (f) {
|
||||
req->filter_link = l;
|
||||
req->pending_id = fn->process(f, req);
|
||||
} else {
|
||||
voicecall_filter_request_complete(req, fn->allow);
|
||||
}
|
||||
voicecall_filter_request_unref(req);
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_next(struct voicecall_filter_request *req,
|
||||
GSourceFunc fn)
|
||||
{
|
||||
req->pending_id = 0;
|
||||
req->next_id = g_idle_add(fn, req);
|
||||
}
|
||||
|
||||
static gboolean voicecall_filter_request_continue_cb(gpointer data)
|
||||
{
|
||||
struct voicecall_filter_request *req = data;
|
||||
|
||||
req->next_id = 0;
|
||||
req->filter_link = req->filter_link->next;
|
||||
if (req->filter_link) {
|
||||
voicecall_filter_request_process(req);
|
||||
} else {
|
||||
voicecall_filter_request_complete(req, req->fn->allow);
|
||||
}
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* voicecall_filter_request_dial
|
||||
*==========================================================================*/
|
||||
|
||||
static struct voicecall_filter_request_dial *
|
||||
voicecall_filter_request_dial_cast
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
return (struct voicecall_filter_request_dial *)req;
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_dial_block_complete_cb
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
struct voicecall_filter_request_dial *dial =
|
||||
voicecall_filter_request_dial_cast(req);
|
||||
|
||||
dial->cb(OFONO_VOICECALL_FILTER_DIAL_BLOCK, req->user_data);
|
||||
}
|
||||
|
||||
static gboolean voicecall_filter_request_dial_block_cb(gpointer data)
|
||||
{
|
||||
struct voicecall_filter_request_dial *dial = data;
|
||||
struct voicecall_filter_request *req = &dial->req;
|
||||
|
||||
req->next_id = 0;
|
||||
voicecall_filter_request_complete(req,
|
||||
voicecall_filter_request_dial_block_complete_cb);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_dial_cb
|
||||
(enum ofono_voicecall_filter_dial_result result, void *data)
|
||||
{
|
||||
struct voicecall_filter_request_dial *dial = data;
|
||||
struct voicecall_filter_request *req = &dial->req;
|
||||
const struct ofono_voicecall_filter *filter = req->filter_link->data;
|
||||
GSourceFunc next_cb;
|
||||
|
||||
if (result == OFONO_VOICECALL_FILTER_DIAL_BLOCK) {
|
||||
ofono_info("%s is refusing to dial %s", filter->name,
|
||||
phone_number_to_string(dial->number));
|
||||
next_cb = voicecall_filter_request_dial_block_cb;
|
||||
} else {
|
||||
/* OFONO_VOICECALL_FILTER_DIAL_CONTINUE */
|
||||
DBG("%s is ok with dialing %s", filter->name,
|
||||
phone_number_to_string(dial->number));
|
||||
next_cb = voicecall_filter_request_continue_cb;
|
||||
}
|
||||
|
||||
voicecall_filter_request_next(req, next_cb);
|
||||
}
|
||||
|
||||
static gboolean voicecall_filter_request_dial_can_process
|
||||
(const struct ofono_voicecall_filter *f)
|
||||
{
|
||||
return f->filter_dial != NULL;
|
||||
}
|
||||
|
||||
static guint voicecall_filter_request_dial_process
|
||||
(const struct ofono_voicecall_filter *f,
|
||||
struct voicecall_filter_request *req)
|
||||
{
|
||||
struct voicecall_filter_request_dial *dial =
|
||||
voicecall_filter_request_dial_cast(req);
|
||||
|
||||
return f->filter_dial(req->chain->vc, dial->number, dial->clir,
|
||||
voicecall_filter_request_dial_cb, dial);
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_dial_allow
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
struct voicecall_filter_request_dial *dial =
|
||||
voicecall_filter_request_dial_cast(req);
|
||||
|
||||
dial->cb(OFONO_VOICECALL_FILTER_DIAL_CONTINUE, req->user_data);
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_dial_free
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
g_slice_free1(sizeof(struct voicecall_filter_request_dial), req);
|
||||
}
|
||||
|
||||
static struct voicecall_filter_request *voicecall_filter_request_dial_new
|
||||
(struct voicecall_filter_chain *chain,
|
||||
const struct ofono_phone_number *number,
|
||||
enum ofono_clir_option clir,
|
||||
ofono_voicecall_filter_dial_cb_t cb,
|
||||
ofono_destroy_func destroy, void *data)
|
||||
{
|
||||
static const struct voicecall_filter_request_fn fn = {
|
||||
.name = "dial",
|
||||
.can_process = voicecall_filter_request_dial_can_process,
|
||||
.process = voicecall_filter_request_dial_process,
|
||||
.allow = voicecall_filter_request_dial_allow,
|
||||
.free = voicecall_filter_request_dial_free
|
||||
};
|
||||
|
||||
struct voicecall_filter_request_dial *dial =
|
||||
g_slice_new0(struct voicecall_filter_request_dial);
|
||||
struct voicecall_filter_request *req = &dial->req;
|
||||
|
||||
voicecall_filter_request_init(req, &fn, chain, NULL, destroy, data);
|
||||
dial->number = number;
|
||||
dial->clir = clir;
|
||||
dial->cb = cb;
|
||||
return req;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* voicecall_filter_request_incoming
|
||||
*==========================================================================*/
|
||||
|
||||
static struct voicecall_filter_request_incoming *
|
||||
voicecall_filter_request_incoming_cast
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
return (struct voicecall_filter_request_incoming *)req;
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_incoming_hangup_complete_cb
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
struct voicecall_filter_request_incoming *in =
|
||||
voicecall_filter_request_incoming_cast(req);
|
||||
|
||||
in->cb(OFONO_VOICECALL_FILTER_INCOMING_HANGUP, req->user_data);
|
||||
}
|
||||
|
||||
static gboolean voicecall_filter_request_incoming_hangup_cb(gpointer data)
|
||||
{
|
||||
struct voicecall_filter_request_incoming *in = data;
|
||||
struct voicecall_filter_request *req = &in->req;
|
||||
|
||||
req->next_id = 0;
|
||||
voicecall_filter_request_complete(req,
|
||||
voicecall_filter_request_incoming_hangup_complete_cb);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_incoming_ignore_complete_cb
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
struct voicecall_filter_request_incoming *in =
|
||||
voicecall_filter_request_incoming_cast(req);
|
||||
|
||||
in->cb(OFONO_VOICECALL_FILTER_INCOMING_IGNORE, req->user_data);
|
||||
}
|
||||
|
||||
static gboolean voicecall_filter_request_incoming_ignore_cb(gpointer data)
|
||||
{
|
||||
struct voicecall_filter_request_incoming *in = data;
|
||||
struct voicecall_filter_request *req = &in->req;
|
||||
|
||||
req->next_id = 0;
|
||||
voicecall_filter_request_complete(req,
|
||||
voicecall_filter_request_incoming_ignore_complete_cb);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_incoming_cb
|
||||
(enum ofono_voicecall_filter_incoming_result result, void *data)
|
||||
{
|
||||
struct voicecall_filter_request_incoming *in = data;
|
||||
struct voicecall_filter_request *req = &in->req;
|
||||
const struct ofono_voicecall_filter *filter = req->filter_link->data;
|
||||
GSourceFunc next_cb;
|
||||
|
||||
if (result == OFONO_VOICECALL_FILTER_INCOMING_HANGUP) {
|
||||
ofono_info("%s hangs up incoming call from %s", filter->name,
|
||||
phone_number_to_string(&req->call->phone_number));
|
||||
next_cb = voicecall_filter_request_incoming_hangup_cb;
|
||||
} else if (result == OFONO_VOICECALL_FILTER_INCOMING_IGNORE) {
|
||||
ofono_info("%s ignores incoming call from %s", filter->name,
|
||||
phone_number_to_string(&req->call->phone_number));
|
||||
next_cb = voicecall_filter_request_incoming_ignore_cb;
|
||||
} else {
|
||||
/* OFONO_VOICECALL_FILTER_INCOMING_CONTINUE */
|
||||
DBG("%s is ok with accepting %s", filter->name,
|
||||
phone_number_to_string(&req->call->phone_number));
|
||||
next_cb = voicecall_filter_request_continue_cb;
|
||||
}
|
||||
|
||||
voicecall_filter_request_next(req, next_cb);
|
||||
}
|
||||
|
||||
static gboolean voicecall_filter_request_incoming_can_process
|
||||
(const struct ofono_voicecall_filter *f)
|
||||
{
|
||||
return f->filter_incoming != NULL;
|
||||
}
|
||||
|
||||
static guint voicecall_filter_request_incoming_process
|
||||
(const struct ofono_voicecall_filter *f,
|
||||
struct voicecall_filter_request *req)
|
||||
{
|
||||
return f->filter_incoming(req->chain->vc, req->call,
|
||||
voicecall_filter_request_incoming_cb,
|
||||
voicecall_filter_request_incoming_cast(req));
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_incoming_allow
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
struct voicecall_filter_request_incoming *in =
|
||||
voicecall_filter_request_incoming_cast(req);
|
||||
|
||||
in->cb(OFONO_VOICECALL_FILTER_INCOMING_CONTINUE, req->user_data);
|
||||
}
|
||||
|
||||
static void voicecall_filter_request_incoming_free
|
||||
(struct voicecall_filter_request *req)
|
||||
{
|
||||
g_slice_free1(sizeof(struct voicecall_filter_request_incoming), req);
|
||||
}
|
||||
|
||||
static struct voicecall_filter_request *voicecall_filter_request_incoming_new
|
||||
(struct voicecall_filter_chain *chain, const struct ofono_call *call,
|
||||
ofono_voicecall_filter_incoming_cb_t cb,
|
||||
ofono_destroy_func destroy, void *data)
|
||||
{
|
||||
static const struct voicecall_filter_request_fn fn = {
|
||||
.name = "incoming",
|
||||
.can_process = voicecall_filter_request_incoming_can_process,
|
||||
.process = voicecall_filter_request_incoming_process,
|
||||
.allow = voicecall_filter_request_incoming_allow,
|
||||
.free = voicecall_filter_request_incoming_free
|
||||
};
|
||||
|
||||
struct voicecall_filter_request_incoming *in =
|
||||
g_slice_new0(struct voicecall_filter_request_incoming);
|
||||
struct voicecall_filter_request *req = &in->req;
|
||||
|
||||
voicecall_filter_request_init(req, &fn, chain, call, destroy, data);
|
||||
in->cb = cb;
|
||||
return req;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* voicecall_filter_chain
|
||||
*==========================================================================*/
|
||||
|
||||
struct voicecall_filter_chain *__ofono_voicecall_filter_chain_new
|
||||
(struct ofono_voicecall *vc)
|
||||
{
|
||||
struct voicecall_filter_chain *chain = NULL;
|
||||
|
||||
if (vc) {
|
||||
chain = g_new0(struct voicecall_filter_chain, 1);
|
||||
chain->vc = vc;
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
void __ofono_voicecall_filter_chain_free(struct voicecall_filter_chain *chain)
|
||||
{
|
||||
if (chain) {
|
||||
__ofono_voicecall_filter_chain_cancel(chain, NULL);
|
||||
g_free(chain);
|
||||
}
|
||||
}
|
||||
|
||||
static GSList *voicecall_filter_chain_select(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call)
|
||||
{
|
||||
if (c) {
|
||||
GSList *selected;
|
||||
|
||||
/* Move selected requests to a separate list */
|
||||
if (call) {
|
||||
GSList *prev = NULL;
|
||||
GSList *l = c->req_list;
|
||||
|
||||
selected = NULL;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct voicecall_filter_request *req = l->data;
|
||||
|
||||
if (req->call == call) {
|
||||
/* This one will get canceled */
|
||||
l->next = selected;
|
||||
selected = l;
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
} else {
|
||||
c->req_list = next;
|
||||
}
|
||||
} else {
|
||||
/* This one survives */
|
||||
prev = l;
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
} else {
|
||||
/* Select everything */
|
||||
selected = c->req_list;
|
||||
c->req_list = NULL;
|
||||
}
|
||||
|
||||
return selected;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_voicecall_filter_chain_restart(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call)
|
||||
{
|
||||
GSList *l, *canceled = voicecall_filter_chain_select(c, call);
|
||||
|
||||
/* Cancel and resubmit each request */
|
||||
for (l = canceled; l; l = l->next) {
|
||||
struct voicecall_filter_request *req = l->data;
|
||||
|
||||
voicecall_filter_request_cancel(req);
|
||||
voicecall_filter_request_process(req);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __ofono_voicecall_filter_chain_cancel(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call)
|
||||
{
|
||||
GSList *l, *canceled = voicecall_filter_chain_select(c, call);
|
||||
|
||||
/* Cancel and deallocate each request */
|
||||
for (l = canceled; l; l = l->next) {
|
||||
struct voicecall_filter_request *req = l->data;
|
||||
|
||||
voicecall_filter_request_cancel(req);
|
||||
voicecall_filter_request_done(req);
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_voicecall_filter_chain_dial(struct voicecall_filter_chain *chain,
|
||||
const struct ofono_phone_number *number,
|
||||
enum ofono_clir_option clir,
|
||||
ofono_voicecall_filter_dial_cb_t cb,
|
||||
ofono_destroy_func destroy, void *user_data)
|
||||
{
|
||||
if (chain && voicecall_filters && number && cb) {
|
||||
voicecall_filter_request_process
|
||||
(voicecall_filter_request_dial_new(chain, number,
|
||||
clir, cb, destroy, user_data));
|
||||
} else {
|
||||
if (cb) {
|
||||
cb(OFONO_VOICECALL_FILTER_DIAL_CONTINUE, user_data);
|
||||
}
|
||||
if (destroy) {
|
||||
destroy(user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_voicecall_filter_chain_dial_check(struct voicecall_filter_chain *c,
|
||||
const struct ofono_call *call,
|
||||
ofono_voicecall_filter_dial_cb_t cb,
|
||||
ofono_destroy_func destroy, void *user_data)
|
||||
{
|
||||
if (c && voicecall_filters && call && cb) {
|
||||
struct voicecall_filter_request *req =
|
||||
voicecall_filter_request_dial_new(c,
|
||||
&call->phone_number, OFONO_CLIR_OPTION_DEFAULT,
|
||||
cb, destroy, user_data);
|
||||
|
||||
req->call = call;
|
||||
voicecall_filter_request_process(req);
|
||||
} else {
|
||||
if (cb) {
|
||||
cb(OFONO_VOICECALL_FILTER_DIAL_CONTINUE, user_data);
|
||||
}
|
||||
if (destroy) {
|
||||
destroy(user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_voicecall_filter_chain_incoming(struct voicecall_filter_chain *fc,
|
||||
const struct ofono_call *call,
|
||||
ofono_voicecall_filter_incoming_cb_t cb,
|
||||
ofono_destroy_func destroy, void *user_data)
|
||||
{
|
||||
if (fc && voicecall_filters && call && cb) {
|
||||
voicecall_filter_request_process
|
||||
(voicecall_filter_request_incoming_new(fc, call,
|
||||
cb, destroy, user_data));
|
||||
} else {
|
||||
if (cb) {
|
||||
cb(OFONO_VOICECALL_FILTER_INCOMING_CONTINUE, user_data);
|
||||
}
|
||||
if (destroy) {
|
||||
destroy(user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ofono_voicecall_filter
|
||||
*==========================================================================*/
|
||||
|
||||
/**
|
||||
* Returns 0 if both are equal;
|
||||
* <0 if a comes before b;
|
||||
* >0 if a comes after b.
|
||||
*/
|
||||
static gint voicecall_filter_sort(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ofono_voicecall_filter *a_filter = a;
|
||||
const struct ofono_voicecall_filter *b_filter = b;
|
||||
|
||||
if (a_filter->priority > b_filter->priority) {
|
||||
/* a comes before b */
|
||||
return -1;
|
||||
} else if (a_filter->priority < b_filter->priority) {
|
||||
/* a comes after b */
|
||||
return 1;
|
||||
} else {
|
||||
/* Whatever, as long as the sort is stable */
|
||||
return strcmp(a_filter->name, b_filter->name);
|
||||
}
|
||||
}
|
||||
|
||||
int ofono_voicecall_filter_register(const struct ofono_voicecall_filter *f)
|
||||
{
|
||||
if (!f || !f->name) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DBG("%s", f->name);
|
||||
voicecall_filters = g_slist_insert_sorted(voicecall_filters, (void*)f,
|
||||
voicecall_filter_sort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ofono_voicecall_filter_unregister(const struct ofono_voicecall_filter *f)
|
||||
{
|
||||
if (f) {
|
||||
DBG("%s", f->name);
|
||||
voicecall_filters = g_slist_remove(voicecall_filters, f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -78,6 +78,8 @@ struct ofono_voicecall {
|
||||
struct ofono_emulator *pending_em;
|
||||
unsigned int pending_id;
|
||||
struct voicecall_agent *vc_agent;
|
||||
struct voicecall_filter_chain *filters;
|
||||
GSList *incoming_filter_list;
|
||||
};
|
||||
|
||||
struct voicecall {
|
||||
@@ -118,6 +120,14 @@ struct emulator_status {
|
||||
int status;
|
||||
};
|
||||
|
||||
struct dial_filter_req {
|
||||
struct ofono_voicecall *vc;
|
||||
struct ofono_phone_number pn;
|
||||
enum ofono_clir_option clir;
|
||||
ofono_voicecall_cb_t cb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static const char *default_en_list[] = { "911", "112", NULL };
|
||||
static const char *default_en_list_no_sim[] = { "119", "118", "999", "110",
|
||||
"08", "000", NULL };
|
||||
@@ -694,6 +704,9 @@ static void voicecall_destroy(gpointer userdata)
|
||||
{
|
||||
struct voicecall *voicecall = (struct voicecall *)userdata;
|
||||
|
||||
__ofono_voicecall_filter_chain_cancel(voicecall->vc->filters,
|
||||
voicecall->call);
|
||||
|
||||
g_free(voicecall->call);
|
||||
g_free(voicecall->message);
|
||||
|
||||
@@ -1496,7 +1509,7 @@ static void manager_dial_callback(const struct ofono_error *error, void *data)
|
||||
|
||||
}
|
||||
|
||||
reply = __ofono_error_failed(vc->pending);
|
||||
reply = __ofono_error_from_error(error, vc->pending);
|
||||
}
|
||||
|
||||
__ofono_dbus_pending_reply(&vc->pending, reply);
|
||||
@@ -1505,6 +1518,168 @@ static void manager_dial_callback(const struct ofono_error *error, void *data)
|
||||
voicecalls_emit_call_added(vc, v);
|
||||
}
|
||||
|
||||
static void dummy_callback(const struct ofono_error *error, void *data)
|
||||
{
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
|
||||
DBG("command failed with error: %s",
|
||||
telephony_error_to_str(error));
|
||||
}
|
||||
|
||||
static void filter_hangup(struct voicecall *v)
|
||||
{
|
||||
struct ofono_voicecall *vc = v->vc;
|
||||
const struct ofono_call *call = v->call;
|
||||
const struct ofono_voicecall_driver *driver = vc->driver;
|
||||
|
||||
switch (call->status) {
|
||||
case OFONO_CALL_STATUS_WAITING:
|
||||
if (driver->set_udub) {
|
||||
driver->set_udub(vc, dummy_callback, vc);
|
||||
return;
|
||||
} else if (driver->release_specific) {
|
||||
driver->release_specific(vc, call->id,
|
||||
dummy_callback, vc);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case OFONO_CALL_STATUS_ACTIVE:
|
||||
case OFONO_CALL_STATUS_DIALING:
|
||||
case OFONO_CALL_STATUS_ALERTING:
|
||||
if (driver->hangup_active) {
|
||||
driver->hangup_active(vc, dummy_callback, vc);
|
||||
return;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
if (driver->release_specific) {
|
||||
driver->release_specific(vc, call->id,
|
||||
dummy_callback, vc);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ofono_warn("Couldn't disconnect %s call %d",
|
||||
call_status_to_string(call->status), call->id);
|
||||
}
|
||||
|
||||
static void filter_dial_check_cb(enum ofono_voicecall_filter_dial_result result,
|
||||
void *data)
|
||||
{
|
||||
struct voicecall *v = data;
|
||||
|
||||
if (result == OFONO_VOICECALL_FILTER_DIAL_CONTINUE) {
|
||||
DBG("No need to release %s call %d",
|
||||
call_status_to_string(v->call->status), v->call->id);
|
||||
} else {
|
||||
DBG("Need to release %s call %d",
|
||||
call_status_to_string(v->call->status), v->call->id);
|
||||
filter_hangup(v);
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_incoming_check_cb
|
||||
(enum ofono_voicecall_filter_incoming_result result, void *data)
|
||||
{
|
||||
struct voicecall *v = data;
|
||||
|
||||
if (result == OFONO_VOICECALL_FILTER_INCOMING_CONTINUE) {
|
||||
DBG("No need to release %s call %d",
|
||||
call_status_to_string(v->call->status), v->call->id);
|
||||
} else {
|
||||
DBG("Need to release %s call %d",
|
||||
call_status_to_string(v->call->status), v->call->id);
|
||||
filter_hangup(v);
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_incoming_cb(enum ofono_voicecall_filter_incoming_result res,
|
||||
void *data)
|
||||
{
|
||||
struct voicecall *v = data;
|
||||
struct ofono_voicecall *vc = v->vc;
|
||||
|
||||
vc->incoming_filter_list = g_slist_remove(vc->incoming_filter_list, v);
|
||||
if (res == OFONO_VOICECALL_FILTER_INCOMING_HANGUP) {
|
||||
if (vc->driver->release_specific) {
|
||||
vc->driver->release_specific(vc, v->call->id,
|
||||
dummy_callback, vc);
|
||||
}
|
||||
voicecall_destroy(v);
|
||||
} else if (res == OFONO_VOICECALL_FILTER_INCOMING_IGNORE) {
|
||||
voicecall_destroy(v);
|
||||
} else if (voicecall_dbus_register(v)) {
|
||||
struct ofono_voicecall *vc = v->vc;
|
||||
|
||||
vc->call_list = g_slist_insert_sorted(vc->call_list, v,
|
||||
call_compare);
|
||||
voicecalls_emit_call_added(vc, v);
|
||||
}
|
||||
}
|
||||
|
||||
void ofono_voicecall_filter_notify(struct ofono_voicecall *vc)
|
||||
{
|
||||
GSList *l;
|
||||
struct voicecall *v;
|
||||
|
||||
/* Cancel all active filtering requests */
|
||||
__ofono_voicecall_filter_chain_cancel(vc->filters, NULL);
|
||||
|
||||
/* Re-check incoming_filter_list */
|
||||
for (l = vc->incoming_filter_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
__ofono_voicecall_filter_chain_incoming(vc->filters, v->call,
|
||||
filter_incoming_cb, NULL, v);
|
||||
}
|
||||
|
||||
/* Re-check the calls that have already passed the filter */
|
||||
for (l = vc->call_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
if (v->call->direction == CALL_DIRECTION_MOBILE_ORIGINATED) {
|
||||
__ofono_voicecall_filter_chain_dial_check(vc->filters,
|
||||
v->call, filter_dial_check_cb, NULL, v);
|
||||
} else {
|
||||
__ofono_voicecall_filter_chain_incoming(vc->filters,
|
||||
v->call, filter_incoming_check_cb, NULL, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dial_filter_cb(enum ofono_voicecall_filter_dial_result result,
|
||||
void *req_data)
|
||||
{
|
||||
struct dial_filter_req *req = req_data;
|
||||
|
||||
if (result == OFONO_VOICECALL_FILTER_DIAL_BLOCK) {
|
||||
struct ofono_error error;
|
||||
|
||||
error.type = OFONO_ERROR_TYPE_ERRNO;
|
||||
error.error = EACCES;
|
||||
req->cb(&error, req->data);
|
||||
} else {
|
||||
struct ofono_voicecall *vc = req->vc;
|
||||
|
||||
/* OFONO_VOICECALL_FILTER_DIAL_CONTINUE */
|
||||
vc->driver->dial(vc, &req->pn, req->clir, req->cb, req->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void dial_filter(struct ofono_voicecall *vc,
|
||||
const struct ofono_phone_number *pn,
|
||||
enum ofono_clir_option clir,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct dial_filter_req *req = g_new0(struct dial_filter_req, 1);
|
||||
|
||||
req->vc = vc;
|
||||
req->pn = *pn;
|
||||
req->clir = clir;
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
__ofono_voicecall_filter_chain_dial(vc->filters, &req->pn, clir,
|
||||
dial_filter_cb, g_free, req);
|
||||
}
|
||||
|
||||
static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
|
||||
enum ofono_clir_option clir,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
@@ -1542,7 +1717,11 @@ static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
|
||||
|
||||
string_to_phone_number(number, &ph);
|
||||
|
||||
vc->driver->dial(vc, &ph, clir, cb, vc);
|
||||
/* No filtering for emergency calls */
|
||||
if (is_emergency_number(vc, number))
|
||||
vc->driver->dial(vc, &ph, clir, cb, vc);
|
||||
else
|
||||
dial_filter(vc, &ph, clir, cb, vc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2158,7 +2337,7 @@ static DBusMessage *voicecall_register_agent(DBusConnection *conn,
|
||||
&agent_path, DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (!__ofono_dbus_valid_object_path(agent_path))
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
vc->vc_agent = voicecall_agent_new(agent_path,
|
||||
@@ -2272,6 +2451,18 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id,
|
||||
|
||||
__ofono_modem_callid_release(modem, id);
|
||||
|
||||
l = g_slist_find_custom(vc->incoming_filter_list, GUINT_TO_POINTER(id),
|
||||
call_compare_by_id);
|
||||
|
||||
if (l) {
|
||||
/* Incoming call was disconnected in the process of being
|
||||
* filtered. voicecall_destroy cancels it. */
|
||||
vc->incoming_filter_list = g_slist_delete_link
|
||||
(vc->incoming_filter_list, l);
|
||||
voicecall_destroy(l->data);
|
||||
return;
|
||||
}
|
||||
|
||||
l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(id),
|
||||
call_compare_by_id);
|
||||
|
||||
@@ -2356,6 +2547,26 @@ void ofono_voicecall_notify(struct ofono_voicecall *vc,
|
||||
call->status, call->id, call->phone_number.number,
|
||||
call->called_number.number, call->name);
|
||||
|
||||
l = g_slist_find_custom(vc->incoming_filter_list,
|
||||
GUINT_TO_POINTER(call->id), call_compare_by_id);
|
||||
|
||||
if (l) {
|
||||
/* The call has changed in the process of being filtered. */
|
||||
DBG("Found filtered call with id: %d", call->id);
|
||||
v = l->data;
|
||||
|
||||
/* Update the call */
|
||||
voicecall_set_call_status(v, call->status);
|
||||
voicecall_set_call_lineid(v, &call->phone_number,
|
||||
call->clip_validity);
|
||||
voicecall_set_call_calledid(v, &call->called_number);
|
||||
voicecall_set_call_name(v, call->name, call->cnap_validity);
|
||||
|
||||
/* And restart the filtering */
|
||||
__ofono_voicecall_filter_chain_restart(vc->filters, v->call);
|
||||
return;
|
||||
}
|
||||
|
||||
l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(call->id),
|
||||
call_compare_by_id);
|
||||
|
||||
@@ -2421,6 +2632,16 @@ void ofono_voicecall_notify(struct ofono_voicecall *vc,
|
||||
|
||||
v->detect_time = time(NULL);
|
||||
|
||||
if (call->status == CALL_STATUS_INCOMING ||
|
||||
call->status == CALL_STATUS_WAITING) {
|
||||
/* Incoming calls have to go through filtering */
|
||||
vc->incoming_filter_list = g_slist_append
|
||||
(vc->incoming_filter_list, v);
|
||||
__ofono_voicecall_filter_chain_incoming(vc->filters, v->call,
|
||||
filter_incoming_cb, NULL, v);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!voicecall_dbus_register(v)) {
|
||||
ofono_error("Unable to register voice call");
|
||||
goto error;
|
||||
@@ -2886,6 +3107,10 @@ static void voicecall_unregister(struct ofono_atom *atom)
|
||||
g_slist_free(vc->call_list);
|
||||
vc->call_list = NULL;
|
||||
|
||||
/* voicecall_destroy cancels the filtering */
|
||||
g_slist_free_full(vc->incoming_filter_list, voicecall_destroy);
|
||||
vc->incoming_filter_list = NULL;
|
||||
|
||||
ofono_modem_remove_interface(modem, OFONO_VOICECALL_MANAGER_INTERFACE);
|
||||
g_dbus_unregister_interface(conn, path,
|
||||
OFONO_VOICECALL_MANAGER_INTERFACE);
|
||||
@@ -2900,6 +3125,8 @@ static void voicecall_remove(struct ofono_atom *atom)
|
||||
if (vc == NULL)
|
||||
return;
|
||||
|
||||
__ofono_voicecall_filter_chain_free(vc->filters);
|
||||
|
||||
if (vc->driver && vc->driver->remove)
|
||||
vc->driver->remove(vc);
|
||||
|
||||
@@ -2954,6 +3181,7 @@ struct ofono_voicecall *ofono_voicecall_create(struct ofono_modem *modem,
|
||||
break;
|
||||
}
|
||||
|
||||
vc->filters = __ofono_voicecall_filter_chain_new(vc);
|
||||
return vc;
|
||||
}
|
||||
|
||||
@@ -3702,6 +3930,7 @@ void ofono_voicecall_register(struct ofono_voicecall *vc)
|
||||
vc->hfp_watch = __ofono_modem_add_atom_watch(modem,
|
||||
OFONO_ATOM_TYPE_EMULATOR_HFP,
|
||||
emulator_hfp_watch, vc, NULL);
|
||||
|
||||
}
|
||||
|
||||
void ofono_voicecall_remove(struct ofono_voicecall *vc)
|
||||
@@ -3719,6 +3948,11 @@ void *ofono_voicecall_get_data(struct ofono_voicecall *vc)
|
||||
return vc->driver_data;
|
||||
}
|
||||
|
||||
struct ofono_modem *ofono_voicecall_get_modem(struct ofono_voicecall *vc)
|
||||
{
|
||||
return __ofono_atom_get_modem(vc->atom);
|
||||
}
|
||||
|
||||
int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
@@ -3816,10 +4050,14 @@ static void dial_request(struct ofono_voicecall *vc)
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
|
||||
|
||||
__ofono_modem_inc_emergency_mode(modem);
|
||||
}
|
||||
|
||||
vc->driver->dial(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT,
|
||||
/* No filtering for emergency calls */
|
||||
vc->driver->dial(vc, &vc->dial_req->ph,
|
||||
OFONO_CLIR_OPTION_DEFAULT, dial_request_cb, vc);
|
||||
} else {
|
||||
dial_filter(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT,
|
||||
dial_request_cb, vc);
|
||||
}
|
||||
}
|
||||
|
||||
static void dial_req_disconnect_cb(const struct ofono_error *error, void *data)
|
||||
|
||||
@@ -16,14 +16,20 @@ TESTS="\
|
||||
test-cdmasms \
|
||||
test-sms-root \
|
||||
test-caif \
|
||||
test-dbus-queue \
|
||||
test-gprs-filter \
|
||||
test-provision \
|
||||
test-ril_util \
|
||||
test-ril_config \
|
||||
test-ril-transport \
|
||||
test-sms-filter \
|
||||
test-voicecall-filter \
|
||||
test-sailfish_cell_info \
|
||||
test-sailfish_cell_info_dbus \
|
||||
test-sailfish_manager \
|
||||
test-sailfish_sim_info \
|
||||
test-sailfish_sim_info_dbus"
|
||||
test-sailfish_sim_info_dbus \
|
||||
test-sailfish_watch"
|
||||
|
||||
pushd `dirname $0` > /dev/null
|
||||
TEST_DIR="$PWD"
|
||||
|
||||
659
ofono/unit/test-dbus-queue.c
Normal file
659
ofono/unit/test-dbus-queue.c
Normal file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
#include "test-dbus.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "dbus-queue.h"
|
||||
|
||||
#include <gutil_log.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#define TEST_TIMEOUT (10) /* seconds */
|
||||
#define TEST_DBUS_INTERFACE "test.interface"
|
||||
#define TEST_DBUS_METHOD "Test"
|
||||
#define TEST_DBUS_PATH "/"
|
||||
|
||||
#define TEST_ERROR_CANCELED "org.ofono.Error.Canceled"
|
||||
#define TEST_ERROR_FAILED "org.ofono.Error.Failed"
|
||||
|
||||
#define GDBUS_TEST_METHOD(fn) GDBUS_ASYNC_METHOD(TEST_DBUS_METHOD, \
|
||||
GDBUS_ARGS( { "arg", "i" }), NULL, fn)
|
||||
|
||||
static gboolean test_debug;
|
||||
|
||||
/* ==== common ==== */
|
||||
|
||||
static gboolean test_timeout(gpointer param)
|
||||
{
|
||||
g_assert(!"TIMEOUT");
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static guint test_setup_timeout(void)
|
||||
{
|
||||
if (test_debug) {
|
||||
return 0;
|
||||
} else {
|
||||
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#define test_register_interface(methods,data) \
|
||||
g_assert(g_dbus_register_interface(ofono_dbus_get_connection(), \
|
||||
TEST_DBUS_PATH, TEST_DBUS_INTERFACE, \
|
||||
methods, NULL, NULL, data, NULL))
|
||||
|
||||
static void test_client_call(struct test_dbus_context* dbus, dbus_int32_t arg,
|
||||
DBusPendingCallNotifyFunction fn)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusConnection* conn = dbus->client_connection;
|
||||
DBusMessage *msg = dbus_message_new_method_call(NULL, TEST_DBUS_PATH,
|
||||
TEST_DBUS_INTERFACE, TEST_DBUS_METHOD);
|
||||
|
||||
dbus_message_append_args(msg, DBUS_TYPE_INT32, &arg, DBUS_TYPE_INVALID);
|
||||
g_assert(dbus_connection_send_with_reply(conn, msg, &call,
|
||||
DBUS_TIMEOUT_INFINITE));
|
||||
dbus_pending_call_set_notify(call, fn, dbus, NULL);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void test_expect_canceled(DBusPendingCall *call, void *unused)
|
||||
{
|
||||
DBG("");
|
||||
test_dbus_check_error_reply(call, TEST_ERROR_CANCELED);
|
||||
}
|
||||
|
||||
static void test_expect_failed(DBusPendingCall *call, void *unused)
|
||||
{
|
||||
DBG("");
|
||||
test_dbus_check_error_reply(call, TEST_ERROR_FAILED);
|
||||
}
|
||||
|
||||
/* ==== basic ==== */
|
||||
|
||||
static void test_basic(void)
|
||||
{
|
||||
__ofono_dbus_queue_free(__ofono_dbus_queue_new());
|
||||
|
||||
/* These are NULL tolerant: */
|
||||
__ofono_dbus_queue_free(NULL);
|
||||
__ofono_dbus_queue_reply_ok(NULL);
|
||||
__ofono_dbus_queue_reply_failed(NULL);
|
||||
__ofono_dbus_queue_reply_all_ok(NULL);
|
||||
__ofono_dbus_queue_reply_all_failed(NULL);
|
||||
__ofono_dbus_queue_reply_msg(NULL, NULL);
|
||||
g_assert(!__ofono_dbus_queue_pending(NULL));
|
||||
g_assert(!__ofono_dbus_queue_set_pending(NULL, NULL));
|
||||
}
|
||||
|
||||
/* ==== free ==== */
|
||||
|
||||
struct test_free_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_queue *queue;
|
||||
};
|
||||
|
||||
static DBusMessage *test_free_cb(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_free_reply(DBusPendingCall *call, void *dbus)
|
||||
{
|
||||
struct test_free_data *test = G_CAST(dbus, struct test_free_data, dbus);
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_error_reply(call, TEST_ERROR_CANCELED);
|
||||
g_main_loop_quit(test->dbus.loop);
|
||||
}
|
||||
|
||||
static DBusMessage *test_free_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct test_free_data *test = data;
|
||||
|
||||
DBG("");
|
||||
|
||||
/* test_free_cb queues the message */
|
||||
__ofono_dbus_queue_request(test->queue, test_free_cb, msg, test);
|
||||
|
||||
/* And this cancels it: */
|
||||
__ofono_dbus_queue_free(test->queue);
|
||||
test->queue = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_free_methods[] = {
|
||||
{ GDBUS_TEST_METHOD(test_free_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void test_free_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_free_data *test = G_CAST(dbus, struct test_free_data, dbus);
|
||||
|
||||
test_register_interface(test_free_methods, test);
|
||||
test_client_call(dbus, 0, test_free_reply);
|
||||
}
|
||||
|
||||
static void test_free(void)
|
||||
{
|
||||
struct test_free_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_free_start;
|
||||
test.queue = __ofono_dbus_queue_new();
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
g_assert(!test.queue); /* Freed by test_free_handler */
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== cancel ==== */
|
||||
|
||||
struct test_cancel_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_queue *queue;
|
||||
};
|
||||
|
||||
static gboolean test_cancel_msg(void *data)
|
||||
{
|
||||
struct test_cancel_data *test = data;
|
||||
|
||||
/* This is will cancel the message: */
|
||||
__ofono_dbus_queue_reply_msg(test->queue, NULL);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static DBusMessage *test_cancel_cb(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
g_idle_add(test_cancel_msg, data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_cancel_reply(DBusPendingCall *call, void *dbus)
|
||||
{
|
||||
struct test_cancel_data *test =
|
||||
G_CAST(dbus, struct test_cancel_data, dbus);
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_error_reply(call, TEST_ERROR_CANCELED);
|
||||
g_main_loop_quit(test->dbus.loop);
|
||||
}
|
||||
|
||||
static DBusMessage *test_cancel_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct test_cancel_data *test = data;
|
||||
|
||||
DBG("");
|
||||
|
||||
__ofono_dbus_queue_request(test->queue, test_cancel_cb, msg, test);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_cancel_methods[] = {
|
||||
{ GDBUS_TEST_METHOD(test_cancel_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void test_cancel_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_cancel_data *test =
|
||||
G_CAST(dbus, struct test_cancel_data, dbus);
|
||||
|
||||
test_register_interface(test_cancel_methods, test);
|
||||
test_client_call(dbus, 0, test_cancel_reply);
|
||||
}
|
||||
|
||||
static void test_cancel(void)
|
||||
{
|
||||
struct test_cancel_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_cancel_start;
|
||||
test.queue = __ofono_dbus_queue_new();
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
__ofono_dbus_queue_free(test.queue);
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== async ==== */
|
||||
|
||||
struct test_async_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_queue *queue;
|
||||
};
|
||||
|
||||
static gboolean test_async_complete(void *data)
|
||||
{
|
||||
struct test_cancel_data *test = data;
|
||||
|
||||
__ofono_dbus_queue_reply_fn(test->queue,
|
||||
dbus_message_new_method_return);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static DBusMessage *test_async_cb(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
g_idle_add(test_async_complete, data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_async_last_reply(DBusPendingCall *call, void *dbus)
|
||||
{
|
||||
struct test_async_data *test =
|
||||
G_CAST(dbus, struct test_async_data, dbus);
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_empty_reply(call, NULL);
|
||||
g_main_loop_quit(test->dbus.loop);
|
||||
}
|
||||
|
||||
static DBusMessage *test_async_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct test_cancel_data *test = data;
|
||||
|
||||
DBG("");
|
||||
__ofono_dbus_queue_request(test->queue, test_async_cb, msg, data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_async_methods[] = {
|
||||
{ GDBUS_TEST_METHOD(test_async_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void test_async_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_async_data *test =
|
||||
G_CAST(dbus, struct test_async_data, dbus);
|
||||
|
||||
test_register_interface(test_async_methods, test);
|
||||
test_client_call(dbus, 0, test_dbus_expect_empty_reply);
|
||||
test_client_call(dbus, 1, test_dbus_expect_empty_reply);
|
||||
test_client_call(dbus, 2, test_dbus_expect_empty_reply);
|
||||
test_client_call(dbus, 3, test_async_last_reply);
|
||||
}
|
||||
|
||||
static void test_async(void)
|
||||
{
|
||||
struct test_async_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_async_start;
|
||||
test.queue = __ofono_dbus_queue_new();
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
__ofono_dbus_queue_free(test.queue);
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== sync ==== */
|
||||
|
||||
struct test_sync_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_queue *queue;
|
||||
};
|
||||
|
||||
static DBusMessage *test_sync_cb(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
|
||||
static void test_sync_reply(DBusPendingCall *call, void *dbus)
|
||||
{
|
||||
struct test_sync_data *test = G_CAST(dbus, struct test_sync_data, dbus);
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_empty_reply(call, NULL);
|
||||
g_main_loop_quit(test->dbus.loop);
|
||||
}
|
||||
|
||||
static DBusMessage *test_sync_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct test_sync_data *test = data;
|
||||
|
||||
DBG("");
|
||||
|
||||
/* test_sync_cb immediately completes it */
|
||||
__ofono_dbus_queue_request(test->queue, test_sync_cb, msg, test);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_sync_methods[] = {
|
||||
{ GDBUS_TEST_METHOD(test_sync_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void test_sync_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_sync_data *test = G_CAST(dbus, struct test_sync_data, dbus);
|
||||
|
||||
test_register_interface(test_sync_methods, test);
|
||||
test_client_call(dbus, 0, test_sync_reply);
|
||||
}
|
||||
|
||||
static void test_sync(void)
|
||||
{
|
||||
struct test_sync_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_sync_start;
|
||||
test.queue = __ofono_dbus_queue_new();
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
__ofono_dbus_queue_free(test.queue);
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== reply ==== */
|
||||
|
||||
struct test_reply_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_queue *queue;
|
||||
};
|
||||
|
||||
static void test_reply_last_reply(DBusPendingCall *call, void *dbus)
|
||||
{
|
||||
struct test_reply_data *test =
|
||||
G_CAST(dbus, struct test_reply_data, dbus);
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_error_reply(call, TEST_ERROR_FAILED);
|
||||
g_main_loop_quit(test->dbus.loop);
|
||||
}
|
||||
|
||||
static DBusMessage *test_reply_1(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DBusMessage *test_reply_2(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DBusMessage *test_reply_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct test_reply_data *test = data;
|
||||
dbus_int32_t arg;
|
||||
|
||||
g_assert(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &arg,
|
||||
DBUS_TYPE_INVALID));
|
||||
|
||||
DBG("%d", arg);
|
||||
switch (arg) {
|
||||
case 0:
|
||||
/* Queue is empty, we can use __ofono_dbus_queue_set_pending */
|
||||
g_assert(__ofono_dbus_queue_set_pending(test->queue, msg));
|
||||
break;
|
||||
case 1:
|
||||
case 4:
|
||||
/* Queue is not empty anymore */
|
||||
g_assert(__ofono_dbus_queue_pending(test->queue));
|
||||
g_assert(!__ofono_dbus_queue_set_pending(test->queue, msg));
|
||||
__ofono_dbus_queue_request(test->queue, test_reply_1,
|
||||
msg, NULL);
|
||||
break;
|
||||
case 2:
|
||||
/* Same callback, different data */
|
||||
__ofono_dbus_queue_request(test->queue, test_reply_1,
|
||||
msg, test);
|
||||
break;
|
||||
case 3:
|
||||
__ofono_dbus_queue_request(test->queue, test_reply_2,
|
||||
msg, NULL);
|
||||
break;
|
||||
case 5:
|
||||
__ofono_dbus_queue_request(test->queue, test_reply_2,
|
||||
msg, NULL);
|
||||
/* This completes the first one, with NULL handler */
|
||||
__ofono_dbus_queue_reply_all_fn_param(test->queue, NULL, NULL);
|
||||
g_assert(__ofono_dbus_queue_pending(test->queue));
|
||||
|
||||
/* And this one completes 2 others with test_reply_1 */
|
||||
__ofono_dbus_queue_reply_all_fn(test->queue,
|
||||
dbus_message_new_method_return);
|
||||
g_assert(__ofono_dbus_queue_pending(test->queue));
|
||||
|
||||
/* This one test_reply_1 with different data */
|
||||
__ofono_dbus_queue_reply_all_fn(test->queue,
|
||||
__ofono_error_canceled);
|
||||
|
||||
/* And this one fails 2 others with test_reply_2 */
|
||||
__ofono_dbus_queue_reply_all_fn(test->queue, NULL);
|
||||
g_assert(!__ofono_dbus_queue_pending(test->queue));
|
||||
|
||||
/* And this one does nothing */
|
||||
__ofono_dbus_queue_reply_all_fn(test->queue,
|
||||
dbus_message_new_method_return);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_reply_methods[] = {
|
||||
{ GDBUS_TEST_METHOD(test_reply_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void test_reply_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_reply_data *test =
|
||||
G_CAST(dbus, struct test_reply_data, dbus);
|
||||
|
||||
test_register_interface(test_reply_methods, test);
|
||||
test_client_call(dbus, 0, test_expect_failed);
|
||||
test_client_call(dbus, 1, test_dbus_expect_empty_reply);
|
||||
test_client_call(dbus, 2, test_expect_canceled);
|
||||
test_client_call(dbus, 3, test_expect_failed);
|
||||
test_client_call(dbus, 4, test_dbus_expect_empty_reply);
|
||||
test_client_call(dbus, 5, test_reply_last_reply);
|
||||
}
|
||||
|
||||
static void test_reply(void)
|
||||
{
|
||||
struct test_reply_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_reply_start;
|
||||
test.queue = __ofono_dbus_queue_new();
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
__ofono_dbus_queue_free(test.queue);
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== ok ==== */
|
||||
|
||||
struct test_ok_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_queue *queue;
|
||||
};
|
||||
|
||||
static DBusMessage *test_ok_1(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DBusMessage *test_ok_2(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
|
||||
static void test_ok_last_reply(DBusPendingCall *call, void *dbus)
|
||||
{
|
||||
struct test_ok_data *test = G_CAST(dbus, struct test_ok_data, dbus);
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_empty_reply(call, NULL);
|
||||
g_main_loop_quit(test->dbus.loop);
|
||||
}
|
||||
|
||||
static DBusMessage *test_ok_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct test_ok_data *test = data;
|
||||
dbus_int32_t arg;
|
||||
|
||||
g_assert(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &arg,
|
||||
DBUS_TYPE_INVALID));
|
||||
|
||||
DBG("%d", arg);
|
||||
if (arg == 0) {
|
||||
/* This is the first call, it blocks the queue */
|
||||
__ofono_dbus_queue_request(test->queue, test_ok_1, msg, test);
|
||||
} else {
|
||||
g_assert(__ofono_dbus_queue_pending(test->queue));
|
||||
__ofono_dbus_queue_request(test->queue, test_ok_2, msg, test);
|
||||
/* This is the second call, complete the first one.
|
||||
* That unblocks the seconds one. */
|
||||
__ofono_dbus_queue_reply_ok(test->queue);
|
||||
|
||||
/* This call has no effect, it's actually an error (the
|
||||
* message has already been replied to) but such situation
|
||||
* is handled by __ofono_dbus_queue_reply_msg */
|
||||
__ofono_dbus_queue_reply_msg(test->queue,
|
||||
dbus_message_new_method_return(msg));
|
||||
|
||||
/* This one does nothing too */
|
||||
__ofono_dbus_queue_reply_fn(test->queue, NULL);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_ok_methods[] = {
|
||||
{ GDBUS_TEST_METHOD(test_ok_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void test_ok_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_ok_data *test = G_CAST(dbus, struct test_ok_data, dbus);
|
||||
|
||||
test_register_interface(test_ok_methods, test);
|
||||
test_client_call(dbus, 0, test_dbus_check_empty_reply);
|
||||
test_client_call(dbus, 1, test_ok_last_reply);
|
||||
}
|
||||
|
||||
static void test_ok(void)
|
||||
{
|
||||
struct test_ok_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_ok_start;
|
||||
test.queue = __ofono_dbus_queue_new();
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
__ofono_dbus_queue_free(test.queue);
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_(name) "/dbus-queue/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
|
||||
test_debug = TRUE;
|
||||
} else {
|
||||
GWARN("Unsupported command line option %s", arg);
|
||||
}
|
||||
}
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
__ofono_log_init("test-dbus-queue",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("free"), test_free);
|
||||
g_test_add_func(TEST_("cancel"), test_cancel);
|
||||
g_test_add_func(TEST_("async"), test_async);
|
||||
g_test_add_func(TEST_("sync"), test_sync);
|
||||
g_test_add_func(TEST_("reply"), test_reply);
|
||||
g_test_add_func(TEST_("ok"), test_ok);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
struct test_polkit_auth_check {
|
||||
void (*function)(dbus_bool_t authorized, void *user_data);
|
||||
void *user_data;
|
||||
@@ -233,13 +235,11 @@ const char *test_dbus_get_object_path(DBusMessageIter *it)
|
||||
return value;
|
||||
}
|
||||
|
||||
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data)
|
||||
void test_dbus_check_empty_reply(DBusPendingCall *call, void *unused)
|
||||
{
|
||||
struct test_dbus_context *test = data;
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusMessageIter it;
|
||||
|
||||
DBG("");
|
||||
g_assert(dbus_message_get_type(reply) ==
|
||||
DBUS_MESSAGE_TYPE_METHOD_RETURN);
|
||||
|
||||
@@ -248,9 +248,29 @@ void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data)
|
||||
|
||||
dbus_message_unref(reply);
|
||||
dbus_pending_call_unref(call);
|
||||
}
|
||||
|
||||
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_dbus_context *test = data;
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_empty_reply(call, data);
|
||||
test_dbus_loop_quit_later(test->loop);
|
||||
}
|
||||
|
||||
void test_dbus_check_error_reply(DBusPendingCall *call, const char *error)
|
||||
{
|
||||
DBusMessage *msg = dbus_pending_call_steal_reply(call);
|
||||
const char *name;
|
||||
|
||||
g_assert(dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_ERROR);
|
||||
name = dbus_message_get_error_name(msg);
|
||||
g_assert(!g_strcmp0(name, error));
|
||||
dbus_message_unref(msg);
|
||||
dbus_pending_call_unref(call);
|
||||
}
|
||||
|
||||
void test_dbus_check_string_reply(DBusPendingCall *call, const char *str)
|
||||
{
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
@@ -307,15 +327,22 @@ static void test_dbus_connection_cb(DBusServer *server, DBusConnection *conn,
|
||||
|
||||
void test_dbus_setup(struct test_dbus_context *test)
|
||||
{
|
||||
char *path;
|
||||
char *address;
|
||||
GMainContext *context;
|
||||
|
||||
/* Generate unique non-existent path */
|
||||
path = g_dir_make_tmp ("test-dbus.XXXXXX", NULL);
|
||||
g_assert(path);
|
||||
rmdir(path);
|
||||
|
||||
address = g_strconcat("unix:path=", path, NULL);
|
||||
|
||||
test->loop = g_main_loop_new(NULL, TRUE);
|
||||
context = g_main_loop_get_context(test->loop);
|
||||
test->server = dbus_server_listen("unix:runtime=yes;unix:tmpdir=/tmp",
|
||||
NULL);
|
||||
|
||||
test->server = dbus_server_listen(address, NULL);
|
||||
g_assert(test->server);
|
||||
address = dbus_server_get_address(test->server);
|
||||
DBG("listening on %s", address);
|
||||
|
||||
dbus_server_setup_with_g_main(test->server, context);
|
||||
@@ -328,7 +355,8 @@ void test_dbus_setup(struct test_dbus_context *test)
|
||||
g_assert(dbus_connection_add_filter(test->client_connection,
|
||||
test_dbus_client_message_cb, test, NULL));
|
||||
DBG("connected on %s", address);
|
||||
dbus_free(address);
|
||||
g_free(address);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
void test_dbus_shutdown(struct test_dbus_context *test)
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
#include <ofono/gdbus.h>
|
||||
|
||||
struct test_dbus_context {
|
||||
GMainLoop *loop;
|
||||
DBusServer *server;
|
||||
DBusConnection *server_connection;
|
||||
DBusConnection *client_connection;
|
||||
GSList* client_signals;
|
||||
void (*start)(struct test_dbus_context *test);
|
||||
guint timeout_id;
|
||||
GMainLoop *loop;
|
||||
DBusServer *server;
|
||||
DBusConnection *server_connection;
|
||||
DBusConnection *client_connection;
|
||||
GSList* client_signals;
|
||||
void (*start)(struct test_dbus_context *test);
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
void test_dbus_setup(struct test_dbus_context *context);
|
||||
@@ -39,7 +39,9 @@ gboolean test_dbus_get_bool(DBusMessageIter *it);
|
||||
const char *test_dbus_get_string(DBusMessageIter *it);
|
||||
const char *test_dbus_get_object_path(DBusMessageIter *it);
|
||||
|
||||
void test_dbus_check_error_reply(DBusPendingCall *call, const char *error);
|
||||
void test_dbus_check_string_reply(DBusPendingCall *call, const char *str);
|
||||
void test_dbus_check_empty_reply(DBusPendingCall *call, void *unused);
|
||||
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data);
|
||||
|
||||
DBusMessage *test_dbus_find_signal(struct test_dbus_context *test,
|
||||
|
||||
1133
ofono/unit/test-gprs-filter.c
Normal file
1133
ofono/unit/test-gprs-filter.c
Normal file
File diff suppressed because it is too large
Load Diff
97
ofono/unit/test-ril-transport.c
Normal file
97
ofono/unit/test-ril-transport.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ofono.h"
|
||||
#include <ofono/ril-transport.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
static void test_null(void)
|
||||
{
|
||||
struct ofono_ril_transport noname;
|
||||
|
||||
memset(&noname, 0, sizeof(noname));
|
||||
g_assert(ofono_ril_transport_register(NULL) == -EINVAL);
|
||||
g_assert(ofono_ril_transport_register(&noname) == -EINVAL);
|
||||
ofono_ril_transport_unregister(NULL);
|
||||
ofono_ril_transport_unregister(&noname);
|
||||
g_assert(!ofono_ril_transport_connect(NULL, NULL));
|
||||
}
|
||||
|
||||
static void test_register(void)
|
||||
{
|
||||
struct ofono_ril_transport foo;
|
||||
struct ofono_ril_transport bar;
|
||||
|
||||
memset(&foo, 0, sizeof(foo));
|
||||
memset(&bar, 0, sizeof(bar));
|
||||
|
||||
foo.name = "foo";
|
||||
bar.name = "bar";
|
||||
g_assert(ofono_ril_transport_register(&foo) == 0);
|
||||
g_assert(ofono_ril_transport_register(&bar) == 0);
|
||||
g_assert(ofono_ril_transport_register(&bar) == (-EALREADY));
|
||||
g_assert(!ofono_ril_transport_connect(foo.name, NULL));
|
||||
g_assert(!ofono_ril_transport_connect("test", NULL));
|
||||
ofono_ril_transport_unregister(&foo);
|
||||
ofono_ril_transport_unregister(&bar);
|
||||
}
|
||||
|
||||
static struct grilio_transport *test_connect_cb(GHashTable *params)
|
||||
{
|
||||
static int dummy;
|
||||
|
||||
return (void*)&dummy;
|
||||
}
|
||||
|
||||
static void test_connect(void)
|
||||
{
|
||||
static const struct ofono_ril_transport test = {
|
||||
.name = "test",
|
||||
.api_version = OFONO_RIL_TRANSPORT_API_VERSION,
|
||||
.connect = test_connect_cb
|
||||
};
|
||||
|
||||
g_assert(ofono_ril_transport_register(&test) == 0);
|
||||
/* The returned pointer points to a static variable, no need to free */
|
||||
g_assert(ofono_ril_transport_connect(test.name, NULL));
|
||||
ofono_ril_transport_unregister(&test);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril-transport/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-ril_util",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("register"), test_register);
|
||||
g_test_add_func(TEST_("connect"), test_connect);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
864
ofono/unit/test-ril_config.c
Normal file
864
ofono/unit/test-ril_config.c
Normal file
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drivers/ril/ril_config.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define TMP_DIR_TEMPLATE "test-ril_config-XXXXXX"
|
||||
|
||||
static void test_get_value(const char *conf, void (*test)(GKeyFile *k))
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/test.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_assert(g_file_set_contents(file, conf, -1, NULL));
|
||||
g_assert(g_key_file_load_from_file(k, file, 0, NULL));
|
||||
|
||||
DBG("%s:\n%s", file, conf);
|
||||
test(k);
|
||||
|
||||
remove(file);
|
||||
remove(dir);
|
||||
|
||||
g_key_file_unref(k);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
static gboolean test_keyfile_empty(GKeyFile *k)
|
||||
{
|
||||
gsize n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
g_strfreev(groups);
|
||||
return !n;
|
||||
}
|
||||
|
||||
static void test_merge_ignore(const char *filename, const char *contents,
|
||||
const char *dirname, const char *filename1, const char *contents1)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/", filename, NULL);
|
||||
char *subdir = g_strconcat(dir, "/", dirname, NULL);
|
||||
char *file1 = g_strconcat(subdir, "/", filename1, NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
static void test_merge1(const char *conf, const char *conf1, const char *out)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, conf, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, conf1, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, out));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== get_string ==== */
|
||||
|
||||
static void test_get_string0_cb(GKeyFile *k)
|
||||
{
|
||||
char *value = ril_config_get_string(k, "g", "k");
|
||||
g_assert(!g_strcmp0(value, "v"));
|
||||
g_free(value);
|
||||
g_assert(!ril_config_get_string(k, RILCONF_SETTINGS_GROUP, "k"));
|
||||
g_assert(!ril_config_get_string(k, "foo", "k"));
|
||||
}
|
||||
|
||||
static void test_get_string0(void)
|
||||
{
|
||||
static const char conf [] = "[g]\nk=v\n";
|
||||
test_get_value(conf, test_get_string0_cb);
|
||||
}
|
||||
|
||||
static void test_get_string1_cb(GKeyFile *k)
|
||||
{
|
||||
char *value = ril_config_get_string(k, RILCONF_SETTINGS_GROUP, "k");
|
||||
g_assert(!g_strcmp0(value, "v"));
|
||||
g_free(value);
|
||||
value = ril_config_get_string(k, "g", "k");
|
||||
g_assert(!g_strcmp0(value, "v"));
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
static void test_get_string1(void)
|
||||
{
|
||||
static const char conf [] = "[" RILCONF_SETTINGS_GROUP "]\nk=v\n";
|
||||
|
||||
test_get_value(conf, test_get_string1_cb);
|
||||
}
|
||||
|
||||
static void test_get_string2_cb(GKeyFile *k)
|
||||
{
|
||||
char *value = ril_config_get_string(k, RILCONF_SETTINGS_GROUP, "k");
|
||||
g_assert(!g_strcmp0(value, "v1"));
|
||||
g_free(value);
|
||||
value = ril_config_get_string(k, "g", "k");
|
||||
g_assert(!g_strcmp0(value, "v2"));
|
||||
g_free(value);
|
||||
value = ril_config_get_string(k, "g1", "k");
|
||||
g_assert(!g_strcmp0(value, "v1"));
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
static void test_get_string2(void)
|
||||
{
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=v1\n\n"
|
||||
"[g]\nk=v2\n";
|
||||
|
||||
test_get_value(conf, test_get_string2_cb);
|
||||
}
|
||||
|
||||
/* ==== get_strings ==== */
|
||||
|
||||
static void test_get_strings0_cb(GKeyFile *k)
|
||||
{
|
||||
char **values = ril_config_get_strings(k, "g", "k", ',');
|
||||
g_assert(values);
|
||||
g_assert(gutil_strv_length(values) == 0);
|
||||
g_strfreev(values);
|
||||
|
||||
values = ril_config_get_strings(k, RILCONF_SETTINGS_GROUP, "k", ',');
|
||||
g_assert(values);
|
||||
g_assert(gutil_strv_length(values) == 0);
|
||||
g_strfreev(values);
|
||||
}
|
||||
|
||||
static void test_get_strings0(void)
|
||||
{
|
||||
static const char conf [] = "[" RILCONF_SETTINGS_GROUP "]\nk=\n";
|
||||
test_get_value(conf, test_get_strings0_cb);
|
||||
}
|
||||
|
||||
static void test_get_strings1_cb(GKeyFile *k)
|
||||
{
|
||||
char **values = ril_config_get_strings(k, "g", "k", ',');
|
||||
g_assert(gutil_strv_length(values) == 2);
|
||||
g_assert(!g_strcmp0(values[0], "v0"));
|
||||
g_assert(!g_strcmp0(values[1], "v1"));
|
||||
g_strfreev(values);
|
||||
|
||||
g_assert(!ril_config_get_strings(k, RILCONF_SETTINGS_GROUP, "k", ','));
|
||||
}
|
||||
|
||||
static void test_get_strings1(void)
|
||||
{
|
||||
static const char conf [] = "[g]\nk=v0 , v1\n";
|
||||
|
||||
test_get_value(conf, test_get_strings1_cb);
|
||||
}
|
||||
|
||||
/* ==== get_integer ==== */
|
||||
|
||||
static void test_get_integer0_cb(GKeyFile *k)
|
||||
{
|
||||
int val = -1;
|
||||
|
||||
g_assert(!ril_config_get_integer(k, "g1", "k1", NULL));
|
||||
g_assert(!ril_config_get_integer(k, "g1", "k1", &val));
|
||||
g_assert(val == -1);
|
||||
|
||||
g_assert(ril_config_get_integer(k, "g", "k", NULL));
|
||||
g_assert(ril_config_get_integer(k, "g", "k", &val));
|
||||
g_assert(val == 1);
|
||||
|
||||
g_assert(ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", &val));
|
||||
g_assert(val == 0);
|
||||
}
|
||||
|
||||
static void test_get_integer0(void)
|
||||
{
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=0\n\n"
|
||||
"[g]\nk=1\n";
|
||||
|
||||
test_get_value(conf, test_get_integer0_cb);
|
||||
}
|
||||
|
||||
static void test_get_integer1_cb(GKeyFile *k)
|
||||
{
|
||||
int val = -1;
|
||||
|
||||
g_assert(!ril_config_get_integer(k, "g", "k", NULL));
|
||||
g_assert(!ril_config_get_integer(k, "g", "k", &val));
|
||||
g_assert(val == -1);
|
||||
|
||||
g_assert(!ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", NULL));
|
||||
g_assert(!ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", &val));
|
||||
g_assert(val == -1);
|
||||
}
|
||||
|
||||
static void test_get_integer1(void)
|
||||
{
|
||||
/* Invalid integer values */
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=foo\n\n"
|
||||
"[g]\nk=bar\n";
|
||||
|
||||
test_get_value(conf, test_get_integer1_cb);
|
||||
}
|
||||
|
||||
static void test_get_integer2_cb(GKeyFile *k)
|
||||
{
|
||||
int val = -1;
|
||||
|
||||
g_assert(ril_config_get_integer(k, "g", "k", NULL));
|
||||
g_assert(ril_config_get_integer(k, "g", "k", &val));
|
||||
g_assert(val == 1);
|
||||
|
||||
g_assert(ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", NULL));
|
||||
g_assert(ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", &val));
|
||||
g_assert(val == 1);
|
||||
}
|
||||
|
||||
static void test_get_integer2(void)
|
||||
{
|
||||
/* Invalid value in [g] but a valid one in [Settings] */
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=1\n"
|
||||
"\n[g]\nk=foo\n";
|
||||
|
||||
test_get_value(conf, test_get_integer2_cb);
|
||||
}
|
||||
|
||||
/* ==== get_boolean ==== */
|
||||
|
||||
static void test_get_boolean0_cb(GKeyFile *k)
|
||||
{
|
||||
gboolean val = FALSE;
|
||||
|
||||
g_assert(!ril_config_get_boolean(k, "g1", "k1", NULL));
|
||||
g_assert(!ril_config_get_boolean(k, "g1", "k1", &val));
|
||||
g_assert(!val);
|
||||
|
||||
g_assert(ril_config_get_boolean(k, "g", "k", NULL));
|
||||
g_assert(ril_config_get_boolean(k, "g", "k", &val));
|
||||
g_assert(val == TRUE);
|
||||
|
||||
g_assert(ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
|
||||
g_assert(val == FALSE);
|
||||
}
|
||||
|
||||
static void test_get_boolean0(void)
|
||||
{
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=false\n\n"
|
||||
"[g]\nk=true\n";
|
||||
|
||||
test_get_value(conf, test_get_boolean0_cb);
|
||||
}
|
||||
|
||||
static void test_get_boolean1_cb(GKeyFile *k)
|
||||
{
|
||||
gboolean val = TRUE;
|
||||
|
||||
g_assert(!ril_config_get_boolean(k, "g", "k", NULL));
|
||||
g_assert(!ril_config_get_boolean(k, "g", "k", &val));
|
||||
g_assert(val == TRUE);
|
||||
|
||||
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", NULL));
|
||||
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
|
||||
g_assert(val == TRUE);
|
||||
}
|
||||
|
||||
static void test_get_boolean1(void)
|
||||
{
|
||||
/* Invalid boolean values */
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=foo\n\n"
|
||||
"[g]\nk=bar\n";
|
||||
|
||||
test_get_value(conf, test_get_boolean1_cb);
|
||||
}
|
||||
|
||||
static void test_get_boolean2_cb(GKeyFile *k)
|
||||
{
|
||||
gboolean val = FALSE;
|
||||
|
||||
g_assert(ril_config_get_boolean(k, "g", "k", NULL));
|
||||
g_assert(ril_config_get_boolean(k, "g", "k", &val));
|
||||
g_assert(val == TRUE);
|
||||
|
||||
g_assert(ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", NULL));
|
||||
g_assert(ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
|
||||
g_assert(val == TRUE);
|
||||
}
|
||||
|
||||
static void test_get_boolean2(void)
|
||||
{
|
||||
/* Invalid value in [g] but a valid one in [Settings] */
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=true\n"
|
||||
"\n[g]\nk=foo\n";
|
||||
|
||||
test_get_value(conf, test_get_boolean2_cb);
|
||||
}
|
||||
|
||||
static void test_get_boolean3_cb(GKeyFile *k)
|
||||
{
|
||||
gboolean val = FALSE;
|
||||
|
||||
g_assert(ril_config_get_boolean(k, "g", "k", NULL));
|
||||
g_assert(ril_config_get_boolean(k, "g", "k", &val));
|
||||
g_assert(val == TRUE);
|
||||
|
||||
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", NULL));
|
||||
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
|
||||
g_assert(val == TRUE);
|
||||
}
|
||||
|
||||
static void test_get_boolean3(void)
|
||||
{
|
||||
/* Valid value in [g] and invalid one in [Settings] */
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=foo\n\n"
|
||||
"[g]\nk=true\n";
|
||||
|
||||
test_get_value(conf, test_get_boolean3_cb);
|
||||
}
|
||||
|
||||
/* ==== get_flag ==== */
|
||||
|
||||
static void test_get_flag_cb(GKeyFile *k)
|
||||
{
|
||||
const int f = 0x01;
|
||||
int mask = 0;
|
||||
|
||||
g_assert(!ril_config_get_flag(k, "g1", "k1", f, &mask));
|
||||
g_assert(!mask);
|
||||
|
||||
g_assert(ril_config_get_flag(k, "g", "k", f, &mask));
|
||||
g_assert(mask & f);
|
||||
|
||||
g_assert(ril_config_get_flag(k, RILCONF_SETTINGS_GROUP, "k", f, &mask));
|
||||
g_assert(!(mask & f));
|
||||
}
|
||||
|
||||
static void test_get_flag(void)
|
||||
{
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk=false\n\n"
|
||||
"[g]\nk=true\n";
|
||||
|
||||
test_get_value(conf, test_get_flag_cb);
|
||||
}
|
||||
|
||||
/* ==== get_enum ==== */
|
||||
|
||||
static void test_get_enum_cb(GKeyFile *k)
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
g_assert(!ril_config_get_enum(k, "g1", "k1", &val, "foo", 1, NULL));
|
||||
g_assert(!val);
|
||||
|
||||
g_assert(!ril_config_get_enum(k, "g", "k", NULL, "foo", 1, NULL));
|
||||
g_assert(!ril_config_get_enum(k, "g", "k", &val, "foo", 1, NULL));
|
||||
g_assert(!val);
|
||||
|
||||
g_assert(ril_config_get_enum(k,"g","k",NULL,"foo",1,"bar",2,NULL));
|
||||
g_assert(ril_config_get_enum(k,"g","k",&val,"bar",2,"foo",1,NULL));
|
||||
g_assert(val == 2);
|
||||
|
||||
g_assert(ril_config_get_enum(k, "g", "x", NULL,
|
||||
"a", 1, "b", 2, "y", 3, NULL));
|
||||
g_assert(ril_config_get_enum(k, "g", "x", &val,
|
||||
"a", 1, "b", 2, "y", 3, NULL));
|
||||
g_assert(val == 3);
|
||||
|
||||
g_assert(ril_config_get_enum(k, RILCONF_SETTINGS_GROUP, "k", NULL,
|
||||
"foo", 1, NULL));
|
||||
g_assert(ril_config_get_enum(k, RILCONF_SETTINGS_GROUP, "k", &val,
|
||||
"foo", 1, NULL));
|
||||
g_assert(val == 1);
|
||||
}
|
||||
|
||||
static void test_get_enum(void)
|
||||
{
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk= foo# comment\n\n"
|
||||
"[g]\nk= bar \nx=y\n";
|
||||
|
||||
test_get_value(conf, test_get_enum_cb);
|
||||
}
|
||||
|
||||
/* ==== get_ints ==== */
|
||||
|
||||
static void test_get_ints_cb(GKeyFile *k)
|
||||
{
|
||||
GUtilInts *ints;
|
||||
const int* data;
|
||||
guint count;
|
||||
|
||||
g_assert(!ril_config_get_ints(k, "g1", "k1"));
|
||||
g_assert(!ril_config_get_ints(k, "g", "k2")); /* Empty */
|
||||
|
||||
ints = ril_config_get_ints(k, "g", "k");
|
||||
data = gutil_ints_get_data(ints, &count);
|
||||
g_assert(count == 2);
|
||||
g_assert(data[0] == 0);
|
||||
g_assert(data[1] == 1);
|
||||
gutil_ints_unref(ints);
|
||||
|
||||
ints = ril_config_get_ints(k, "g", "k1");
|
||||
data = gutil_ints_get_data(ints, &count);
|
||||
g_assert(count == 3);
|
||||
g_assert(data[0] == 2);
|
||||
g_assert(data[1] == 3);
|
||||
g_assert(data[2] == 4);
|
||||
gutil_ints_unref(ints);
|
||||
}
|
||||
|
||||
static void test_get_ints(void)
|
||||
{
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk = 0, 1, x\n"
|
||||
"[g]\nk1=2,3,4 # comment\nk2=\n";
|
||||
|
||||
test_get_value(conf, test_get_ints_cb);
|
||||
}
|
||||
|
||||
/* ==== ints_to_string ==== */
|
||||
|
||||
static void test_ints_to_string(void)
|
||||
{
|
||||
static const int data[] = { 1, 2 };
|
||||
GUtilInts* ints = gutil_ints_new_static(data, G_N_ELEMENTS(data));
|
||||
char *str = ril_config_ints_to_string(ints, ',');
|
||||
g_assert(!g_strcmp0(str, "1,2"));
|
||||
g_free(str);
|
||||
gutil_ints_unref(ints);
|
||||
|
||||
g_assert(!ril_config_ints_to_string(NULL, 0));
|
||||
}
|
||||
|
||||
/* ==== merge_basic ==== */
|
||||
|
||||
static void test_merge_basic(void)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *nonexistent = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
|
||||
ril_config_merge_files(NULL, NULL);
|
||||
|
||||
remove(nonexistent);
|
||||
ril_config_merge_files(k, nonexistent);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
ril_config_merge_files(k, NULL);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
ril_config_merge_files(k, "");
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
g_key_file_unref(k);
|
||||
g_free(nonexistent);
|
||||
}
|
||||
|
||||
/* ==== merge_simple ==== */
|
||||
|
||||
static void test_merge_simple(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *data;
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== merge_empty_dir ==== */
|
||||
|
||||
static void test_merge_empty_dir(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_ignore ==== */
|
||||
|
||||
static void test_merge_ignore0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *subdir2 = g_strconcat(subdir, "/dir.conf", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
/* Two empty subdirectories, one with matching name, one not */
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(!mkdir(subdir2, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
g_free(subdir2);
|
||||
}
|
||||
|
||||
static void test_merge_ignore1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
|
||||
/* File has no suffix */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "file", contents1);
|
||||
}
|
||||
|
||||
static void test_merge_ignore2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[[[[[[[";
|
||||
|
||||
/* File is not a valid keyfile */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "a.conf", contents1);
|
||||
}
|
||||
|
||||
/* ==== merge_sort ==== */
|
||||
|
||||
static void test_merge_sort(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
static const char contents2 [] = "[foo]\nb=4\n";
|
||||
static const char result [] = "[foo]\na=1\nb=4\n";
|
||||
|
||||
/* Test file sort order */
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/1.conf", NULL);
|
||||
char *file2 = g_strconcat(subdir, "/2.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
g_assert(g_file_set_contents(file2, contents2, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, result));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(file2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(file2);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_group ==== */
|
||||
|
||||
static void test_merge_remove_group(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\n\n[bar]\nb=1\n";
|
||||
static const char contents1 [] = "[!bar]\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_key ==== */
|
||||
|
||||
static void test_merge_remove_key(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\n!b=\n\n!=\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_default_value ==== */
|
||||
|
||||
static void test_merge_default_value(void)
|
||||
{
|
||||
/* b is assigned the default value, a stays as is */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\na:=2\nb:=3\n";
|
||||
static const char result [] = "[foo]\na=1\nb=3\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_add ==== */
|
||||
|
||||
static void test_merge_list_add0(void)
|
||||
{
|
||||
/* Adding empty list */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add1(void)
|
||||
{
|
||||
/* a=1 turns into a=1,2, */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=2,\n";
|
||||
static const char result [] = "[foo]\na=1,2,\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add2(void)
|
||||
{
|
||||
/* 2 is already there */
|
||||
static const char contents [] = "[foo]\na=1,2,\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na?=2\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add3(void)
|
||||
{
|
||||
/* 2 is already there, 3 is not */
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1,2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add4(void)
|
||||
{
|
||||
/* b=2,3, is created */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\nb?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1\nb=2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add5(void)
|
||||
{
|
||||
/* Add a new group */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[bar]\nb=2\n";
|
||||
static const char result [] = "[foo]\na=1\n\n[bar]\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_remove ==== */
|
||||
|
||||
static void test_merge_list_remove0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=2,\n";
|
||||
static const char result [] = "[foo]\na=1,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=3\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove3(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\nb-=1\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_config/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-ril_config",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("get_string0"), test_get_string0);
|
||||
g_test_add_func(TEST_("get_string1"), test_get_string1);
|
||||
g_test_add_func(TEST_("get_string2"), test_get_string2);
|
||||
g_test_add_func(TEST_("get_strings0"), test_get_strings0);
|
||||
g_test_add_func(TEST_("get_strings1"), test_get_strings1);
|
||||
g_test_add_func(TEST_("get_integer0"), test_get_integer0);
|
||||
g_test_add_func(TEST_("get_integer1"), test_get_integer1);
|
||||
g_test_add_func(TEST_("get_integer2"), test_get_integer2);
|
||||
g_test_add_func(TEST_("get_boolean0"), test_get_boolean0);
|
||||
g_test_add_func(TEST_("get_boolean1"), test_get_boolean1);
|
||||
g_test_add_func(TEST_("get_boolean2"), test_get_boolean2);
|
||||
g_test_add_func(TEST_("get_boolean3"), test_get_boolean3);
|
||||
g_test_add_func(TEST_("get_flag"), test_get_flag);
|
||||
g_test_add_func(TEST_("get_enum"), test_get_enum);
|
||||
g_test_add_func(TEST_("get_ints"), test_get_ints);
|
||||
g_test_add_func(TEST_("ints_to_string"), test_ints_to_string);
|
||||
g_test_add_func(TEST_("merge_basic"), test_merge_basic);
|
||||
g_test_add_func(TEST_("merge_simple"), test_merge_simple);
|
||||
g_test_add_func(TEST_("merge_empty_dir"), test_merge_empty_dir);
|
||||
g_test_add_func(TEST_("merge_ignore0"), test_merge_ignore0);
|
||||
g_test_add_func(TEST_("merge_ignore1"), test_merge_ignore1);
|
||||
g_test_add_func(TEST_("merge_ignore2"), test_merge_ignore2);
|
||||
g_test_add_func(TEST_("merge_sort"), test_merge_sort);
|
||||
g_test_add_func(TEST_("merge_remove_group"), test_merge_remove_group);
|
||||
g_test_add_func(TEST_("merge_remove_key"), test_merge_remove_key);
|
||||
g_test_add_func(TEST_("merge_default_value"), test_merge_default_value);
|
||||
g_test_add_func(TEST_("merge_list_add0"), test_merge_list_add0);
|
||||
g_test_add_func(TEST_("merge_list_add1"), test_merge_list_add1);
|
||||
g_test_add_func(TEST_("merge_list_add2"), test_merge_list_add2);
|
||||
g_test_add_func(TEST_("merge_list_add3"), test_merge_list_add3);
|
||||
g_test_add_func(TEST_("merge_list_add4"), test_merge_list_add4);
|
||||
g_test_add_func(TEST_("merge_list_add5"), test_merge_list_add5);
|
||||
g_test_add_func(TEST_("merge_list_remove0"), test_merge_list_remove0);
|
||||
g_test_add_func(TEST_("merge_list_remove1"), test_merge_list_remove1);
|
||||
g_test_add_func(TEST_("merge_list_remove2"), test_merge_list_remove2);
|
||||
g_test_add_func(TEST_("merge_list_remove3"), test_merge_list_remove3);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -81,27 +81,6 @@ void test_parse_mcc_mnc(void)
|
||||
g_assert(!op.tech);
|
||||
}
|
||||
|
||||
void test_parse_int(void)
|
||||
{
|
||||
int value;
|
||||
|
||||
g_assert(!ril_parse_int(NULL, 0, NULL));
|
||||
g_assert(!ril_parse_int("", 0, NULL));
|
||||
g_assert(!ril_parse_int("garbage", 0, NULL));
|
||||
g_assert(!ril_parse_int("0 trailing garbage", 0, NULL));
|
||||
g_assert(ril_parse_int("0", 0, NULL));
|
||||
g_assert(ril_parse_int("0", 0, &value));
|
||||
g_assert(value == 0);
|
||||
g_assert(!ril_parse_int("0x10000000000000000", 0, &value));
|
||||
g_assert(!ril_parse_int("-2147483649", 0, &value));
|
||||
g_assert(!ril_parse_int("4294967295", 0, &value));
|
||||
g_assert(ril_parse_int(" 0x7fffffff ", 0, &value));
|
||||
g_assert(value == 0x7fffffff);
|
||||
g_assert(ril_parse_int(" 7fffffff ", 16, &value));
|
||||
g_assert(value == 0x7fffffff);
|
||||
g_assert(!ril_parse_int("0xffffffff", 0, &value));
|
||||
}
|
||||
|
||||
void test_strings(void)
|
||||
{
|
||||
g_assert(!g_strcmp0(ril_error_to_string(RIL_E_SUCCESS), "OK"));
|
||||
@@ -128,7 +107,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
g_test_add_func(TEST_("parse_tech"), test_parse_tech);
|
||||
g_test_add_func(TEST_("parse_mcc_mnc"), test_parse_mcc_mnc);
|
||||
g_test_add_func(TEST_("parse_int"), test_parse_int);
|
||||
g_test_add_func(TEST_("strings"), test_strings);
|
||||
|
||||
return g_test_run();
|
||||
|
||||
710
ofono/unit/test-sailfish_watch.c
Normal file
710
ofono/unit/test-sailfish_watch.c
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sailfish_watch.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
static GSList *g_modem_list = NULL;
|
||||
static struct ofono_watchlist *g_modemwatches = NULL;
|
||||
|
||||
#define TEST_PATH "/test_0"
|
||||
#define TEST_PATH_1 "/test_1"
|
||||
#define TEST_ICCID "0000000000000000000"
|
||||
#define TEST_IMSI "244120000000000"
|
||||
#define TEST_SPN "Test"
|
||||
|
||||
/* Fake ofono_atom */
|
||||
|
||||
struct ofono_atom {
|
||||
enum ofono_atom_type type;
|
||||
gboolean registered;
|
||||
void *data;
|
||||
struct ofono_modem *modem;
|
||||
};
|
||||
|
||||
void *__ofono_atom_get_data(struct ofono_atom *atom)
|
||||
{
|
||||
return atom->data;
|
||||
}
|
||||
|
||||
/* Fake ofono_netreg */
|
||||
|
||||
struct ofono_netreg {
|
||||
struct ofono_atom atom;
|
||||
};
|
||||
|
||||
/* Fake ofono_sim */
|
||||
|
||||
struct ofono_sim {
|
||||
struct ofono_atom atom;
|
||||
const char *spn;
|
||||
const char *spn_dc;
|
||||
const char *imsi;
|
||||
const char *iccid;
|
||||
enum ofono_sim_state state;
|
||||
struct ofono_watchlist *spn_watches;
|
||||
struct ofono_watchlist *imsi_watches;
|
||||
struct ofono_watchlist *iccid_watches;
|
||||
struct ofono_watchlist *state_watches;
|
||||
};
|
||||
|
||||
static unsigned int add_watch_item(struct ofono_watchlist *list,
|
||||
void *notify, void *data, ofono_destroy_func destroy)
|
||||
{
|
||||
struct ofono_watchlist_item *watch =
|
||||
g_new0(struct ofono_watchlist_item, 1);
|
||||
|
||||
watch->notify = notify;
|
||||
watch->destroy = destroy;
|
||||
watch->notify_data = data;
|
||||
return __ofono_watchlist_add_item(list, watch);
|
||||
}
|
||||
|
||||
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
|
||||
ofono_sim_iccid_event_cb_t cb, void *data,
|
||||
ofono_destroy_func destroy)
|
||||
{
|
||||
guint id = add_watch_item(sim->iccid_watches, cb, data, destroy);
|
||||
|
||||
if (sim->iccid) {
|
||||
cb(sim->iccid, data);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void ofono_sim_remove_iccid_watch(struct ofono_sim *sim, unsigned int id)
|
||||
{
|
||||
__ofono_watchlist_remove_item(sim->iccid_watches, id);
|
||||
}
|
||||
|
||||
static void iccid_watches_cb(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct ofono_watchlist_item *item = data;
|
||||
ofono_sim_iccid_event_cb_t cb = item->notify;
|
||||
|
||||
cb(sim->iccid, item->notify_data);
|
||||
}
|
||||
|
||||
static inline void iccid_watches_notify(struct ofono_sim *sim)
|
||||
{
|
||||
g_slist_foreach(sim->iccid_watches->items, iccid_watches_cb, sim);
|
||||
}
|
||||
|
||||
unsigned int ofono_sim_add_imsi_watch(struct ofono_sim *sim,
|
||||
ofono_sim_imsi_event_cb_t cb, void *data,
|
||||
ofono_destroy_func destroy)
|
||||
{
|
||||
guint id = add_watch_item(sim->imsi_watches, cb, data, destroy);
|
||||
|
||||
if (sim->imsi) {
|
||||
cb(sim->imsi, data);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void ofono_sim_remove_imsi_watch(struct ofono_sim *sim, unsigned int id)
|
||||
{
|
||||
__ofono_watchlist_remove_item(sim->imsi_watches, id);
|
||||
}
|
||||
|
||||
static void imsi_watches_cb(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct ofono_watchlist_item *item = data;
|
||||
ofono_sim_imsi_event_cb_t cb = item->notify;
|
||||
|
||||
cb(sim->imsi, item->notify_data);
|
||||
}
|
||||
|
||||
static inline void imsi_watches_notify(struct ofono_sim *sim)
|
||||
{
|
||||
g_slist_foreach(sim->imsi_watches->items, imsi_watches_cb, sim);
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_sim_add_spn_watch(struct ofono_sim *sim, unsigned int *id,
|
||||
ofono_sim_spn_cb_t cb, void *data, ofono_destroy_func destroy)
|
||||
{
|
||||
*id = add_watch_item(sim->spn_watches, cb, data, destroy);
|
||||
if (sim->spn) {
|
||||
cb(sim->spn, sim->spn_dc, data);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_sim_remove_spn_watch(struct ofono_sim *sim, unsigned int *id)
|
||||
{
|
||||
if (__ofono_watchlist_remove_item(sim->spn_watches, *id)) {
|
||||
*id = 0;
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void spn_watches_cb(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct ofono_watchlist_item *item = data;
|
||||
ofono_sim_spn_cb_t notify = item->notify;
|
||||
|
||||
notify(sim->spn, sim->spn_dc, item->notify_data);
|
||||
}
|
||||
|
||||
static inline void spn_watches_notify(struct ofono_sim *sim)
|
||||
{
|
||||
g_slist_foreach(sim->spn_watches->items, spn_watches_cb, sim);
|
||||
}
|
||||
|
||||
unsigned int ofono_sim_add_state_watch(struct ofono_sim *sim,
|
||||
ofono_sim_state_event_cb_t notify,
|
||||
void *data, ofono_destroy_func destroy)
|
||||
{
|
||||
return add_watch_item(sim->state_watches, notify, data, destroy);
|
||||
}
|
||||
|
||||
void ofono_sim_remove_state_watch(struct ofono_sim *sim, unsigned int id)
|
||||
{
|
||||
__ofono_watchlist_remove_item(sim->state_watches, id);
|
||||
}
|
||||
|
||||
static void state_watches_cb(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct ofono_watchlist_item *item = data;
|
||||
ofono_sim_state_event_cb_t notify = item->notify;
|
||||
|
||||
notify(sim->state, item->notify_data);
|
||||
}
|
||||
|
||||
static void state_watches_notify(struct ofono_sim *sim)
|
||||
{
|
||||
g_slist_foreach(sim->state_watches->items, state_watches_cb, sim);
|
||||
}
|
||||
|
||||
/* Fake modem */
|
||||
|
||||
struct ofono_modem {
|
||||
const char *path;
|
||||
gboolean online;
|
||||
GSList *atoms;
|
||||
struct ofono_watchlist *atom_watches;
|
||||
struct ofono_watchlist *online_watches;
|
||||
struct ofono_sim sim;
|
||||
struct ofono_netreg netreg;
|
||||
};
|
||||
|
||||
struct atom_watch {
|
||||
struct ofono_watchlist_item item;
|
||||
enum ofono_atom_type type;
|
||||
};
|
||||
|
||||
void __ofono_modemwatch_init(void)
|
||||
{
|
||||
g_assert(!g_modem_list);
|
||||
g_assert(!g_modemwatches);
|
||||
g_modemwatches = __ofono_watchlist_new(g_free);
|
||||
}
|
||||
|
||||
void __ofono_modemwatch_cleanup(void)
|
||||
{
|
||||
g_assert(!g_modem_list);
|
||||
__ofono_watchlist_free(g_modemwatches);
|
||||
g_modemwatches = NULL;
|
||||
}
|
||||
|
||||
unsigned int __ofono_modemwatch_add(ofono_modemwatch_cb_t cb, void *data,
|
||||
ofono_destroy_func destroy)
|
||||
{
|
||||
return add_watch_item(g_modemwatches, cb, data, destroy);
|
||||
}
|
||||
|
||||
gboolean __ofono_modemwatch_remove(unsigned int id)
|
||||
{
|
||||
return __ofono_watchlist_remove_item(g_modemwatches, id);
|
||||
}
|
||||
|
||||
static void call_modemwatches(struct ofono_modem *modem, gboolean added)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
DBG("%p added:%d", modem, added);
|
||||
for (l = g_modemwatches->items; l; l = l->next) {
|
||||
struct ofono_watchlist_item *watch = l->data;
|
||||
ofono_modemwatch_cb_t notify = watch->notify;
|
||||
|
||||
notify(modem, added, watch->notify_data);
|
||||
}
|
||||
}
|
||||
|
||||
const char *ofono_modem_get_path(struct ofono_modem *modem)
|
||||
{
|
||||
return modem->path;
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_modem_get_online(struct ofono_modem *modem)
|
||||
{
|
||||
return modem && modem->online;
|
||||
}
|
||||
|
||||
struct ofono_modem *ofono_modem_find(ofono_modem_compare_cb_t func,
|
||||
void *user_data)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = g_modem_list; l; l = l->next) {
|
||||
struct ofono_modem *modem = l->data;
|
||||
|
||||
if (func(modem, user_data)) {
|
||||
return modem;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int __ofono_modem_add_atom_watch(struct ofono_modem *modem,
|
||||
enum ofono_atom_type type, ofono_atom_watch_func notify,
|
||||
void *data, ofono_destroy_func destroy)
|
||||
{
|
||||
GSList *l;
|
||||
unsigned int id;
|
||||
struct atom_watch *watch = g_new0(struct atom_watch, 1);
|
||||
|
||||
watch->type = type;
|
||||
watch->item.notify = notify;
|
||||
watch->item.destroy = destroy;
|
||||
watch->item.notify_data = data;
|
||||
id = __ofono_watchlist_add_item(modem->atom_watches, &watch->item);
|
||||
|
||||
for (l = modem->atoms; l; l = l->next) {
|
||||
struct ofono_atom *atom = l->data;
|
||||
|
||||
if (atom->type == type && atom->registered) {
|
||||
notify(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void call_watches(struct ofono_atom *atom,
|
||||
enum ofono_atom_watch_condition cond)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = atom->modem->atom_watches->items; l; l = l->next) {
|
||||
struct atom_watch *watch = l->data;
|
||||
|
||||
if (watch->type == atom->type) {
|
||||
ofono_atom_watch_func notify = watch->item.notify;
|
||||
|
||||
notify(atom, cond, watch->item.notify_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean __ofono_modem_remove_atom_watch(struct ofono_modem *modem,
|
||||
unsigned int id)
|
||||
{
|
||||
return __ofono_watchlist_remove_item(modem->atom_watches, id);
|
||||
}
|
||||
|
||||
unsigned int __ofono_modem_add_online_watch(struct ofono_modem *modem,
|
||||
ofono_modem_online_notify_func notify,
|
||||
void *data, ofono_destroy_func destroy)
|
||||
{
|
||||
return add_watch_item(modem->online_watches, notify, data, destroy);
|
||||
}
|
||||
|
||||
void __ofono_modem_remove_online_watch(struct ofono_modem *modem,
|
||||
unsigned int id)
|
||||
{
|
||||
__ofono_watchlist_remove_item(modem->online_watches, id);
|
||||
}
|
||||
|
||||
static void notify_online_watches_cb(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct ofono_watchlist_item *item = data;
|
||||
ofono_modem_online_notify_func notify = item->notify;
|
||||
|
||||
notify(modem, modem->online, item->notify_data);
|
||||
}
|
||||
|
||||
static void notify_online_watches(struct ofono_modem *modem)
|
||||
{
|
||||
g_slist_foreach(modem->online_watches->items,
|
||||
notify_online_watches_cb, modem);
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
|
||||
static void test_modem_register_atom(struct ofono_modem *modem,
|
||||
struct ofono_atom *atom)
|
||||
{
|
||||
if (!atom->registered) {
|
||||
atom->registered = TRUE;
|
||||
modem->atoms = g_slist_append(modem->atoms, atom);
|
||||
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_modem_unregister_atom(struct ofono_modem *modem,
|
||||
struct ofono_atom *atom)
|
||||
{
|
||||
if (atom->registered) {
|
||||
atom->registered = FALSE;
|
||||
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_UNREGISTERED);
|
||||
modem->atoms = g_slist_remove(modem->atoms, atom);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_modem_init1(struct ofono_modem *modem, const char *path)
|
||||
{
|
||||
struct ofono_netreg *netreg = &modem->netreg;
|
||||
struct ofono_sim *sim = &modem->sim;
|
||||
|
||||
/* Assume that the structure has been zero-initialized */
|
||||
modem->path = path;
|
||||
modem->atom_watches = __ofono_watchlist_new(g_free);
|
||||
modem->online_watches = __ofono_watchlist_new(g_free);
|
||||
|
||||
netreg->atom.type = OFONO_ATOM_TYPE_NETREG;
|
||||
netreg->atom.modem = modem;
|
||||
netreg->atom.data = netreg;
|
||||
|
||||
sim->atom.type = OFONO_ATOM_TYPE_SIM;
|
||||
sim->atom.modem = modem;
|
||||
sim->atom.data = sim;
|
||||
|
||||
sim->iccid_watches = __ofono_watchlist_new(g_free);
|
||||
sim->imsi_watches = __ofono_watchlist_new(g_free);
|
||||
sim->state_watches = __ofono_watchlist_new(g_free);
|
||||
sim->spn_watches = __ofono_watchlist_new(g_free);
|
||||
sim->state = OFONO_SIM_STATE_NOT_PRESENT;
|
||||
|
||||
g_modem_list = g_slist_prepend(g_modem_list, modem);
|
||||
call_modemwatches(modem, TRUE);
|
||||
}
|
||||
|
||||
static void test_modem_init(struct ofono_modem *modem)
|
||||
{
|
||||
test_modem_init1(modem, TEST_PATH);
|
||||
}
|
||||
|
||||
static void test_modem_shutdown(struct ofono_modem *modem)
|
||||
{
|
||||
struct ofono_sim *sim = &modem->sim;
|
||||
|
||||
call_modemwatches(modem, FALSE);
|
||||
g_modem_list = g_slist_remove(g_modem_list, modem);
|
||||
g_slist_free(modem->atoms);
|
||||
__ofono_watchlist_free(sim->iccid_watches);
|
||||
__ofono_watchlist_free(sim->imsi_watches);
|
||||
__ofono_watchlist_free(sim->state_watches);
|
||||
__ofono_watchlist_free(sim->spn_watches);
|
||||
|
||||
__ofono_watchlist_free(modem->atom_watches);
|
||||
__ofono_watchlist_free(modem->online_watches);
|
||||
}
|
||||
|
||||
static void test_inc_cb(struct sailfish_watch *watch, void *user_data)
|
||||
{
|
||||
(*((int *)user_data))++;
|
||||
}
|
||||
|
||||
/* ==== basic ==== */
|
||||
|
||||
static void test_basic(void)
|
||||
{
|
||||
struct sailfish_watch *watch;
|
||||
struct sailfish_watch *watch1;
|
||||
struct ofono_modem modem, modem1;
|
||||
|
||||
/* NULL resistance */
|
||||
g_assert(!sailfish_watch_new(NULL));
|
||||
g_assert(!sailfish_watch_ref(NULL));
|
||||
sailfish_watch_unref(NULL);
|
||||
g_assert(!sailfish_watch_add_modem_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_online_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_sim_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_sim_state_changed_handler(NULL, NULL,
|
||||
NULL));
|
||||
g_assert(!sailfish_watch_add_iccid_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_imsi_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_spn_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_netreg_changed_handler(NULL, NULL, NULL));
|
||||
sailfish_watch_remove_handler(NULL, 0);
|
||||
sailfish_watch_remove_handlers(NULL, NULL, 0);
|
||||
|
||||
/* Instance caching */
|
||||
memset(&modem, 0, sizeof(modem));
|
||||
memset(&modem1, 0, sizeof(modem1));
|
||||
__ofono_modemwatch_init();
|
||||
test_modem_init1(&modem, TEST_PATH);
|
||||
|
||||
watch = sailfish_watch_new(TEST_PATH);
|
||||
watch1 = sailfish_watch_new(TEST_PATH_1);
|
||||
|
||||
/* The second modem is added after the watch is created */
|
||||
test_modem_init1(&modem1, TEST_PATH_1);
|
||||
|
||||
/* The second notification has no effect */
|
||||
call_modemwatches(&modem1, TRUE);
|
||||
|
||||
g_assert(watch);
|
||||
g_assert(watch1);
|
||||
g_assert(watch->modem == &modem);
|
||||
g_assert(watch1->modem == &modem1);
|
||||
g_assert(sailfish_watch_new(TEST_PATH) == watch);
|
||||
g_assert(sailfish_watch_new(TEST_PATH_1) == watch1);
|
||||
sailfish_watch_unref(watch);
|
||||
sailfish_watch_unref(watch1);
|
||||
|
||||
/* More NULLs and zeros */
|
||||
g_assert(!sailfish_watch_add_modem_changed_handler(watch, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_online_changed_handler(watch, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_sim_changed_handler(watch, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_sim_state_changed_handler(watch, NULL,
|
||||
NULL));
|
||||
g_assert(!sailfish_watch_add_iccid_changed_handler(watch, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_imsi_changed_handler(watch, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_spn_changed_handler(watch, NULL, NULL));
|
||||
g_assert(!sailfish_watch_add_netreg_changed_handler(watch, NULL, NULL));
|
||||
sailfish_watch_remove_handler(watch, 0);
|
||||
sailfish_watch_remove_handlers(watch, NULL, 0);
|
||||
|
||||
/* The first modem is removed when the watch is still alive */
|
||||
test_modem_shutdown(&modem);
|
||||
sailfish_watch_unref(watch);
|
||||
sailfish_watch_unref(watch1);
|
||||
test_modem_shutdown(&modem1);
|
||||
__ofono_modemwatch_cleanup();
|
||||
}
|
||||
|
||||
/* ==== modem ==== */
|
||||
|
||||
static void test_modem(void)
|
||||
{
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_modem modem;
|
||||
gulong id;
|
||||
int n = 0;
|
||||
|
||||
__ofono_modemwatch_init();
|
||||
watch = sailfish_watch_new(TEST_PATH);
|
||||
|
||||
id = sailfish_watch_add_modem_changed_handler(watch, test_inc_cb, &n);
|
||||
g_assert(id);
|
||||
memset(&modem, 0, sizeof(modem));
|
||||
test_modem_init(&modem);
|
||||
g_assert(n == 1);
|
||||
|
||||
sailfish_watch_remove_handler(watch, id);
|
||||
sailfish_watch_unref(watch);
|
||||
test_modem_shutdown(&modem);
|
||||
__ofono_modemwatch_cleanup();
|
||||
}
|
||||
|
||||
/* ==== online ==== */
|
||||
|
||||
static void test_online(void)
|
||||
{
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_modem modem;
|
||||
gulong id;
|
||||
int n = 0;
|
||||
|
||||
memset(&modem, 0, sizeof(modem));
|
||||
__ofono_modemwatch_init();
|
||||
test_modem_init(&modem);
|
||||
watch = sailfish_watch_new(TEST_PATH);
|
||||
g_assert(!watch->online);
|
||||
|
||||
modem.online = TRUE;
|
||||
id = sailfish_watch_add_online_changed_handler(watch, test_inc_cb, &n);
|
||||
notify_online_watches(&modem);
|
||||
g_assert(watch->online);
|
||||
g_assert(n == 1);
|
||||
notify_online_watches(&modem); /* Second one has no effect */
|
||||
g_assert(n == 1);
|
||||
|
||||
test_modem_shutdown(&modem);
|
||||
g_assert(!watch->online);
|
||||
g_assert(n == 2);
|
||||
|
||||
sailfish_watch_remove_handler(watch, id);
|
||||
sailfish_watch_unref(watch);
|
||||
__ofono_modemwatch_cleanup();
|
||||
}
|
||||
|
||||
/* ==== netreg ==== */
|
||||
|
||||
static void test_netreg(void)
|
||||
{
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_modem modem;
|
||||
gulong id;
|
||||
int n = 0;
|
||||
|
||||
memset(&modem, 0, sizeof(modem));
|
||||
__ofono_modemwatch_init();
|
||||
test_modem_init(&modem);
|
||||
watch = sailfish_watch_new(TEST_PATH);
|
||||
g_assert(!watch->netreg);
|
||||
|
||||
id = sailfish_watch_add_netreg_changed_handler(watch, test_inc_cb, &n);
|
||||
test_modem_register_atom(&modem, &modem.netreg.atom);
|
||||
g_assert(watch->netreg == &modem.netreg);
|
||||
g_assert(n == 1);
|
||||
|
||||
test_modem_unregister_atom(&modem, &modem.netreg.atom);
|
||||
g_assert(!watch->netreg);
|
||||
g_assert(n == 2);
|
||||
|
||||
test_modem_register_atom(&modem, &modem.netreg.atom);
|
||||
g_assert(watch->netreg == &modem.netreg);
|
||||
g_assert(n == 3);
|
||||
|
||||
test_modem_shutdown(&modem);
|
||||
g_assert(!watch->netreg);
|
||||
g_assert(n == 4);
|
||||
|
||||
sailfish_watch_remove_handler(watch, id);
|
||||
sailfish_watch_unref(watch);
|
||||
__ofono_modemwatch_cleanup();
|
||||
}
|
||||
|
||||
/* ==== sim ==== */
|
||||
|
||||
static void test_sim(void)
|
||||
{
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_modem modem;
|
||||
struct ofono_sim *sim = &modem.sim;
|
||||
gulong id[4];
|
||||
int n[G_N_ELEMENTS(id)];
|
||||
|
||||
#define SIM 0
|
||||
#define ICCID 1
|
||||
#define IMSI 2
|
||||
#define SPN 3
|
||||
|
||||
memset(&modem, 0, sizeof(modem));
|
||||
__ofono_modemwatch_init();
|
||||
test_modem_init(&modem);
|
||||
watch = sailfish_watch_new(TEST_PATH);
|
||||
g_assert(!watch->iccid);
|
||||
g_assert(!watch->imsi);
|
||||
g_assert(!watch->spn);
|
||||
|
||||
memset(id, 0, sizeof(id));
|
||||
memset(n, 0, sizeof(n));
|
||||
id[SIM] = sailfish_watch_add_sim_changed_handler(watch,
|
||||
test_inc_cb, n + SIM);
|
||||
id[ICCID] = sailfish_watch_add_iccid_changed_handler(watch,
|
||||
test_inc_cb, n + ICCID);
|
||||
id[IMSI] = sailfish_watch_add_imsi_changed_handler(watch,
|
||||
test_inc_cb, n + IMSI);
|
||||
id[SPN] = sailfish_watch_add_spn_changed_handler(watch,
|
||||
test_inc_cb, n + SPN);
|
||||
test_modem_register_atom(&modem, &modem.sim.atom);
|
||||
g_assert(watch->sim == &modem.sim);
|
||||
g_assert(n[SIM] == 1);
|
||||
|
||||
/* Simulate insert */
|
||||
sim->state = OFONO_SIM_STATE_INSERTED;
|
||||
state_watches_notify(sim);
|
||||
|
||||
/* ICCID retrieval */
|
||||
sim->iccid = TEST_ICCID;
|
||||
iccid_watches_notify(sim);
|
||||
g_assert(!g_strcmp0(watch->iccid, sim->iccid));
|
||||
g_assert(n[ICCID] == 1);
|
||||
|
||||
/* EFspn retrieval */
|
||||
sim->spn = TEST_SPN;
|
||||
spn_watches_notify(sim);
|
||||
/* Not yet... We first expect IMSI */
|
||||
g_assert(!watch->spn);
|
||||
g_assert(n[SPN] == 0);
|
||||
|
||||
sim->imsi = TEST_IMSI;
|
||||
imsi_watches_notify(sim);
|
||||
g_assert(!g_strcmp0(watch->imsi, sim->imsi));
|
||||
g_assert(!g_strcmp0(watch->spn, sim->spn));
|
||||
g_assert(n[IMSI] == 1);
|
||||
g_assert(n[SPN] == 1);
|
||||
|
||||
/* Ready */
|
||||
sim->state = OFONO_SIM_STATE_READY;
|
||||
state_watches_notify(sim);
|
||||
|
||||
/* And finally remove the SIM */
|
||||
sim->state = OFONO_SIM_STATE_NOT_PRESENT;
|
||||
state_watches_notify(sim);
|
||||
g_assert(!watch->iccid);
|
||||
g_assert(!watch->imsi);
|
||||
g_assert(!watch->spn);
|
||||
g_assert(n[ICCID] == 2);
|
||||
g_assert(n[IMSI] == 2);
|
||||
g_assert(n[SPN] == 2);
|
||||
|
||||
test_modem_unregister_atom(&modem, &modem.sim.atom);
|
||||
g_assert(!watch->sim);
|
||||
g_assert(n[SIM] == 2);
|
||||
|
||||
sailfish_watch_remove_all_handlers(watch, id);
|
||||
sailfish_watch_unref(watch);
|
||||
test_modem_shutdown(&modem);
|
||||
__ofono_modemwatch_cleanup();
|
||||
}
|
||||
|
||||
#define TEST_(name) "/sailfish_watch/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
__ofono_log_init("test-sailfish_watch",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("modem"), test_modem);
|
||||
g_test_add_func(TEST_("online"), test_online);
|
||||
g_test_add_func(TEST_("netreg"), test_netreg);
|
||||
g_test_add_func(TEST_("sim"), test_sim);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
1210
ofono/unit/test-voicecall-filter.c
Normal file
1210
ofono/unit/test-voicecall-filter.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,8 @@ Source: %{name}-%{version}.tar.bz2
|
||||
Requires: dbus
|
||||
Requires: systemd
|
||||
Requires: ofono-configs
|
||||
Requires: libgrilio >= 1.0.20
|
||||
Requires: libglibutil >= 1.0.23
|
||||
Requires: libgrilio >= 1.0.25
|
||||
Requires: libglibutil >= 1.0.30
|
||||
Requires: mobile-broadband-provider-info
|
||||
Requires(preun): systemd
|
||||
Requires(post): systemd
|
||||
@@ -21,8 +21,8 @@ BuildRequires: pkgconfig(dbus-glib-1)
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(libudev) >= 145
|
||||
BuildRequires: pkgconfig(libwspcodec) >= 2.0
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.20
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.23
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.25
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.30
|
||||
BuildRequires: pkgconfig(libdbuslogserver-dbus)
|
||||
BuildRequires: pkgconfig(libmce-glib) >= 1.0.5
|
||||
BuildRequires: pkgconfig(mobile-broadband-provider-info)
|
||||
|
||||
Reference in New Issue
Block a user