mirror of
https://github.com/sailfishos/ofono
synced 2025-11-20 23:39:15 +08:00
Compare commits
195 Commits
mer/1.20+g
...
mer/1.21+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
05dec021c0 | ||
|
|
6f7209b045 | ||
|
|
a766281a02 | ||
|
|
13b4802bec | ||
|
|
e1547fdaf4 | ||
|
|
08c36b2885 | ||
|
|
0180c9febf | ||
|
|
49034cfc69 | ||
|
|
4685e3f0de | ||
|
|
72be5bdff2 | ||
|
|
79c1abfdd3 | ||
|
|
c88cffaa2e | ||
|
|
17e66090ec | ||
|
|
100cf7df1d | ||
|
|
280ed19215 | ||
|
|
ae0f5b0ff6 | ||
|
|
dbfc642eb3 | ||
|
|
e5e5108913 | ||
|
|
9035db3129 | ||
|
|
81391a4101 | ||
|
|
60d449c01d | ||
|
|
b0ccc39866 | ||
|
|
bd2aa28405 | ||
|
|
67e31bb519 | ||
|
|
b848827976 | ||
|
|
ab6764dcc0 | ||
|
|
da42039c80 | ||
|
|
392c00c65e | ||
|
|
7a0fe98d95 | ||
|
|
d508a2f2bb | ||
|
|
8f070cf583 | ||
|
|
d2d8117723 | ||
|
|
6897e57353 | ||
|
|
6a8c2aa9c1 | ||
|
|
076e388d45 | ||
|
|
bcafe0dc3d | ||
|
|
9272075f55 | ||
|
|
526072d7a3 | ||
|
|
0680063527 | ||
|
|
4e08680e5f | ||
|
|
1d85caa7f9 | ||
|
|
db0ef91c81 | ||
|
|
54d8c78a50 | ||
|
|
905c886269 | ||
|
|
f0c7a373ae | ||
|
|
4673da16d5 | ||
|
|
0dc2acee4e | ||
|
|
f749284029 | ||
|
|
778b9f08aa | ||
|
|
40db3f7067 | ||
|
|
e198cf04c0 | ||
|
|
fbd59ba56f | ||
|
|
cff9ded7e6 | ||
|
|
c74386b5e6 | ||
|
|
028f54c26f | ||
|
|
c066f34ea1 | ||
|
|
b1c79d5cae | ||
|
|
0cc61dcfe8 | ||
|
|
5852bebda0 | ||
|
|
768c028a11 | ||
|
|
6b93ea0cc6 | ||
|
|
4a485a7aa0 | ||
|
|
f6fb277cf4 | ||
|
|
03f150838b | ||
|
|
9731ca1a87 | ||
|
|
a09f4c070d | ||
|
|
f018f5a255 | ||
|
|
286396bf91 | ||
|
|
5d6baccced | ||
|
|
514f4cf9cc | ||
|
|
ff8408e6dd | ||
|
|
df1294d77c | ||
|
|
2323ebacb3 | ||
|
|
c780eff0ce | ||
|
|
373248a35b | ||
|
|
fe219b648d | ||
|
|
33f55c569f | ||
|
|
d6cf954354 | ||
|
|
d8e852cb5e | ||
|
|
83e3ec0e98 | ||
|
|
e35f537f72 | ||
|
|
c7daf5aa43 | ||
|
|
490a9c06f4 | ||
|
|
320b3f4605 | ||
|
|
e35dae17d9 | ||
|
|
f4522f4a00 | ||
|
|
ce85c94426 | ||
|
|
4027bdc04e | ||
|
|
c57f99bf01 | ||
|
|
54d610ce6a | ||
|
|
f7f9e32743 | ||
|
|
8c9e370486 | ||
|
|
19b80236f6 | ||
|
|
2ec6fc749d | ||
|
|
0a3bdd20f4 | ||
|
|
284919e76a | ||
|
|
ddcbb89fa1 | ||
|
|
5ec6b8e7ec | ||
|
|
f94681f6f6 | ||
|
|
de8edc84fa | ||
|
|
90faf1b3a5 | ||
|
|
2b139b6974 | ||
|
|
168f193efb | ||
|
|
32d8b5ccfc | ||
|
|
f400ceff80 | ||
|
|
2186c60630 | ||
|
|
d5fb195e2f | ||
|
|
cbb08079d2 | ||
|
|
0583a831fb | ||
|
|
a8a0758e90 | ||
|
|
9e267487f4 | ||
|
|
c8a774dfee | ||
|
|
b88518d0f3 | ||
|
|
b223ccc675 | ||
|
|
947a41a5fc |
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>
|
||||
9
ofono/.gitignore
vendored
9
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,15 +44,22 @@ 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-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
unit/test-rilmodem-sms
|
||||
unit/test-sailfish_cell_info
|
||||
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
|
||||
|
||||
|
||||
@@ -123,3 +123,6 @@ Piotr Haber <gluedig@gmail.com>
|
||||
André Draszik <git@andred.net>
|
||||
Lukasz Nowak <lnowak@tycoint.com>
|
||||
Jonas Bonn <jonas@southpole.se>
|
||||
Matthijs Kooijman <matthijs@stdin.nl>
|
||||
Clayton Craft <clayton@craftyguy.net>
|
||||
Joey Hewitt <joey@joeyhewitt.com>
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
ver 1.21:
|
||||
Fix issue with USSD notification received handling.
|
||||
Fix issue with crashing SIM filesystem notifications.
|
||||
Fix issue with LTE bearer reporting and Huawei modems.
|
||||
Fix issue with invalid memory access and QMI.
|
||||
Add support for QMI SIM writing functionality.
|
||||
Add support for RAT selection for QMI modems.
|
||||
Add support for network monitor agent interface.
|
||||
Add support for Cinterion Hardware Monitor interface.
|
||||
Add support for LTE atom driver for Huawei modems.
|
||||
Add support for LTE atom driver for AT modems.
|
||||
Add support for Intel xmm7xxx series modems.
|
||||
|
||||
ver 1.20:
|
||||
Fix issue with context removal before activation.
|
||||
Fix issue with update during GPRS context activation.
|
||||
|
||||
@@ -23,8 +23,11 @@ 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/netmon.h include/lte.h
|
||||
include/sms-filter.h include/gprs-filter.h \
|
||||
include/voicecall-filter.h \
|
||||
include/netmon.h include/lte.h \
|
||||
include/storage.h \
|
||||
gdbus/gdbus.h
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
@@ -164,8 +167,12 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
drivers/ril/ril_ussd.c \
|
||||
drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_vendor.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
# Vendor specific extensions
|
||||
builtin_sources += drivers/ril/ril_vendor_mtk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
@@ -292,7 +299,8 @@ builtin_sources += $(qmi_sources) \
|
||||
drivers/qmimodem/gprs.c \
|
||||
drivers/qmimodem/gprs-context.c \
|
||||
drivers/qmimodem/radio-settings.c \
|
||||
drivers/qmimodem/location-reporting.c
|
||||
drivers/qmimodem/location-reporting.c \
|
||||
drivers/qmimodem/netmon.c
|
||||
|
||||
builtin_modules += gobi
|
||||
builtin_sources += plugins/gobi.c
|
||||
@@ -323,7 +331,8 @@ builtin_sources += drivers/atmodem/atmodem.h \
|
||||
drivers/atmodem/gprs.c \
|
||||
drivers/atmodem/gprs-context.c \
|
||||
drivers/atmodem/sim-auth.c \
|
||||
drivers/atmodem/gnss.c
|
||||
drivers/atmodem/gnss.c \
|
||||
drivers/atmodem/lte.c
|
||||
|
||||
builtin_modules += nwmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
@@ -454,6 +463,11 @@ builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/gemaltomodem/gemaltomodem.c \
|
||||
drivers/gemaltomodem/location-reporting.c
|
||||
|
||||
builtin_modules += xmm7modem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/xmm7modem/xmm7modem.h \
|
||||
drivers/xmm7modem/xmm7modem.c \
|
||||
drivers/xmm7modem/radio-settings.c
|
||||
|
||||
if PHONESIM
|
||||
builtin_modules += phonesim
|
||||
@@ -561,8 +575,8 @@ builtin_sources += plugins/quectel.c
|
||||
builtin_modules += ublox
|
||||
builtin_sources += plugins/ublox.c
|
||||
|
||||
builtin_modules += he910
|
||||
builtin_sources += plugins/he910.c
|
||||
builtin_modules += xmm7xxx
|
||||
builtin_sources += plugins/xmm7xxx.c
|
||||
endif
|
||||
|
||||
builtin_modules += connman
|
||||
@@ -723,9 +737,11 @@ 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/hfp.h src/siri.c \
|
||||
src/netmon.c src/lte.c
|
||||
src/netmon.c src/lte.c \
|
||||
src/netmonagent.c src/netmonagent.h
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -735,7 +751,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
|
||||
|
||||
@@ -774,7 +791,8 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/telit-modem.txt \
|
||||
doc/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt \
|
||||
doc/lte-api.txt
|
||||
doc/lte-api.txt \
|
||||
doc/cinterion-hardware-monitor-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -882,7 +900,9 @@ test_scripts = test/backtrace \
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling \
|
||||
test/set-lte-property
|
||||
test/set-lte-property \
|
||||
test/test-serving-cell-info
|
||||
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -902,19 +922,31 @@ 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
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-Iplugins/sailfish_cell_info
|
||||
-Iplugins/sailfish_manager
|
||||
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info
|
||||
|
||||
unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||
unit/test-sailfish_cell_info_dbus.c \
|
||||
unit/fake_sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager
|
||||
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info_dbus
|
||||
|
||||
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
@@ -925,6 +957,19 @@ unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info
|
||||
|
||||
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
|
||||
unit/test-dbus.c unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/storage.c src/watch.c src/log.c
|
||||
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
|
||||
-Iplugins/sailfish_manager
|
||||
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info_dbus
|
||||
|
||||
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
@@ -937,11 +982,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)
|
||||
@@ -1018,6 +1079,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 \
|
||||
@@ -1025,12 +1094,29 @@ 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_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 \
|
||||
@@ -1163,6 +1249,10 @@ include/ofono/version.h: include/version.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
|
||||
|
||||
include/ofono/gdbus.h: $(abs_top_srcdir)/gdbus/gdbus.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $< $@
|
||||
|
||||
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $< $@
|
||||
|
||||
@@ -22,6 +22,7 @@ AC_DEFUN([COMPILER_FLAGS], [
|
||||
CFLAGS="$CFLAGS -Wmissing-declarations"
|
||||
CFLAGS="$CFLAGS -Wredundant-decls"
|
||||
CFLAGS="$CFLAGS -Wcast-align"
|
||||
CFLAGS="$CFLAGS -Wno-format-truncation"
|
||||
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.20)
|
||||
AC_INIT(ofono, 1.21)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -184,8 +184,8 @@ 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.18, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.18 is required))
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.21, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.21 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||
@@ -202,6 +202,13 @@ AC_ARG_ENABLE(sailfish-manager,
|
||||
[enable_sailfish_manager=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
|
||||
|
||||
if (test "${enable_sailfish_manager}" = "yes"); then
|
||||
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
|
||||
AC_MSG_ERROR(dbus-glib is required by unit tests))
|
||||
AC_SUBST(DBUS_GLIB_CFLAGS)
|
||||
AC_SUBST(DBUS_GLIB_LIBS)
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
|
||||
[don't allow to add or remove connection context over D-Bus]), [
|
||||
if (test "${enableval}" = "no"); then
|
||||
|
||||
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
HardwareMonitor hierarchy
|
||||
=========================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.cinterion.HardwareMonitor
|
||||
Object path /{device0,device1,...}
|
||||
|
||||
Methods array{string,variant} GetStatistics
|
||||
|
||||
Returns an array of dict entries representing the
|
||||
current temperature and supply voltage of the modem.
|
||||
|
||||
Units:
|
||||
Temperature: Celsius
|
||||
Voltage: mV
|
||||
@@ -22,6 +22,34 @@ Methods a{sv} GetServingCellInformation()
|
||||
are available, their valid value ranges and
|
||||
applicability to different cell types.
|
||||
|
||||
void RegisterAgent(object path)
|
||||
|
||||
Registers an agent which will be called whenever the
|
||||
modem registers to or moves to a new cell.
|
||||
|
||||
void UnregisterAgent(object path)
|
||||
|
||||
Unregisters an agent.
|
||||
|
||||
NetworkMonitorAgent Hierarchy [experimental]
|
||||
=============================
|
||||
|
||||
Service unique name
|
||||
Interface org.ofono.NetworkMonitorAgent
|
||||
Object path freely definable
|
||||
|
||||
Methods void ServingCellInformationChanged(a{sv}) [noreply]
|
||||
|
||||
This method is called whenever the serving cell
|
||||
information has been updated.
|
||||
|
||||
Possible Errors: None
|
||||
|
||||
void Release() [noreply]
|
||||
|
||||
Agent is being released, possibly because of oFono
|
||||
terminating, NetworkMonitor interface is being torn
|
||||
down or modem off. No UnregisterAgent call is needed.
|
||||
|
||||
Network Monitor Property Types
|
||||
==============================
|
||||
@@ -77,7 +105,7 @@ byte TimingAdvance [optional, gsm]
|
||||
|
||||
Contains the Timing Advance. Valid range of values is 0-219.
|
||||
|
||||
byte Strength [optional, gsm, umts]
|
||||
byte Strength [optional, gsm, umts, lte]
|
||||
|
||||
Contains the signal strength. Valid values are 0-31. Refer to <rssi>
|
||||
in 27.007, Section 8.5.
|
||||
|
||||
@@ -52,6 +52,7 @@ static int atmodem_init(void)
|
||||
at_gprs_context_init();
|
||||
at_sim_auth_init();
|
||||
at_gnss_init();
|
||||
at_lte_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -76,6 +77,7 @@ static void atmodem_exit(void)
|
||||
at_gprs_exit();
|
||||
at_gprs_context_exit();
|
||||
at_gnss_exit();
|
||||
at_lte_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
||||
|
||||
@@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void);
|
||||
|
||||
extern void at_gnss_init(void);
|
||||
extern void at_gnss_exit(void);
|
||||
|
||||
extern void at_lte_init(void);
|
||||
extern void at_lte_exit(void);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gatchat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/log.h>
|
||||
@@ -614,3 +615,42 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req)
|
||||
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||
* of "a.b.c.d.m.m.m.m" for IPv4.
|
||||
* address/netmask must be able to hold
|
||||
* 255.255.255.255 + null = 16 characters
|
||||
*/
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask)
|
||||
{
|
||||
const char *s = addrnetmask;
|
||||
const char *net = NULL;
|
||||
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
/* Count 7 dots for ipv4, less or more means error. */
|
||||
for (i = 0; i < 9; i++, s++) {
|
||||
s = strchr(s, '.');
|
||||
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
if (i == 3) {
|
||||
/* set netmask ptr and break the string */
|
||||
net = s + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 7) {
|
||||
memcpy(address, addrnetmask, net - addrnetmask);
|
||||
address[net - addrnetmask - 1] = '\0';
|
||||
strcpy(netmask, net);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@ struct at_util_sim_state_query *at_util_sim_state_query_new(GAtChat *chat,
|
||||
GDestroyNotify destroy);
|
||||
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
||||
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask);
|
||||
|
||||
struct cb_data {
|
||||
void *cb;
|
||||
void *data;
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "atmodem.h"
|
||||
#include "vendor.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
@@ -430,7 +430,7 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -327,6 +327,26 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
||||
ofono_gprs_bearer_notify(gprs, bearer);
|
||||
}
|
||||
|
||||
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
GAtResultIter iter;
|
||||
const char *mode;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!strcmp("LTE", mode))
|
||||
ofono_gprs_bearer_notify(gprs, 7); /* LTE */
|
||||
|
||||
/* in other modes, notification ^MODE is used */
|
||||
}
|
||||
|
||||
static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -432,6 +452,8 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
case OFONO_VENDOR_HUAWEI:
|
||||
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_register(gd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||
FALSE, gprs, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
@@ -445,6 +467,7 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
|
||||
FALSE, gprs, NULL);
|
||||
|
||||
142
ofono/drivers/atmodem/lte.c
Normal file
142
ofono/drivers/atmodem/lte.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
struct lte_driver_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("LTE config with APN: %s", info->apn);
|
||||
|
||||
if (strlen(info->apn) > 0)
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"",
|
||||
info->apn);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\"");
|
||||
|
||||
/* We can't do much in case of failure so don't check response. */
|
||||
if (g_at_chat_send(ldd->chat, buf, NULL,
|
||||
at_lte_set_default_attach_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static gboolean lte_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
|
||||
ofono_lte_register(lte);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct lte_driver_data *ldd;
|
||||
|
||||
DBG("at lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_driver_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ldd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
g_idle_add(lte_delayed_register, lte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("at lte remove");
|
||||
|
||||
g_at_chat_unref(ldd->chat);
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "atmodem",
|
||||
.probe = at_lte_probe,
|
||||
.remove = at_lte_remove,
|
||||
.set_default_attach_info = at_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void at_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void at_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -1088,6 +1088,27 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
GAtResultIter iter;
|
||||
const char *mode;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!strcmp("LTE", mode))
|
||||
nd->tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
|
||||
/* for other technologies, notification ^MODE is used */
|
||||
}
|
||||
|
||||
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
@@ -1896,6 +1917,10 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for 4G system mode reports */
|
||||
g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for network time reports */
|
||||
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
@@ -47,4 +47,5 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_UBLOX,
|
||||
OFONO_VENDOR_UBLOX_TOBY_L2,
|
||||
OFONO_VENDOR_CINTERION,
|
||||
OFONO_VENDOR_XMM,
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "cdmamodem.h"
|
||||
#include "drivers/atmodem/vendor.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
@@ -285,7 +285,7 @@ static int cdma_connman_probe(struct ofono_cdma_connman *cm,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -42,11 +42,13 @@
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
|
||||
static const char *syscfgex_prefix[] = { "^SYSCFGEX:", NULL };
|
||||
|
||||
#define HUAWEI_BAND_ANY 0x3FFFFFFF
|
||||
|
||||
struct radio_settings_data {
|
||||
GAtChat *chat;
|
||||
ofono_bool_t syscfgex_cap;
|
||||
};
|
||||
|
||||
static const struct huawei_band_gsm_table {
|
||||
@@ -176,20 +178,76 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void syscfgex_query_mode_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode;
|
||||
struct ofono_error error;
|
||||
GAtResultIter iter;
|
||||
const char *acqorder;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (g_at_result_iter_next(&iter, "^SYSCFGEX:") == FALSE)
|
||||
goto error;
|
||||
|
||||
if (g_at_result_iter_next_string(&iter, &acqorder) == FALSE)
|
||||
goto error;
|
||||
|
||||
if ((strcmp(acqorder, "00") == 0) ||
|
||||
(strstr(acqorder, "01") &&
|
||||
strstr(acqorder, "02") &&
|
||||
strstr(acqorder, "03")))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
else if (strstr(acqorder, "03"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
else if (strstr(acqorder, "02"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
else if (strstr(acqorder, "01"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
else
|
||||
goto error;
|
||||
|
||||
cb(&error, mode, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, "AT^SYSCFG?", syscfg_prefix,
|
||||
syscfg_query_mode_cb, cbd, g_free) == 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
if (rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFGEX?",
|
||||
syscfgex_prefix,
|
||||
syscfgex_query_mode_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
if (!rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFG?",
|
||||
syscfg_prefix,
|
||||
syscfg_query_mode_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
static void syscfgxx_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -200,12 +258,11 @@ static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
static void syscfg_set_rat_mode(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[40];
|
||||
unsigned int value = 2, acq_order = 0;
|
||||
@@ -231,7 +288,7 @@ static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
value, acq_order);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfg_modify_mode_cb, cbd, g_free) > 0)
|
||||
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -239,7 +296,55 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
static void syscfgex_set_rat_mode(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[50];
|
||||
char *atcmd = "AT^SYSCFGEX=\"%s\",40000000,2,4,40000000,,";
|
||||
char *acqorder = "030201";
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
acqorder = "00";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
acqorder = "01";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
acqorder = "02";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
acqorder = "03";
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), atcmd, acqorder);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (rsd->syscfgex_cap)
|
||||
syscfgex_set_rat_mode(rsd, mode, cb, data);
|
||||
else
|
||||
syscfg_set_rat_mode(rsd, mode, cb, data);
|
||||
}
|
||||
|
||||
static void syscfgxx_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -250,13 +355,54 @@ static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
static void syscfgex_set_band(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[50];
|
||||
char *atcmd = "AT^SYSCFGEX=\"99\",%x,2,4,40000000,,";
|
||||
unsigned int huawei_band;
|
||||
|
||||
if (band_gsm == OFONO_RADIO_BAND_GSM_ANY
|
||||
&& band_umts == OFONO_RADIO_BAND_UMTS_ANY) {
|
||||
huawei_band = HUAWEI_BAND_ANY;
|
||||
} else {
|
||||
unsigned int huawei_band_gsm;
|
||||
unsigned int huawei_band_umts;
|
||||
|
||||
huawei_band_gsm = band_gsm_to_huawei(band_gsm);
|
||||
|
||||
if (!huawei_band_gsm)
|
||||
goto error;
|
||||
|
||||
huawei_band_umts = band_umts_to_huawei(band_umts);
|
||||
|
||||
if (!huawei_band_umts)
|
||||
goto error;
|
||||
|
||||
huawei_band = huawei_band_gsm | huawei_band_umts;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), atcmd, huawei_band);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_set_band(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[40];
|
||||
unsigned int huawei_band;
|
||||
@@ -284,7 +430,7 @@ static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfg_modify_band_cb, cbd, g_free) > 0)
|
||||
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -292,6 +438,20 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (rsd->syscfgex_cap)
|
||||
syscfgex_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||
else
|
||||
syscfg_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||
}
|
||||
|
||||
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
@@ -364,6 +524,21 @@ static void syscfg_support_cb(gboolean ok, GAtResult *result,
|
||||
ofono_radio_settings_register(rs);
|
||||
}
|
||||
|
||||
static void syscfgex_support_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (!ok) {
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||
syscfg_support_cb, rs, NULL);
|
||||
}
|
||||
|
||||
rsd->syscfgex_cap = 1;
|
||||
ofono_radio_settings_register(rs);
|
||||
}
|
||||
|
||||
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
@@ -378,8 +553,8 @@ static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||
syscfg_support_cb, rs, NULL);
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFGEX=?", syscfgex_prefix,
|
||||
syscfgex_support_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -400,8 +575,8 @@ static struct ofono_radio_settings_driver driver = {
|
||||
.remove = huawei_radio_settings_remove,
|
||||
.query_rat_mode = huawei_query_rat_mode,
|
||||
.set_rat_mode = huawei_set_rat_mode,
|
||||
.query_band = huawei_query_band,
|
||||
.set_band = huawei_set_band,
|
||||
.query_band = huawei_query_band,
|
||||
.set_band = huawei_set_band,
|
||||
};
|
||||
|
||||
void huawei_radio_settings_init(void)
|
||||
|
||||
@@ -42,13 +42,14 @@
|
||||
|
||||
#include "ifxmodem.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *xdns_prefix[] = { "+XDNS:", NULL };
|
||||
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
||||
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||
|
||||
enum state {
|
||||
STATE_IDLE,
|
||||
@@ -59,17 +60,20 @@ enum state {
|
||||
|
||||
struct gprs_context_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
unsigned int active_context;
|
||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||
GAtRawIP *rawip;
|
||||
enum state state;
|
||||
enum ofono_gprs_proto proto;
|
||||
char address[32];
|
||||
char dns1[32];
|
||||
char dns2[32];
|
||||
char address[64];
|
||||
char gateway[64];
|
||||
char netmask[64];
|
||||
char dns1[64];
|
||||
char dns2[64];
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data; /* Callback data */
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static void rawip_debug(const char *str, void *data)
|
||||
@@ -257,11 +261,136 @@ error:
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
GAtResultIter iter;
|
||||
|
||||
const char *laddrnetmask = NULL;
|
||||
const char *gw = NULL;
|
||||
const char *interface;
|
||||
const char *dns[3];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
gcd->cb(&error, gcd->cb_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
|
||||
/* skip cid, bearer_id, apn */
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &laddrnetmask))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[0]))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[1]))
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(gcd->dns1, dns[0], sizeof(gcd->dns1));
|
||||
strncpy(gcd->dns2, dns[1], sizeof(gcd->dns2));
|
||||
dns[2] = 0;
|
||||
|
||||
DBG("DNS: %s, %s\n", gcd->dns1, gcd->dns2);
|
||||
|
||||
if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
|
||||
gcd->address, gcd->netmask) < 0) {
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw)
|
||||
strncpy(gcd->gateway, gw, sizeof(gcd->gateway));
|
||||
|
||||
gcd->state = STATE_ACTIVE;
|
||||
|
||||
DBG("address: %s\n", gcd->address);
|
||||
DBG("netmask: %s\n", gcd->netmask);
|
||||
DBG("DNS1: %s\n", gcd->dns1);
|
||||
DBG("DNS2: %s\n", gcd->dns2);
|
||||
DBG("Gateway: %s\n", gcd->gateway);
|
||||
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
|
||||
|
||||
if (gcd->netmask[0])
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
|
||||
|
||||
if (gcd->gateway[0])
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void ifx_read_settings(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
gcd->address[0] = '\0';
|
||||
gcd->gateway[0] = '\0';
|
||||
gcd->netmask[0] = '\0';
|
||||
gcd->dns1[0] = '\0';
|
||||
gcd->dns2[0] = '\0';
|
||||
|
||||
/* read IP configuration info */
|
||||
if(gcd->vendor == OFONO_VENDOR_XMM) {
|
||||
snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%u",
|
||||
gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
|
||||
cgcontrdp_cb, gc, NULL) > 0)
|
||||
return;
|
||||
} else {
|
||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||
address_cb, gc, NULL) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void ifx_gprs_read_settings(struct ofono_gprs_context *gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
DBG("cid %u", cid);
|
||||
|
||||
gcd->active_context = cid;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
ifx_read_settings(gc);
|
||||
}
|
||||
|
||||
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
@@ -271,19 +400,14 @@ static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||
address_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
ifx_read_settings(gc);
|
||||
}
|
||||
|
||||
static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[128];
|
||||
char buf[384];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
@@ -387,7 +511,8 @@ static void deactivate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
g_at_chat_resume(gcd->chat);
|
||||
if (gcd->vendor != OFONO_VENDOR_XMM)
|
||||
g_at_chat_resume(gcd->chat);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
@@ -409,11 +534,25 @@ static void ifx_gprs_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
g_at_rawip_shutdown(gcd->rawip);
|
||||
|
||||
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
||||
if (g_at_chat_send(chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
if (gcd->vendor == OFONO_VENDOR_XMM) {
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
} else {
|
||||
if (g_at_chat_send(chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ifx_gprs_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
DBG("");
|
||||
ifx_gprs_deactivate_primary(gc, cid, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
@@ -451,14 +590,13 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
g_at_rawip_unref(gcd->rawip);
|
||||
gcd->rawip = NULL;
|
||||
g_at_chat_resume(gcd->chat);
|
||||
}
|
||||
|
||||
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
||||
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
g_at_chat_resume(gcd->chat);
|
||||
}
|
||||
|
||||
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
@@ -470,23 +608,27 @@ static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (g_at_chat_get_slave(chat) == NULL)
|
||||
return -EINVAL;
|
||||
if (vendor != OFONO_VENDOR_XMM) {
|
||||
if (g_at_chat_get_slave(chat) == NULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gcd = g_try_new0(struct gprs_context_data, 1);
|
||||
if (gcd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gcd->vendor = vendor;
|
||||
gcd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
|
||||
chat = g_at_chat_get_slave(gcd->chat);
|
||||
if (vendor != OFONO_VENDOR_XMM)
|
||||
chat = g_at_chat_get_slave(gcd->chat);
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
@@ -516,6 +658,8 @@ static struct ofono_gprs_context_driver driver = {
|
||||
.remove = ifx_gprs_context_remove,
|
||||
.activate_primary = ifx_gprs_activate_primary,
|
||||
.deactivate_primary = ifx_gprs_deactivate_primary,
|
||||
.read_settings = ifx_gprs_read_settings,
|
||||
.detach_shutdown = ifx_gprs_detach_shutdown
|
||||
};
|
||||
|
||||
void ifx_gprs_context_init(void)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
extern void ifx_voicecall_init(void);
|
||||
extern void ifx_voicecall_exit(void);
|
||||
|
||||
@@ -646,8 +646,31 @@ error:
|
||||
/* ISI callback: PIN state (enabled/disabled) query */
|
||||
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
||||
{
|
||||
check_sec_response(msg, opaque, SEC_CODE_STATE_OK_RESP,
|
||||
SEC_CODE_STATE_FAIL_RESP);
|
||||
struct isi_cb_data *cbd = opaque;
|
||||
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
||||
int locked;
|
||||
uint8_t state;
|
||||
uint8_t status;
|
||||
|
||||
if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
|
||||
!g_isi_msg_data_get_byte(msg, 1, &status))
|
||||
goto error;
|
||||
|
||||
if (state != SEC_CODE_STATE_OK_RESP)
|
||||
goto error;
|
||||
|
||||
if (status == SEC_CODE_ENABLE)
|
||||
locked = 1;
|
||||
else if (status == SEC_CODE_DISABLE)
|
||||
locked = 0;
|
||||
else
|
||||
goto error;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, locked, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void isi_query_locked(struct ofono_sim *sim,
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
|
||||
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
|
||||
|
||||
#define QMI_NAS_SET_SYSTEM_SELECTION_PREF 51
|
||||
#define QMI_NAS_GET_SYSTEM_SELECTION_PREF 52
|
||||
|
||||
/* Set NAS state report conditions */
|
||||
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
|
||||
@@ -97,6 +99,7 @@ struct qmi_nas_network_rat {
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define QMI_NAS_NETWORK_RAT_NONE 0x00
|
||||
#define QMI_NAS_NETWORK_RAT_GSM 0x04
|
||||
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
|
||||
#define QMI_NAS_NETWORK_RAT_LTE 0x08
|
||||
@@ -149,6 +152,18 @@ struct qmi_nas_current_plmn {
|
||||
#define QMI_NAS_REGISTRATION_STATE_DENIED 0x03
|
||||
#define QMI_NAS_REGISTRATION_STATE_UNKNOWN 0x04
|
||||
|
||||
#define QMI_NAS_RESULT_3GGP_DST 0x1b
|
||||
#define QMI_NAS_RESULT_3GPP_TIME 0x1c
|
||||
struct qmi_nas_3gpp_time {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t timezone;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* cs_state/ps_state */
|
||||
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
|
||||
@@ -163,4 +178,13 @@ struct qmi_nas_home_network {
|
||||
char desc[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define QMI_NAS_RAT_MODE_PREF_ANY (-1)
|
||||
#define QMI_NAS_RAT_MODE_PREF_GSM (1 << 2)
|
||||
#define QMI_NAS_RAT_MODE_PREF_UMTS (1 << 3)
|
||||
#define QMI_NAS_RAT_MODE_PREF_LTE (1 << 4)
|
||||
|
||||
#define QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||
|
||||
#define QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||
|
||||
int qmi_nas_rat_to_tech(uint8_t rat);
|
||||
|
||||
286
ofono/drivers/qmimodem/netmon.c
Normal file
286
ofono/drivers/qmimodem/netmon.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
#include "src/common.h"
|
||||
|
||||
struct netmon_data {
|
||||
struct qmi_service *nas;
|
||||
};
|
||||
|
||||
static void get_rssi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_netmon *netmon = cbd->user;
|
||||
ofono_netmon_cb_t cb = cbd->cb;
|
||||
struct {
|
||||
enum ofono_netmon_cell_type type;
|
||||
int rssi;
|
||||
int ber;
|
||||
int rsrq;
|
||||
int rsrp;
|
||||
} props;
|
||||
uint16_t len;
|
||||
int16_t rsrp;
|
||||
const struct {
|
||||
int8_t value;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) *rsrq;
|
||||
const struct {
|
||||
uint16_t count;
|
||||
struct {
|
||||
uint8_t rssi;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__)) *rssi;
|
||||
const struct {
|
||||
uint16_t count;
|
||||
struct {
|
||||
uint16_t rate;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__)) *ber;
|
||||
int i;
|
||||
uint16_t num;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* RSSI */
|
||||
rssi = qmi_result_get(result, 0x11, &len);
|
||||
num = GUINT16_FROM_LE(rssi->count);
|
||||
if (rssi) {
|
||||
for (i = 0; i < num; i++) {
|
||||
DBG("RSSI: %hhu on RAT %hhd",
|
||||
rssi->info[i].rssi,
|
||||
rssi->info[i].rat);
|
||||
}
|
||||
|
||||
/* Get cell type from RSSI info... it will be the same
|
||||
* for all the other entries
|
||||
*/
|
||||
props.type = qmi_nas_rat_to_tech(rssi->info[0].rat);
|
||||
switch (rssi->info[0].rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||
break;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_UMTS;
|
||||
break;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_LTE;
|
||||
break;
|
||||
default:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||
break;
|
||||
}
|
||||
|
||||
props.rssi = (rssi->info[0].rssi + 113) / 2;
|
||||
if (props.rssi > 31) props.rssi = 31;
|
||||
if (props.rssi < 0) props.rssi = 0;
|
||||
} else {
|
||||
props.type = QMI_NAS_NETWORK_RAT_GSM;
|
||||
props.rssi = -1;
|
||||
}
|
||||
|
||||
/* Bit error rate */
|
||||
ber = qmi_result_get(result, 0x15, &len);
|
||||
num = GUINT16_FROM_LE(ber->count);
|
||||
if (ber) {
|
||||
for (i = 0; i < ber->count; i++) {
|
||||
DBG("Bit error rate: %hu on RAT %hhd",
|
||||
GUINT16_FROM_LE(ber->info[i].rate),
|
||||
ber->info[i].rat);
|
||||
}
|
||||
|
||||
props.ber = GUINT16_FROM_LE(ber->info[0].rate);
|
||||
if (props.ber > 7)
|
||||
props.ber = -1;
|
||||
} else {
|
||||
props.ber = -1;
|
||||
}
|
||||
|
||||
/* LTE RSRQ */
|
||||
rsrq = qmi_result_get(result, 0x16, &len);
|
||||
if (rsrq) {
|
||||
DBG("RSRQ: %hhd on RAT %hhd",
|
||||
rsrq->value,
|
||||
rsrq->rat);
|
||||
|
||||
if (rsrq->value == 0) {
|
||||
props.rsrq = -1;
|
||||
} else {
|
||||
props.rsrq = (rsrq->value + 19) * 2;
|
||||
if (props.rsrq > 34) props.rsrq = 34;
|
||||
if (props.rsrq < 0) props.rsrq = 0;
|
||||
}
|
||||
} else {
|
||||
props.rsrq = -1;
|
||||
}
|
||||
|
||||
/* LTE RSRP */
|
||||
if (qmi_result_get_int16(result, 0x18, &rsrp)) {
|
||||
DBG("Got LTE RSRP: %hd", rsrp);
|
||||
|
||||
if (rsrp == 0) {
|
||||
props.rsrp = -1;
|
||||
} else {
|
||||
props.rsrp = rsrp + 140;
|
||||
if (props.rsrp > 97) props.rsrp = 97;
|
||||
if (props.rsrp < 0) props.rsrp = 0;
|
||||
}
|
||||
} else {
|
||||
props.rsrp = -1;
|
||||
}
|
||||
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
props.type,
|
||||
OFONO_NETMON_INFO_RSSI, props.rssi,
|
||||
OFONO_NETMON_INFO_BER, props.ber,
|
||||
OFONO_NETMON_INFO_RSRQ, props.rsrq,
|
||||
OFONO_NETMON_INFO_RSRP, props.rsrp,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct netmon_data *data = ofono_netmon_get_data(netmon);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = netmon;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto out;
|
||||
|
||||
/* Request all signal strength items: mask=0xff */
|
||||
qmi_param_append_uint16(param, 0x10, 255);
|
||||
|
||||
if (qmi_service_send(data->nas, QMI_NAS_GET_RSSI, param,
|
||||
get_rssi_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
out:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_netmon *netmon = user_data;
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_netmon_remove(netmon);
|
||||
return;
|
||||
}
|
||||
|
||||
nmd->nas = qmi_service_ref(service);
|
||||
|
||||
ofono_netmon_register(netmon);
|
||||
}
|
||||
|
||||
static int qmi_netmon_probe(struct ofono_netmon *netmon,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
struct qmi_device *device = user_data;
|
||||
struct netmon_data *nmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
nmd = g_new0(struct netmon_data, 1);
|
||||
|
||||
ofono_netmon_set_data(netmon, nmd);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, netmon, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmi_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
|
||||
qmi_service_unregister_all(nmd->nas);
|
||||
|
||||
qmi_service_unref(nmd->nas);
|
||||
|
||||
g_free(nmd);
|
||||
}
|
||||
|
||||
static struct ofono_netmon_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_netmon_probe,
|
||||
.remove = qmi_netmon_remove,
|
||||
.request_update = qmi_netmon_request_update,
|
||||
};
|
||||
|
||||
void qmi_netmon_init(void)
|
||||
{
|
||||
ofono_netmon_driver_register(&driver);
|
||||
}
|
||||
|
||||
void qmi_netmon_exit(void)
|
||||
{
|
||||
ofono_netmon_driver_unregister(&driver);
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -43,6 +44,38 @@ struct netreg_data {
|
||||
uint8_t current_rat;
|
||||
};
|
||||
|
||||
static bool extract_ss_info_time(
|
||||
struct qmi_result *result,
|
||||
struct ofono_network_time *time)
|
||||
{
|
||||
const struct qmi_nas_3gpp_time *time_3gpp = NULL;
|
||||
uint8_t dst_3gpp;
|
||||
bool dst_3gpp_valid;
|
||||
uint16_t len;
|
||||
|
||||
/* parse 3gpp time & dst */
|
||||
dst_3gpp_valid = qmi_result_get_uint8(result, QMI_NAS_RESULT_3GGP_DST,
|
||||
&dst_3gpp);
|
||||
|
||||
time_3gpp = qmi_result_get(result, QMI_NAS_RESULT_3GPP_TIME, &len);
|
||||
if (time_3gpp && len == sizeof(struct qmi_nas_3gpp_time) &&
|
||||
dst_3gpp_valid) {
|
||||
time->year = le16toh(time_3gpp->year);
|
||||
time->mon = time_3gpp->month;
|
||||
time->mday = time_3gpp->day;
|
||||
time->hour = time_3gpp->hour;
|
||||
time->min = time_3gpp->minute;
|
||||
time->sec = time_3gpp->second;
|
||||
time->utcoff = time_3gpp->timezone * 15 * 60;
|
||||
time->dst = dst_3gpp;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: 3gpp2 */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
int *lac, int *cellid, int *tech,
|
||||
struct ofono_network_operator *operator)
|
||||
@@ -124,11 +157,15 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct ofono_network_time net_time;
|
||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||
int status, lac, cellid, tech;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (extract_ss_info_time(result, &net_time))
|
||||
ofono_netreg_time_notify(netreg, &net_time);
|
||||
|
||||
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
|
||||
&data->operator))
|
||||
return;
|
||||
@@ -356,7 +393,7 @@ static void qmi_register_manual(struct ofono_netreg *netreg,
|
||||
|
||||
info.mcc = atoi(mcc);
|
||||
info.mnc = atoi(mnc);
|
||||
info.rat = data->current_rat;
|
||||
info.rat = QMI_NAS_NETWORK_RAT_NO_CHANGE;
|
||||
|
||||
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
|
||||
sizeof(info), &info);
|
||||
@@ -450,10 +487,11 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
||||
if (ss) {
|
||||
int strength;
|
||||
|
||||
DBG("signal with %d dBm on %d", ss->dbm, ss->rat);
|
||||
|
||||
strength = dbm_to_strength(ss->dbm);
|
||||
|
||||
DBG("signal with %d%%(%d dBm) on %d",
|
||||
strength, ss->dbm, ss->rat);
|
||||
|
||||
ofono_netreg_strength_notify(netreg, strength);
|
||||
}
|
||||
|
||||
@@ -473,10 +511,17 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
||||
static void set_event_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_netreg_register(netreg);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||
event_notify, netreg, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, netreg, NULL);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
@@ -498,12 +543,6 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||
event_notify, netreg, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, netreg, NULL);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto done;
|
||||
|
||||
@@ -73,6 +73,8 @@ struct qmi_device {
|
||||
void *shutdown_user_data;
|
||||
qmi_destroy_func_t shutdown_destroy;
|
||||
guint shutdown_source;
|
||||
bool shutting_down : 1;
|
||||
bool destroyed : 1;
|
||||
};
|
||||
|
||||
struct qmi_service {
|
||||
@@ -1000,7 +1002,10 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
g_free(device->version_str);
|
||||
g_free(device->version_list);
|
||||
|
||||
g_free(device);
|
||||
if (device->shutting_down)
|
||||
device->destroyed = true;
|
||||
else
|
||||
g_free(device);
|
||||
}
|
||||
|
||||
void qmi_device_set_debug(struct qmi_device *device,
|
||||
@@ -1021,6 +1026,23 @@ void qmi_device_set_close_on_unref(struct qmi_device *device, bool do_close)
|
||||
device->close_on_unref = do_close;
|
||||
}
|
||||
|
||||
void qmi_result_print_tlvs(struct qmi_result *result)
|
||||
{
|
||||
const void *ptr = result->data;
|
||||
uint16_t len = result->length;
|
||||
|
||||
while (len > QMI_TLV_HDR_SIZE) {
|
||||
const struct qmi_tlv_hdr *tlv = ptr;
|
||||
uint16_t tlv_length = GUINT16_FROM_LE(tlv->length);
|
||||
|
||||
DBG("tlv: 0x%02x len 0x%04x", tlv->type, tlv->length);
|
||||
|
||||
ptr += QMI_TLV_HDR_SIZE + tlv_length;
|
||||
len -= QMI_TLV_HDR_SIZE + tlv_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const void *tlv_get(const void *data, uint16_t size,
|
||||
uint8_t type, uint16_t *length)
|
||||
{
|
||||
@@ -1255,6 +1277,9 @@ static void shutdown_destroy(gpointer user_data)
|
||||
device->shutdown_destroy(device->shutdown_user_data);
|
||||
|
||||
device->shutdown_source = 0;
|
||||
|
||||
if (device->destroyed)
|
||||
g_free(device);
|
||||
}
|
||||
|
||||
static gboolean shutdown_callback(gpointer user_data)
|
||||
@@ -1264,9 +1289,13 @@ static gboolean shutdown_callback(gpointer user_data)
|
||||
if (device->release_users > 0)
|
||||
return TRUE;
|
||||
|
||||
device->shutting_down = true;
|
||||
|
||||
if (device->shutdown_func)
|
||||
device->shutdown_func(device->shutdown_user_data);
|
||||
|
||||
device->shutting_down = true;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1691,6 +1720,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
uint16_t len, tmp;
|
||||
|
||||
if (!result || !type)
|
||||
return false;
|
||||
|
||||
ptr = tlv_get(result->data, result->length, type, &len);
|
||||
if (!ptr)
|
||||
return false;
|
||||
|
||||
memcpy(&tmp, ptr, 2);
|
||||
|
||||
if (value)
|
||||
*value = GINT16_FROM_LE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value)
|
||||
{
|
||||
|
||||
@@ -130,13 +130,15 @@ const void *qmi_result_get(struct qmi_result *result, uint8_t type,
|
||||
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
|
||||
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
uint8_t *value);
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value);
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value);
|
||||
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
||||
uint32_t *value);
|
||||
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
uint64_t *value);
|
||||
|
||||
void qmi_result_print_tlvs(struct qmi_result *result);
|
||||
|
||||
struct qmi_service;
|
||||
|
||||
|
||||
@@ -41,12 +41,14 @@ static int qmimodem_init(void)
|
||||
qmi_gprs_context_init();
|
||||
qmi_radio_settings_init();
|
||||
qmi_location_reporting_init();
|
||||
qmi_netmon_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmimodem_exit(void)
|
||||
{
|
||||
qmi_netmon_exit();
|
||||
qmi_location_reporting_exit();
|
||||
qmi_radio_settings_exit();
|
||||
qmi_gprs_context_exit();
|
||||
|
||||
@@ -53,3 +53,6 @@ extern void qmi_radio_settings_exit(void);
|
||||
|
||||
extern void qmi_location_reporting_init(void);
|
||||
extern void qmi_location_reporting_exit(void);
|
||||
|
||||
extern void qmi_netmon_init(void);
|
||||
extern void qmi_netmon_exit(void);
|
||||
|
||||
@@ -29,15 +29,202 @@
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
#include "dms.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct settings_data {
|
||||
struct qmi_service *nas;
|
||||
struct qmi_service *dms;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
static void get_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
uint16_t pref;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_result_get_uint16(result,
|
||||
QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref);
|
||||
|
||||
switch (pref) {
|
||||
case QMI_NAS_RAT_MODE_PREF_GSM:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_UMTS:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_LTE:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL,
|
||||
get_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void set_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_GSM;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_UMTS;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param) {
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE,
|
||||
pref);
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_SET_SYSTEM_SELECTION_PREF, param,
|
||||
set_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void get_caps_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
|
||||
const struct qmi_dms_device_caps *caps;
|
||||
unsigned int available_rats;
|
||||
uint16_t len;
|
||||
uint8_t i;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto error;
|
||||
|
||||
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
|
||||
if (!caps)
|
||||
goto error;
|
||||
|
||||
available_rats = 0;
|
||||
for (i = 0; i < caps->radio_if_count; i++) {
|
||||
switch (caps->radio_if[i]) {
|
||||
case QMI_DMS_RADIO_IF_GSM:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_UMTS:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_LTE:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_available_rats(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (!rsd->dms)
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL,
|
||||
get_caps_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service)
|
||||
return;
|
||||
|
||||
data->dms = qmi_service_ref(service);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
@@ -74,11 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, data);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||
create_dms_cb, rs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
@@ -100,6 +288,9 @@ static struct ofono_radio_settings_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_radio_settings_probe,
|
||||
.remove = qmi_radio_settings_remove,
|
||||
.set_rat_mode = qmi_set_rat_mode,
|
||||
.query_rat_mode = qmi_query_rat_mode,
|
||||
.query_available_rats = qmi_query_available_rats,
|
||||
};
|
||||
|
||||
void qmi_radio_settings_init(void)
|
||||
|
||||
@@ -317,6 +317,124 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void write_generic_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_write_cb_t cb = cbd->cb;
|
||||
uint16_t len;
|
||||
const uint8_t *card_result;
|
||||
uint8_t sw1, sw2;
|
||||
|
||||
card_result = qmi_result_get(result, 0x10, &len);
|
||||
if (card_result == NULL || len != 2) {
|
||||
DBG("card_result: %p, len: %d", card_result, (int) len);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
sw1 = card_result[0];
|
||||
sw2 = card_result[1];
|
||||
|
||||
DBG("%02x, %02x", sw1, sw2);
|
||||
|
||||
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
||||
(sw1 == 0x90 && sw2 != 0x00)) {
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("%s: error sw1 %02x sw2 %02x", __func__, sw1, sw2);
|
||||
|
||||
error.type = OFONO_ERROR_TYPE_SIM;
|
||||
error.error = (sw1 << 8) | sw2;
|
||||
|
||||
cb(&error, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void write_generic(struct ofono_sim *sim,
|
||||
uint16_t qmi_message, int fileid,
|
||||
int start_or_recordnum,
|
||||
int length, const unsigned char *value,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char write_data[4 + length];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("file id 0x%04x path len %d", fileid, path_len);
|
||||
|
||||
fileid_len = create_fileid_data(data->app_type, fileid,
|
||||
path, path_len, fileid_data);
|
||||
|
||||
if (fileid_len < 0)
|
||||
goto error;
|
||||
|
||||
write_data[0] = start_or_recordnum & 0xff;
|
||||
write_data[1] = (start_or_recordnum & 0xff00) >> 8;
|
||||
write_data[2] = length & 0xff;
|
||||
write_data[3] = (length & 0xff00) >> 8;
|
||||
memcpy(&write_data[4], value, length);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
|
||||
qmi_param_append(param, 0x02, fileid_len, fileid_data);
|
||||
qmi_param_append(param, 0x03, 4 + length, write_data);
|
||||
|
||||
if (qmi_service_send(data->uim, qmi_message, param,
|
||||
write_generic_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_write_transparent(struct ofono_sim *sim,
|
||||
int fileid, int start, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_TRANSPARENT, fileid, start,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_linear(struct ofono_sim *sim,
|
||||
int fileid, int record, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, record,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_cyclic(struct ofono_sim *sim,
|
||||
int fileid, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, 0,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void get_imsi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -777,6 +895,9 @@ static struct ofono_sim_driver driver = {
|
||||
.read_file_transparent = qmi_read_transparent,
|
||||
.read_file_linear = qmi_read_record,
|
||||
.read_file_cyclic = qmi_read_record,
|
||||
.write_file_transparent = qmi_write_transparent,
|
||||
.write_file_linear = qmi_write_linear,
|
||||
.write_file_cyclic = qmi_write_cyclic,
|
||||
.read_imsi = qmi_read_imsi,
|
||||
.query_passwd_state = qmi_query_passwd_state,
|
||||
.query_pin_retries = qmi_query_pin_retries,
|
||||
|
||||
@@ -277,7 +277,7 @@ static void qmi_bearer_query(struct ofono_sms *sms,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->major < 1 && data->minor < 2)
|
||||
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
|
||||
@@ -315,7 +315,7 @@ static void qmi_bearer_set(struct ofono_sms *sms, int bearer,
|
||||
|
||||
DBG("bearer %d", bearer);
|
||||
|
||||
if (data->major < 1 && data->minor < 2)
|
||||
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||
goto error;
|
||||
|
||||
domain = bearer_to_domain(bearer);
|
||||
@@ -411,7 +411,7 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
|
||||
new_list->count = GUINT16_TO_LE(1);
|
||||
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
|
||||
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
|
||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NV;
|
||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NONE;
|
||||
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
|
||||
|
||||
param = qmi_param_new();
|
||||
|
||||
@@ -62,6 +62,7 @@ struct qmi_wms_param_message {
|
||||
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
||||
#define QMI_WMS_STORAGE_TYPE_NV 1
|
||||
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
||||
#define QMI_WMS_STORAGE_TYPE_NONE 255
|
||||
|
||||
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||
#define MAX_RETRIES (5)
|
||||
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
@@ -105,10 +106,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) &&
|
||||
@@ -144,7 +145,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) &&
|
||||
@@ -175,7 +176,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) &&
|
||||
@@ -296,8 +297,8 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
DBG_(self, "");
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
|
||||
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
@@ -314,7 +315,7 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
@@ -328,7 +329,7 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
||||
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
@@ -338,18 +339,16 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
|
||||
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
||||
{
|
||||
ril_cell_info_set_rate(self,
|
||||
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self,
|
||||
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
@@ -373,16 +372,11 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
const gboolean sim_card_was_ready = self->sim_card_ready;
|
||||
|
||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (self->sim_card_ready != sim_card_was_ready) {
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||
ril_cell_info_refresh(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
|
||||
/* sailfish_cell_info interface callbacks */
|
||||
@@ -483,10 +477,8 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
ril_cell_info_refresh(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,10 @@
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
@@ -186,9 +190,18 @@ 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;
|
||||
@@ -223,6 +236,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,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,7 @@
|
||||
#include "ril_network.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
@@ -207,10 +208,15 @@ GRilIoRequest *ril_request_deactivate_data_call_new(int cid)
|
||||
* ril_data_call
|
||||
*==========================================================================*/
|
||||
|
||||
static struct ril_data_call *ril_data_call_new()
|
||||
{
|
||||
return g_new0(struct ril_data_call, 1);
|
||||
}
|
||||
|
||||
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
|
||||
{
|
||||
if (call) {
|
||||
struct ril_data_call *dc = g_new0(struct ril_data_call, 1);
|
||||
struct ril_data_call *dc = ril_data_call_new();
|
||||
dc->cid = call->cid;
|
||||
dc->status = call->status;
|
||||
dc->active = call->active;
|
||||
@@ -227,13 +233,18 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_call_destroy(struct ril_data_call *call)
|
||||
{
|
||||
g_free(call->ifname);
|
||||
g_strfreev(call->dnses);
|
||||
g_strfreev(call->addresses);
|
||||
g_strfreev(call->gateways);
|
||||
}
|
||||
|
||||
void ril_data_call_free(struct ril_data_call *call)
|
||||
{
|
||||
if (call) {
|
||||
g_free(call->ifname);
|
||||
g_strfreev(call->dnses);
|
||||
g_strfreev(call->addresses);
|
||||
g_strfreev(call->gateways);
|
||||
ril_data_call_destroy(call);
|
||||
g_free(call);
|
||||
}
|
||||
}
|
||||
@@ -251,7 +262,7 @@ static void ril_data_call_list_free(struct ril_data_call_list *list)
|
||||
}
|
||||
}
|
||||
|
||||
static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
|
||||
static gint ril_data_call_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ril_data_call *ca = a;
|
||||
const struct ril_data_call *cb = b;
|
||||
@@ -265,7 +276,7 @@ static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
|
||||
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case OFONO_GPRS_PROTO_IPV6:
|
||||
@@ -279,7 +290,7 @@ static const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_data_protocol_to_ofono(gchar *str)
|
||||
int ril_data_protocol_to_ofono(const gchar *str)
|
||||
{
|
||||
if (str) {
|
||||
if (!strcmp(str, PROTO_IPV6_STR)) {
|
||||
@@ -293,14 +304,13 @@ static int ril_data_protocol_to_ofono(gchar *str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct ril_data_call *ril_data_call_parse(int version,
|
||||
GRilIoParser *rilp)
|
||||
static gboolean ril_data_call_parse_default(struct ril_data_call *call,
|
||||
int version, GRilIoParser *rilp)
|
||||
{
|
||||
int prot;
|
||||
char *prot_str;
|
||||
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
|
||||
guint32 active = RIL_DATA_CALL_INACTIVE;
|
||||
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
|
||||
|
||||
/* RIL_Data_Call_Response_v6 (see ril.h) */
|
||||
grilio_parser_get_uint32(rilp, &status);
|
||||
@@ -335,13 +345,49 @@ static struct ril_data_call *ril_data_call_parse(int version,
|
||||
}
|
||||
|
||||
g_free(prot_str);
|
||||
return call;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
|
||||
int version, GRilIoParser *parser)
|
||||
{
|
||||
GRilIoParser copy = *parser;
|
||||
struct ril_data_call *call = ril_data_call_new();
|
||||
gboolean parsed = ril_vendor_hook_data_call_parse(hook, call,
|
||||
version, parser);
|
||||
|
||||
if (!parsed) {
|
||||
/* Try the default parser */
|
||||
ril_data_call_destroy(call);
|
||||
memset(call, 0, sizeof(*call));
|
||||
*parser = copy;
|
||||
parsed = ril_data_call_parse_default(call, version, parser);
|
||||
}
|
||||
|
||||
if (parsed) {
|
||||
DBG("[status=%d,retry=%d,cid=%d,active=%d,type=%s,ifname=%s,"
|
||||
"mtu=%d,address=%s,dns=%s %s,gateways=%s]",
|
||||
call->status, call->retry_time,
|
||||
call->cid, call->active,
|
||||
ril_data_ofono_protocol_to_ril(call->prot),
|
||||
call->ifname, call->mtu,
|
||||
call->addresses ? call->addresses[0] : NULL,
|
||||
call->dnses ? call->dnses[0] : NULL,
|
||||
(call->dnses && call->dnses[0] &&
|
||||
call->dnses[1]) ? call->dnses[1] : "",
|
||||
call->gateways ? call->gateways[0] : NULL);
|
||||
return call;
|
||||
} else {
|
||||
ril_data_call_free(call);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
guint len, enum ril_data_call_format format)
|
||||
guint len, struct ril_vendor_hook *hook,
|
||||
enum ril_data_call_format format)
|
||||
{
|
||||
unsigned int version, n, i;
|
||||
guint32 version, n, i;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
@@ -359,25 +405,14 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
}
|
||||
|
||||
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
|
||||
struct ril_data_call *call =
|
||||
ril_data_call_parse(list->version, &rilp);
|
||||
struct ril_data_call *call = ril_data_call_parse(hook,
|
||||
list->version, &rilp);
|
||||
|
||||
DBG("[status=%d,retry=%d,cid=%d,"
|
||||
"active=%d,type=%s,ifname=%s,mtu=%d,"
|
||||
"address=%s, dns=%s %s,gateways=%s]",
|
||||
call->status, call->retry_time,
|
||||
call->cid, call->active,
|
||||
ril_data_ofono_protocol_to_ril(call->prot),
|
||||
call->ifname, call->mtu,
|
||||
call->addresses ? call->addresses[0] : NULL,
|
||||
call->dnses ? call->dnses[0] : NULL,
|
||||
(call->dnses && call->dnses[0] &&
|
||||
call->dnses[1]) ? call->dnses[1] : "",
|
||||
call->gateways ? call->gateways[0] : NULL);
|
||||
|
||||
list->num++;
|
||||
list->calls = g_slist_insert_sorted(list->calls, call,
|
||||
ril_data_call_parse_compare);
|
||||
if (call) {
|
||||
list->num++;
|
||||
list->calls = g_slist_insert_sorted(list->calls,
|
||||
call, ril_data_call_compare);
|
||||
}
|
||||
}
|
||||
|
||||
if (list->calls) {
|
||||
@@ -471,7 +506,7 @@ static int ril_data_call_list_move_calls(struct ril_data_call_list *dest,
|
||||
dest->num++;
|
||||
src->calls = g_slist_delete_link(src->calls, l);
|
||||
dest->calls = g_slist_insert_sorted(dest->calls,
|
||||
call, ril_data_call_parse_compare);
|
||||
call, ril_data_call_compare);
|
||||
}
|
||||
|
||||
l = next;
|
||||
@@ -527,7 +562,7 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
|
||||
}
|
||||
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format));
|
||||
priv->vendor_hook, priv->options.data_call_format));
|
||||
}
|
||||
|
||||
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
@@ -544,7 +579,7 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
priv->query_id = 0;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format));
|
||||
priv->vendor_hook, priv->options.data_call_format));
|
||||
} else {
|
||||
/* RADIO_NOT_AVAILABLE == no calls */
|
||||
ril_data_set_calls(self, NULL);
|
||||
@@ -750,7 +785,7 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
list = ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format);
|
||||
priv->vendor_hook, priv->options.data_call_format);
|
||||
}
|
||||
|
||||
if (list) {
|
||||
@@ -854,19 +889,23 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: add comments about tethering, other non-public
|
||||
* profiles...
|
||||
*/
|
||||
ioreq = grilio_request_new();
|
||||
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
|
||||
grilio_request_append_format(ioreq, "%d", tech);
|
||||
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
|
||||
grilio_request_append_utf8(ioreq, setup->apn);
|
||||
grilio_request_append_utf8(ioreq, setup->username);
|
||||
grilio_request_append_utf8(ioreq, setup->password);
|
||||
grilio_request_append_format(ioreq, "%d", auth);
|
||||
grilio_request_append_utf8(ioreq, proto_str);
|
||||
/* Give vendor code a chance to build a vendor specific packet */
|
||||
ioreq = ril_vendor_hook_data_call_req(priv->vendor_hook, tech,
|
||||
DATA_PROFILE_DEFAULT_STR, setup->apn, setup->username,
|
||||
setup->password, auth, proto_str);
|
||||
|
||||
if (!ioreq) {
|
||||
/* The default one */
|
||||
ioreq = grilio_request_new();
|
||||
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
|
||||
grilio_request_append_format(ioreq, "%d", tech);
|
||||
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
|
||||
grilio_request_append_utf8(ioreq, setup->apn);
|
||||
grilio_request_append_utf8(ioreq, setup->username);
|
||||
grilio_request_append_utf8(ioreq, setup->password);
|
||||
grilio_request_append_format(ioreq, "%d", auth);
|
||||
grilio_request_append_utf8(ioreq, proto_str);
|
||||
}
|
||||
|
||||
GASSERT(!req->pending_id);
|
||||
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
||||
@@ -1114,7 +1153,8 @@ static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config)
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_vendor_hook *vendor_hook)
|
||||
{
|
||||
GASSERT(dm);
|
||||
if (G_LIKELY(dm)) {
|
||||
@@ -1147,6 +1187,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
priv->dm = ril_data_manager_ref(dm);
|
||||
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,
|
||||
ril_data_call_list_changed_cb,
|
||||
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
|
||||
@@ -1457,6 +1498,7 @@ static void ril_data_finalize(GObject *object)
|
||||
ril_network_unref(priv->network);
|
||||
ril_data_manager_unref(priv->dm);
|
||||
ril_data_call_list_free(self->data_calls);
|
||||
ril_vendor_hook_unref(priv->vendor_hook);
|
||||
G_OBJECT_CLASS(ril_data_parent_class)->finalize(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,
|
||||
@@ -96,7 +99,8 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config);
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_vendor_hook *vendor_hook);
|
||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||
void ril_data_unref(struct ril_data *data);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
@@ -124,6 +128,9 @@ 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,
|
||||
int cid);
|
||||
|
||||
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto);
|
||||
int ril_data_protocol_to_ofono(const gchar *str);
|
||||
|
||||
/* Constructors of various kinds of RIL requests */
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||
|
||||
@@ -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
|
||||
@@ -378,7 +378,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 +396,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
|
||||
@@ -58,8 +58,6 @@ struct ril_modem_data {
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gboolean pre_sim_done;
|
||||
gboolean allow_data;
|
||||
gulong imsi_event_id;
|
||||
|
||||
guint online_check_id;
|
||||
@@ -249,7 +247,6 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->pre_sim_done = TRUE;
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (md->modem.config.enable_voicecall) {
|
||||
@@ -288,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)
|
||||
@@ -469,11 +468,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) 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
|
||||
@@ -27,6 +27,14 @@ struct ril_netmon {
|
||||
guint register_id;
|
||||
};
|
||||
|
||||
/* This number must be in sync with ril_netmon_notify_ofono: */
|
||||
#define RIL_NETMON_MAX_OFONO_PARAMS (8)
|
||||
|
||||
struct ril_netmon_ofono_param {
|
||||
enum ofono_netmon_info type;
|
||||
int value;
|
||||
};
|
||||
|
||||
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
||||
{
|
||||
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
||||
@@ -50,58 +58,171 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
|
||||
enum ofono_netmon_cell_type type, int mcc, int mnc,
|
||||
struct ril_netmon_ofono_param *params, int nparams)
|
||||
{
|
||||
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
int i;
|
||||
|
||||
/* Better not to push uninitialized data to the stack ... */
|
||||
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
|
||||
params[i].type = OFONO_NETMON_INFO_INVALID;
|
||||
params[i].value = SAILFISH_CELL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon, type,
|
||||
OFONO_NETMON_INFO_MCC, s_mcc,
|
||||
OFONO_NETMON_INFO_MNC, s_mnc,
|
||||
params[0].type, params[0].value,
|
||||
params[1].type, params[1].value,
|
||||
params[2].type, params[2].value,
|
||||
params[3].type, params[3].value,
|
||||
params[4].type, params[4].value,
|
||||
params[5].type, params[5].value,
|
||||
params[6].type, params[6].value,
|
||||
params[7].type, params[7].value,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_gsm *gsm)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, gsm->mcc, gsm->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_GSM,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_LAC, gsm->lac,
|
||||
OFONO_NETMON_INFO_CI, gsm->cid,
|
||||
OFONO_NETMON_INFO_RSSI, gsm->signalStrength,
|
||||
OFONO_NETMON_INFO_BER, gsm->bitErrorRate,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
if (gsm->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||
params[n].value = gsm->lac;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = gsm->cid;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->arfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||
params[n].value = gsm->arfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = gsm->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_BER;
|
||||
params[n].value = gsm->bitErrorRate;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_GSM,
|
||||
gsm->mcc, gsm->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_wcdma *wcdma)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, wcdma->mcc, wcdma->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_UMTS,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_LAC, wcdma->lac,
|
||||
OFONO_NETMON_INFO_CI, wcdma->cid,
|
||||
OFONO_NETMON_INFO_PSC, wcdma->psc,
|
||||
OFONO_NETMON_INFO_RSSI, wcdma->signalStrength,
|
||||
OFONO_NETMON_INFO_BER, wcdma->bitErrorRate,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
if (wcdma->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||
params[n].value = wcdma->lac;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = wcdma->cid;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->psc != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_PSC;
|
||||
params[n].value = wcdma->psc;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->uarfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||
params[n].value = wcdma->uarfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = wcdma->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_BER;
|
||||
params[n].value = wcdma->bitErrorRate;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_UMTS,
|
||||
wcdma->mcc, wcdma->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_lte *lte)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, lte->mcc, lte->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_LTE,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_CI, lte->ci,
|
||||
OFONO_NETMON_INFO_RSSI, lte->signalStrength,
|
||||
OFONO_NETMON_INFO_TIMING_ADVANCE, lte->timingAdvance,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
if (lte->ci != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = lte->ci;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->earfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_EARFCN;
|
||||
params[n].value = lte->earfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = lte->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->rsrp != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSRQ;
|
||||
params[n].value = lte->rsrp;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->rsrq != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSRP;
|
||||
params[n].value = lte->rsrq;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->cqi != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CQI;
|
||||
params[n].value = lte->cqi;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->timingAdvance != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
|
||||
params[n].value = lte->timingAdvance;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_LTE,
|
||||
lte->mcc, lte->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "ril_radio_caps.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <sailfish_manager.h>
|
||||
@@ -46,7 +47,7 @@
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include "storage.h"
|
||||
#include <ofono/storage.h>
|
||||
|
||||
#define OFONO_RADIO_ACCESS_MODE_ALL (OFONO_RADIO_ACCESS_MODE_GSM |\
|
||||
OFONO_RADIO_ACCESS_MODE_UMTS |\
|
||||
@@ -62,7 +63,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
|
||||
@@ -73,6 +77,7 @@
|
||||
#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
|
||||
|
||||
/*
|
||||
@@ -81,36 +86,40 @@
|
||||
* 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_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_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_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_DEFAULT_LEGACY_IMEI_QUERY "legacyImeiQuery"
|
||||
|
||||
/* 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,
|
||||
@@ -184,6 +193,8 @@ typedef struct sailfish_slot_impl {
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
struct ril_oem_raw *oem_raw;
|
||||
const struct ril_vendor_driver *vendor;
|
||||
struct ril_vendor_hook *vendor_hook;
|
||||
struct ril_data *data;
|
||||
gboolean legacy_imei_query;
|
||||
guint start_timeout;
|
||||
@@ -397,6 +408,11 @@ static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
|
||||
slot->received_sim_status = FALSE;
|
||||
}
|
||||
|
||||
if (slot->vendor_hook) {
|
||||
ril_vendor_hook_unref(slot->vendor_hook);
|
||||
slot->vendor_hook = NULL;
|
||||
}
|
||||
|
||||
if (slot->io) {
|
||||
int i;
|
||||
|
||||
@@ -715,10 +731,12 @@ static void ril_plugin_caps_switch_aborted(struct ril_radio_caps_manager *mgr,
|
||||
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
||||
guint id, guint code, const void *data, guint data_len, void *user_data)
|
||||
{
|
||||
static const GLogModule *log_module = &ril_debug_trace_module;
|
||||
ril_slot *slot = user_data;
|
||||
struct ril_vendor_hook *hook = slot->vendor_hook;
|
||||
static const GLogModule* log_module = &ril_debug_trace_module;
|
||||
const char *prefix = io->name ? io->name : "";
|
||||
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
|
||||
const char *scode;
|
||||
const char *scode = NULL;
|
||||
|
||||
switch (type) {
|
||||
case GRILIO_PACKET_REQ:
|
||||
@@ -726,7 +744,10 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
||||
code == RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION) {
|
||||
scode = "V9_SET_UICC_SUBSCRIPTION";
|
||||
} else {
|
||||
scode = ril_request_to_string(code);
|
||||
scode = ril_vendor_hook_request_to_string(hook, code);
|
||||
if (!scode) {
|
||||
scode = ril_request_to_string(code);
|
||||
}
|
||||
}
|
||||
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c [%08x] %s",
|
||||
prefix, dir, id, scode);
|
||||
@@ -742,8 +763,12 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
||||
break;
|
||||
case GRILIO_PACKET_UNSOL:
|
||||
case GRILIO_PACKET_UNSOL_ACK_EXP:
|
||||
scode = ril_vendor_hook_event_to_string(hook, code);
|
||||
if (!scode) {
|
||||
scode = ril_unsol_event_to_string(code);
|
||||
}
|
||||
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c %s",
|
||||
prefix, dir, ril_unsol_event_to_string(code));
|
||||
prefix, dir, scode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -960,12 +985,17 @@ 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,
|
||||
slot->radio, slot->network, slot->io, &slot->data_opt,
|
||||
&slot->config);
|
||||
&slot->config, slot->vendor_hook);
|
||||
|
||||
GASSERT(!slot->cell_info);
|
||||
if (slot->io->ril_version >= 9) {
|
||||
@@ -1140,14 +1170,19 @@ static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *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->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->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;
|
||||
@@ -1175,6 +1210,29 @@ static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
|
||||
return slot;
|
||||
}
|
||||
|
||||
static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
|
||||
{
|
||||
if (slot->vendor) {
|
||||
struct ril_slot_config *config = &slot->config;
|
||||
struct ril_vendor_defaults defaults;
|
||||
|
||||
/* Let the vendor extension to adjust (some) defaults */
|
||||
memset(&defaults, 0, sizeof(defaults));
|
||||
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);
|
||||
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,
|
||||
const char *name, guint slot_index)
|
||||
{
|
||||
@@ -1244,6 +1302,25 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
DBG("%s: " RILCONF_SLOT " %u", group, config->slot);
|
||||
}
|
||||
|
||||
/* vendorDriver */
|
||||
sval = ril_config_get_string(file, group, RILCONF_VENDOR_DRIVER);
|
||||
if (sval) {
|
||||
const struct ril_vendor_driver *vendor;
|
||||
RIL_VENDOR_DRIVER_FOREACH(vendor) {
|
||||
if (!strcasecmp(vendor->name, sval)) {
|
||||
DBG("%s: " RILCONF_VENDOR_DRIVER " %s", group,
|
||||
sval);
|
||||
slot->vendor = vendor;
|
||||
ril_plugin_slot_apply_vendor_defaults(slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!slot->vendor) {
|
||||
ofono_warn("Unknown vendor '%s'", sval);
|
||||
}
|
||||
g_free(sval);
|
||||
}
|
||||
|
||||
/* startTimeout */
|
||||
if (ril_config_get_integer(file, group, RILCONF_START_TIMEOUT,
|
||||
&ival) && ival >= 0) {
|
||||
@@ -1264,6 +1341,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) {
|
||||
@@ -1299,6 +1383,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;
|
||||
@@ -1574,22 +1672,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) {
|
||||
@@ -1664,7 +1756,7 @@ static void ril_plugin_set_storage_perm(const char *path,
|
||||
|
||||
static void ril_plugin_switch_identity(const struct ril_plugin_identity *id)
|
||||
{
|
||||
ril_plugin_set_storage_perm(STORAGEDIR, id);
|
||||
ril_plugin_set_storage_perm(ofono_storage_dir(), id);
|
||||
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
|
||||
ofono_error("prctl(PR_SET_KEEPCAPS) failed: %s",
|
||||
strerror(errno));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1321,7 +1350,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 +1363,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);
|
||||
}
|
||||
|
||||
@@ -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,11 +18,15 @@
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
#include "simutil.h"
|
||||
#include "util.h"
|
||||
#include "ofono.h"
|
||||
|
||||
#define SIM_STATE_CHANGE_TIMEOUT_SECS (5)
|
||||
#define FAC_LOCK_QUERY_TIMEOUT_SECS (10)
|
||||
#define FAC_LOCK_QUERY_RETRIES (1)
|
||||
#define SIM_IO_TIMEOUT_SECS (20)
|
||||
|
||||
#define EF_STATUS_INVALIDATED 0
|
||||
#define EF_STATUS_VALID 1
|
||||
@@ -65,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;
|
||||
@@ -75,13 +84,17 @@ struct ril_sim {
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
gboolean empty_pin_query_allowed;
|
||||
gboolean inserted;
|
||||
guint idle_id;
|
||||
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;
|
||||
char *allocated_log_prefix;
|
||||
|
||||
struct sailfish_watch *watch;
|
||||
gulong sim_state_watch_id;
|
||||
|
||||
/* query_passwd_state context */
|
||||
ofono_sim_passwd_cb_t query_passwd_state_cb;
|
||||
void *query_passwd_state_cb_data;
|
||||
@@ -95,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;
|
||||
@@ -166,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)
|
||||
{
|
||||
@@ -416,14 +449,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);
|
||||
@@ -467,7 +499,7 @@ 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();
|
||||
|
||||
@@ -485,9 +517,8 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
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);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_IO, cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -497,19 +528,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) {
|
||||
@@ -528,7 +559,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,
|
||||
@@ -558,13 +589,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) {
|
||||
@@ -585,7 +615,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);
|
||||
}
|
||||
|
||||
@@ -622,12 +652,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;
|
||||
@@ -653,7 +681,7 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
{
|
||||
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);
|
||||
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);
|
||||
@@ -665,10 +693,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);
|
||||
}
|
||||
|
||||
@@ -850,6 +876,18 @@ static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
/* That will simulate SIM card removal: */
|
||||
ril_sim_card_reset(sd->card);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_sim_parse_retry_count(const void *data, guint len)
|
||||
{
|
||||
int retry_count = -1;
|
||||
@@ -864,10 +902,14 @@ 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)
|
||||
{
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
if (app_id) {
|
||||
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, app_id);
|
||||
pin, sd->card->app->aid);
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
return req;
|
||||
@@ -1223,7 +1265,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);
|
||||
}
|
||||
|
||||
@@ -1279,7 +1321,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);
|
||||
}
|
||||
|
||||
@@ -1335,11 +1377,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;
|
||||
@@ -1356,24 +1396,47 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
|
||||
cb(ril_error_failure(&error), FALSE, cbd->data);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_query_facility_lock_retry(GRilIoRequest* req,
|
||||
int ril_status, const void* response_data,
|
||||
guint response_len, void* user_data)
|
||||
{
|
||||
return (ril_status == GRILIO_STATUS_TIMEOUT);
|
||||
}
|
||||
|
||||
static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
enum ofono_sim_password_type type,
|
||||
ofono_query_facility_lock_cb_t cb, void *data)
|
||||
{
|
||||
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));
|
||||
|
||||
/* Make sure that this request gets completed sooner or later */
|
||||
grilio_request_set_timeout(req, FAC_LOCK_QUERY_TIMEOUT_SECS * 1000);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, FAC_LOCK_QUERY_RETRIES);
|
||||
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;
|
||||
@@ -1391,6 +1454,14 @@ static gboolean ril_sim_register(gpointer user)
|
||||
sd->card_event_id[SIM_CARD_APP_EVENT] =
|
||||
ril_sim_card_add_app_changed_handler(sd->card,
|
||||
ril_sim_app_changed_cb, sd);
|
||||
sd->sim_state_watch_id =
|
||||
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);
|
||||
@@ -1409,6 +1480,7 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->card = ril_sim_card_ref(modem->sim_card);
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
sd->watch = sailfish_watch_new(ril_modem_get_path(modem));
|
||||
|
||||
if (modem->log_prefix && modem->log_prefix[0]) {
|
||||
sd->log_prefix = sd->allocated_log_prefix =
|
||||
@@ -1429,6 +1501,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);
|
||||
|
||||
@@ -1445,6 +1518,9 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
}
|
||||
|
||||
sailfish_watch_remove_handler(sd->watch, sd->sim_state_watch_id);
|
||||
sailfish_watch_unref(sd->watch);
|
||||
|
||||
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
|
||||
G_N_ELEMENTS(sd->card_event_id));
|
||||
ril_sim_card_unref(sd->card);
|
||||
|
||||
@@ -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);
|
||||
@@ -78,6 +81,9 @@ 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; }
|
||||
|
||||
#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,16 @@ 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
|
||||
|
||||
@@ -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
|
||||
@@ -41,16 +41,22 @@ struct ofono_sim;
|
||||
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
|
||||
|
||||
struct ril_data;
|
||||
struct ril_data_call;
|
||||
struct ril_modem;
|
||||
struct ril_radio;
|
||||
struct ril_network;
|
||||
struct ril_sim_card;
|
||||
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 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,
|
||||
|
||||
164
ofono/drivers/ril/ril_vendor.c
Normal file
164
ofono/drivers/ril/ril_vendor.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* 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
|
||||
* 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 "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
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,
|
||||
struct ril_network *network)
|
||||
{
|
||||
if (vendor) {
|
||||
const void *data = vendor->driver_data;
|
||||
|
||||
/*
|
||||
* NOTE: we are looking for the callback in the base but
|
||||
* keeping the original driver data.
|
||||
*/
|
||||
while (!vendor->create_hook && vendor->base) {
|
||||
vendor = vendor->base;
|
||||
}
|
||||
if (vendor->create_hook) {
|
||||
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,
|
||||
ril_vendor_hook_free_proc free)
|
||||
{
|
||||
self->proc = proc;
|
||||
self->free = free;
|
||||
g_atomic_int_set(&self->ref_count, 1);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *self)
|
||||
{
|
||||
if (self) {
|
||||
GASSERT(self->ref_count > 0);
|
||||
g_atomic_int_inc(&self->ref_count);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static void ril_vendor_hook_free(struct ril_vendor_hook *self)
|
||||
{
|
||||
if (self->free) {
|
||||
self->free(self);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_vendor_hook_unref(struct ril_vendor_hook *self)
|
||||
{
|
||||
if (self) {
|
||||
GASSERT(self->ref_count > 0);
|
||||
if (g_atomic_int_dec_and_test(&self->ref_count)) {
|
||||
ril_vendor_hook_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
|
||||
struct ril_vendor_defaults *defaults)
|
||||
{
|
||||
if (vendor) {
|
||||
while (!vendor->get_defaults && vendor->base) {
|
||||
vendor = vendor->base;
|
||||
}
|
||||
if (vendor->get_defaults) {
|
||||
vendor->get_defaults(defaults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *self,
|
||||
guint request)
|
||||
{
|
||||
if (self) {
|
||||
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||
|
||||
while (!proc->request_to_string && proc->base) {
|
||||
proc = proc->base;
|
||||
}
|
||||
if (proc->request_to_string) {
|
||||
return proc->request_to_string(self, request);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *self,
|
||||
guint event)
|
||||
{
|
||||
if (self) {
|
||||
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||
|
||||
while (!proc->event_to_string && proc->base) {
|
||||
proc = proc->base;
|
||||
}
|
||||
if (proc->event_to_string) {
|
||||
return proc->event_to_string(self, event);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *self,
|
||||
int tech, const char *profile, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
if (self) {
|
||||
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||
|
||||
while (!proc->data_call_req && proc->base) {
|
||||
proc = proc->base;
|
||||
}
|
||||
if (proc->data_call_req) {
|
||||
return proc->data_call_req(self, tech, profile, apn,
|
||||
username, password, auth, proto);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *self,
|
||||
struct ril_data_call *call, int ver, GRilIoParser *rilp)
|
||||
{
|
||||
if (self) {
|
||||
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||
|
||||
while (!proc->data_call_parse && proc->base) {
|
||||
proc = proc->base;
|
||||
}
|
||||
if (proc->data_call_parse) {
|
||||
return proc->data_call_parse(self, call, ver, rilp);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
103
ofono/drivers/ril/ril_vendor.h
Normal file
103
ofono/drivers/ril/ril_vendor.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* 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
|
||||
* 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 RIL_VENDOR_H
|
||||
#define RIL_VENDOR_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_vendor_defaults {
|
||||
gboolean empty_pin_query;
|
||||
gboolean legacy_imei_query;
|
||||
gboolean enable_cbs;
|
||||
gboolean query_available_band_mode;
|
||||
};
|
||||
|
||||
struct ril_vendor_driver {
|
||||
const char *name;
|
||||
const void *driver_data;
|
||||
const struct ril_vendor_driver *base;
|
||||
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,
|
||||
struct ril_network *network);
|
||||
};
|
||||
|
||||
struct ril_vendor_hook_proc {
|
||||
const struct ril_vendor_hook_proc *base;
|
||||
const char *(*request_to_string)(struct ril_vendor_hook *hook,
|
||||
guint request);
|
||||
const char *(*event_to_string)(struct ril_vendor_hook *hook,
|
||||
guint event);
|
||||
GRilIoRequest *(*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);
|
||||
gboolean (*data_call_parse)(struct ril_vendor_hook *hook,
|
||||
struct ril_data_call *call, int version,
|
||||
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,
|
||||
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,
|
||||
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);
|
||||
|
||||
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *hook,
|
||||
guint request);
|
||||
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *hook,
|
||||
guint event);
|
||||
GRilIoRequest *ril_vendor_hook_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);
|
||||
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *hook,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
|
||||
/* Put vendor driver descriptors to the "__vendor" section */
|
||||
#define RIL_VENDOR_DRIVER_DEFINE(name) \
|
||||
const struct ril_vendor_driver name \
|
||||
__attribute__((used, section("__vendor"))) =
|
||||
#define RIL_VENDOR_DRIVER_FOREACH(var) \
|
||||
for ((var) = __start___vendor; (var) < __stop___vendor; (var)++)
|
||||
extern const struct ril_vendor_driver __start___vendor[];
|
||||
extern const struct ril_vendor_driver __stop___vendor[];
|
||||
|
||||
#endif /* RIL_VENDOR_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
654
ofono/drivers/ril/ril_vendor_mtk.c
Normal file
654
ofono/drivers/ril/ril_vendor_mtk.c
Normal file
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* 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
|
||||
* 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 "ril_plugin.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_parser.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_queue.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define SET_INITIAL_ATTACH_APN_TIMEOUT (20*1000)
|
||||
|
||||
enum ril_mtk_watch_events {
|
||||
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
|
||||
};
|
||||
|
||||
struct ril_vendor_hook_mtk {
|
||||
struct ril_vendor_hook hook;
|
||||
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;
|
||||
};
|
||||
|
||||
/* driver_data point this this: */
|
||||
struct ril_vendor_mtk_driver_data {
|
||||
const char *name;
|
||||
const struct ril_mtk_msg *msg;
|
||||
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;
|
||||
|
||||
/* 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_incoming_call_indication;
|
||||
guint unsol_set_attach_apn;
|
||||
};
|
||||
|
||||
static const struct ril_mtk_msg msg_mtk1 = {
|
||||
.attach_apn_has_roaming_protocol = TRUE,
|
||||
.request_resume_registration = 2050,
|
||||
.unsol_ps_network_state_changed = 3012,
|
||||
.unsol_registration_suspended = 3021,
|
||||
.unsol_incoming_call_indication = 3037,
|
||||
.unsol_set_attach_apn = 3065
|
||||
};
|
||||
|
||||
static const struct ril_mtk_msg msg_mtk2 = {
|
||||
.attach_apn_has_roaming_protocol = FALSE,
|
||||
.request_resume_registration = 2065,
|
||||
.unsol_ps_network_state_changed = 3015,
|
||||
.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
|
||||
(struct ril_vendor_hook *hook)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||
const struct ril_mtk_msg *msg = self->msg;
|
||||
|
||||
if (request == msg->request_resume_registration) {
|
||||
return "MTK_RESUME_REGISTRATION";
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return ril_vendor_mtk_unsol_msg_name(self->msg, event);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_registration_suspended(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;
|
||||
GRilIoParser rilp;
|
||||
int session_id;
|
||||
|
||||
GASSERT(id == msg->unsol_registration_suspended);
|
||||
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();
|
||||
DBG("slot=%u,session_id=%d", self->slot, session_id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, session_id);
|
||||
grilio_queue_send_request(self->q, req,
|
||||
msg->request_resume_registration);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 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_call_state_changed(GRilIoChannel *io,
|
||||
guint id, const void *data, guint len, void *user_data)
|
||||
{
|
||||
/* Ignore the payload, let ril_voicecall.c do its normal stuff */
|
||||
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)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, 8); /* Number of parameters */
|
||||
grilio_request_append_format(req, "%d", tech);
|
||||
grilio_request_append_utf8(req, profile);
|
||||
grilio_request_append_utf8(req, apn);
|
||||
grilio_request_append_utf8(req, username);
|
||||
grilio_request_append_utf8(req, password);
|
||||
grilio_request_append_format(req, "%d", auth);
|
||||
grilio_request_append_utf8(req, proto);
|
||||
grilio_request_append_format(req, "%d", self->slot+1);
|
||||
return req;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_vendor_hook *hook,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
if (version < 11) {
|
||||
int prot;
|
||||
char *prot_str;
|
||||
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
|
||||
guint32 active = RIL_DATA_CALL_INACTIVE;
|
||||
|
||||
/* RIL_Data_Call_Response_v6 with MTK specific additions */
|
||||
grilio_parser_get_uint32(rilp, &status);
|
||||
grilio_parser_get_int32(rilp, &call->retry_time);
|
||||
grilio_parser_get_int32(rilp, &call->cid);
|
||||
grilio_parser_get_uint32(rilp, &active);
|
||||
grilio_parser_get_int32(rilp, &call->mtu); /* MTK specific */
|
||||
prot_str = grilio_parser_get_utf8(rilp);
|
||||
prot = ril_data_protocol_to_ofono(prot_str);
|
||||
g_free(prot_str);
|
||||
|
||||
if (prot >= 0) {
|
||||
call->ifname = grilio_parser_get_utf8(rilp);
|
||||
call->addresses = grilio_parser_split_utf8(rilp, " ");
|
||||
call->dnses = grilio_parser_split_utf8(rilp, " ");
|
||||
call->gateways = grilio_parser_split_utf8(rilp, " ");
|
||||
if (call->ifname && call->addresses) {
|
||||
call->prot = prot;
|
||||
call->status = status;
|
||||
call->active = active;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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 void ril_vendor_mtk_hook_subscribe(struct ril_vendor_hook_mtk *self)
|
||||
{
|
||||
const struct ril_mtk_msg *msg = self->msg;
|
||||
|
||||
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
|
||||
grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_vendor_mtk_registration_suspended,
|
||||
msg->unsol_registration_suspended, self);
|
||||
if (msg->unsol_set_attach_apn) {
|
||||
self->ril_event_id[MTK_EVENT_SET_ATTACH_APN] =
|
||||
grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_vendor_mtk_set_attach_apn,
|
||||
msg->unsol_set_attach_apn, self);
|
||||
}
|
||||
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_call_state_changed,
|
||||
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)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||
|
||||
DBG("slot %u", self->slot);
|
||||
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 = {
|
||||
.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
|
||||
};
|
||||
|
||||
static const struct ril_vendor_driver ril_vendor_mtk_base = {
|
||||
.get_defaults = ril_vendor_mtk_get_defaults,
|
||||
.create_hook = ril_vendor_mtk_create_hook_from_data
|
||||
};
|
||||
|
||||
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_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_mtk2_data = {
|
||||
.name = "mtk2",
|
||||
.msg = &msg_mtk2,
|
||||
.proc = &ril_vendor_mtk2_proc
|
||||
};
|
||||
|
||||
#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_mtk2) {
|
||||
.name = "mtk2",
|
||||
.driver_data = &ril_vendor_mtk2_data,
|
||||
.base = &ril_vendor_mtk_base
|
||||
};
|
||||
|
||||
/* Auto-selection */
|
||||
|
||||
static gboolean ril_vendor_mtk_auto_set_type
|
||||
(struct ril_vendor_hook_mtk_auto *self,
|
||||
const struct ril_vendor_mtk_driver_data *type)
|
||||
{
|
||||
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
grilio_channel_remove_handler(mtk->io, self->detect_id);
|
||||
self->detect_id = 0;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *self)
|
||||
{
|
||||
guint i;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_auto_free(struct ril_vendor_hook *hook)
|
||||
{
|
||||
struct ril_vendor_hook_mtk_auto *self =
|
||||
ril_vendor_hook_mtk_auto_cast(hook);
|
||||
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||
|
||||
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, struct ril_network *network)
|
||||
{
|
||||
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) {
|
||||
.name = "mtk",
|
||||
.get_defaults = ril_vendor_mtk_get_defaults,
|
||||
.create_hook = ril_vendor_mtk_create_hook_auto
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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,
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
/* size of RIL_CellInfoTdscdma */
|
||||
#define NETMON_RIL_CELLINFO_SIZE_TDSCDMA 24
|
||||
|
||||
#define MSECS_RATE_INVALID (0x7fffffff)
|
||||
#define SECS_TO_MSECS(x) ((x) * 1000)
|
||||
|
||||
struct netmon_data {
|
||||
GRil *ril;
|
||||
};
|
||||
@@ -96,11 +99,9 @@ static int ril_cell_type_to_size(int cell_type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
||||
static int process_cellinfo_list(struct ril_msg *message,
|
||||
struct ofono_netmon *netmon)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_netmon_cb_t cb = cbd->cb;
|
||||
struct ofono_netmon *netmon = cbd->data;
|
||||
struct parcel rilp;
|
||||
int skip_len;
|
||||
int cell_info_cnt;
|
||||
@@ -114,7 +115,7 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
||||
int i, j;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
return OFONO_ERROR_TYPE_FAILURE;
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
@@ -146,7 +147,7 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
||||
}
|
||||
|
||||
if (!registered)
|
||||
goto error;
|
||||
return OFONO_ERROR_TYPE_FAILURE;
|
||||
|
||||
if (cell_type == NETMON_RIL_CELLINFO_TYPE_GSM) {
|
||||
mcc = parcel_r_int32(&rilp);
|
||||
@@ -216,17 +217,53 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
||||
OFONO_NETMON_INFO_BER, ber,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
return OFONO_ERROR_TYPE_NO_ERROR;
|
||||
}
|
||||
|
||||
static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_netmon_cb_t cb = cbd->cb;
|
||||
struct ofono_netmon *netmon = cbd->data;
|
||||
|
||||
if (process_cellinfo_list(message, netmon) ==
|
||||
OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_cellinfo_notify(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_netmon *netmon = user_data;
|
||||
|
||||
process_cellinfo_list(message, netmon);
|
||||
}
|
||||
|
||||
static void setup_cell_info_notify(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
struct parcel rilp;
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1); /* Number of elements */
|
||||
|
||||
parcel_w_int32(&rilp, MSECS_RATE_INVALID);
|
||||
|
||||
if (g_ril_send(nmd->ril, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
&rilp, NULL, NULL, NULL) == 0)
|
||||
ofono_error("%s: setup failed\n", __func__);
|
||||
|
||||
if (g_ril_register(nmd->ril, RIL_UNSOL_CELL_INFO_LIST,
|
||||
ril_cellinfo_notify, netmon) == 0)
|
||||
ofono_error("%s: setup failed\n", __func__);
|
||||
}
|
||||
|
||||
static int ril_netmon_probe(struct ofono_netmon *netmon,
|
||||
unsigned int vendor, void *user)
|
||||
{
|
||||
@@ -237,6 +274,8 @@ static int ril_netmon_probe(struct ofono_netmon *netmon,
|
||||
|
||||
ofono_netmon_set_data(netmon, ud);
|
||||
|
||||
setup_cell_info_notify(netmon);
|
||||
|
||||
g_idle_add(ril_delayed_register, netmon);
|
||||
|
||||
return 0;
|
||||
@@ -257,18 +296,55 @@ static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
struct cb_data *cbd = cb_data_new(cb, data, nmd);
|
||||
|
||||
if (g_ril_send(nmd->ril, RIL_REQUEST_GET_CELL_INFO_LIST, NULL,
|
||||
ril_netmon_update_cb, cbd, NULL) > 0)
|
||||
ril_netmon_update_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void periodic_update_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_netmon_cb_t cb = cbd->cb;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_netmon_periodic_update(struct ofono_netmon *netmon,
|
||||
unsigned int enable, unsigned int period,
|
||||
ofono_netmon_cb_t cb, void *data)
|
||||
{
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, nmd);
|
||||
struct parcel rilp;
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1); /* Number of elements */
|
||||
|
||||
if (enable)
|
||||
parcel_w_int32(&rilp, SECS_TO_MSECS(period));
|
||||
else
|
||||
parcel_w_int32(&rilp, MSECS_RATE_INVALID);
|
||||
|
||||
if (g_ril_send(nmd->ril, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
&rilp, periodic_update_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static struct ofono_netmon_driver driver = {
|
||||
.name = RILMODEM,
|
||||
.probe = ril_netmon_probe,
|
||||
.remove = ril_netmon_remove,
|
||||
.request_update = ril_netmon_request_update,
|
||||
.enable_periodic_update = ril_netmon_periodic_update,
|
||||
};
|
||||
|
||||
void ril_netmon_init(void)
|
||||
|
||||
@@ -267,7 +267,7 @@ static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[128];
|
||||
char buf[384];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
|
||||
233
ofono/drivers/xmm7modem/radio-settings.c
Normal file
233
ofono/drivers/xmm7modem/radio-settings.c
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "xmm7modem.h"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *xact_prefix[] = { "+XACT:", NULL };
|
||||
|
||||
struct radio_settings_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void xact_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode;
|
||||
struct ofono_error error;
|
||||
GAtResultIter iter;
|
||||
int value, preferred;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (g_at_result_iter_next(&iter, "+XACT:") == FALSE)
|
||||
goto error;
|
||||
|
||||
if (g_at_result_iter_next_number(&iter, &value) == FALSE)
|
||||
goto error;
|
||||
|
||||
if (g_at_result_iter_next_number(&iter, &preferred) == FALSE)
|
||||
goto error;
|
||||
|
||||
switch (value) {
|
||||
case 0:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case 1:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case 2:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
case 3:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case 4:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
case 5:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
case 6:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
break;
|
||||
default:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
cb(&error, mode, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void xmm_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, "AT+XACT?", xact_prefix,
|
||||
xact_query_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void xact_modify_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void xmm_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[20];
|
||||
int value = 6, preferred = 2;
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
value = 6;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
value = 0;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
value = 1;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
value = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (value == 6)
|
||||
snprintf(buf, sizeof(buf), "AT+XACT=%u,%u", value, preferred);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "AT+XACT=%u", value);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
xact_modify_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void xact_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
|
||||
if (!ok) {
|
||||
ofono_radio_settings_remove(rs);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_radio_settings_register(rs);
|
||||
}
|
||||
|
||||
static int xmm_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *user)
|
||||
{
|
||||
GAtChat *chat = user;
|
||||
struct radio_settings_data *rsd;
|
||||
|
||||
rsd = g_try_new0(struct radio_settings_data, 1);
|
||||
if (rsd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rsd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
|
||||
g_at_chat_send(rsd->chat, "AT+XACT=?", xact_prefix,
|
||||
xact_support_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xmm_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
|
||||
g_at_chat_unref(rsd->chat);
|
||||
g_free(rsd);
|
||||
}
|
||||
|
||||
static struct ofono_radio_settings_driver driver = {
|
||||
.name = "xmm7modem",
|
||||
.probe = xmm_radio_settings_probe,
|
||||
.remove = xmm_radio_settings_remove,
|
||||
.query_rat_mode = xmm_query_rat_mode,
|
||||
.set_rat_mode = xmm_set_rat_mode
|
||||
};
|
||||
|
||||
void xmm_radio_settings_init(void)
|
||||
{
|
||||
ofono_radio_settings_driver_register(&driver);
|
||||
}
|
||||
|
||||
void xmm_radio_settings_exit(void)
|
||||
{
|
||||
ofono_radio_settings_driver_unregister(&driver);
|
||||
}
|
||||
50
ofono/drivers/xmm7modem/xmm7modem.c
Normal file
50
ofono/drivers/xmm7modem/xmm7modem.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <gatchat.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/modem.h>
|
||||
|
||||
#include "xmm7modem.h"
|
||||
|
||||
static int xmm7modem_init(void)
|
||||
{
|
||||
xmm_radio_settings_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xmm7modem_exit(void)
|
||||
{
|
||||
xmm_radio_settings_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(xmm7modem, "Intel xmm7xxx series modem driver",
|
||||
VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
xmm7modem_init, xmm7modem_exit)
|
||||
27
ofono/drivers/xmm7modem/xmm7modem.h
Normal file
27
ofono/drivers/xmm7modem/xmm7modem.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
|
||||
#define XMM7MODEM "xmm7modem"
|
||||
|
||||
extern void xmm_radio_settings_init(void);
|
||||
extern void xmm_radio_settings_exit(void);
|
||||
@@ -543,7 +543,7 @@ static void at_f_cb(GAtServer *server, GAtServerRequestType type,
|
||||
G_AT_SERVER_RESULT_ERROR);
|
||||
return;
|
||||
}
|
||||
/* intentional fallback here */
|
||||
/* fall through */
|
||||
|
||||
case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
|
||||
/* default behavior on AT&F same as ATZ */
|
||||
|
||||
@@ -401,9 +401,11 @@ static enum rcr_result ipcp_client_rcr(struct ipcp_data *ipcp,
|
||||
break;
|
||||
|
||||
/*
|
||||
* Fall through, reject IP_ADDRESS if peer sends
|
||||
* us 0 (expecting us to provide its IP address)
|
||||
* Reject IP_ADDRESS if peer sends us 0 (expecting
|
||||
* us to provide its IP address)
|
||||
*/
|
||||
|
||||
/* fall through */
|
||||
default:
|
||||
if (options == NULL) {
|
||||
guint16 max_len = ntohs(packet->length) - 4;
|
||||
|
||||
@@ -189,9 +189,12 @@ static enum rcr_result ipv6cp_client_rcr(struct ipv6cp_data *ipv6cp,
|
||||
|
||||
if (ipv6cp->peer_addr != 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Fall through, reject zero Interface ID
|
||||
* Reject zero Interface ID
|
||||
*/
|
||||
|
||||
/* fall through */
|
||||
default:
|
||||
if (options == NULL) {
|
||||
guint16 max_len = ntohs(packet->length) - 4;
|
||||
|
||||
@@ -338,6 +338,8 @@ const char *ril_request_id_to_string(int req)
|
||||
return "RIL_REQUEST_GET_CELL_INFO_LIST";
|
||||
case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
|
||||
return "RIL_REQUEST_SET_INITIAL_ATTACH_APN";
|
||||
case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
|
||||
return "RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE";
|
||||
default:
|
||||
return "<INVALID>";
|
||||
}
|
||||
@@ -416,6 +418,8 @@ const char *ril_unsol_request_to_string(int request)
|
||||
return "UNSOL_EXIT_EMERGENCY_CALLBACK_MODE";
|
||||
case RIL_UNSOL_RIL_CONNECTED:
|
||||
return "UNSOL_RIL_CONNECTED";
|
||||
case RIL_UNSOL_CELL_INFO_LIST:
|
||||
return "RIL_UNSOL_CELL_INFO_LIST";
|
||||
default:
|
||||
return "<unknown request>";
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define __PARCEL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct parcel {
|
||||
char *data;
|
||||
|
||||
@@ -348,6 +348,7 @@
|
||||
#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
|
||||
|
||||
/* RIL Unsolicited Messages */
|
||||
@@ -388,6 +389,7 @@
|
||||
#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
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
@@ -63,6 +63,7 @@ extern "C" {
|
||||
#define OFONO_NETWORK_TIME_INTERFACE OFONO_SERVICE ".NetworkTime"
|
||||
#define OFONO_SIRI_INTERFACE OFONO_SERVICE ".Siri"
|
||||
#define OFONO_NETMON_INTERFACE OFONO_SERVICE ".NetworkMonitor"
|
||||
#define OFONO_NETMON_AGENT_INTERFACE OFONO_SERVICE ".NetworkMonitorAgent"
|
||||
#define OFONO_LTE_INTERFACE OFONO_SERVICE ".LongTermEvolution"
|
||||
|
||||
/* CDMA Interfaces */
|
||||
|
||||
@@ -29,8 +29,14 @@ extern "C" {
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_gprs_context;
|
||||
struct ofono_modem;
|
||||
|
||||
#define OFONO_GPRS_MAX_APN_LENGTH 127
|
||||
/*
|
||||
* ETSI 123.003, Section 9.1:
|
||||
* the APN has, after encoding as defined in the paragraph below, a maximum
|
||||
* length of 100 octets
|
||||
*/
|
||||
#define OFONO_GPRS_MAX_APN_LENGTH 100
|
||||
#define OFONO_GPRS_MAX_USERNAME_LENGTH 63
|
||||
#define OFONO_GPRS_MAX_PASSWORD_LENGTH 255
|
||||
|
||||
|
||||
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,6 +29,7 @@ extern "C" {
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_gprs;
|
||||
struct ofono_sim;
|
||||
|
||||
enum ofono_modem_type {
|
||||
@@ -82,6 +83,7 @@ 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);
|
||||
|
||||
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
|
||||
void *ofono_modem_get_data(struct ofono_modem *modem);
|
||||
|
||||
@@ -39,6 +39,10 @@ struct ofono_netmon_driver {
|
||||
void (*remove)(struct ofono_netmon *netmon);
|
||||
void (*request_update)(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb, void *data);
|
||||
void (*enable_periodic_update)(struct ofono_netmon *netmon,
|
||||
unsigned int enable,
|
||||
unsigned int period,
|
||||
ofono_netmon_cb_t cb, void *data);
|
||||
};
|
||||
|
||||
enum ofono_netmon_cell_type {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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
|
||||
@@ -24,6 +24,8 @@ enum sailfish_cell_type {
|
||||
SAILFISH_CELL_TYPE_LTE
|
||||
};
|
||||
|
||||
#define SAILFISH_CELL_INVALID_VALUE (INT_MAX)
|
||||
|
||||
struct sailfish_cell_info_gsm {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
|
||||
@@ -119,6 +119,13 @@ typedef void (*ofono_sms_filter_recv_datagram_cb_t)
|
||||
#define OFONO_SMS_FILTER_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_SMS_FILTER_PRIORITY_HIGH (100)
|
||||
|
||||
/*
|
||||
* The api_version field makes it possible to keep using old plugins
|
||||
* even if struct ofono_sms_filter gets extended with new callbacks.
|
||||
*/
|
||||
|
||||
#define OFONO_SMS_FILTER_API_VERSION (0)
|
||||
|
||||
/*
|
||||
* The filter callbacks either invoke the completion callback directly
|
||||
* or return the id of the cancellable asynchronous operation (but never
|
||||
@@ -135,6 +142,7 @@ typedef void (*ofono_sms_filter_recv_datagram_cb_t)
|
||||
*/
|
||||
struct ofono_sms_filter {
|
||||
const char *name;
|
||||
int api_version; /* OFONO_SMS_FILTER_API_VERSION */
|
||||
int priority;
|
||||
unsigned int (*filter_send_text)(struct ofono_modem *modem,
|
||||
const struct ofono_sms_address *addr,
|
||||
|
||||
32
ofono/include/storage.h
Normal file
32
ofono/include/storage.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Telephony stack for Linux
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_STORAGE_H
|
||||
#define __OFONO_STORAGE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const char *ofono_config_dir(void);
|
||||
const char *ofono_storage_dir(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_STORAGE_H */
|
||||
127
ofono/include/voicecall-filter.h
Normal file
127
ofono/include/voicecall-filter.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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);
|
||||
};
|
||||
|
||||
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:
|
||||
*/
|
||||
@@ -29,6 +29,7 @@ extern "C" {
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_voicecall;
|
||||
|
||||
typedef void (*ofono_voicecall_cb_t)(const struct ofono_error *error,
|
||||
@@ -152,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);
|
||||
|
||||
|
||||
@@ -195,6 +195,7 @@ static void sim_watch(struct ofono_atom *atom,
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
|
||||
if (ctx->simwatch_id) {
|
||||
sim_state_watch(OFONO_SIM_STATE_NOT_PRESENT, data);
|
||||
ofono_sim_remove_state_watch(ctx->sim, ctx->simwatch_id);
|
||||
ctx->simwatch_id = 0;
|
||||
}
|
||||
|
||||
@@ -25,12 +25,17 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gatchat.h>
|
||||
#include <gattty.h>
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
@@ -46,7 +51,17 @@
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
#define HARDWARE_MONITOR_INTERFACE OFONO_SERVICE ".cinterion.HardwareMonitor"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *sctm_prefix[] = { "^SCTM:", NULL };
|
||||
static const char *sbv_prefix[] = { "^SBV:", NULL };
|
||||
|
||||
struct gemalto_hardware_monitor {
|
||||
DBusMessage *msg;
|
||||
int32_t temperature;
|
||||
int32_t voltage;
|
||||
};
|
||||
|
||||
struct gemalto_data {
|
||||
GAtChat *app;
|
||||
@@ -54,6 +69,7 @@ struct gemalto_data {
|
||||
struct ofono_sim *sim;
|
||||
gboolean have_sim;
|
||||
struct at_util_sim_state_query *sim_state_query;
|
||||
struct gemalto_hardware_monitor *hm;
|
||||
};
|
||||
|
||||
static int gemalto_probe(struct ofono_modem *modem)
|
||||
@@ -142,6 +158,148 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void gemalto_sctm_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct gemalto_data *data = user_data;
|
||||
DBusMessage *reply;
|
||||
GAtResultIter iter;
|
||||
DBusMessageIter dbus_iter;
|
||||
DBusMessageIter dbus_dict;
|
||||
|
||||
if (data->hm->msg == NULL)
|
||||
return;
|
||||
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^SCTM:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &data->hm->temperature))
|
||||
goto error;
|
||||
|
||||
reply = dbus_message_new_method_return(data->hm->msg);
|
||||
|
||||
dbus_message_iter_init_append(reply, &dbus_iter);
|
||||
|
||||
dbus_message_iter_open_container(&dbus_iter, DBUS_TYPE_ARRAY,
|
||||
OFONO_PROPERTIES_ARRAY_SIGNATURE,
|
||||
&dbus_dict);
|
||||
|
||||
ofono_dbus_dict_append(&dbus_dict, "Temperature",
|
||||
DBUS_TYPE_INT32, &data->hm->temperature);
|
||||
|
||||
ofono_dbus_dict_append(&dbus_dict, "Voltage",
|
||||
DBUS_TYPE_UINT32, &data->hm->voltage);
|
||||
|
||||
dbus_message_iter_close_container(&dbus_iter, &dbus_dict);
|
||||
|
||||
__ofono_dbus_pending_reply(&data->hm->msg, reply);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
__ofono_dbus_pending_reply(&data->hm->msg,
|
||||
__ofono_error_failed(data->hm->msg));
|
||||
}
|
||||
|
||||
static void gemalto_sbv_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct gemalto_data *data = user_data;
|
||||
GAtResultIter iter;
|
||||
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^SBV:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &data->hm->voltage))
|
||||
goto error;
|
||||
|
||||
if (g_at_chat_send(data->app, "AT^SCTM?", sctm_prefix, gemalto_sctm_cb,
|
||||
data, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
__ofono_dbus_pending_reply(&data->hm->msg,
|
||||
__ofono_error_failed(data->hm->msg));
|
||||
}
|
||||
|
||||
static DBusMessage *hardware_monitor_get_statistics(DBusConnection *conn,
|
||||
DBusMessage *msg,
|
||||
void *user_data)
|
||||
{
|
||||
struct gemalto_data *data = user_data;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->hm->msg != NULL)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
if (!g_at_chat_send(data->app, "AT^SBV", sbv_prefix, gemalto_sbv_cb,
|
||||
data, NULL))
|
||||
return __ofono_error_failed(msg);
|
||||
|
||||
data->hm->msg = dbus_message_ref(msg);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable hardware_monitor_methods[] = {
|
||||
{ GDBUS_ASYNC_METHOD("GetStatistics",
|
||||
NULL, GDBUS_ARGS({ "Statistics", "a{sv}" }),
|
||||
hardware_monitor_get_statistics) },
|
||||
{}
|
||||
};
|
||||
|
||||
static void hardware_monitor_cleanup(void *user_data)
|
||||
{
|
||||
struct gemalto_data *data = user_data;
|
||||
struct gemalto_hardware_monitor *hm = data->hm;
|
||||
|
||||
g_free(hm);
|
||||
}
|
||||
|
||||
static int gemalto_hardware_monitor_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
DBG("");
|
||||
|
||||
/* Enable temperature output */
|
||||
g_at_chat_send(data->app, "AT^SCTM=0,1", none_prefix, NULL, NULL, NULL);
|
||||
|
||||
/* Create Hardware Monitor DBus interface */
|
||||
data->hm = g_try_new0(struct gemalto_hardware_monitor, 1);
|
||||
if (data->hm == NULL)
|
||||
return -EIO;
|
||||
|
||||
if (!g_dbus_register_interface(conn, path, HARDWARE_MONITOR_INTERFACE,
|
||||
hardware_monitor_methods, NULL, NULL,
|
||||
data, hardware_monitor_cleanup)) {
|
||||
ofono_error("Could not register %s interface under %s",
|
||||
HARDWARE_MONITOR_INTERFACE, path);
|
||||
g_free(data->hm);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ofono_modem_add_interface(modem, HARDWARE_MONITOR_INTERFACE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gemalto_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
@@ -181,6 +339,8 @@ static int gemalto_enable(struct ofono_modem *modem)
|
||||
g_at_chat_send(data->app, "AT+CFUN=4", none_prefix,
|
||||
cfun_enable, modem, NULL);
|
||||
|
||||
gemalto_hardware_monitor_enable(modem);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
@@ -203,12 +363,19 @@ static void gemalto_smso_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
static int gemalto_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_cancel_all(data->app);
|
||||
g_at_chat_unregister_all(data->app);
|
||||
|
||||
if (g_dbus_unregister_interface(conn, path,
|
||||
HARDWARE_MONITOR_INTERFACE))
|
||||
ofono_modem_remove_interface(modem,
|
||||
HARDWARE_MONITOR_INTERFACE);
|
||||
|
||||
/* Shutdown the modem */
|
||||
g_at_chat_send(data->app, "AT^SMSO", none_prefix, gemalto_smso_cb,
|
||||
modem, NULL);
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/devinfo.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/netmon.h>
|
||||
#include <ofono/phonebook.h>
|
||||
#include <ofono/voicecall.h>
|
||||
#include <ofono/sim.h>
|
||||
@@ -45,6 +46,7 @@
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/message-waiting.h>
|
||||
|
||||
#include <drivers/qmimodem/qmi.h>
|
||||
#include <drivers/qmimodem/dms.h>
|
||||
@@ -483,6 +485,15 @@ static void gobi_post_sim(struct ofono_modem *modem)
|
||||
|
||||
if (data->features & GOBI_WMS)
|
||||
ofono_sms_create(modem, 0, "qmimodem", data->device);
|
||||
|
||||
if ((data->features & GOBI_WMS) && (data->features & GOBI_UIM) &&
|
||||
!ofono_modem_get_boolean(modem, "ForceSimLegacy")) {
|
||||
struct ofono_message_waiting *mw =
|
||||
ofono_message_waiting_create(modem);
|
||||
|
||||
if (mw)
|
||||
ofono_message_waiting_register(mw);
|
||||
}
|
||||
}
|
||||
|
||||
static void gobi_post_online(struct ofono_modem *modem)
|
||||
@@ -493,8 +504,10 @@ static void gobi_post_online(struct ofono_modem *modem)
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (data->features & GOBI_NAS)
|
||||
if (data->features & GOBI_NAS) {
|
||||
ofono_netreg_create(modem, 0, "qmimodem", data->device);
|
||||
ofono_netmon_create(modem, 0, "qmimodem", data->device);
|
||||
}
|
||||
|
||||
if (data->features & GOBI_VOICE)
|
||||
ofono_ussd_create(modem, 0, "qmimodem", data->device);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -365,7 +365,7 @@ static void get_rf_power_status_cb(struct ril_msg *message, gpointer user_data)
|
||||
}
|
||||
|
||||
power_status = parcel_r_string(&rilp);
|
||||
if (power_status == NULL || power_status == '\0')
|
||||
if (power_status == NULL || *power_status == '\0')
|
||||
return;
|
||||
|
||||
enabled = strtol(power_status, &endptr, 10);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
struct sfos_bt {
|
||||
unsigned int emu_watch;
|
||||
struct ofono_modem *modem;
|
||||
struct ofono_emulator *em;
|
||||
GSList* ems;
|
||||
unsigned char speaker_volume;
|
||||
unsigned char microphone_volume;
|
||||
};
|
||||
@@ -43,22 +43,39 @@ struct sfos_bt {
|
||||
static GSList *modems;
|
||||
static guint modemwatch_id;
|
||||
|
||||
static void sfos_bt_send_unsolicited(struct sfos_bt *bt,
|
||||
const char *format, ...) G_GNUC_PRINTF(2, 3);
|
||||
|
||||
static void sfos_bt_send_unsolicited(struct sfos_bt *bt,
|
||||
const char *format, ...)
|
||||
{
|
||||
if (bt->ems) {
|
||||
GSList *l;
|
||||
GString* buf = g_string_sized_new(15);
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
g_string_vprintf(buf, format, va);
|
||||
va_end(va);
|
||||
|
||||
for (l = bt->ems; l; l = l->next) {
|
||||
ofono_emulator_send_unsolicited(l->data, buf->str);
|
||||
}
|
||||
|
||||
g_string_free(buf, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_hfp_microphone_volume(struct sfos_bt *sfos_bt,
|
||||
unsigned char gain)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "+VGM:%d", (int) gain);
|
||||
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
|
||||
sfos_bt_send_unsolicited(sfos_bt, "+VGM:%d", (int) gain);
|
||||
}
|
||||
|
||||
static void set_hfp_speaker_volume(struct sfos_bt *sfos_bt,
|
||||
unsigned char gain)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "+VGS:%d", (int) gain);
|
||||
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
|
||||
sfos_bt_send_unsolicited(sfos_bt, "+VGS:%d", (int) gain);
|
||||
}
|
||||
|
||||
static DBusMessage *cv_set_property(DBusConnection *conn, DBusMessage *msg,
|
||||
@@ -165,8 +182,8 @@ static const GDBusSignalTable cv_signals[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
int sfos_bt_call_volume_set(struct ofono_modem *modem, unsigned char volume,
|
||||
const char *gain)
|
||||
static int sfos_bt_call_volume_set(struct ofono_modem *modem,
|
||||
unsigned char volume, const char *gain)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
@@ -233,7 +250,7 @@ static void sfos_bt_vgs_cb(struct ofono_emulator *em,
|
||||
set_gain(em, req, userdata, gain);
|
||||
}
|
||||
|
||||
void sfos_bt_cv_dbus_new(struct sfos_bt *sfos_bt)
|
||||
static void sfos_bt_cv_dbus_new(struct sfos_bt *sfos_bt)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
@@ -255,7 +272,7 @@ static void sfos_bt_remove_handler(struct ofono_emulator *em)
|
||||
ofono_emulator_remove_handler(em, "+VGM");
|
||||
}
|
||||
|
||||
void sfos_bt_cv_dbus_free(struct sfos_bt *sfos_bt)
|
||||
static void sfos_bt_cv_dbus_free(struct sfos_bt *sfos_bt)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
@@ -269,19 +286,24 @@ static void sfos_bt_emu_watch_cb(struct ofono_atom *atom,
|
||||
enum ofono_atom_watch_condition cond,
|
||||
void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
struct sfos_bt *bt = data;
|
||||
struct ofono_emulator *em = __ofono_atom_get_data(atom);
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED){
|
||||
sfos_bt->em = __ofono_atom_get_data(atom);
|
||||
sfos_bt_cv_dbus_new(sfos_bt);
|
||||
ofono_emulator_add_handler(sfos_bt->em, "+VGS",
|
||||
sfos_bt_vgs_cb, sfos_bt, NULL);
|
||||
ofono_emulator_add_handler(sfos_bt->em, "+VGM",
|
||||
sfos_bt_vgm_cb, sfos_bt, NULL);
|
||||
if (!bt->ems)
|
||||
sfos_bt_cv_dbus_new(bt);
|
||||
|
||||
bt->ems = g_slist_append(bt->ems, em);
|
||||
ofono_emulator_add_handler(em, "+VGS", sfos_bt_vgs_cb, bt,
|
||||
NULL);
|
||||
ofono_emulator_add_handler(em, "+VGM", sfos_bt_vgm_cb, bt,
|
||||
NULL);
|
||||
} else {
|
||||
sfos_bt_cv_dbus_free(sfos_bt);
|
||||
sfos_bt_remove_handler(sfos_bt->em);
|
||||
sfos_bt->em = NULL;
|
||||
sfos_bt_remove_handler(em);
|
||||
bt->ems = g_slist_remove(bt->ems, em);
|
||||
|
||||
if (!bt->ems)
|
||||
sfos_bt_cv_dbus_free(bt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,20 +314,25 @@ static void sfos_bt_emu_watch_destroy(void *data)
|
||||
sfos_bt->emu_watch = 0;
|
||||
}
|
||||
|
||||
static void sfos_bt_free_em(gpointer data)
|
||||
{
|
||||
sfos_bt_remove_handler((struct ofono_emulator*)data);
|
||||
}
|
||||
|
||||
static void sfos_bt_free(void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
struct sfos_bt *bt = data;
|
||||
|
||||
if (sfos_bt->emu_watch)
|
||||
__ofono_modem_remove_atom_watch(sfos_bt->modem,
|
||||
sfos_bt->emu_watch);
|
||||
if (bt->emu_watch)
|
||||
__ofono_modem_remove_atom_watch(bt->modem, bt->emu_watch);
|
||||
|
||||
if (sfos_bt->em) {
|
||||
sfos_bt_cv_dbus_free(sfos_bt);
|
||||
sfos_bt_remove_handler(sfos_bt->em);
|
||||
if (bt->ems) {
|
||||
sfos_bt_cv_dbus_free(bt);
|
||||
g_slist_free_full(bt->ems, sfos_bt_free_em);
|
||||
bt->ems = NULL;
|
||||
}
|
||||
|
||||
g_free(sfos_bt);
|
||||
g_free(bt);
|
||||
}
|
||||
|
||||
static gint sfos_bt_find_modem(gconstpointer listdata, gconstpointer modem)
|
||||
|
||||
@@ -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
|
||||
@@ -178,7 +178,7 @@ static void sailfish_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
static void sailfish_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
const dbus_bool_t registered = (entry->cell.registered != FALSE);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
@@ -195,7 +195,7 @@ static void sailfish_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
||||
for (i = 0; i < n; i++) {
|
||||
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
|
||||
if (value != INT_MAX) {
|
||||
if (value != SAILFISH_CELL_INVALID_VALUE) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
@@ -279,8 +279,8 @@ static const GDBusSignalTable sailfish_cell_info_dbus_cell_signals[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_id(
|
||||
struct sailfish_cell_info_dbus *dbus, guint id)
|
||||
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_id
|
||||
(struct sailfish_cell_info_dbus *dbus, guint id)
|
||||
{
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
@@ -376,7 +376,7 @@ static void sailfish_cell_info_dbus_property_changed
|
||||
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
const dbus_bool_t registered = (cell->registered != FALSE);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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
|
||||
@@ -22,9 +22,8 @@
|
||||
#include <gutil_macros.h>
|
||||
#include <string.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
#include "src/ofono.h"
|
||||
#include "src/storage.h"
|
||||
|
||||
#include <sailfish_manager.h>
|
||||
#include <sailfish_cell_info.h>
|
||||
@@ -796,9 +795,6 @@ void sailfish_manager_set_sim_state(struct sailfish_slot *s,
|
||||
slot->pub.sim_present = present;
|
||||
sailfish_manager_dbus_signal_sim(p->dbus,
|
||||
slot->index, present);
|
||||
if (!present) {
|
||||
sailfish_sim_info_invalidate(slot->siminfo);
|
||||
}
|
||||
sailfish_manager_update_modem_paths_full(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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
|
||||
@@ -23,9 +23,9 @@
|
||||
#include <gutil_misc.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
#include "storage.h"
|
||||
#include "src/ofono.h"
|
||||
#include "src/common.h"
|
||||
#include "src/storage.h"
|
||||
|
||||
#define SAILFISH_SIM_INFO_STORE "cache"
|
||||
#define SAILFISH_SIM_INFO_STORE_GROUP "sim"
|
||||
@@ -65,6 +65,7 @@ struct sailfish_sim_info_priv {
|
||||
guint netreg_status_watch_id;
|
||||
gboolean update_imsi_cache;
|
||||
gboolean update_iccid_map;
|
||||
int queued_signals;
|
||||
};
|
||||
|
||||
enum sailfish_sim_info_signal {
|
||||
@@ -94,12 +95,37 @@ G_DEFINE_TYPE(SailfishSimInfo, sailfish_sim_info, G_TYPE_OBJECT)
|
||||
/* Skip the leading slash from the modem path: */
|
||||
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
|
||||
|
||||
static int sailfish_sim_info_signal_bit(enum sailfish_sim_info_signal id)
|
||||
{
|
||||
return (1 << id);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_signal_emit(struct sailfish_sim_info *self,
|
||||
enum sailfish_sim_info_signal id)
|
||||
{
|
||||
self->priv->queued_signals &= ~sailfish_sim_info_signal_bit(id);
|
||||
g_signal_emit(self, sailfish_sim_info_signals[id], 0);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_signal_queue(struct sailfish_sim_info *self,
|
||||
enum sailfish_sim_info_signal id)
|
||||
{
|
||||
self->priv->queued_signals |= sailfish_sim_info_signal_bit(id);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_emit_queued_signals
|
||||
(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; priv->queued_signals && i < SIGNAL_COUNT; i++) {
|
||||
if (priv->queued_signals & sailfish_sim_info_signal_bit(i)) {
|
||||
sailfish_sim_info_signal_emit(self, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_update_imsi_cache(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
@@ -178,8 +204,15 @@ static void sailfish_sim_info_update_public_spn(struct sailfish_sim_info *self)
|
||||
|
||||
if (g_strcmp0(priv->public_spn, spn)) {
|
||||
g_free(priv->public_spn);
|
||||
self->spn = priv->public_spn = g_strdup(spn);
|
||||
sailfish_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
if (spn && spn[0]) {
|
||||
DBG_(self, "public spn \"%s\"", spn);
|
||||
priv->public_spn = g_strdup(spn);
|
||||
} else {
|
||||
DBG_(self, "no public spn");
|
||||
priv->public_spn = NULL;
|
||||
}
|
||||
self->spn = priv->public_spn;
|
||||
sailfish_sim_info_signal_queue(self, SIGNAL_SPN_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,16 +221,13 @@ static void sailfish_sim_info_set_cached_spn(struct sailfish_sim_info *self,
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
GASSERT(spn);
|
||||
if (g_strcmp0(priv->cached_spn, spn)) {
|
||||
DBG_(self, "%s", spn);
|
||||
g_free(priv->cached_spn);
|
||||
if (spn) {
|
||||
DBG_(self, "cached spn \"%s\"", spn);
|
||||
priv->cached_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
sailfish_sim_info_update_imsi_cache(self);
|
||||
} else {
|
||||
priv->cached_spn = NULL;
|
||||
}
|
||||
priv->cached_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
sailfish_sim_info_update_imsi_cache(self);
|
||||
sailfish_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
@@ -207,6 +237,7 @@ static void sailfish_sim_info_set_spn(struct sailfish_sim_info *self,
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
GASSERT(spn);
|
||||
if (g_strcmp0(priv->sim_spn, spn)) {
|
||||
DBG_(self, "%s", spn);
|
||||
g_free(priv->sim_spn);
|
||||
@@ -254,29 +285,24 @@ static void sailfish_sim_info_update_default_spn(struct sailfish_sim_info *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_set_imsi(struct sailfish_sim_info *self,
|
||||
const char *imsi)
|
||||
static void sailfish_sim_info_update_imsi(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
const char *imsi = priv->watch->imsi;
|
||||
|
||||
if (g_strcmp0(priv->imsi, imsi)) {
|
||||
/* IMSI only gets reset when ICCID disappears, ignore NULL IMSI here */
|
||||
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
|
||||
DBG_(self, "%s", imsi);
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(imsi);
|
||||
priv->update_iccid_map = TRUE;
|
||||
sailfish_sim_info_update_iccid_map(self);
|
||||
sailfish_sim_info_update_imsi_cache(self);
|
||||
sailfish_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
sailfish_sim_info_signal_queue(self, SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_update_imsi(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_watch *watch = self->priv->watch;
|
||||
|
||||
if (watch->imsi && watch->imsi[0]) {
|
||||
sailfish_sim_info_set_imsi(self, watch->imsi);
|
||||
}
|
||||
/* Check if MCC/MNC have changed */
|
||||
sailfish_sim_info_update_default_spn(self);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_network_check(struct sailfish_sim_info *self)
|
||||
@@ -333,7 +359,8 @@ static void sailfish_sim_info_load_cache(struct sailfish_sim_info *self)
|
||||
self->imsi = priv->imsi = imsi;
|
||||
DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
|
||||
sailfish_sim_info_update_iccid_map(self);
|
||||
sailfish_sim_info_signal_emit(self,
|
||||
sailfish_sim_info_update_default_spn(self);
|
||||
sailfish_sim_info_signal_queue(self,
|
||||
SIGNAL_IMSI_CHANGED);
|
||||
} else if (imsi) {
|
||||
g_free(imsi);
|
||||
@@ -378,38 +405,32 @@ static void sailfish_sim_info_set_iccid(struct sailfish_sim_info *self,
|
||||
if (g_strcmp0(priv->iccid, iccid)) {
|
||||
g_free(priv->iccid);
|
||||
self->iccid = priv->iccid = g_strdup(iccid);
|
||||
sailfish_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
|
||||
sailfish_sim_info_signal_queue(self, SIGNAL_ICCID_CHANGED);
|
||||
if (iccid) {
|
||||
sailfish_sim_info_load_cache(self);
|
||||
} else {
|
||||
DBG_(self, "no more iccid");
|
||||
if (priv->imsi) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = NULL;
|
||||
sailfish_sim_info_signal_emit(self,
|
||||
sailfish_sim_info_signal_queue(self,
|
||||
SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
if (priv->sim_spn) {
|
||||
g_free(priv->sim_spn);
|
||||
priv->sim_spn = NULL;
|
||||
sailfish_sim_info_set_cached_spn(self, NULL);
|
||||
}
|
||||
if (priv->cached_spn) {
|
||||
g_free(priv->cached_spn);
|
||||
priv->cached_spn = NULL;
|
||||
}
|
||||
/* No more default SPN too */
|
||||
priv->default_spn[0] = 0;
|
||||
sailfish_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_sim_watch_cb(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
|
||||
struct ofono_sim *sim = self->priv->watch->sim;
|
||||
|
||||
sailfish_sim_info_update_default_spn(self);
|
||||
if (ofono_sim_get_state(sim) == OFONO_SIM_STATE_NOT_PRESENT) {
|
||||
sailfish_sim_info_set_iccid(self, NULL);
|
||||
}
|
||||
sailfish_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_iccid_watch_cb(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
@@ -417,24 +438,34 @@ static void sailfish_sim_info_iccid_watch_cb(struct sailfish_watch *watch,
|
||||
|
||||
DBG_(self, "%s", watch->iccid);
|
||||
sailfish_sim_info_set_iccid(self, watch->iccid);
|
||||
sailfish_sim_info_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_imsi_watch_cb(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_update_imsi(SAILFISH_SIMINFO(data));
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
|
||||
|
||||
sailfish_sim_info_update_imsi(self);
|
||||
sailfish_sim_info_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_spn_watch_cb(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_update_spn(SAILFISH_SIMINFO(data));
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
|
||||
|
||||
sailfish_sim_info_update_spn(self);
|
||||
sailfish_sim_info_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_netreg_watch(int status, int lac, int ci,
|
||||
int tech, const char *mcc, const char *mnc, void *data)
|
||||
{
|
||||
sailfish_sim_info_network_check(SAILFISH_SIMINFO(data));
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
|
||||
|
||||
sailfish_sim_info_network_check(self);
|
||||
sailfish_sim_info_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_netreg_watch_done(void *data)
|
||||
@@ -475,7 +506,10 @@ static void sailfish_sim_info_set_netreg(struct sailfish_sim_info *self,
|
||||
static void sailfish_sim_info_netreg_changed(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_set_netreg(SAILFISH_SIMINFO(data), watch->netreg);
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
|
||||
|
||||
sailfish_sim_info_set_netreg(self, watch->netreg);
|
||||
sailfish_sim_info_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
|
||||
@@ -490,12 +524,6 @@ struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
|
||||
priv = self->priv;
|
||||
priv->watch = watch;
|
||||
self->path = watch->path;
|
||||
priv->watch_event_id[WATCH_EVENT_SIM] =
|
||||
sailfish_watch_add_sim_changed_handler(watch,
|
||||
sailfish_sim_info_sim_watch_cb, self);
|
||||
priv->watch_event_id[WATCH_EVENT_SIM_STATE] =
|
||||
sailfish_watch_add_sim_state_changed_handler(watch,
|
||||
sailfish_sim_info_sim_watch_cb, self);
|
||||
priv->watch_event_id[WATCH_EVENT_ICCID] =
|
||||
sailfish_watch_add_iccid_changed_handler(watch,
|
||||
sailfish_sim_info_iccid_watch_cb, self);
|
||||
@@ -513,6 +541,9 @@ struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
|
||||
sailfish_sim_info_update_imsi(self);
|
||||
sailfish_sim_info_update_spn(self);
|
||||
sailfish_sim_info_network_check(self);
|
||||
|
||||
/* Clear queued events, if any */
|
||||
priv->queued_signals = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -534,13 +565,6 @@ void sailfish_sim_info_unref(struct sailfish_sim_info *self)
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_sim_info_invalidate(struct sailfish_sim_info *self)
|
||||
{
|
||||
if (self) {
|
||||
sailfish_sim_info_set_iccid(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *s,
|
||||
sailfish_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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
|
||||
@@ -48,7 +48,6 @@ typedef void (*sailfish_sim_info_cb_t)(struct sailfish_sim_info *si,
|
||||
struct sailfish_sim_info *sailfish_sim_info_new(const char *path);
|
||||
struct sailfish_sim_info *sailfish_sim_info_ref(struct sailfish_sim_info *si);
|
||||
void sailfish_sim_info_unref(struct sailfish_sim_info *si);
|
||||
void sailfish_sim_info_invalidate(struct sailfish_sim_info *si);
|
||||
gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *si,
|
||||
sailfish_sim_info_cb_t cb, void *user_data);
|
||||
gulong sailfish_sim_info_add_imsi_changed_handler(struct sailfish_sim_info *si,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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
|
||||
@@ -126,24 +126,6 @@ static inline void sailfish_watch_resume_signals(struct sailfish_watch *self)
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_watch_sim_state_notify(enum ofono_sim_state new_state,
|
||||
void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
sailfish_watch_signal_queue(self, SIGNAL_SIM_STATE_CHANGED);
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_watch_sim_state_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->sim_state_watch_id);
|
||||
priv->sim_state_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_iccid_update(struct sailfish_watch *self,
|
||||
const char *iccid)
|
||||
{
|
||||
@@ -238,6 +220,35 @@ static void sailfish_watch_imsi_destroy(void *user_data)
|
||||
priv->imsi_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_sim_state_notify(enum ofono_sim_state new_state,
|
||||
void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
/*
|
||||
* ofono core doesn't notify SIM watches when SIM card gets removed.
|
||||
* So we have to reset things here based on the SIM state.
|
||||
*/
|
||||
if (new_state == OFONO_SIM_STATE_NOT_PRESENT) {
|
||||
sailfish_watch_iccid_update(self, NULL);
|
||||
}
|
||||
if (new_state != OFONO_SIM_STATE_READY) {
|
||||
sailfish_watch_imsi_update(self, NULL);
|
||||
sailfish_watch_spn_update(self, NULL);
|
||||
}
|
||||
sailfish_watch_signal_queue(self, SIGNAL_SIM_STATE_CHANGED);
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_watch_sim_state_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->sim_state_watch_id);
|
||||
priv->sim_state_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_set_sim(struct sailfish_watch *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
@@ -271,6 +282,11 @@ static void sailfish_watch_set_sim(struct sailfish_watch *self,
|
||||
self->sim = sim;
|
||||
sailfish_watch_signal_queue(self, SIGNAL_SIM_CHANGED);
|
||||
sailfish_watch_suspend_signals(self);
|
||||
|
||||
/* Reset the current state */
|
||||
sailfish_watch_iccid_update(self, NULL);
|
||||
sailfish_watch_imsi_update(self, NULL);
|
||||
sailfish_watch_spn_update(self, NULL);
|
||||
if (sim) {
|
||||
priv->sim_state_watch_id =
|
||||
ofono_sim_add_state_watch(sim,
|
||||
@@ -293,12 +309,6 @@ static void sailfish_watch_set_sim(struct sailfish_watch *self,
|
||||
ofono_sim_add_imsi_watch(self->sim,
|
||||
sailfish_watch_imsi_notify, self,
|
||||
sailfish_watch_imsi_destroy);
|
||||
} else {
|
||||
/* And these will just queue the signals
|
||||
* if necessary */
|
||||
sailfish_watch_iccid_update(self, NULL);
|
||||
sailfish_watch_imsi_update(self, NULL);
|
||||
sailfish_watch_spn_update(self, NULL);
|
||||
}
|
||||
|
||||
/* Emit the pending signals. */
|
||||
@@ -451,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,
|
||||
|
||||
@@ -127,6 +127,7 @@ static void set_power_by_mce_state(struct ofono_modem *modem,
|
||||
case MCE_NORMAL:
|
||||
if (isi->online_cbd)
|
||||
report_online(isi, mce_state == MCE_NORMAL);
|
||||
/* fall through */
|
||||
default:
|
||||
report_powered(modem, isi, TRUE);
|
||||
}
|
||||
|
||||
@@ -48,9 +48,9 @@ static const char *none_prefix[] = { NULL };
|
||||
|
||||
enum supported_models {
|
||||
SARA_G270 = 1102,
|
||||
TOBYL2_COMPATIBLE_MODE = 1141,
|
||||
TOBYL2_MEDIUM_THROUGHPUT_MODE = 1143,
|
||||
TOBYL2_HIGH_THROUGHPUT_MODE = 1146,
|
||||
TOBYL2_COMPATIBLE_MODE = 1141,
|
||||
TOBYL2_MEDIUM_THROUGHPUT_MODE = 1143,
|
||||
TOBYL2_HIGH_THROUGHPUT_MODE = 1146,
|
||||
};
|
||||
|
||||
struct ublox_data {
|
||||
@@ -178,6 +178,7 @@ static int ublox_enable(struct ofono_modem *modem)
|
||||
break;
|
||||
case TOBYL2_MEDIUM_THROUGHPUT_MODE:
|
||||
DBG("low/medium throughtput profile unsupported");
|
||||
break;
|
||||
default:
|
||||
DBG("unknown ublox model id %d", data->model_id);
|
||||
return -EINVAL;
|
||||
|
||||
@@ -261,18 +261,34 @@ static gboolean setup_sierra(struct modem_info *modem)
|
||||
if (g_strcmp0(info->interface, "255/255/255") == 0) {
|
||||
if (g_strcmp0(info->number, "01") == 0)
|
||||
diag = info->devnode;
|
||||
if (g_strcmp0(info->number, "03") == 0)
|
||||
else if (g_strcmp0(info->number, "03") == 0)
|
||||
mdm = info->devnode;
|
||||
else if (g_strcmp0(info->number, "04") == 0)
|
||||
app = info->devnode;
|
||||
else if (g_strcmp0(info->number, "07") == 0)
|
||||
net = info->devnode;
|
||||
else if (g_strcmp0(info->number, "0a") == 0) {
|
||||
if (g_strcmp0(info->subsystem, "net") == 0)
|
||||
else if (g_strcmp0(info->subsystem, "net") == 0) {
|
||||
/*
|
||||
* When using the voice firmware on a mc7304
|
||||
* the second cdc-wdm interface doesn't handle
|
||||
* qmi messages properly.
|
||||
* Some modems still have a working second
|
||||
* cdc-wdm interface, some are not. But always
|
||||
* the first interface works.
|
||||
*/
|
||||
if (g_strcmp0(info->number, "08") == 0) {
|
||||
net = info->devnode;
|
||||
else if (g_strcmp0(info->subsystem,
|
||||
"usbmisc") == 0)
|
||||
} else if (g_strcmp0(info->number, "0a") == 0) {
|
||||
if (net == NULL)
|
||||
net = info->devnode;
|
||||
}
|
||||
} else if (g_strcmp0(info->subsystem, "usbmisc") == 0) {
|
||||
if (g_strcmp0(info->number, "08") == 0) {
|
||||
qmi = info->devnode;
|
||||
} else if (g_strcmp0(info->number, "0a") == 0) {
|
||||
if (qmi == NULL)
|
||||
qmi = info->devnode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -860,7 +876,7 @@ static gboolean setup_quectel(struct modem_info *modem)
|
||||
|
||||
static gboolean setup_quectelqmi(struct modem_info *modem)
|
||||
{
|
||||
const char *qmi = NULL, *net = NULL, *gps = NULL;
|
||||
const char *qmi = NULL, *net = NULL, *gps = NULL, *aux = NULL;
|
||||
GSList *list;
|
||||
|
||||
DBG("%s", modem->syspath);
|
||||
@@ -878,8 +894,11 @@ static gboolean setup_quectelqmi(struct modem_info *modem)
|
||||
else if (g_strcmp0(info->subsystem, "usbmisc") == 0)
|
||||
qmi = info->devnode;
|
||||
} else if (g_strcmp0(info->interface, "255/0/0") == 0 &&
|
||||
g_strcmp0(info->number, "02") == 0) {
|
||||
g_strcmp0(info->number, "01") == 0) {
|
||||
gps = info->devnode;
|
||||
} else if (g_strcmp0(info->interface, "255/0/0") == 0 &&
|
||||
g_strcmp0(info->number, "02") == 0) {
|
||||
aux = info->devnode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,8 +912,12 @@ static gboolean setup_quectelqmi(struct modem_info *modem)
|
||||
ofono_modem_set_string(modem->modem, "Device", qmi);
|
||||
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
|
||||
|
||||
DBG("gps=%s aux=%s", gps, aux);
|
||||
|
||||
if (gps)
|
||||
ofono_modem_set_string(modem->modem, "GPS", gps);
|
||||
if (aux)
|
||||
ofono_modem_set_string(modem->modem, "Aux", aux);
|
||||
|
||||
ofono_modem_set_driver(modem->modem, "gobi");
|
||||
|
||||
@@ -990,8 +1013,6 @@ static gboolean setup_isi_serial(struct modem_info* modem)
|
||||
if (value)
|
||||
ofono_modem_set_integer(modem->modem, "Address", atoi(value));
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Device", info->devnode);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -1098,6 +1119,42 @@ static gboolean setup_gemalto(struct modem_info* modem)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_xmm7xxx(struct modem_info *modem)
|
||||
{
|
||||
const char *mdm = NULL, *net = NULL;
|
||||
GSList *list;
|
||||
|
||||
DBG("%s %s\n", __DATE__, __TIME__);
|
||||
DBG("%s %s %s %s %s %s\n", modem->syspath, modem->devname,
|
||||
modem->driver, modem->vendor, modem->model, modem->sysattr);
|
||||
|
||||
for (list = modem->devices; list; list = list->next) {
|
||||
struct device_info *info = list->data;
|
||||
|
||||
DBG("%s %s %s %s %s %s %s\n", info->devpath, info->devnode,
|
||||
info->interface, info->number, info->label,
|
||||
info->sysattr, info->subsystem);
|
||||
|
||||
if (g_strcmp0(info->subsystem, "tty") == 0) {
|
||||
if (g_strcmp0(info->number, "02") == 0)
|
||||
mdm = info->devnode;
|
||||
} else if (g_strcmp0(info->subsystem, "net") == 0) {
|
||||
if (g_strcmp0(info->number, "00") == 0)
|
||||
net = info->devnode;
|
||||
}
|
||||
}
|
||||
|
||||
if (mdm == NULL || net == NULL)
|
||||
return FALSE;
|
||||
|
||||
DBG("modem=%s net=%s\n", mdm, net);
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Modem", mdm);
|
||||
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
gboolean (*setup)(struct modem_info *modem);
|
||||
@@ -1125,6 +1182,7 @@ static struct {
|
||||
{ "quectelqmi", setup_quectelqmi},
|
||||
{ "ublox", setup_ublox },
|
||||
{ "gemalto", setup_gemalto },
|
||||
{ "xmm7xxx", setup_xmm7xxx },
|
||||
/* Following are non-USB modems */
|
||||
{ "ifx", setup_ifx },
|
||||
{ "u8500", setup_isi_serial },
|
||||
@@ -1302,7 +1360,7 @@ static void add_serial_device(struct udev_device *dev)
|
||||
|
||||
devnode = udev_device_get_devnode(dev);
|
||||
|
||||
if (!syspath || !devname || !devpath || !devnode)
|
||||
if (!syspath || !devpath)
|
||||
return;
|
||||
|
||||
modem = g_hash_table_lookup(modem_list, syspath);
|
||||
@@ -1314,7 +1372,7 @@ static void add_serial_device(struct udev_device *dev)
|
||||
modem->type = MODEM_TYPE_SERIAL;
|
||||
modem->syspath = g_strdup(syspath);
|
||||
modem->devname = g_strdup(devname);
|
||||
modem->driver = g_strdup("legacy");
|
||||
modem->driver = g_strdup(driver);
|
||||
|
||||
g_hash_table_replace(modem_list, modem->syspath, modem);
|
||||
}
|
||||
@@ -1334,7 +1392,7 @@ static void add_serial_device(struct udev_device *dev)
|
||||
info->subsystem = g_strdup(subsystem);
|
||||
info->dev = udev_device_ref(dev);
|
||||
|
||||
modem->devices = g_slist_append(modem->devices, info);
|
||||
modem->serial = info;
|
||||
}
|
||||
|
||||
static void add_device(const char *syspath, const char *devname,
|
||||
@@ -1501,6 +1559,8 @@ static struct {
|
||||
{ "gemalto", "qmi_wwan", "1e2d", "0053" },
|
||||
{ "telit", "cdc_ncm", "1bc7", "0036" },
|
||||
{ "telit", "cdc_acm", "1bc7", "0036" },
|
||||
{ "xmm7xxx", "cdc_acm", "8087", "0930" },
|
||||
{ "xmm7xxx", "cdc_ncm", "8087", "0930" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
399
ofono/plugins/xmm7xxx.c
Normal file
399
ofono/plugins/xmm7xxx.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gatchat.h>
|
||||
#include <gattty.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/devinfo.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/stk.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *xsimstate_prefix[] = { "+XSIMSTATE:", NULL };
|
||||
|
||||
struct xmm7xxx_data {
|
||||
GAtChat *chat; /* AT chat */
|
||||
struct ofono_sim *sim;
|
||||
ofono_bool_t have_sim;
|
||||
ofono_bool_t sms_phonebook_added;
|
||||
};
|
||||
|
||||
static void xmm7xxx_debug(const char *str, void *user_data)
|
||||
{
|
||||
const char *prefix = user_data;
|
||||
|
||||
ofono_info("%s%s", prefix, str);
|
||||
}
|
||||
|
||||
static GAtChat *open_device(struct ofono_modem *modem,
|
||||
const char *key, char *debug)
|
||||
{
|
||||
const char *device;
|
||||
GAtSyntax *syntax;
|
||||
GIOChannel *channel;
|
||||
GAtChat *chat;
|
||||
GHashTable *options;
|
||||
|
||||
device = ofono_modem_get_string(modem, key);
|
||||
if (device == NULL)
|
||||
return NULL;
|
||||
|
||||
DBG("%s %s", key, device);
|
||||
|
||||
options = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
if (options == NULL)
|
||||
return NULL;
|
||||
|
||||
g_hash_table_insert(options, "Baud", "115200");
|
||||
channel = g_at_tty_open(device, options);
|
||||
g_hash_table_destroy(options);
|
||||
|
||||
if (channel == NULL)
|
||||
return NULL;
|
||||
|
||||
syntax = g_at_syntax_new_gsm_permissive();
|
||||
chat = g_at_chat_new(channel, syntax);
|
||||
g_at_syntax_unref(syntax);
|
||||
g_io_channel_unref(channel);
|
||||
|
||||
if (chat == NULL)
|
||||
return NULL;
|
||||
|
||||
if (getenv("OFONO_AT_DEBUG"))
|
||||
g_at_chat_set_debug(chat, xmm7xxx_debug, debug);
|
||||
|
||||
return chat;
|
||||
}
|
||||
|
||||
static void switch_sim_state_status(struct ofono_modem *modem, int status)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p, SIM status: %d", modem, status);
|
||||
|
||||
switch (status) {
|
||||
case 0: /* SIM not inserted */
|
||||
case 9: /* SIM removed */
|
||||
if (data->have_sim == TRUE) {
|
||||
ofono_sim_inserted_notify(data->sim, FALSE);
|
||||
data->have_sim = FALSE;
|
||||
data->sms_phonebook_added = FALSE;
|
||||
}
|
||||
break;
|
||||
case 2: /* SIM inserted, PIN verification not needed - READY */
|
||||
case 3: /* SIM inserted, PIN verified - READY */
|
||||
case 7:
|
||||
if (data->have_sim == FALSE) {
|
||||
ofono_sim_inserted_notify(data->sim, TRUE);
|
||||
data->have_sim = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ofono_warn("Unknown SIM state %d received", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void xsimstate_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
int status;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+XSIM:"))
|
||||
return;
|
||||
|
||||
g_at_result_iter_next_number(&iter, &status);
|
||||
|
||||
DBG("status=%d\n", status);
|
||||
|
||||
switch_sim_state_status(modem, status);
|
||||
}
|
||||
|
||||
static void xsimstate_query_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
int status, mode;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+XSIMSTATE:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &status))
|
||||
return;
|
||||
|
||||
DBG("mode=%d, status=%d\n", mode, status);
|
||||
|
||||
switch_sim_state_status(modem, status);
|
||||
}
|
||||
|
||||
static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok) {
|
||||
g_at_chat_unref(data->chat);
|
||||
data->chat = NULL;
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch data carrier detect signal off.
|
||||
* When the DCD is disabled the modem does not hangup anymore
|
||||
* after the data connection.
|
||||
*/
|
||||
g_at_chat_send(data->chat, "AT&C0", NULL, NULL, NULL, NULL);
|
||||
|
||||
data->have_sim = FALSE;
|
||||
data->sms_phonebook_added = FALSE;
|
||||
|
||||
ofono_modem_set_powered(modem, TRUE);
|
||||
|
||||
g_at_chat_register(data->chat, "+XSIM:", xsimstate_notify,
|
||||
FALSE, modem, NULL);
|
||||
|
||||
g_at_chat_send(data->chat, "AT+XSIMSTATE=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
g_at_chat_send(data->chat, "AT+XSIMSTATE?", xsimstate_prefix,
|
||||
xsimstate_query_cb, modem, NULL);
|
||||
}
|
||||
|
||||
static int xmm7xxx_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
data->chat = open_device(modem, "Modem", "Modem: ");
|
||||
if (data->chat == NULL)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Disable command echo and
|
||||
* enable the Extended Error Result Codes
|
||||
*/
|
||||
g_at_chat_send(data->chat, "ATE0 +CMEE=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
/* Set phone functionality */
|
||||
g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix,
|
||||
cfun_enable_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_unref(data->chat);
|
||||
data->chat = NULL;
|
||||
|
||||
if (ok)
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
}
|
||||
|
||||
static int xmm7xxx_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_cancel_all(data->chat);
|
||||
g_at_chat_unregister_all(data->chat);
|
||||
|
||||
/* Power down modem */
|
||||
g_at_chat_send(data->chat, "AT+CFUN=0", none_prefix,
|
||||
cfun_disable_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void xmm7xxx_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_devinfo_create(modem, OFONO_VENDOR_IFX, "atmodem", data->chat);
|
||||
data->sim = ofono_sim_create(modem, OFONO_VENDOR_IFX, "atmodem",
|
||||
data->chat);
|
||||
}
|
||||
|
||||
static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_modem_online_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void xmm7xxx_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *user_data)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
char const *command = online ? "AT+CFUN=1" : "AT+CFUN=4";
|
||||
|
||||
DBG("modem %p %s", modem, online ? "online" : "offline");
|
||||
|
||||
if (g_at_chat_send(data->chat, command, none_prefix,
|
||||
set_online_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void xmm7xxx_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
ofono_lte_create(modem, "atmodem", data->chat);
|
||||
ofono_radio_settings_create(modem, 0, "xmm7modem", data->chat);
|
||||
}
|
||||
|
||||
static void xmm7xxx_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_netreg_create(modem, OFONO_VENDOR_IFX, "atmodem", data->chat);
|
||||
|
||||
gprs = ofono_gprs_create(modem, OFONO_VENDOR_IFX, "atmodem",
|
||||
data->chat);
|
||||
gc = ofono_gprs_context_create(modem, OFONO_VENDOR_XMM, "ifxmodem",
|
||||
data->chat);
|
||||
|
||||
if (gprs && gc)
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
|
||||
static int xmm7xxx_probe(struct ofono_modem *modem)
|
||||
{
|
||||
struct xmm7xxx_data *data;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
data = g_try_new0(struct xmm7xxx_data, 1);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ofono_modem_set_data(modem, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xmm7xxx_remove(struct ofono_modem *modem)
|
||||
{
|
||||
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_modem_set_data(modem, NULL);
|
||||
|
||||
/* Cleanup after hot-unplug */
|
||||
g_at_chat_unref(data->chat);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver xmm7xxx_driver = {
|
||||
.name = "xmm7xxx",
|
||||
.probe = xmm7xxx_probe,
|
||||
.remove = xmm7xxx_remove,
|
||||
.enable = xmm7xxx_enable,
|
||||
.disable = xmm7xxx_disable,
|
||||
.set_online = xmm7xxx_set_online,
|
||||
.pre_sim = xmm7xxx_pre_sim,
|
||||
.post_sim = xmm7xxx_post_sim,
|
||||
.post_online = xmm7xxx_post_online,
|
||||
};
|
||||
|
||||
static int xmm7xxx_init(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
return ofono_modem_driver_register(&xmm7xxx_driver);
|
||||
}
|
||||
|
||||
static void xmm7xxx_exit(void)
|
||||
{
|
||||
ofono_modem_driver_unregister(&xmm7xxx_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(xmm7xxx, "Intel XMM7xxx driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, xmm7xxx_init, xmm7xxx_exit)
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -702,9 +703,15 @@ gboolean is_valid_apn(const char *apn)
|
||||
int i;
|
||||
int last_period = 0;
|
||||
|
||||
if (apn == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (apn[0] == '.' || apn[0] == '\0')
|
||||
return FALSE;
|
||||
|
||||
if (strlen(apn) > OFONO_GPRS_MAX_APN_LENGTH)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; apn[i] != '\0'; i++) {
|
||||
if (g_ascii_isalnum(apn[i]))
|
||||
continue;
|
||||
@@ -736,3 +743,25 @@ void ofono_call_init(struct ofono_call *call)
|
||||
call->cnap_validity = CNAP_VALIDITY_NOT_AVAILABLE;
|
||||
call->clip_validity = CLIP_VALIDITY_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
const char *call_status_to_string(enum call_status status)
|
||||
{
|
||||
switch (status) {
|
||||
case CALL_STATUS_ACTIVE:
|
||||
return "active";
|
||||
case CALL_STATUS_HELD:
|
||||
return "held";
|
||||
case CALL_STATUS_DIALING:
|
||||
return "dialing";
|
||||
case CALL_STATUS_ALERTING:
|
||||
return "alerting";
|
||||
case CALL_STATUS_INCOMING:
|
||||
return "incoming";
|
||||
case CALL_STATUS_WAITING:
|
||||
return "waiting";
|
||||
case CALL_STATUS_DISCONNECTED:
|
||||
return "disconnected";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user