mirror of
https://github.com/sailfishos/ofono
synced 2025-11-29 22:21:10 +08:00
Compare commits
219 Commits
mer/1.19+g
...
mer/1.20+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0b4e8694d | ||
|
|
c8db770c99 | ||
|
|
1534143e31 | ||
|
|
d9ad9caf30 | ||
|
|
71de574e87 | ||
|
|
11efbd68e6 | ||
|
|
9981f07797 | ||
|
|
24733f776e | ||
|
|
50ec234239 | ||
|
|
b4991076c6 | ||
|
|
8b02884696 | ||
|
|
8e224a21f6 | ||
|
|
96e191b2d2 | ||
|
|
7ae3aad622 | ||
|
|
3d5d88241e | ||
|
|
31e62567e6 | ||
|
|
8c3127ef21 | ||
|
|
1c1fc4199e | ||
|
|
bfe2f95c4c | ||
|
|
7e4d99236b | ||
|
|
0935a227be | ||
|
|
ffdeb3692c | ||
|
|
627904e382 | ||
|
|
0ab0677765 | ||
|
|
fe6af108ca | ||
|
|
650ff3642f | ||
|
|
41d310aa61 | ||
|
|
27adf83a4b | ||
|
|
55d227ba46 | ||
|
|
dcc1d366f0 | ||
|
|
83cf94824d | ||
|
|
3a0c598805 | ||
|
|
b098314251 | ||
|
|
4ae6c6c0b1 | ||
|
|
d5f0f3b32d | ||
|
|
0209e9847b | ||
|
|
a499ac07ca | ||
|
|
04342bbe69 | ||
|
|
d0d3e4f2f1 | ||
|
|
edcbc5c7e3 | ||
|
|
1df55e3042 | ||
|
|
df93fceb4f | ||
|
|
d21d1a166f | ||
|
|
458f905262 | ||
|
|
9f474ba723 | ||
|
|
a3b4421422 | ||
|
|
28bc1e37ed | ||
|
|
c0b96a4319 | ||
|
|
4296616d00 | ||
|
|
3a43f96fe4 | ||
|
|
b82a1001e2 | ||
|
|
84dc7e2016 | ||
|
|
1482728a61 | ||
|
|
428f62041b | ||
|
|
4b6ec99973 | ||
|
|
0c01da5378 | ||
|
|
8004756c3d | ||
|
|
e01df1a3f1 | ||
|
|
46820a7ba0 | ||
|
|
0493629a9d | ||
|
|
41b3459a5d | ||
|
|
b27373c8a4 | ||
|
|
b450c8fbe3 | ||
|
|
1ac24f32e3 | ||
|
|
977fc5bc15 | ||
|
|
787bddf47b | ||
|
|
c32cd532f2 | ||
|
|
18f2345124 | ||
|
|
00b623e8c4 | ||
|
|
452108d058 | ||
|
|
6b0712dae4 | ||
|
|
9a309f499b | ||
|
|
a204c993e5 | ||
|
|
e881376127 | ||
|
|
66c98d724c | ||
|
|
5c38fe6a84 | ||
|
|
e3bb317504 | ||
|
|
713022a7e8 | ||
|
|
6b79f32715 | ||
|
|
2386e99ad8 | ||
|
|
6ca82960c9 | ||
|
|
93891578fc | ||
|
|
7bcadcd300 | ||
|
|
b3f8dc4a24 | ||
|
|
38e3122217 | ||
|
|
f7de0ab3ef | ||
|
|
defe008062 | ||
|
|
ec930e17c8 | ||
|
|
9f1731cffa | ||
|
|
ed8d55d2d5 | ||
|
|
7b6a461b83 | ||
|
|
3b0ff8fd83 | ||
|
|
00b5886cf9 | ||
|
|
c16fd4e642 | ||
|
|
4b92ac8ba6 | ||
|
|
5b432b8280 | ||
|
|
31aff54463 | ||
|
|
c669ec3c88 | ||
|
|
8c2f54abe0 | ||
|
|
804121cbed | ||
|
|
839e626ee6 | ||
|
|
3a17724136 | ||
|
|
7b0c6610e0 | ||
|
|
0e0b1e98c5 | ||
|
|
b0975c44b1 | ||
|
|
25a6049cf6 | ||
|
|
02fcbdb245 | ||
|
|
a3a8ea4183 | ||
|
|
92d7fb848b | ||
|
|
0b6327a7fc | ||
|
|
84bd588152 | ||
|
|
9e952cf042 | ||
|
|
27a1a05aa7 | ||
|
|
657841e2b0 | ||
|
|
02172f6922 | ||
|
|
0dd225b594 | ||
|
|
452d0d4b5a | ||
|
|
2edae61c0b | ||
|
|
141abd5390 | ||
|
|
22faa0f26a | ||
|
|
4d2453f3a8 | ||
|
|
7a5f52c1f3 | ||
|
|
1ad109f8c7 | ||
|
|
1347755b6f | ||
|
|
62253744a7 | ||
|
|
9a608210cd | ||
|
|
adbfdb23a7 | ||
|
|
ac5d0abe5e | ||
|
|
8dbaaa5efe | ||
|
|
fa1bcc1c19 | ||
|
|
32138ecd04 | ||
|
|
5e999f0b47 | ||
|
|
5c74095f44 | ||
|
|
55befb87cd | ||
|
|
9d7a0f8615 | ||
|
|
974100732c | ||
|
|
35a6a4d8d0 | ||
|
|
f2a64c4d15 | ||
|
|
ed1e90990e | ||
|
|
c8a4727243 | ||
|
|
2ccabbbdef | ||
|
|
7c3638143d | ||
|
|
a0e8b24c70 | ||
|
|
41d432211e | ||
|
|
94f6138e23 | ||
|
|
e82ce81858 | ||
|
|
c18fa5e038 | ||
|
|
c7c53adbb5 | ||
|
|
30a9ef7e7a | ||
|
|
064181f903 | ||
|
|
7d22ed86f8 | ||
|
|
0641a981d1 | ||
|
|
ceb6741a67 | ||
|
|
4797cab10b | ||
|
|
fbf001bbec | ||
|
|
8e90e96509 | ||
|
|
80e9b97036 | ||
|
|
01103f32ae | ||
|
|
4bef0c7b33 | ||
|
|
693d5a77bd | ||
|
|
a2333ead45 | ||
|
|
aa6a436af5 | ||
|
|
ee350d6b4b | ||
|
|
26b85c0606 | ||
|
|
068190a7a5 | ||
|
|
1b292f7cf2 | ||
|
|
cd9a19c090 | ||
|
|
6d357e70a4 | ||
|
|
8f4817106d | ||
|
|
d2ce689008 | ||
|
|
b470166c87 | ||
|
|
158a0da0b2 | ||
|
|
b4bbf0462c | ||
|
|
d80b96790f | ||
|
|
accb571fd6 | ||
|
|
523a4b6a81 | ||
|
|
9d8a6a4978 | ||
|
|
f2fa85aa47 | ||
|
|
a189d13b4a | ||
|
|
3b79a77d78 | ||
|
|
c2ee34e51c | ||
|
|
c3bead1c9b | ||
|
|
a26f1a4b5c | ||
|
|
1eacfdf592 | ||
|
|
ba14ed43e4 | ||
|
|
802b3008be | ||
|
|
3b0191d145 | ||
|
|
282d32f70d | ||
|
|
e0c349a18c | ||
|
|
69d65dc002 | ||
|
|
33e70ddce4 | ||
|
|
d3ada8fcb3 | ||
|
|
4c21ca4e26 | ||
|
|
a3301ec1d2 | ||
|
|
6f11bfc632 | ||
|
|
74262b9ef8 | ||
|
|
199a610607 | ||
|
|
af2d223f0f | ||
|
|
0b6fcf8b71 | ||
|
|
cc05aeccd1 | ||
|
|
5728444ad3 | ||
|
|
4cbb6b5919 | ||
|
|
5699bb4932 | ||
|
|
09fa97c53a | ||
|
|
3eaa8a46bd | ||
|
|
4401319136 | ||
|
|
472ddcf0b1 | ||
|
|
b7e0f276a1 | ||
|
|
5d251aea3a | ||
|
|
cdc0065284 | ||
|
|
6d65dc5bf0 | ||
|
|
5d02c0bba4 | ||
|
|
b99513e080 | ||
|
|
3cf328c781 | ||
|
|
bce68611a1 | ||
|
|
cc497feee7 | ||
|
|
725606af8d | ||
|
|
52db6e5459 | ||
|
|
83441bc203 |
8
ofono/.gitignore
vendored
8
ofono/.gitignore
vendored
@@ -42,12 +42,15 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
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_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sms-filter
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
|
||||
@@ -57,9 +60,14 @@ unit/test-grilunsol
|
||||
unit/test-provision
|
||||
unit/html
|
||||
|
||||
plugins/sailfish_manager/*.gcda
|
||||
plugins/sailfish_manager/*.gcno
|
||||
drivers/*/*.gcda
|
||||
drivers/*/*.gcno
|
||||
drivers/*/*.gcov
|
||||
plugins/*/*.gcda
|
||||
plugins/*/*.gcno
|
||||
plugins/*/*.gcov
|
||||
*/*.gcda
|
||||
*/*.gcno
|
||||
*/*.gcov
|
||||
|
||||
@@ -116,3 +116,10 @@ Martin Chaplet <m.chaplet@kerlink.fr>
|
||||
Suman Mallela <suman.m@intel.com>
|
||||
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
|
||||
Antoine Aubert <a.aubert@overkiz.com>
|
||||
Djalal Harouni <djalal@endocode.com>
|
||||
Christophe Ronco <c.ronco@kerlink.fr>
|
||||
Vincent Cesson <vincent.cesson@smile.fr>
|
||||
Piotr Haber <gluedig@gmail.com>
|
||||
André Draszik <git@andred.net>
|
||||
Lukasz Nowak <lnowak@tycoint.com>
|
||||
Jonas Bonn <jonas@southpole.se>
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
ver 1.20:
|
||||
Fix issue with context removal before activation.
|
||||
Fix issue with update during GPRS context activation.
|
||||
Fix issue with receiving UTF-16 encoded messages.
|
||||
Fix issue with invalid access in CBS decoding.
|
||||
Fix issue with signal strength on QMI modems.
|
||||
Fix issue with PIN handling with QMI modems.
|
||||
Fix issue with QMI notification message handling.
|
||||
Fix issue with facility lock query on SIM removal.
|
||||
Fix issue with parsing +CLCC and +CCWA fields.
|
||||
Add support for obtaining IMSI via EF reading.
|
||||
Add support for additional netmon info types.
|
||||
Add support for provisioning via configuration files.
|
||||
Add support for Gemalto P-family series of modems.
|
||||
Add support for Telit HE910 and UE910 variants.
|
||||
Add support for Intel SoFIA SIM Toolkit interfaces.
|
||||
Add support for Intel SoFIA LTE features.
|
||||
Add support for U-Blox TOBY-L2 LTE feature.
|
||||
Add support for dedicated LTE atom.
|
||||
|
||||
ver 1.19:
|
||||
Fix issue with DHCP parsing and Huawei modems.
|
||||
Fix issue with detecting Huawei E3372 modem.
|
||||
|
||||
@@ -23,13 +23,14 @@ 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/netmon.h
|
||||
include/sms-filter.h \
|
||||
include/netmon.h include/lte.h
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
nodist_pkginclude_HEADERS += include/sailfish_manager.h \
|
||||
include/sailfish_watch.h
|
||||
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
|
||||
include/sailfish_manager.h include/sailfish_watch.h
|
||||
endif
|
||||
|
||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
||||
@@ -112,8 +113,6 @@ gril_sources = gril/gril.h gril/gril.c \
|
||||
btio_sources = btio/btio.h btio/btio.c
|
||||
|
||||
if UDEV
|
||||
builtin_modules += udev
|
||||
builtin_sources += plugins/udev.c
|
||||
builtin_cflags += @UDEV_CFLAGS@
|
||||
builtin_libadd += @UDEV_LIBS@
|
||||
|
||||
@@ -123,7 +122,9 @@ endif
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
builtin_modules += sailfish_manager
|
||||
builtin_sources += plugins/sailfish_manager/sailfish_manager.c \
|
||||
builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_manager_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
@@ -139,7 +140,6 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_cell_info_dbus.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
@@ -183,8 +183,8 @@ builtin_sources += plugins/ril.c plugins/ril.h
|
||||
builtin_modules += infineon
|
||||
builtin_sources += plugins/infineon.c
|
||||
|
||||
builtin_modules += ril_sofia3gr
|
||||
builtin_sources += plugins/ril_sofia3gr.c
|
||||
builtin_modules += ril_intel
|
||||
builtin_sources += plugins/ril_intel.c
|
||||
|
||||
builtin_modules += rilmodem
|
||||
builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
@@ -209,7 +209,8 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/netmon.c \
|
||||
drivers/rilmodem/stk.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/infineonmodem/infineon_constants.h
|
||||
drivers/infineonmodem/infineon_constants.h \
|
||||
drivers/rilmodem/lte.c
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -268,11 +269,13 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
|
||||
drivers/qmimodem/ctl.h \
|
||||
drivers/qmimodem/dms.h \
|
||||
drivers/qmimodem/nas.h \
|
||||
drivers/qmimodem/nas.c \
|
||||
drivers/qmimodem/uim.h \
|
||||
drivers/qmimodem/wms.h \
|
||||
drivers/qmimodem/wds.h \
|
||||
drivers/qmimodem/pds.h \
|
||||
drivers/qmimodem/common.h
|
||||
drivers/qmimodem/common.h \
|
||||
drivers/qmimodem/wda.h
|
||||
|
||||
builtin_modules += qmimodem
|
||||
builtin_sources += $(qmi_sources) \
|
||||
@@ -377,7 +380,8 @@ builtin_modules += telitmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/telitmodem/telitmodem.h \
|
||||
drivers/telitmodem/telitmodem.c \
|
||||
drivers/telitmodem/location-reporting.c
|
||||
drivers/telitmodem/location-reporting.c \
|
||||
drivers/telitmodem/gprs-context-ncm.c
|
||||
|
||||
builtin_modules += hsomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
@@ -439,7 +443,16 @@ builtin_modules += ubloxmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/ubloxmodem/ubloxmodem.h \
|
||||
drivers/ubloxmodem/ubloxmodem.c \
|
||||
drivers/ubloxmodem/gprs-context.c
|
||||
drivers/ubloxmodem/gprs-context.c \
|
||||
drivers/ubloxmodem/netmon.c \
|
||||
drivers/ubloxmodem/lte.c
|
||||
|
||||
|
||||
builtin_modules += gemaltomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/gemaltomodem/gemaltomodem.h \
|
||||
drivers/gemaltomodem/gemaltomodem.c \
|
||||
drivers/gemaltomodem/location-reporting.c
|
||||
|
||||
|
||||
if PHONESIM
|
||||
@@ -506,6 +519,9 @@ builtin_sources += plugins/caif.c
|
||||
builtin_modules += cinterion
|
||||
builtin_sources += plugins/cinterion.c
|
||||
|
||||
builtin_modules += gemalto
|
||||
builtin_sources += plugins/gemalto.c
|
||||
|
||||
builtin_modules += nokia
|
||||
builtin_sources += plugins/nokia.c
|
||||
|
||||
@@ -533,6 +549,12 @@ builtin_sources += plugins/samsung.c
|
||||
builtin_modules += sim900
|
||||
builtin_sources += plugins/sim900.c
|
||||
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c
|
||||
|
||||
builtin_modules += quectel
|
||||
builtin_sources += plugins/quectel.c
|
||||
|
||||
@@ -546,11 +568,11 @@ endif
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
|
||||
if BLUETOOTH
|
||||
if BLUEZ4
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += sap
|
||||
builtin_sources += plugins/sap.c plugins/bluez4.h
|
||||
|
||||
@@ -627,8 +649,9 @@ builtin_sources += plugins/provision.h
|
||||
builtin_modules += cdma_provision
|
||||
builtin_sources += plugins/cdma-provision.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
builtin_modules += file_provision
|
||||
builtin_sources += plugins/file-provision.c
|
||||
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
@@ -700,8 +723,9 @@ 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/hfp.h src/siri.c \
|
||||
src/netmon.c
|
||||
src/netmon.c src/lte.c
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -749,7 +773,8 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/certification.txt doc/siri-api.txt \
|
||||
doc/telit-modem.txt \
|
||||
doc/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt
|
||||
doc/allowed-apns-api.txt \
|
||||
doc/lte-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -856,7 +881,8 @@ test_scripts = test/backtrace \
|
||||
test/get-serving-cell-info \
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling
|
||||
test/disable-throttling \
|
||||
test/set-lte-property
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -877,10 +903,18 @@ 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-provision unit/test-sms-filter
|
||||
|
||||
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
|
||||
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_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
@@ -894,6 +928,7 @@ unit_tests += unit/test-sailfish_sim_info
|
||||
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/log.c
|
||||
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@@ -907,6 +942,14 @@ endif
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
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)
|
||||
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_util_OBJECTS)
|
||||
unit_tests += unit/test-ril_util
|
||||
|
||||
else
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-sms \
|
||||
@@ -983,6 +1026,12 @@ unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_provision_OBJECTS)
|
||||
|
||||
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)
|
||||
|
||||
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
|
||||
gatchat/ringbuffer.h gatchat/ringbuffer.c \
|
||||
unit/rilmodem-test-server.h \
|
||||
@@ -1046,13 +1095,6 @@ tools_lookup_provider_name_LDADD = @GLIB_LIBS@
|
||||
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
||||
tools_tty_redirector_LDADD = @GLIB_LIBS@
|
||||
|
||||
if QMIMODEM
|
||||
noinst_PROGRAMS += tools/qmi
|
||||
|
||||
tools_qmi_SOURCES = $(qmi_sources) tools/qmi.c
|
||||
tools_qmi_LDADD = @GLIB_LIBS@
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
noinst_PROGRAMS += tools/stktest
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.19)
|
||||
AC_INIT(ofono, 1.20)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -184,12 +184,12 @@ 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.16, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.16 is required))
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.18, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.18 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, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||
enable_sailfish_manager=yes
|
||||
|
||||
@@ -19,7 +19,7 @@ Besides the kernel coding style above, oFono has special flavors for its own.
|
||||
Some of them are mandatory (marked as 'M'), while some others are optional
|
||||
(marked as 'O'), but generally preferred.
|
||||
|
||||
M1: Blank line before and after an if/while/do/for statement
|
||||
M1: Blank line before and after an if/while/do/for/switch statement
|
||||
============================================================
|
||||
There should be a blank line before if statement unless the if is nested and
|
||||
not preceded by an expression or variable declaration.
|
||||
|
||||
@@ -76,6 +76,22 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
fd, byte Acquire()
|
||||
|
||||
Attempts to establish the SCO audio connection
|
||||
returning the filedescriptor of the connection and the
|
||||
codec in use.
|
||||
|
||||
Note: Contrary to Connect this does not call
|
||||
NewConnection so it can be called in a blocking
|
||||
manner.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.Failed
|
||||
[service].Error.NotAvailable
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
Signals PropertyChanged(string name, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
|
||||
35
ofono/doc/lte-api.txt
Normal file
35
ofono/doc/lte-api.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
LongTermEvolution Hierarchy
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.LongTermEvolution
|
||||
Object path [variable prefix]/{modem0,modem1,...}
|
||||
|
||||
|
||||
Methods dict GetProperties()
|
||||
|
||||
Returns all LongTermEvolution configuration properties.
|
||||
|
||||
void SetProperty(string property, variant value)
|
||||
|
||||
Changes the value of the specified property. Only
|
||||
properties that are listed as readwrite are
|
||||
changeable. On success a PropertyChanged signal
|
||||
will be emitted.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.Failed
|
||||
|
||||
Signals PropertyChanged(string property, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
property.
|
||||
|
||||
Properties string DefaultAccessPointName [readwrite]
|
||||
|
||||
On LongTermEvolution, contexts activate automatically.
|
||||
This property allows selection of an APN to be used on
|
||||
next automatic activation.
|
||||
|
||||
Setting this property to an empty string clears the
|
||||
default APN from the modem.
|
||||
@@ -81,3 +81,42 @@ byte Strength [optional, gsm, umts]
|
||||
|
||||
Contains the signal strength. Valid values are 0-31. Refer to <rssi>
|
||||
in 27.007, Section 8.5.
|
||||
|
||||
byte ReceivedSignalCodePower [optional, umts]
|
||||
|
||||
Contains the Received Signal Code Power. Valid range of values
|
||||
is 0-96. Refer to <rscp> in 27.007, Section 8.69 for more details.
|
||||
|
||||
byte ReceivedEnergyRatio [optional, umts]
|
||||
|
||||
Contains the Ratio of received energy per PN chip to the total
|
||||
received power spectral density. Valid range of values is 0-49.
|
||||
Refer to <ecno> in 27.007, Section 8.69 for more details.
|
||||
|
||||
byte ReferenceSignalReceivedQuality [optional, lte]
|
||||
|
||||
Contains the Reference Signal Received Quality. Valid range of
|
||||
values is 0-34. Refer to <rsrq> in 27.007, Section 8.69 for more
|
||||
details.
|
||||
|
||||
byte ReferenceSignalReceivedPower [optional, lte]
|
||||
|
||||
Contains the Reference Signal Received Power. Valid range of values
|
||||
is 0-97. Refer to <rsrp> in 27.007, Section 8.69 for more details.
|
||||
|
||||
uint16 EARFCN [optional, lte]
|
||||
|
||||
Contains E-UTRA Absolute Radio Frequency Channel Number. Valid
|
||||
range of values is 0-65535. Refer to Carrier frequency and
|
||||
EARFCN in 36.101, Section 5.7.3 for more details.
|
||||
|
||||
byte EBand [optional, lte]
|
||||
|
||||
Contains E-UTRA operating Band. Valid range of values is 1-43.
|
||||
Refer to Operating bands in 36.101, Section 5.5 for more
|
||||
details.
|
||||
|
||||
byte ChannelQualityIndicator [optional, lte]
|
||||
|
||||
Contains Channel Quality Indicator. Refer to Channel Quality
|
||||
Indicator definition in 36.213, Section 7.2.3 for more details.
|
||||
|
||||
@@ -17,3 +17,30 @@ GPS:
|
||||
After setting the configuration, a power cycle is required.
|
||||
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
|
||||
can be checked using 'AT+CGMR'.
|
||||
|
||||
LE910 V2
|
||||
========
|
||||
|
||||
Default USB composition of LE910V2 uses PID 0x36 (AT#PORTCFG=0)
|
||||
and consists of 6 serial ports (CDC-ACM standard, /dev/ttyACMx)
|
||||
and 1 network adapter using CDC-NCM standard (wwanx or usbx).
|
||||
|
||||
NCM interface configuration follows Telit documentation
|
||||
(both documents available on Telit Download Zone - registration required)
|
||||
"GE/HE/UE910, UL865, LE910 V2 Linux USB Driver - User Guide r0"
|
||||
(document 1VV0301255 Rev.0 - 2016-01-22)
|
||||
and "Telit LE910-V2 NCM SETUP r3"
|
||||
(document 1VV0301246 Rev.3 - 2016-11-29).
|
||||
|
||||
After context is setup, NCM mode activated and PDP context activated
|
||||
connection configuration can be read using
|
||||
AT+CGPADDR=context_id and AT+CGCONTRDP=context_id commands.
|
||||
This is done automatically and results available via
|
||||
org.ofono.ConnectionContext.GetProperties DBus method.
|
||||
|
||||
Then Linux network interface needs to be configured:
|
||||
ifconfig <Interface> <Address> netmask <Netmask> up
|
||||
route add default gw <Gateway>
|
||||
arp -s <Gateway> 11:22:33:44:55:66
|
||||
|
||||
Only after these steps network interface is usable.
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
static const char *cgdata_prefix[] = { "+CGDATA:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
enum state {
|
||||
@@ -67,6 +68,7 @@ struct gprs_context_data {
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data; /* Callback data */
|
||||
unsigned int vendor;
|
||||
gboolean use_atd99;
|
||||
};
|
||||
|
||||
static void ppp_debug(const char *str, void *data)
|
||||
@@ -210,7 +212,7 @@ static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gcd->vendor == OFONO_VENDOR_SIMCOM_SIM900)
|
||||
if (gcd->use_atd99)
|
||||
sprintf(buf, "ATD*99***%u#", gcd->active_context);
|
||||
else
|
||||
sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
|
||||
@@ -382,6 +384,43 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
g_at_ppp_shutdown(gcd->ppp);
|
||||
}
|
||||
|
||||
static void at_cgdata_test_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);
|
||||
GAtResultIter iter;
|
||||
const char *data_type;
|
||||
gboolean found = FALSE;
|
||||
|
||||
gcd->use_atd99 = TRUE;
|
||||
|
||||
if (!ok) {
|
||||
DBG("not ok");
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
if (!g_at_result_iter_next(&iter, "+CGDATA:")) {
|
||||
DBG("no +CGDATA line");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!g_at_result_iter_open_list(&iter)) {
|
||||
DBG("no list found");
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (!found && g_at_result_iter_next_string(&iter, &data_type)) {
|
||||
if (g_str_equal(data_type, "PPP")) {
|
||||
found = TRUE;
|
||||
gcd->use_atd99 = FALSE;
|
||||
}
|
||||
}
|
||||
error:
|
||||
DBG("use_atd99:%d", gcd->use_atd99);
|
||||
}
|
||||
|
||||
static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
@@ -409,6 +448,15 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
if (chat == NULL)
|
||||
return 0;
|
||||
|
||||
switch (vendor) {
|
||||
case OFONO_VENDOR_SIMCOM_SIM900:
|
||||
gcd->use_atd99 = FALSE;
|
||||
break;
|
||||
default:
|
||||
g_at_chat_send(chat, "AT+CGDATA=?", cgdata_prefix,
|
||||
at_cgdata_test_cb, gc, NULL);
|
||||
}
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -50,6 +50,8 @@ struct gprs_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
unsigned int last_auto_context_id;
|
||||
gboolean telit_try_reattach;
|
||||
int attached;
|
||||
};
|
||||
|
||||
static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
@@ -73,8 +75,10 @@ static void at_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
|
||||
|
||||
if (g_at_chat_send(gd->chat, buf, none_prefix,
|
||||
at_cgatt_cb, cbd, g_free) > 0)
|
||||
at_cgatt_cb, cbd, g_free) > 0) {
|
||||
gd->attached = attached;
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
@@ -194,6 +198,28 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
|
||||
NULL, NULL, NULL, gd->vendor) == FALSE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Telit AT modem firmware (tested with UE910-EUR) generates
|
||||
* +CGREG: 0\r\n\r\n+CGEV: NW DETACH
|
||||
* after a context is de-activated and ppp connection closed.
|
||||
* Then, after a random amount of time (observed from a few seconds
|
||||
* to a few hours), an unsolicited +CGREG: 1 arrives.
|
||||
* Attempt to fix the problem, by sending AT+CGATT=1 once.
|
||||
* This does not re-activate the context, but if a network connection
|
||||
* is still correct, will generate an immediate +CGREG: 1.
|
||||
*/
|
||||
if (gd->vendor == OFONO_VENDOR_TELIT) {
|
||||
if (gd->attached && !status && !gd->telit_try_reattach) {
|
||||
DBG("Trying to re-attach gprs network");
|
||||
gd->telit_try_reattach = TRUE;
|
||||
g_at_chat_send(gd->chat, "AT+CGATT=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
gd->telit_try_reattach = FALSE;
|
||||
}
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
|
||||
@@ -214,6 +240,11 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
if (g_str_equal(event, "NW DETACH") ||
|
||||
g_str_equal(event, "ME DETACH")) {
|
||||
if (gd->vendor == OFONO_VENDOR_TELIT &&
|
||||
gd->telit_try_reattach)
|
||||
return;
|
||||
|
||||
gd->attached = FALSE;
|
||||
ofono_gprs_detached_notify(gprs);
|
||||
return;
|
||||
} else if (g_str_has_prefix(event, "ME PDN ACT")) {
|
||||
@@ -323,6 +354,9 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||
case 3:
|
||||
bearer = 5; /* HSDPA */
|
||||
break;
|
||||
case 4:
|
||||
bearer = 7; /* LTE */
|
||||
break;
|
||||
default:
|
||||
bearer = 0;
|
||||
break;
|
||||
@@ -522,7 +556,7 @@ static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
|
||||
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
|
||||
continue;
|
||||
|
||||
if (!g_at_result_iter_close_list(&iter))
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
continue;
|
||||
|
||||
if (g_at_result_iter_open_list(&iter))
|
||||
|
||||
@@ -51,6 +51,7 @@ struct sim_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
guint ready_id;
|
||||
guint passwd_type_mask;
|
||||
struct at_util_sim_state_query *sim_state_query;
|
||||
};
|
||||
|
||||
@@ -1293,14 +1294,15 @@ static void sim_state_cb(gboolean present, gpointer user_data)
|
||||
struct cb_data *cbd = user_data;
|
||||
struct sim_data *sd = cbd->user;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
void *data = cbd->data;
|
||||
|
||||
at_util_sim_state_query_free(sd->sim_state_query);
|
||||
sd->sim_state_query = NULL;
|
||||
|
||||
if (present == 1)
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
@@ -1458,9 +1460,8 @@ static void at_pin_enable(struct ofono_sim *sim,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
int ret;
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
||||
@@ -1489,10 +1490,8 @@ static void at_change_passwd(struct ofono_sim *sim,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
int ret;
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len ||
|
||||
at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
||||
@@ -1549,9 +1548,8 @@ static void at_query_clck(struct ofono_sim *sim,
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
||||
@@ -1567,13 +1565,42 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static gboolean at_sim_register(gpointer user)
|
||||
static void at_clck_query_cb(gboolean ok, GAtResult *result, gpointer user)
|
||||
{
|
||||
struct ofono_sim *sim = user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
GAtResultIter iter;
|
||||
const char *fac;
|
||||
|
||||
if (!ok)
|
||||
goto done;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
/* e.g. +CLCK: ("SC","FD","PN","PU","PP","PC","PF") */
|
||||
if (!g_at_result_iter_next(&iter, "+CLCK:") ||
|
||||
!g_at_result_iter_open_list(&iter))
|
||||
goto done;
|
||||
|
||||
/* Clear the default mask */
|
||||
sd->passwd_type_mask = 0;
|
||||
|
||||
/* Set the bits for <fac>s that are actually supported */
|
||||
while (g_at_result_iter_next_string(&iter, &fac)) {
|
||||
unsigned int i;
|
||||
|
||||
/* Find it in the list of known <fac>s */
|
||||
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++) {
|
||||
if (!g_strcmp0(at_clck_cpwd_fac[i], fac)) {
|
||||
sd->passwd_type_mask |= (1 << i);
|
||||
DBG("found %s", fac);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ofono_sim_register(sim);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
@@ -1581,6 +1608,7 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct sim_data *sd;
|
||||
unsigned int i;
|
||||
|
||||
sd = g_new0(struct sim_data, 1);
|
||||
sd->chat = g_at_chat_clone(chat);
|
||||
@@ -1590,9 +1618,15 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
|
||||
|
||||
ofono_sim_set_data(sim, sd);
|
||||
g_idle_add(at_sim_register, sim);
|
||||
|
||||
return 0;
|
||||
/* <fac>s supported by default */
|
||||
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++)
|
||||
if (at_clck_cpwd_fac[i])
|
||||
sd->passwd_type_mask |= (1 << i);
|
||||
|
||||
/* Query supported <fac>s */
|
||||
return g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
|
||||
at_clck_query_cb, sim, NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
static void at_sim_remove(struct ofono_sim *sim)
|
||||
|
||||
@@ -319,26 +319,6 @@ static void at_cnma_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
"Further SMS reception is not guaranteed");
|
||||
}
|
||||
|
||||
static gboolean at_parse_cmt(GAtResult *result, const char **pdu, int *pdulen)
|
||||
{
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, pdulen))
|
||||
return FALSE;
|
||||
|
||||
*pdu = g_at_result_pdu(result);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||
{
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
@@ -347,11 +327,21 @@ static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||
DBG("");
|
||||
|
||||
/* We must acknowledge the PDU using CNMA */
|
||||
if (data->cnma_ack_pdu)
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
||||
data->cnma_ack_pdu_len, data->cnma_ack_pdu);
|
||||
else /* Should be a safe fallback */
|
||||
if (data->cnma_ack_pdu) {
|
||||
switch (data->vendor) {
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1");
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
||||
data->cnma_ack_pdu_len,
|
||||
data->cnma_ack_pdu);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Should be a safe fallback */
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=0");
|
||||
}
|
||||
|
||||
g_at_chat_send(data->chat, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
||||
}
|
||||
@@ -409,16 +399,34 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_sms *sms = user_data;
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
GAtResultIter iter;
|
||||
const char *hexpdu;
|
||||
unsigned char pdu[176];
|
||||
long pdu_len;
|
||||
int tpdu_len;
|
||||
unsigned char pdu[176];
|
||||
|
||||
if (!at_parse_cmt(result, &hexpdu, &tpdu_len)) {
|
||||
ofono_error("Unable to parse CMT notification");
|
||||
return;
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
||||
goto err;
|
||||
|
||||
switch (data->vendor) {
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||
goto err;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
hexpdu = g_at_result_pdu(result);
|
||||
|
||||
if (strlen(hexpdu) > sizeof(pdu) * 2) {
|
||||
ofono_error("Bad PDU length in CMT notification");
|
||||
return;
|
||||
@@ -431,6 +439,9 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
if (data->vendor != OFONO_VENDOR_SIMCOM)
|
||||
at_ack_delivery(sms);
|
||||
|
||||
err:
|
||||
ofono_error("Unable to parse CMT notification");
|
||||
}
|
||||
|
||||
static void at_cmgr_notify(GAtResult *result, gpointer user_data)
|
||||
@@ -742,7 +753,7 @@ static void at_sms_initialized(struct ofono_sms *sms)
|
||||
|
||||
static void at_sms_not_supported(struct ofono_sms *sms)
|
||||
{
|
||||
ofono_error("SMS not supported by this modem. If this is in error"
|
||||
ofono_error("SMS not supported by this modem. If this is an error"
|
||||
" please submit patches to support this hardware");
|
||||
|
||||
ofono_sms_remove(sms);
|
||||
|
||||
49
ofono/drivers/gemaltomodem/gemaltomodem.c
Normal file
49
ofono/drivers/gemaltomodem/gemaltomodem.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Vincent Cesson. 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 "gemaltomodem.h"
|
||||
|
||||
static int gemaltomodem_init(void)
|
||||
{
|
||||
gemalto_location_reporting_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gemaltomodem_exit(void)
|
||||
{
|
||||
gemalto_location_reporting_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
gemaltomodem_init, gemaltomodem_exit)
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2017 Vincent Cesson. 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
|
||||
@@ -19,11 +19,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
extern void gemalto_location_reporting_init();
|
||||
extern void gemalto_location_reporting_exit();
|
||||
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Vincent Cesson. 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 <unistd.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
#include "gattty.h"
|
||||
|
||||
#include "gemaltomodem.h"
|
||||
|
||||
static const char *sgpsc_prefix[] = { "^SGPSC:", NULL };
|
||||
|
||||
struct gps_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void gemalto_gps_disable_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_location_reporting *lr = cbd->user;
|
||||
ofono_location_reporting_disable_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("lr=%p, ok=%d", lr, ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_disable(
|
||||
struct ofono_location_reporting *lr,
|
||||
ofono_location_reporting_disable_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("lr=%p", lr);
|
||||
|
||||
cbd->user = lr;
|
||||
|
||||
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",0", sgpsc_prefix,
|
||||
gemalto_gps_disable_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static int enable_data_stream(struct ofono_location_reporting *lr)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
const char *gps_dev;
|
||||
GHashTable *options;
|
||||
GIOChannel *channel;
|
||||
int fd;
|
||||
|
||||
modem = ofono_location_reporting_get_modem(lr);
|
||||
gps_dev = ofono_modem_get_string(modem, "GPS");
|
||||
|
||||
options = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
if (options == NULL)
|
||||
return -1;
|
||||
|
||||
g_hash_table_insert(options, "Baud", "115200");
|
||||
|
||||
channel = g_at_tty_open(gps_dev, options);
|
||||
|
||||
g_hash_table_destroy(options);
|
||||
|
||||
if (channel == NULL)
|
||||
return -1;
|
||||
|
||||
fd = g_io_channel_unix_get_fd(channel);
|
||||
|
||||
g_io_channel_set_close_on_unref(channel, FALSE);
|
||||
g_io_channel_unref(channel);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void gemalto_sgpsc_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_location_reporting_enable_cb_t cb = cbd->cb;
|
||||
struct ofono_location_reporting *lr = cbd->user;
|
||||
struct ofono_error error;
|
||||
int fd;
|
||||
|
||||
DBG("lr=%p ok=%d", lr, ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fd = enable_data_stream(lr);
|
||||
|
||||
if (fd < 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cb(&error, fd, cbd->data);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_enable(struct ofono_location_reporting *lr,
|
||||
ofono_location_reporting_enable_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("lr=%p", lr);
|
||||
|
||||
cbd->user = lr;
|
||||
|
||||
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",2", sgpsc_prefix,
|
||||
gemalto_sgpsc_cb, cbd, NULL) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_support_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_location_reporting *lr = user_data;
|
||||
|
||||
if (!ok) {
|
||||
ofono_location_reporting_remove(lr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_location_reporting_register(lr);
|
||||
}
|
||||
|
||||
static int gemalto_location_reporting_probe(struct ofono_location_reporting *lr,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct gps_data *gd;
|
||||
|
||||
gd = g_try_new0(struct gps_data, 1);
|
||||
if (gd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_location_reporting_set_data(lr, gd);
|
||||
|
||||
g_at_chat_send(gd->chat, "AT^SGPSC=?", sgpsc_prefix,
|
||||
gemalto_location_reporting_support_cb,
|
||||
lr, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_remove(struct ofono_location_reporting *lr)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
|
||||
ofono_location_reporting_set_data(lr, NULL);
|
||||
|
||||
g_at_chat_unref(gd->chat);
|
||||
g_free(gd);
|
||||
}
|
||||
|
||||
static struct ofono_location_reporting_driver driver = {
|
||||
.name = "gemaltomodem",
|
||||
.type = OFONO_LOCATION_REPORTING_TYPE_NMEA,
|
||||
.probe = gemalto_location_reporting_probe,
|
||||
.remove = gemalto_location_reporting_remove,
|
||||
.enable = gemalto_location_reporting_enable,
|
||||
.disable = gemalto_location_reporting_disable,
|
||||
};
|
||||
|
||||
void gemalto_location_reporting_init()
|
||||
{
|
||||
ofono_location_reporting_driver_register(&driver);
|
||||
}
|
||||
|
||||
void gemalto_location_reporting_exit()
|
||||
{
|
||||
ofono_location_reporting_driver_unregister(&driver);
|
||||
}
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/devinfo.h>
|
||||
@@ -125,7 +127,8 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
|
||||
}
|
||||
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
|
||||
if (!str) {
|
||||
/* Telit qmi modems return a "0" string when ESN is not available. */
|
||||
if (!str || strcmp(str, "0") == 0) {
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
@@ -24,18 +24,22 @@
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "wda.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_context_data {
|
||||
struct qmi_service *wds;
|
||||
struct qmi_service *wda;
|
||||
struct qmi_device *dev;
|
||||
unsigned int active_context;
|
||||
uint32_t pkt_handle;
|
||||
};
|
||||
@@ -61,8 +65,12 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
|
||||
|
||||
switch (status->status) {
|
||||
case QMI_WDS_CONN_STATUS_DISCONNECTED:
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
data->active_context = 0;
|
||||
if (data->pkt_handle) {
|
||||
/* The context has been disconnected by the network */
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
data->pkt_handle = 0;
|
||||
data->active_context = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -75,18 +83,68 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
|
||||
struct ofono_modem *modem;
|
||||
const char *interface;
|
||||
uint8_t pdp_type, ip_family;
|
||||
uint32_t ip_addr;
|
||||
struct in_addr addr;
|
||||
char* straddr;
|
||||
char* apn;
|
||||
const char *dns[3] = { NULL, NULL, NULL };
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
|
||||
apn = qmi_result_get_string(result, QMI_WDS_RESULT_APN);
|
||||
if (apn) {
|
||||
DBG("APN: %s", apn);
|
||||
g_free(apn);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_PDP_TYPE, &pdp_type))
|
||||
DBG("PDP type %d", pdp_type);
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
|
||||
DBG("IP family %d", ip_family);
|
||||
|
||||
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_IP_ADDRESS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("IP addr: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_address(gc, straddr, 1);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_GATEWAY, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("Gateway: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, straddr);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_GATEWAY_NETMASK, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("Gateway netmask: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, straddr);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_PRIMARY_DNS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
dns[0] = inet_ntoa(addr);
|
||||
DBG("Primary DNS: %s", dns[0]);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_SECONDARY_DNS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
dns[1] = inet_ntoa(addr);
|
||||
DBG("Secondary DNS: %s", dns[1]);
|
||||
}
|
||||
|
||||
if (dns[0])
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
done:
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
@@ -94,8 +152,6 @@ done:
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
@@ -120,8 +176,12 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
data->pkt_handle = handle;
|
||||
|
||||
/* Duplicate cbd, the old one will be freed when this method returns */
|
||||
cbd = cb_data_new(cb, cbd->data);
|
||||
cbd->user = gc;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_GET_SETTINGS, NULL,
|
||||
get_settings_cb, cbd, NULL) > 0)
|
||||
get_settings_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
@@ -131,12 +191,39 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
data->active_context = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gets called for "automatic" contexts, those which are
|
||||
* not activated via activate_primary. For these, we will still need
|
||||
* to call start_net in order to get the packet handle for the context.
|
||||
* The process for automatic contexts is essentially identical to that
|
||||
* for others.
|
||||
*/
|
||||
static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("cid %u", cid);
|
||||
|
||||
data->active_context = cid;
|
||||
|
||||
cbd->user = gc;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_START_NET, NULL,
|
||||
start_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
data->active_context = 0;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
@@ -151,6 +238,7 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct qmi_param *param;
|
||||
uint8_t ip_family;
|
||||
uint8_t auth;
|
||||
|
||||
DBG("cid %u", ctx->cid);
|
||||
|
||||
@@ -178,8 +266,31 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
|
||||
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = QMI_WDS_AUTHENTICATION_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = QMI_WDS_AUTHENTICATION_PAP;
|
||||
break;
|
||||
default:
|
||||
auth = QMI_WDS_AUTHENTICATION_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
qmi_param_append_uint8(param, QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE,
|
||||
auth);
|
||||
|
||||
if (ctx->username[0] != '\0')
|
||||
qmi_param_append(param, QMI_WDS_PARAM_USERNAME,
|
||||
strlen(ctx->username), ctx->username);
|
||||
|
||||
if (ctx->password[0] != '\0')
|
||||
qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
|
||||
strlen(ctx->password), ctx->password);
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_START_NET, param,
|
||||
start_net_cb, cbd, NULL) > 0)
|
||||
start_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
@@ -202,17 +313,19 @@ static void stop_net_cb(struct qmi_result *result, void *user_data)
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
data->active_context = 0;
|
||||
|
||||
data->pkt_handle = 0;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
|
||||
g_free(cbd);
|
||||
data->active_context = 0;
|
||||
}
|
||||
|
||||
static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
@@ -233,17 +346,26 @@ static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_STOP_NET, param,
|
||||
stop_net_cb, cbd, NULL) > 0)
|
||||
stop_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
qmi_deactivate_primary(gc, cid, NULL, NULL);
|
||||
}
|
||||
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
@@ -263,6 +385,69 @@ static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
pkt_status_notify, gc, NULL);
|
||||
}
|
||||
|
||||
static void get_data_format_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
uint32_t llproto;
|
||||
enum qmi_device_expected_data_format expected_llproto;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
|
||||
if (!qmi_result_get_uint32(result, QMI_WDA_LL_PROTOCOL, &llproto))
|
||||
goto done;
|
||||
|
||||
expected_llproto = qmi_device_get_expected_data_format(data->dev);
|
||||
|
||||
if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_802_3) &&
|
||||
(expected_llproto ==
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP)) {
|
||||
if (!qmi_device_set_expected_data_format(data->dev,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3))
|
||||
DBG("Fail to set expected data to 802.3");
|
||||
else
|
||||
DBG("expected data set to 802.3");
|
||||
} else if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP) &&
|
||||
(expected_llproto ==
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3)) {
|
||||
if (!qmi_device_set_expected_data_format(data->dev,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP))
|
||||
DBG("Fail to set expected data to raw-ip");
|
||||
else
|
||||
DBG("expected data set to raw-ip");
|
||||
}
|
||||
|
||||
done:
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void create_wda_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
DBG("Failed to request WDA service, continue initialization");
|
||||
goto error;
|
||||
}
|
||||
|
||||
data->wda = qmi_service_ref(service);
|
||||
|
||||
if (qmi_service_send(data->wda, QMI_WDA_GET_DATA_FORMAT, NULL,
|
||||
get_data_format_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
@@ -274,8 +459,9 @@ static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
data = g_new0(struct gprs_context_data, 1);
|
||||
|
||||
ofono_gprs_context_set_data(gc, data);
|
||||
data->dev = device;
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_WDS, create_wds_cb, gc, NULL);
|
||||
qmi_service_create(device, QMI_SERVICE_WDA, create_wda_cb, gc, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -288,9 +474,15 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->wds);
|
||||
if (data->wds) {
|
||||
qmi_service_unregister_all(data->wds);
|
||||
qmi_service_unref(data->wds);
|
||||
}
|
||||
|
||||
qmi_service_unref(data->wds);
|
||||
if (data->wda) {
|
||||
qmi_service_unregister_all(data->wda);
|
||||
qmi_service_unref(data->wda);
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
@@ -301,6 +493,8 @@ static struct ofono_gprs_context_driver driver = {
|
||||
.remove = qmi_gprs_context_remove,
|
||||
.activate_primary = qmi_activate_primary,
|
||||
.deactivate_primary = qmi_deactivate_primary,
|
||||
.read_settings = qmi_gprs_read_settings,
|
||||
.detach_shutdown = qmi_gprs_context_detach_shutdown,
|
||||
};
|
||||
|
||||
void qmi_gprs_context_init(void)
|
||||
|
||||
@@ -30,16 +30,18 @@
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
|
||||
#include "src/common.h"
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_data {
|
||||
struct qmi_service *nas;
|
||||
};
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status)
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
{
|
||||
const struct qmi_nas_serving_system *ss;
|
||||
uint16_t len;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
@@ -47,14 +49,46 @@ static bool extract_ss_info(struct qmi_result *result, int *status)
|
||||
if (!ss)
|
||||
return false;
|
||||
|
||||
if (ss->ps_state == QMI_NAS_ATTACH_STATUS_ATTACHED)
|
||||
*status = 0x01;
|
||||
if (ss->ps_state == QMI_NAS_ATTACH_STATE_ATTACHED)
|
||||
*status = NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
else
|
||||
*status = 0x00;
|
||||
*status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
|
||||
*tech = -1;
|
||||
for (i = 0; i < ss->radio_if_count; i++) {
|
||||
DBG("radio in use %d", ss->radio_if[i]);
|
||||
|
||||
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||
{
|
||||
int status;
|
||||
int tech;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!extract_ss_info(result, &status, &tech))
|
||||
return -1;
|
||||
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED)
|
||||
if (tech == ACCESS_TECHNOLOGY_EUTRAN) {
|
||||
/* On LTE we are effectively always attached; and
|
||||
* the default bearer is established as soon as the
|
||||
* network is joined.
|
||||
*/
|
||||
/* FIXME: query default profile number and APN
|
||||
* instead of assuming profile 1 and ""
|
||||
*/
|
||||
ofono_gprs_cid_activated(gprs, 1 , "automatic");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -62,10 +96,10 @@ static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!extract_ss_info(result, &status))
|
||||
return;
|
||||
status = handle_ss_info(result, gprs);
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
if (status >= 0)
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
|
||||
static void attach_detach_cb(struct qmi_result *result, void *user_data)
|
||||
@@ -124,22 +158,26 @@ error:
|
||||
static void get_ss_info_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_gprs *gprs = cbd->user;
|
||||
ofono_gprs_status_cb_t cb = cbd->cb;
|
||||
int status;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto error;
|
||||
|
||||
if (!extract_ss_info(result, &status)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
status = handle_ss_info(result, gprs);
|
||||
|
||||
if (status < 0)
|
||||
goto error;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
@@ -150,6 +188,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = gprs;
|
||||
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||
get_ss_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
@@ -174,6 +213,13 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
|
||||
/*
|
||||
* First get the SS info - the modem may already be connected,
|
||||
* and the state-change notification may never arrive
|
||||
*/
|
||||
qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||
ss_info_notify, gprs, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, gprs, NULL);
|
||||
|
||||
@@ -194,7 +240,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
|
||||
ofono_gprs_set_data(gprs, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, gprs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, gprs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
38
ofono/drivers/qmimodem/nas.c
Normal file
38
ofono/drivers/qmimodem/nas.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nas.h"
|
||||
|
||||
#include "src/common.h"
|
||||
|
||||
int qmi_nas_rat_to_tech(uint8_t rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -19,6 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define QMI_NAS_RESET 0 /* Reset NAS service state variables */
|
||||
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
|
||||
#define QMI_NAS_EVENT 2 /* Connection state report indication */
|
||||
@@ -63,7 +65,7 @@ struct qmi_nas_rf_info {
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Get the signal strength */
|
||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x10
|
||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x01
|
||||
|
||||
/* Scan for visible network */
|
||||
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
|
||||
@@ -140,9 +142,17 @@ struct qmi_nas_current_plmn {
|
||||
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
|
||||
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
|
||||
|
||||
#define QMI_NAS_ATTACH_STATUS_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATUS_ATTACHED 0x01
|
||||
#define QMI_NAS_ATTACH_STATUS_DETACHED 0x02
|
||||
/* qmi_nas_serving_system.status */
|
||||
#define QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED 0x00
|
||||
#define QMI_NAS_REGISTRATION_STATE_REGISTERED 0x01
|
||||
#define QMI_NAS_REGISTRATION_STATE_SEARCHING 0x02
|
||||
#define QMI_NAS_REGISTRATION_STATE_DENIED 0x03
|
||||
#define QMI_NAS_REGISTRATION_STATE_UNKNOWN 0x04
|
||||
|
||||
/* cs_state/ps_state */
|
||||
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
|
||||
#define QMI_NAS_ATTACH_STATE_DETACHED 0x02
|
||||
|
||||
/* Get info about home network */
|
||||
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
|
||||
@@ -152,3 +162,5 @@ struct qmi_nas_home_network {
|
||||
uint8_t desc_len;
|
||||
char desc[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
int qmi_nas_rat_to_tech(uint8_t rat);
|
||||
|
||||
@@ -43,20 +43,6 @@ struct netreg_data {
|
||||
uint8_t current_rat;
|
||||
};
|
||||
|
||||
static int rat_to_tech(uint8_t rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
int *lac, int *cellid, int *tech,
|
||||
struct ofono_network_operator *operator)
|
||||
@@ -64,7 +50,7 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
const struct qmi_nas_serving_system *ss;
|
||||
const struct qmi_nas_current_plmn *plmn;
|
||||
uint8_t i, roaming;
|
||||
uint16_t value16, len;
|
||||
uint16_t value16, len, opname_len;
|
||||
uint32_t value32;
|
||||
|
||||
DBG("");
|
||||
@@ -82,13 +68,13 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
for (i = 0; i < ss->radio_if_count; i++) {
|
||||
DBG("radio in use %d", ss->radio_if[i]);
|
||||
|
||||
*tech = rat_to_tech(ss->radio_if[i]);
|
||||
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_NAS_RESULT_ROAMING_STATUS,
|
||||
&roaming)) {
|
||||
if (ss->status == 1 && roaming == 0)
|
||||
*status = 5;
|
||||
*status = NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||
}
|
||||
|
||||
if (!operator)
|
||||
@@ -100,8 +86,21 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
GUINT16_FROM_LE(plmn->mcc));
|
||||
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
|
||||
GUINT16_FROM_LE(plmn->mnc));
|
||||
strncpy(operator->name, plmn->desc, plmn->desc_len);
|
||||
operator->name[plmn->desc_len] = '\0';
|
||||
opname_len = plmn->desc_len;
|
||||
if (opname_len > OFONO_MAX_OPERATOR_NAME_LENGTH)
|
||||
opname_len = OFONO_MAX_OPERATOR_NAME_LENGTH;
|
||||
|
||||
/*
|
||||
* Telit QMI modems can return non-utf-8 characters in
|
||||
* plmn-desc. When that happens, libdbus will abort ofono.
|
||||
* If non-utf-8 characters are detected, use mccmnc string.
|
||||
*/
|
||||
if (g_utf8_validate(plmn->desc, opname_len, NULL)) {
|
||||
strncpy(operator->name, plmn->desc, opname_len);
|
||||
operator->name[opname_len] = '\0';
|
||||
} else
|
||||
snprintf(operator->name, OFONO_MAX_OPERATOR_NAME_LENGTH,
|
||||
"%s%s", operator->mcc, operator->mnc);
|
||||
|
||||
DBG("%s (%s:%s)", operator->name, operator->mcc, operator->mnc);
|
||||
}
|
||||
@@ -265,7 +264,7 @@ static void scan_nets_cb(struct qmi_result *result, void *user_data)
|
||||
DBG("%03d:%02d %d", netrat->info[i].mcc, netrat->info[i].mnc,
|
||||
netrat->info[i].rat);
|
||||
|
||||
list[i].tech = rat_to_tech(netrat->info[i].rat);
|
||||
list[i].tech = qmi_nas_rat_to_tech(netrat->info[i].rat);
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -543,7 +542,7 @@ static int qmi_netreg_probe(struct ofono_netreg *netreg,
|
||||
|
||||
ofono_netreg_set_data(netreg, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS,
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, netreg, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
@@ -33,12 +35,18 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "ctl.h"
|
||||
|
||||
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data);
|
||||
|
||||
struct discovery {
|
||||
qmi_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
struct qmi_device {
|
||||
int ref_count;
|
||||
int fd;
|
||||
@@ -49,6 +57,7 @@ struct qmi_device {
|
||||
GQueue *req_queue;
|
||||
GQueue *control_queue;
|
||||
GQueue *service_queue;
|
||||
GQueue *discovery_queue;
|
||||
uint8_t next_control_tid;
|
||||
uint16_t next_service_tid;
|
||||
qmi_debug_func_t debug_func;
|
||||
@@ -60,6 +69,10 @@ struct qmi_device {
|
||||
uint8_t version_count;
|
||||
GHashTable *service_list;
|
||||
unsigned int release_users;
|
||||
qmi_shutdown_func_t shutdown_func;
|
||||
void *shutdown_user_data;
|
||||
qmi_destroy_func_t shutdown_destroy;
|
||||
guint shutdown_source;
|
||||
};
|
||||
|
||||
struct qmi_service {
|
||||
@@ -209,6 +222,14 @@ static gint __request_compare(gconstpointer a, gconstpointer b)
|
||||
return req->tid - tid;
|
||||
}
|
||||
|
||||
static void __discovery_free(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct discovery *d = data;
|
||||
qmi_destroy_func_t destroy = d->destroy;
|
||||
|
||||
destroy(d);
|
||||
}
|
||||
|
||||
static void __notify_free(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct qmi_notify *notify = data;
|
||||
@@ -313,8 +334,12 @@ static const char *__service_type_to_string(uint8_t type)
|
||||
return "UIM";
|
||||
case QMI_SERVICE_PBM:
|
||||
return "PBM";
|
||||
case QMI_SERVICE_QCHAT:
|
||||
return "QCHAT";
|
||||
case QMI_SERVICE_RMTFS:
|
||||
return "RMTFS";
|
||||
case QMI_SERVICE_TEST:
|
||||
return "TEST";
|
||||
case QMI_SERVICE_LOC:
|
||||
return "LOC";
|
||||
case QMI_SERVICE_SAR:
|
||||
@@ -326,9 +351,21 @@ static const char *__service_type_to_string(uint8_t type)
|
||||
case QMI_SERVICE_TS:
|
||||
return "TS";
|
||||
case QMI_SERVICE_TMD:
|
||||
return "TMS";
|
||||
return "TMD";
|
||||
case QMI_SERVICE_WDA:
|
||||
return "WDA";
|
||||
case QMI_SERVICE_CSVT:
|
||||
return "CSVT";
|
||||
case QMI_SERVICE_COEX:
|
||||
return "COEX";
|
||||
case QMI_SERVICE_PDC:
|
||||
return "PDC";
|
||||
case QMI_SERVICE_RFRPE:
|
||||
return "RFRPE";
|
||||
case QMI_SERVICE_DSD:
|
||||
return "DSD";
|
||||
case QMI_SERVICE_SSCTL:
|
||||
return "SSCTL";
|
||||
case QMI_SERVICE_CAT_OLD:
|
||||
return "CAT";
|
||||
case QMI_SERVICE_RMS:
|
||||
@@ -758,7 +795,7 @@ static void handle_packet(struct qmi_device *device,
|
||||
|
||||
tid = GUINT16_FROM_LE(service->transaction);
|
||||
|
||||
if (service->type == 0x04 && tid == 0x0000) {
|
||||
if (service->type == 0x04) {
|
||||
handle_indication(device, hdr->service, hdr->client,
|
||||
message, length, data);
|
||||
return;
|
||||
@@ -838,6 +875,21 @@ static void read_watch_destroy(gpointer user_data)
|
||||
device->read_watch = 0;
|
||||
}
|
||||
|
||||
static void __qmi_device_discovery_started(struct qmi_device *device,
|
||||
struct discovery *d)
|
||||
{
|
||||
g_queue_push_tail(device->discovery_queue, d);
|
||||
}
|
||||
|
||||
static void __qmi_device_discovery_complete(struct qmi_device *device,
|
||||
struct discovery *d)
|
||||
{
|
||||
if (g_queue_remove(device->discovery_queue, d) != TRUE)
|
||||
return;
|
||||
|
||||
__discovery_free(d, NULL);
|
||||
}
|
||||
|
||||
static void service_destroy(gpointer data)
|
||||
{
|
||||
struct qmi_service *service = data;
|
||||
@@ -891,6 +943,7 @@ struct qmi_device *qmi_device_new(int fd)
|
||||
device->req_queue = g_queue_new();
|
||||
device->control_queue = g_queue_new();
|
||||
device->service_queue = g_queue_new();
|
||||
device->discovery_queue = g_queue_new();
|
||||
|
||||
device->service_list = g_hash_table_new_full(g_direct_hash,
|
||||
g_direct_equal, NULL, service_destroy);
|
||||
@@ -927,6 +980,9 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
g_queue_foreach(device->req_queue, __request_free, NULL);
|
||||
g_queue_free(device->req_queue);
|
||||
|
||||
g_queue_foreach(device->discovery_queue, __discovery_free, NULL);
|
||||
g_queue_free(device->discovery_queue);
|
||||
|
||||
if (device->write_watch > 0)
|
||||
g_source_remove(device->write_watch);
|
||||
|
||||
@@ -936,6 +992,9 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
if (device->close_on_unref)
|
||||
close(device->fd);
|
||||
|
||||
if (device->shutdown_source)
|
||||
g_source_remove(device->shutdown_source);
|
||||
|
||||
g_hash_table_destroy(device->service_list);
|
||||
|
||||
g_free(device->version_str);
|
||||
@@ -987,6 +1046,7 @@ static const void *tlv_get(const void *data, uint16_t size,
|
||||
}
|
||||
|
||||
struct discover_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
qmi_discover_func_t func;
|
||||
void *user_data;
|
||||
@@ -994,6 +1054,21 @@ struct discover_data {
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static void discover_data_free(gpointer user_data)
|
||||
{
|
||||
struct discover_data *data = user_data;
|
||||
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void discover_callback(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data)
|
||||
{
|
||||
@@ -1007,8 +1082,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
uint8_t count;
|
||||
unsigned int i;
|
||||
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
count = 0;
|
||||
list = NULL;
|
||||
|
||||
@@ -1079,10 +1152,7 @@ done:
|
||||
if (data->func)
|
||||
data->func(count, list, data->user_data);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
|
||||
static gboolean discover_reply(gpointer user_data)
|
||||
@@ -1096,10 +1166,7 @@ static gboolean discover_reply(gpointer user_data)
|
||||
data->func(device->version_count,
|
||||
device->version_list, data->user_data);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1120,13 +1187,15 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = discover_data_free;
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
if (device->version_list) {
|
||||
g_timeout_add_seconds(0, discover_reply, data);
|
||||
data->timeout = g_timeout_add_seconds(0, discover_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1147,6 +1216,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
|
||||
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1177,63 +1247,249 @@ static void release_client(struct qmi_device *device,
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
}
|
||||
|
||||
struct shutdown_data {
|
||||
struct qmi_device *device;
|
||||
qmi_shutdown_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
static gboolean shutdown_reply(gpointer user_data)
|
||||
static void shutdown_destroy(gpointer user_data)
|
||||
{
|
||||
struct shutdown_data *data = user_data;
|
||||
struct qmi_device *device = user_data;
|
||||
|
||||
if (data->func)
|
||||
data->func(data->user_data);
|
||||
if (device->shutdown_destroy)
|
||||
device->shutdown_destroy(device->shutdown_user_data);
|
||||
|
||||
g_free(data);
|
||||
|
||||
return FALSE;
|
||||
device->shutdown_source = 0;
|
||||
}
|
||||
|
||||
static gboolean shutdown_timeout(gpointer user_data)
|
||||
static gboolean shutdown_callback(gpointer user_data)
|
||||
{
|
||||
struct shutdown_data *data = user_data;
|
||||
struct qmi_device *device = data->device;
|
||||
struct qmi_device *device = user_data;
|
||||
|
||||
if (device->release_users > 0)
|
||||
return TRUE;
|
||||
|
||||
return shutdown_reply(data);
|
||||
if (device->shutdown_func)
|
||||
device->shutdown_func(device->shutdown_user_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy)
|
||||
{
|
||||
struct shutdown_data *data;
|
||||
|
||||
if (!device)
|
||||
return false;
|
||||
|
||||
if (device->shutdown_source > 0)
|
||||
return false;
|
||||
|
||||
__debug_device(device, "device %p shutdown", device);
|
||||
|
||||
data = g_try_new0(struct shutdown_data, 1);
|
||||
if (!data)
|
||||
device->shutdown_source = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
|
||||
0, shutdown_callback, device,
|
||||
shutdown_destroy);
|
||||
if (device->shutdown_source == 0)
|
||||
return false;
|
||||
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
if (device->release_users > 0)
|
||||
g_timeout_add_seconds(0, shutdown_timeout, data);
|
||||
else
|
||||
g_timeout_add_seconds(0, shutdown_reply, data);
|
||||
device->shutdown_func = func;
|
||||
device->shutdown_user_data = user_data;
|
||||
device->shutdown_destroy = destroy;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_device_file_name(struct qmi_device *device,
|
||||
char *file_name, int size)
|
||||
{
|
||||
pid_t pid;
|
||||
char temp[100];
|
||||
ssize_t result;
|
||||
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
pid = getpid();
|
||||
|
||||
snprintf(temp, 100, "/proc/%d/fd/%d", (int) pid, device->fd);
|
||||
temp[99] = 0;
|
||||
|
||||
result = readlink(temp, file_name, size - 1);
|
||||
|
||||
if (result == -1 || result >= size - 1) {
|
||||
DBG("Error %d in readlink", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
file_name[result] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *get_first_dir_in_directory(char *dir_path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dir_entry;
|
||||
char *dir_name = NULL;
|
||||
|
||||
dir = opendir(dir_path);
|
||||
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
dir_entry = readdir(dir);
|
||||
|
||||
while ((dir_entry != NULL)) {
|
||||
if (dir_entry->d_type == DT_DIR &&
|
||||
strcmp(dir_entry->d_name, ".") != 0 &&
|
||||
strcmp(dir_entry->d_name, "..") != 0) {
|
||||
dir_name = g_strdup(dir_entry->d_name);
|
||||
break;
|
||||
}
|
||||
|
||||
dir_entry = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return dir_name;
|
||||
}
|
||||
|
||||
static char *get_device_interface(struct qmi_device *device)
|
||||
{
|
||||
char * const driver_names[] = { "usbmisc", "usb" };
|
||||
unsigned int i;
|
||||
char file_path[PATH_MAX];
|
||||
char *file_name;
|
||||
char *interface = NULL;
|
||||
|
||||
if (!get_device_file_name(device, file_path, sizeof(file_path)))
|
||||
return NULL;
|
||||
|
||||
file_name = basename(file_path);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(driver_names) && !interface; i++) {
|
||||
gchar *sysfs_path;
|
||||
|
||||
sysfs_path = g_strdup_printf("/sys/class/%s/%s/device/net/",
|
||||
driver_names[i], file_name);
|
||||
interface = get_first_dir_in_directory(sysfs_path);
|
||||
g_free(sysfs_path);
|
||||
}
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
|
||||
struct qmi_device *device)
|
||||
{
|
||||
char *sysfs_path = NULL;
|
||||
char *interface = NULL;
|
||||
int fd = -1;
|
||||
char value;
|
||||
enum qmi_device_expected_data_format expected =
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
|
||||
|
||||
if (!device)
|
||||
goto done;
|
||||
|
||||
interface = get_device_interface(device);
|
||||
|
||||
if (!interface) {
|
||||
DBG("Error while getting interface name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Build sysfs file path and open it */
|
||||
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||
|
||||
fd = open(sysfs_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
/* maybe not supported by kernel */
|
||||
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (read(fd, &value, 1) != 1) {
|
||||
DBG("Error %d in read(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (value == 'Y')
|
||||
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP;
|
||||
else if (value == 'N')
|
||||
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3;
|
||||
else
|
||||
DBG("Unexpected sysfs file contents");
|
||||
|
||||
done:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (sysfs_path)
|
||||
g_free(sysfs_path);
|
||||
|
||||
if (interface)
|
||||
g_free(interface);
|
||||
|
||||
return expected;
|
||||
}
|
||||
|
||||
bool qmi_device_set_expected_data_format(struct qmi_device *device,
|
||||
enum qmi_device_expected_data_format format)
|
||||
{
|
||||
bool res = false;
|
||||
char *sysfs_path = NULL;
|
||||
char *interface = NULL;
|
||||
int fd = -1;
|
||||
char value;
|
||||
|
||||
if (!device)
|
||||
goto done;
|
||||
|
||||
switch (format) {
|
||||
case QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3:
|
||||
value = 'N';
|
||||
break;
|
||||
case QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP:
|
||||
value = 'Y';
|
||||
break;
|
||||
default:
|
||||
DBG("Unhandled format: %d", (int) format);
|
||||
goto done;
|
||||
}
|
||||
|
||||
interface = get_device_interface(device);
|
||||
|
||||
if (!interface) {
|
||||
DBG("Error while getting interface name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Build sysfs file path and open it */
|
||||
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||
|
||||
fd = open(sysfs_path, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
/* maybe not supported by kernel */
|
||||
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (write(fd, &value, 1) != 1) {
|
||||
DBG("Error %d in write(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
res = true;
|
||||
|
||||
done:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (sysfs_path)
|
||||
g_free(sysfs_path);
|
||||
|
||||
if (interface)
|
||||
g_free(interface);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct qmi_param *qmi_param_new(void)
|
||||
{
|
||||
struct qmi_param *param;
|
||||
@@ -1501,6 +1757,7 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
}
|
||||
|
||||
struct service_create_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
bool shared;
|
||||
uint8_t type;
|
||||
@@ -1512,16 +1769,29 @@ struct service_create_data {
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static gboolean service_create_reply(gpointer user_data)
|
||||
static void service_create_data_free(gpointer user_data)
|
||||
{
|
||||
struct service_create_data *data = user_data;
|
||||
|
||||
data->func(NULL, data->user_data);
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static gboolean service_create_reply(gpointer user_data)
|
||||
{
|
||||
struct service_create_data *data = user_data;
|
||||
|
||||
data->timeout = 0;
|
||||
data->func(NULL, data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1537,8 +1807,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
||||
uint16_t len;
|
||||
unsigned int hash_id;
|
||||
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
result_code = tlv_get(buffer, length, 0x02, &len);
|
||||
if (!result_code)
|
||||
goto done;
|
||||
@@ -1580,13 +1848,9 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
||||
|
||||
done:
|
||||
data->func(service, data->user_data);
|
||||
|
||||
qmi_service_unref(service);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
|
||||
static void service_create_discover(uint8_t count,
|
||||
@@ -1617,7 +1881,9 @@ static void service_create_discover(uint8_t count,
|
||||
if (data->timeout > 0)
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
g_timeout_add_seconds(0, service_create_reply, data);
|
||||
data->timeout = g_timeout_add_seconds(0,
|
||||
service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1640,6 +1906,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = service_create_data_free;
|
||||
data->device = device;
|
||||
data->shared = shared;
|
||||
data->type = type;
|
||||
@@ -1662,6 +1929,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
||||
|
||||
done:
|
||||
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1680,17 +1948,23 @@ bool qmi_service_create(struct qmi_device *device,
|
||||
}
|
||||
|
||||
struct service_create_shared_data {
|
||||
struct discovery super;
|
||||
struct qmi_service *service;
|
||||
struct qmi_device *device;
|
||||
qmi_create_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static gboolean service_create_shared_reply(gpointer user_data)
|
||||
static void service_create_shared_data_free(gpointer user_data)
|
||||
{
|
||||
struct service_create_shared_data *data = user_data;
|
||||
|
||||
data->func(data->service, data->user_data);
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
qmi_service_unref(data->service);
|
||||
|
||||
@@ -1698,6 +1972,16 @@ static gboolean service_create_shared_reply(gpointer user_data)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static gboolean service_create_shared_reply(gpointer user_data)
|
||||
{
|
||||
struct service_create_shared_data *data = user_data;
|
||||
|
||||
data->timeout = 0;
|
||||
data->func(data->service, data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1724,13 +2008,16 @@ bool qmi_service_create_shared(struct qmi_device *device,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = service_create_shared_data_free;
|
||||
data->service = qmi_service_ref(service);
|
||||
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
g_timeout_add(0, service_create_shared_reply, data);
|
||||
data->timeout = g_timeout_add(0,
|
||||
service_create_shared_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,18 +35,32 @@
|
||||
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
|
||||
#define QMI_SERVICE_UIM 11 /* UIM service */
|
||||
#define QMI_SERVICE_PBM 12 /* Phonebook service */
|
||||
#define QMI_SERVICE_QCHAT 13
|
||||
#define QMI_SERVICE_RMTFS 14 /* Remote file system service */
|
||||
#define QMI_SERVICE_TEST 15
|
||||
#define QMI_SERVICE_LOC 16 /* Location service */
|
||||
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
|
||||
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
|
||||
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
|
||||
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
|
||||
#define QMI_SERVICE_TMD 24 /* Thermal mitigation device service */
|
||||
#define QMI_SERVICE_WDA 26 /* Wireless data administrative service */
|
||||
#define QMI_SERVICE_CSVT 29
|
||||
#define QMI_SERVICE_COEX 34
|
||||
#define QMI_SERVICE_PDC 36 /* Persistent device configuration service */
|
||||
#define QMI_SERVICE_RFRPE 41
|
||||
#define QMI_SERVICE_DSD 42
|
||||
#define QMI_SERVICE_SSCTL 43
|
||||
#define QMI_SERVICE_CAT_OLD 224 /* Card application toolkit service */
|
||||
#define QMI_SERVICE_RMS 225 /* Remote management service */
|
||||
#define QMI_SERVICE_OMA 226 /* OMA device management service */
|
||||
|
||||
enum qmi_device_expected_data_format {
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
|
||||
};
|
||||
|
||||
struct qmi_version {
|
||||
uint8_t type;
|
||||
uint16_t major;
|
||||
@@ -82,6 +96,10 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy);
|
||||
|
||||
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
|
||||
struct qmi_device *device);
|
||||
bool qmi_device_set_expected_data_format(struct qmi_device *device,
|
||||
enum qmi_device_expected_data_format format);
|
||||
|
||||
struct qmi_param;
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, rs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "dms.h"
|
||||
#include "uim.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
@@ -38,15 +39,36 @@
|
||||
#define EF_STATUS_INVALIDATED 0
|
||||
#define EF_STATUS_VALID 1
|
||||
|
||||
struct sim_data {
|
||||
struct qmi_service *uim;
|
||||
uint32_t event_mask;
|
||||
/* max number of retry of commands that can temporary fail */
|
||||
#define MAX_RETRY_COUNT 100
|
||||
|
||||
enum get_card_status_result {
|
||||
GET_CARD_STATUS_RESULT_OK, /* No error */
|
||||
GET_CARD_STATUS_RESULT_ERROR, /* Definitive error */
|
||||
GET_CARD_STATUS_RESULT_TEMP_ERROR, /* error, a retry could work */
|
||||
};
|
||||
|
||||
/* information from QMI_UIM_GET_CARD_STATUS command */
|
||||
struct sim_status {
|
||||
uint8_t card_state;
|
||||
uint8_t app_type;
|
||||
uint8_t passwd_state;
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
};
|
||||
|
||||
struct sim_data {
|
||||
struct qmi_device *qmi_dev;
|
||||
struct qmi_service *dms;
|
||||
struct qmi_service *uim;
|
||||
uint32_t event_mask;
|
||||
uint8_t app_type;
|
||||
uint32_t retry_count;
|
||||
guint poll_source;
|
||||
};
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data);
|
||||
|
||||
static int create_fileid_data(uint8_t app_type, int fileid,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
@@ -146,7 +168,7 @@ static void qmi_read_attributes(struct ofono_sim *sim, int fileid,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
struct qmi_param *param;
|
||||
@@ -211,7 +233,7 @@ static void qmi_read_transparent(struct ofono_sim *sim,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char read_data[4];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
@@ -257,7 +279,7 @@ static void qmi_read_record(struct ofono_sim *sim,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char read_data[4];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
@@ -295,76 +317,96 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
||||
static void get_imsi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_imsi_cb_t cb = cbd->cb;
|
||||
char *str;
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
DBG("");
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_data);
|
||||
}
|
||||
|
||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMSI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data->retries, user_data);
|
||||
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
|
||||
|
||||
qmi_free(str);
|
||||
}
|
||||
|
||||
static void card_setup(const struct qmi_uim_slot_info *slot,
|
||||
static void qmi_read_imsi(struct ofono_sim *sim,
|
||||
ofono_sim_imsi_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);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->dms, QMI_DMS_GET_IMSI, NULL,
|
||||
get_imsi_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
/* Return true if a retry could give another (better) result */
|
||||
static bool get_card_status(const struct qmi_uim_slot_info *slot,
|
||||
const struct qmi_uim_app_info1 *info1,
|
||||
const struct qmi_uim_app_info2 *info2,
|
||||
struct sim_data *data)
|
||||
struct sim_status *sim_stat)
|
||||
{
|
||||
data->card_state = slot->card_state;
|
||||
data->app_type = info1->app_type;
|
||||
bool need_retry = false;
|
||||
sim_stat->card_state = slot->card_state;
|
||||
sim_stat->app_type = info1->app_type;
|
||||
|
||||
switch (info1->app_state) {
|
||||
case 0x02: /* PIN1 or UPIN is required */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
||||
break;
|
||||
case 0x03: /* PUK1 or PUK for UPIN is required */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
break;
|
||||
case 0x04: /* Personalization state must be checked. */
|
||||
/* This is temporary, we could retry and get another result */
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
need_retry = true;
|
||||
break;
|
||||
case 0x07: /* Ready */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||
break;
|
||||
default:
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
DBG("info1->app_state:0x%x: OFONO_SIM_PASSWORD_INVALID",
|
||||
info1->app_state);
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
||||
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
||||
|
||||
return need_retry;
|
||||
}
|
||||
|
||||
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
static enum get_card_status_result handle_get_card_status_result(
|
||||
struct qmi_result *result, struct sim_status *sim_stat)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
const void *ptr;
|
||||
const struct qmi_uim_card_status *status;
|
||||
uint16_t len, offset;
|
||||
uint8_t i;
|
||||
|
||||
DBG("");
|
||||
enum get_card_status_result res = GET_CARD_STATUS_RESULT_ERROR;
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
@@ -397,15 +439,211 @@ static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
index = GUINT16_FROM_LE(status->index_gw_pri);
|
||||
|
||||
if ((index & 0xff) == i && (index >> 8) == n)
|
||||
card_setup(slot, info1, info2, data);
|
||||
if ((index & 0xff) == i && (index >> 8) == n) {
|
||||
if (get_card_status(slot, info1, info2,
|
||||
sim_stat))
|
||||
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
|
||||
else
|
||||
res = GET_CARD_STATUS_RESULT_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean query_passwd_state_retry(gpointer userdata)
|
||||
{
|
||||
struct cb_data *cbd = userdata;
|
||||
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
|
||||
data->poll_source = 0;
|
||||
|
||||
qmi_query_passwd_state(sim, cb, cbd->data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void query_passwd_state_cb(struct qmi_result *result,
|
||||
void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct sim_status sim_stat;
|
||||
enum get_card_status_result res;
|
||||
struct cb_data *retry_cbd;
|
||||
|
||||
res = handle_get_card_status_result(result, &sim_stat);
|
||||
switch (res) {
|
||||
case GET_CARD_STATUS_RESULT_OK:
|
||||
DBG("passwd state %d", sim_stat.passwd_state);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
|
||||
break;
|
||||
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
|
||||
data->retry_count++;
|
||||
if (data->retry_count > MAX_RETRY_COUNT) {
|
||||
DBG("Failed after %d attempts", data->retry_count);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
} else {
|
||||
DBG("Retry command");
|
||||
retry_cbd = cb_data_new(cb, cbd->data);
|
||||
retry_cbd->user = sim;
|
||||
data->poll_source = g_timeout_add(20,
|
||||
query_passwd_state_retry,
|
||||
retry_cbd);
|
||||
}
|
||||
break;
|
||||
case GET_CARD_STATUS_RESULT_ERROR:
|
||||
DBG("Command failed");
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_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);
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = sim;
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||
query_passwd_state_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
struct sim_status sim_stat;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||
GET_CARD_STATUS_RESULT_OK) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.retries, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_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);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||
query_pin_retries_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void pin_send_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_lock_unlock_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_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
ofono_sim_lock_unlock_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);
|
||||
int passwd_len;
|
||||
struct qmi_param *param;
|
||||
struct qmi_uim_param_message_info *info_data;
|
||||
unsigned char session_info_data[2];
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!passwd)
|
||||
goto error;
|
||||
|
||||
passwd_len = strlen(passwd);
|
||||
|
||||
if (passwd_len <= 0 || passwd_len > 0xFF)
|
||||
goto error;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* param info */
|
||||
info_data = alloca(2 + passwd_len);
|
||||
info_data->pin_id = 0x01; /* PIN 1 */
|
||||
info_data->length = (uint8_t) passwd_len;
|
||||
memcpy(info_data->pin_value, passwd, passwd_len);
|
||||
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_INFO, 2 + passwd_len,
|
||||
info_data);
|
||||
/* param Session Information */
|
||||
session_info_data[0] = 0x6;
|
||||
session_info_data[1] = 0x0;
|
||||
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_SESSION_INFO, 2,
|
||||
session_info_data);
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_VERIFY_PIN, param,
|
||||
pin_send_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct sim_status sim_stat;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||
GET_CARD_STATUS_RESULT_OK) {
|
||||
data->app_type = 0; /* Unknown */
|
||||
sim_stat.card_state = 0x00; /* Absent */
|
||||
} else {
|
||||
data->app_type = sim_stat.app_type;
|
||||
}
|
||||
|
||||
ofono_sim_register(sim);
|
||||
|
||||
switch (data->card_state) {
|
||||
switch (sim_stat.card_state) {
|
||||
case 0x00: /* Absent */
|
||||
case 0x02: /* Error */
|
||||
break;
|
||||
@@ -465,30 +703,44 @@ static void create_uim_cb(struct qmi_service *service, void *user_data)
|
||||
return;
|
||||
|
||||
error:
|
||||
qmi_service_unref(data->uim);
|
||||
|
||||
ofono_sim_remove(sim);
|
||||
}
|
||||
|
||||
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request DMS service");
|
||||
ofono_sim_remove(sim);
|
||||
return;
|
||||
}
|
||||
|
||||
data->dms = qmi_service_ref(service);
|
||||
|
||||
qmi_service_create(data->qmi_dev, QMI_SERVICE_UIM, create_uim_cb, sim,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int qmi_sim_probe(struct ofono_sim *sim,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
struct qmi_device *device = user_data;
|
||||
struct sim_data *data;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
data = g_new0(struct sim_data, 1);
|
||||
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
data->retries[i] = -1;
|
||||
data->qmi_dev = device;
|
||||
|
||||
ofono_sim_set_data(sim, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_UIM, create_uim_cb, sim, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||
create_dms_cb, sim, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -501,9 +753,18 @@ static void qmi_sim_remove(struct ofono_sim *sim)
|
||||
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->uim);
|
||||
if (data->poll_source > 0)
|
||||
g_source_remove(data->poll_source);
|
||||
|
||||
qmi_service_unref(data->uim);
|
||||
if (data->uim) {
|
||||
qmi_service_unregister_all(data->uim);
|
||||
qmi_service_unref(data->uim);
|
||||
data->uim = NULL;
|
||||
}
|
||||
if (data->dms) {
|
||||
qmi_service_unregister_all(data->dms);
|
||||
qmi_service_unref(data->dms);
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
@@ -516,8 +777,10 @@ static struct ofono_sim_driver driver = {
|
||||
.read_file_transparent = qmi_read_transparent,
|
||||
.read_file_linear = qmi_read_record,
|
||||
.read_file_cyclic = qmi_read_record,
|
||||
.read_imsi = qmi_read_imsi,
|
||||
.query_passwd_state = qmi_query_passwd_state,
|
||||
.query_pin_retries = qmi_query_pin_retries,
|
||||
.send_passwd = qmi_pin_send,
|
||||
};
|
||||
|
||||
void qmi_sim_init(void)
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
|
||||
#define QMI_UIM_GET_FILE_ATTRIBUTES 36 /* Get file attributes */
|
||||
|
||||
#define QMI_UIM_VERIFY_PIN 38 /* Verify PIN */
|
||||
|
||||
#define QMI_UIM_EVENT_REGISTRATION 46 /* Register for indications */
|
||||
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
|
||||
|
||||
@@ -91,3 +93,12 @@ struct qmi_uim_file_attributes {
|
||||
uint16_t raw_len;
|
||||
uint8_t raw_value[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Verify PIN parameter */
|
||||
#define QMI_UIM_PARAM_MESSAGE_SESSION_INFO 0x01
|
||||
#define QMI_UIM_PARAM_MESSAGE_INFO 0x02
|
||||
struct qmi_uim_param_message_info {
|
||||
uint8_t pin_id;
|
||||
uint8_t length;
|
||||
uint8_t pin_value[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
25
ofono/drivers/qmimodem/wda.h
Normal file
25
ofono/drivers/qmimodem/wda.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Kerlink SA. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define QMI_WDA_SET_DATA_FORMAT 32 /* Set data format */
|
||||
#define QMI_WDA_GET_DATA_FORMAT 33 /* Get data format */
|
||||
|
||||
/* Get and set data format interface */
|
||||
#define QMI_WDA_LL_PROTOCOL 0x11 /* uint32_t */
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_UNKNOWN 0
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_802_3 1
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP 2
|
||||
@@ -30,6 +30,13 @@
|
||||
/* Start WDS network interface */
|
||||
#define QMI_WDS_PARAM_APN 0x14 /* string */
|
||||
#define QMI_WDS_PARAM_IP_FAMILY 0x19 /* uint8 */
|
||||
#define QMI_WDS_PARAM_USERNAME 0x17 /* string */
|
||||
#define QMI_WDS_PARAM_PASSWORD 0x18 /* string */
|
||||
#define QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE 0x16 /* uint8 */
|
||||
|
||||
#define QMI_WDS_AUTHENTICATION_NONE 0x0
|
||||
#define QMI_WDS_AUTHENTICATION_PAP 0x1
|
||||
#define QMI_WDS_AUTHENTICATION_CHAP 0x2
|
||||
|
||||
#define QMI_WDS_RESULT_PKT_HANDLE 0x01 /* uint32 */
|
||||
|
||||
@@ -51,10 +58,12 @@ struct qmi_wds_notify_conn_status {
|
||||
|
||||
/* Get the runtime data session settings */
|
||||
#define QMI_WDS_RESULT_PDP_TYPE 0x11 /* uint8 */
|
||||
#define QMI_WDS_RESULT_APN 0x14 /* string */
|
||||
#define QMI_WDS_RESULT_PRIMARY_DNS 0x15 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_GATEWAY 0x20 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_GATEWAY_NETMASK 0x21 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_IP_FAMILY 0x2b /* uint8 */
|
||||
|
||||
#define QMI_WDS_PDP_TYPE_IPV4 0x00
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
|
||||
struct ril_cell_info_priv {
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct sailfish_cell_info info;
|
||||
GRilIoChannel *io;
|
||||
MceDisplay *display;
|
||||
struct ril_radio *radio;
|
||||
@@ -60,63 +62,22 @@ G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
static inline void ril_cell_free(struct sailfish_cell *cell)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
if (c1->type != c2->type) {
|
||||
return c1->type - c2->type;
|
||||
} else if (c1->type == RIL_CELL_INFO_TYPE_GSM) {
|
||||
const struct ril_cell_info_gsm *g1 = &c1->info.gsm;
|
||||
const struct ril_cell_info_gsm *g2 = &c2->info.gsm;
|
||||
|
||||
if (g1->lac != g2->lac) {
|
||||
return g1->lac - g2->lac;
|
||||
} else {
|
||||
return g1->cid - g2->cid;
|
||||
}
|
||||
} else if (c2->type == RIL_CELL_INFO_TYPE_WCDMA) {
|
||||
const struct ril_cell_info_wcdma *w1 = &c1->info.wcdma;
|
||||
const struct ril_cell_info_wcdma *w2 = &c2->info.wcdma;
|
||||
|
||||
if (w1->lac != w2->lac) {
|
||||
return w1->lac - w2->lac;
|
||||
} else {
|
||||
return w1->cid - w2->cid;
|
||||
}
|
||||
} else {
|
||||
const struct ril_cell_info_lte *l1 = &c1->info.lte;
|
||||
const struct ril_cell_info_lte *l2 = &c2->info.lte;
|
||||
|
||||
GASSERT(c1->type == RIL_CELL_INFO_TYPE_LTE);
|
||||
if (l1->ci != l2->ci) {
|
||||
return l1->ci - l2->ci;
|
||||
} else if (l1->pci != l2->pci) {
|
||||
return l1->pci - l2->pci;
|
||||
} else {
|
||||
return l1->tac - l2->tac;
|
||||
}
|
||||
}
|
||||
} else if (c1) {
|
||||
return 1;
|
||||
} else if (c2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
g_slice_free(struct sailfish_cell, cell);
|
||||
}
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
static void ril_cell_free1(gpointer cell)
|
||||
{
|
||||
return ril_cell_compare_location(v1, v2);
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
@@ -127,21 +88,21 @@ static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
|
||||
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||
{
|
||||
if (!ril_cell_info_list_identical(self->cells, l)) {
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
self->cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals[
|
||||
SIGNAL_CELLS_CHANGED], 0);
|
||||
if (!ril_cell_info_list_identical(self->info.cells, l)) {
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
self->info.cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals
|
||||
[SIGNAL_CELLS_CHANGED], 0);
|
||||
} else {
|
||||
g_slist_free_full(l, g_free);
|
||||
g_slist_free_full(l, ril_cell_free1);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = INT_MAX;
|
||||
@@ -166,21 +127,21 @@ static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
|
||||
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
|
||||
gsm->timingAdvance);
|
||||
cell->type = RIL_CELL_INFO_TYPE_GSM;
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = INT_MAX;
|
||||
@@ -197,21 +158,21 @@ static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
"strength=%d,err=%d", registered, wcdma->mcc,
|
||||
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
|
||||
wcdma->signalStrength, wcdma->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_WCDMA;
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_lte *lte = &cell->info.lte;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = INT_MAX;
|
||||
@@ -233,18 +194,18 @@ static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
cell->type = RIL_CELL_INFO_TYPE_LTE;
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
|
||||
struct ril_cell **cell_ptr)
|
||||
struct sailfish_cell **cell_ptr)
|
||||
{
|
||||
int type, reg;
|
||||
|
||||
@@ -253,7 +214,7 @@ static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
|
||||
/* Skip timestamp */
|
||||
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||
int skip = 0;
|
||||
struct ril_cell *cell = NULL;
|
||||
struct sailfish_cell *cell = NULL;
|
||||
|
||||
/* Normalize the boolean value */
|
||||
reg = (reg != FALSE);
|
||||
@@ -302,13 +263,13 @@ static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct ril_cell *c;
|
||||
struct sailfish_cell *c;
|
||||
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
|
||||
if (c) {
|
||||
l = g_slist_insert_sorted(l, c,
|
||||
ril_cell_compare_func);
|
||||
sailfish_cell_compare_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,11 +292,10 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
}
|
||||
@@ -344,21 +304,19 @@ static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->set_rate_id);
|
||||
priv->set_rate_id = 0;
|
||||
GASSERT(self->set_rate_id);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = grilio_channel_send_request_full(priv->io, req,
|
||||
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,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -366,14 +324,13 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id, FALSE);
|
||||
priv->set_rate_id = grilio_channel_send_request_full(priv->io, req,
|
||||
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,
|
||||
ril_cell_info_set_rate_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -381,29 +338,24 @@ 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)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
ril_cell_info_set_rate(self,
|
||||
(priv->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||
(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);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_card_ready) {
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
|
||||
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
@@ -421,124 +373,160 @@ 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);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
const gboolean sim_card_was_ready = priv->sim_card_ready;
|
||||
const gboolean sim_card_was_ready = self->sim_card_ready;
|
||||
|
||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (priv->sim_card_ready != sim_card_was_ready) {
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (self->sim_card_ready != sim_card_was_ready) {
|
||||
ril_cell_info_refresh(self);
|
||||
if (priv->sim_card_ready) {
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
|
||||
ril_cell_info_cb_t cb, void *arg)
|
||||
/* sailfish_cell_info interface callbacks */
|
||||
|
||||
struct ril_cell_info_signal_data {
|
||||
sailfish_cell_info_cb_t cb;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static inline struct ril_cell_info *ril_cell_info_cast
|
||||
(struct sailfish_cell_info *info)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
return G_CAST(info, struct ril_cell_info, info);
|
||||
}
|
||||
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
|
||||
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
g_object_ref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
|
||||
{
|
||||
g_object_unref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_cell_info_signal_data *data = user_data;
|
||||
|
||||
data->cb(&self->info, data->arg);
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_disconnect_notify(gpointer data,
|
||||
GClosure *closure)
|
||||
{
|
||||
g_slice_free1(sizeof(struct ril_cell_info_signal_data), data);
|
||||
}
|
||||
|
||||
static gulong ril_cell_info_add_cells_changed_handler_proc
|
||||
(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
if (cb) {
|
||||
struct ril_cell_info_signal_data *data =
|
||||
g_slice_new(struct ril_cell_info_signal_data);
|
||||
|
||||
data->cb = cb;
|
||||
data->arg = arg;
|
||||
return g_signal_connect_data(ril_cell_info_cast(info),
|
||||
SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_CALLBACK(ril_cell_info_cells_changed_cb),
|
||||
data, ril_cell_info_cells_disconnect_notify,
|
||||
G_CONNECT_AFTER);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
|
||||
gulong id)
|
||||
{
|
||||
if (G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, MceDisplay *display,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card)
|
||||
{
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
|
||||
ril_cell_info_ref_proc,
|
||||
ril_cell_info_unref_proc,
|
||||
ril_cell_info_add_cells_changed_handler_proc,
|
||||
ril_cell_info_remove_handler_proc
|
||||
};
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->display = mce_display_ref(display);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
|
||||
self->info.proc = &ril_cell_info_proc;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->display = mce_display_ref(display);
|
||||
self->radio = ril_radio_ref(radio);
|
||||
self->sim_card = ril_sim_card_ref(sim_card);
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
priv->display_state_event_id =
|
||||
self->display_state_event_id =
|
||||
mce_display_add_state_changed_handler(display,
|
||||
ril_cell_info_display_state_cb, self);
|
||||
priv->radio_state_event_id =
|
||||
self->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(radio,
|
||||
ril_cell_info_radio_state_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
self->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
if (priv->sim_card_ready) {
|
||||
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);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_CELL_INFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_unref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_CELL_INFO(self));
|
||||
}
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_CELL_INFO_TYPE,
|
||||
struct ril_cell_info_priv);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, &priv->event_id, 1);
|
||||
if (priv->query_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = 0;
|
||||
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
|
||||
if (self->query_id) {
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = 0;
|
||||
}
|
||||
if (priv->set_rate_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
|
||||
if (self->set_rate_id) {
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id,
|
||||
FALSE);
|
||||
priv->set_rate_id = 0;
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
gutil_disconnect_handlers(priv->display,
|
||||
&priv->display_state_event_id, 1);
|
||||
ril_radio_remove_handlers(priv->radio, &priv->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(priv->sim_card,
|
||||
&priv->sim_status_event_id, 1);
|
||||
gutil_disconnect_handlers(self->display,
|
||||
&self->display_state_event_id, 1);
|
||||
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(self->sim_card,
|
||||
&self->sim_status_event_id, 1);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
mce_display_unref(priv->display);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
g_free(self->log_prefix);
|
||||
grilio_channel_unref(self->io);
|
||||
mce_display_unref(self->display);
|
||||
ril_radio_unref(self->radio);
|
||||
ril_sim_card_unref(self->sim_card);
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
@@ -548,7 +536,6 @@ static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_cell_info_priv));
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,40 +18,11 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
#include <mce_display.h>
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
struct ril_cell {
|
||||
enum ril_cell_info_type type;
|
||||
gboolean registered;
|
||||
union {
|
||||
struct ril_cell_info_gsm gsm;
|
||||
struct ril_cell_info_wcdma wcdma;
|
||||
struct ril_cell_info_lte lte;
|
||||
} info;
|
||||
};
|
||||
|
||||
struct ril_cell_info_priv;
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct ril_cell_info_priv *priv;
|
||||
GSList *cells;
|
||||
};
|
||||
|
||||
typedef void (*ril_cell_info_cb_t)(struct ril_cell_info *info, void *arg);
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2);
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2);
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, MceDisplay *display,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card);
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *info);
|
||||
void ril_cell_info_unref(struct ril_cell_info *info);
|
||||
struct ril_cell *ril_cell_find_cell(struct ril_cell_info *info,
|
||||
const struct ril_cell *cell);
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *info,
|
||||
ril_cell_info_cb_t cb, void *arg);
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *info, gulong id);
|
||||
|
||||
#endif /* RIL_CELL_INFO_H */
|
||||
|
||||
|
||||
@@ -1,587 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_cell_info.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
struct ril_cell_entry {
|
||||
guint cell_id;
|
||||
char *path;
|
||||
struct ril_cell cell;
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus {
|
||||
struct ril_cell_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
};
|
||||
|
||||
#define RIL_CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
|
||||
#define RIL_CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define RIL_CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
#define RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
|
||||
#define RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define RIL_CELL_DBUS_REMOVED_SIGNAL "Removed"
|
||||
|
||||
struct ril_cell_property {
|
||||
const char *name;
|
||||
glong off;
|
||||
int flag;
|
||||
};
|
||||
|
||||
#define RIL_CELL_GSM_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_gsm,name), value }
|
||||
#define RIL_CELL_WCDMA_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_wcdma,name), value }
|
||||
#define RIL_CELL_LTE_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_lte,name), value }
|
||||
|
||||
static const struct ril_cell_property ril_cell_gsm_properties [] = {
|
||||
RIL_CELL_GSM_PROPERTY(0x001,mcc),
|
||||
RIL_CELL_GSM_PROPERTY(0x002,mnc),
|
||||
RIL_CELL_GSM_PROPERTY(0x004,lac),
|
||||
RIL_CELL_GSM_PROPERTY(0x008,cid),
|
||||
RIL_CELL_GSM_PROPERTY(0x010,arfcn),
|
||||
RIL_CELL_GSM_PROPERTY(0x020,bsic),
|
||||
RIL_CELL_GSM_PROPERTY(0x040,signalStrength),
|
||||
RIL_CELL_GSM_PROPERTY(0x080,bitErrorRate),
|
||||
RIL_CELL_GSM_PROPERTY(0x100,timingAdvance)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_wcdma_properties [] = {
|
||||
RIL_CELL_WCDMA_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x04,lac),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x08,cid),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x10,psc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x20,uarfcn),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x40,signalStrength),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x80,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_lte_properties [] = {
|
||||
RIL_CELL_LTE_PROPERTY(0x001,mcc),
|
||||
RIL_CELL_LTE_PROPERTY(0x002,mnc),
|
||||
RIL_CELL_LTE_PROPERTY(0x004,ci),
|
||||
RIL_CELL_LTE_PROPERTY(0x008,pci),
|
||||
RIL_CELL_LTE_PROPERTY(0x010,tac),
|
||||
RIL_CELL_LTE_PROPERTY(0x020,earfcn),
|
||||
RIL_CELL_LTE_PROPERTY(0x040,signalStrength),
|
||||
RIL_CELL_LTE_PROPERTY(0x080,rsrp),
|
||||
RIL_CELL_LTE_PROPERTY(0x100,rsrq),
|
||||
RIL_CELL_LTE_PROPERTY(0x200,rssnr),
|
||||
RIL_CELL_LTE_PROPERTY(0x400,cqi),
|
||||
RIL_CELL_LTE_PROPERTY(0x800,timingAdvance)
|
||||
};
|
||||
|
||||
#define RIL_CELL_PROPERTY_REGISTERED 0x1000
|
||||
|
||||
typedef void (*ril_cell_info_dbus_append_fn)(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry);
|
||||
|
||||
static const char *ril_cell_info_dbus_cell_type_str(enum ril_cell_info_type t)
|
||||
{
|
||||
switch (t) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
return "gsm";
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
return "cdma";
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
return "lte";
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
return "wcdma";
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
return "tdscdma";
|
||||
case RIL_CELL_INFO_TYPE_NONE:
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ril_cell_property *ril_cell_info_dbus_cell_properties(
|
||||
enum ril_cell_info_type type, int *count)
|
||||
{
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
*count = G_N_ELEMENTS(ril_cell_gsm_properties);
|
||||
return ril_cell_gsm_properties;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
*count = G_N_ELEMENTS(ril_cell_wcdma_properties);
|
||||
return ril_cell_wcdma_properties;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
*count = G_N_ELEMENTS(ril_cell_lte_properties);
|
||||
return ril_cell_lte_properties;
|
||||
default:
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static void ril_cell_info_destroy_entry(struct ril_cell_entry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
g_free(entry->path);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_reply(DBusMessage *msg,
|
||||
const struct ril_cell_entry *entry,
|
||||
ril_cell_info_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
append(&it, entry);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_version(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_int32_t version = RIL_CELL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
const char *type = ril_cell_info_dbus_cell_type_str(entry->cell.type);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
int i, n;
|
||||
DBusMessageIter dict;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
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) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_close_container(it, &dict);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_all(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
ril_cell_info_dbus_append_version(it, entry);
|
||||
ril_cell_info_dbus_append_type(it, entry);
|
||||
ril_cell_info_dbus_append_registered(it, entry);
|
||||
ril_cell_info_dbus_append_properties(it, entry);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_type(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_type);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_registered(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_registered);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_properties(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_properties);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_cell_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll", NULL,
|
||||
GDBUS_ARGS({ "version", "i" },
|
||||
{ "type", "s" },
|
||||
{ "registered", "b" },
|
||||
{ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
|
||||
GDBUS_ARGS({ "version", "i" }),
|
||||
ril_cell_info_dbus_cell_get_version) },
|
||||
{ GDBUS_METHOD("GetType", NULL,
|
||||
GDBUS_ARGS({ "type", "s" }),
|
||||
ril_cell_info_dbus_cell_get_type) },
|
||||
{ GDBUS_METHOD("GetRegistered", NULL,
|
||||
GDBUS_ARGS({ "registered", "b" }),
|
||||
ril_cell_info_dbus_cell_get_registered) },
|
||||
{ GDBUS_METHOD("GetProperties", NULL,
|
||||
GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_properties) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_cell_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "registered", "b" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_id(
|
||||
struct ril_cell_info_dbus *dbus, guint id)
|
||||
{
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (entry->cell_id == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint ril_cell_info_dbus_next_cell_id(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
while (ril_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
|
||||
dbus->next_cell_id++;
|
||||
}
|
||||
return dbus->next_cell_id++;
|
||||
}
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_cell(
|
||||
struct ril_cell_info_dbus *dbus, const struct ril_cell *cell)
|
||||
{
|
||||
if (cell) {
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!ril_cell_compare_location(&entry->cell, cell)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_emit_path_list(struct ril_cell_info_dbus *dbus,
|
||||
const char *name, GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static int ril_cell_info_dbus_compare(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
{
|
||||
if (c1->type == c2->type) {
|
||||
int i, n, mask = 0;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(c1->type, &n);
|
||||
|
||||
if (c1->registered != c2->registered) {
|
||||
mask |= RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const glong offset = prop[i].off;
|
||||
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
|
||||
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
|
||||
if (v1 != v2) {
|
||||
mask |= prop[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_property_changed(struct ril_cell_info_dbus *dbus,
|
||||
const struct ril_cell_entry *entry, int mask)
|
||||
{
|
||||
int i, n;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & RIL_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
mask &= ~RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, RIL_CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_update_entries(struct ril_cell_info_dbus *dbus,
|
||||
gboolean emit_signals)
|
||||
{
|
||||
GSList *l;
|
||||
GPtrArray* added = NULL;
|
||||
GPtrArray* removed = NULL;
|
||||
|
||||
/* Remove non-existent cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
|
||||
ril_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
if (emit_signals) {
|
||||
if (!removed) {
|
||||
removed =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_free);
|
||||
}
|
||||
/* Steal the path */
|
||||
g_ptr_array_add(removed, entry->path);
|
||||
entry->path = NULL;
|
||||
}
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
|
||||
/* Add new cells */
|
||||
for (l = dbus->info->cells; l; l = l->next) {
|
||||
const struct ril_cell *cell = l->data;
|
||||
struct ril_cell_entry *entry =
|
||||
ril_cell_info_dbus_find_cell(dbus, cell);
|
||||
|
||||
if (entry) {
|
||||
if (emit_signals) {
|
||||
int diff = ril_cell_info_dbus_compare(cell,
|
||||
&entry->cell);
|
||||
entry->cell = *cell;
|
||||
ril_cell_info_dbus_property_changed(dbus,
|
||||
entry, diff);
|
||||
} else {
|
||||
entry->cell = *cell;
|
||||
}
|
||||
} else {
|
||||
entry = g_new0(struct ril_cell_entry, 1);
|
||||
entry->cell = *cell;
|
||||
entry->cell_id = ril_cell_info_dbus_next_cell_id(dbus);
|
||||
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
|
||||
entry->cell_id);
|
||||
dbus->entries = g_slist_append(dbus->entries, entry);
|
||||
DBG("%s added", entry->path);
|
||||
g_dbus_register_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
ril_cell_info_dbus_cell_methods,
|
||||
ril_cell_info_dbus_cell_signals, NULL,
|
||||
entry, NULL);
|
||||
if (emit_signals) {
|
||||
if (!added) {
|
||||
added = g_ptr_array_new();
|
||||
}
|
||||
g_ptr_array_add(added, entry->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
|
||||
g_ptr_array_free(removed, TRUE);
|
||||
}
|
||||
|
||||
if (added) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
|
||||
g_ptr_array_free(added, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_cells_changed_cb(struct ril_cell_info *info,
|
||||
void *arg)
|
||||
{
|
||||
DBG("");
|
||||
ril_cell_info_dbus_update_entries((struct ril_cell_info_dbus *)arg,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct ril_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
ril_cell_info_dbus_get_cells) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = g_new0(struct ril_cell_info_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->info = ril_cell_info_ref(info);
|
||||
dbus->handler_id = ril_cell_info_add_cells_changed_handler(info,
|
||||
ril_cell_info_dbus_cells_changed_cb, dbus);
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, ril_cell_info_dbus_methods,
|
||||
ril_cell_info_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ril_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_cell_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
/* Unregister cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
l = l->next;
|
||||
}
|
||||
g_slist_free(dbus->entries);
|
||||
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
ril_cell_info_remove_handler(dbus->info, dbus->handler_id);
|
||||
ril_cell_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ril_config.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
@@ -190,12 +191,10 @@ GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
GUtilIntArray *array = gutil_int_array_new();
|
||||
|
||||
while (*ptr) {
|
||||
const char *str = *ptr++;
|
||||
char *end = NULL;
|
||||
long ival = strtol(str, &end, 0);
|
||||
int val;
|
||||
|
||||
if (str[0] && !end[0]) {
|
||||
gutil_int_array_append(array, ival);
|
||||
if (ril_parse_int(*ptr++, 0, &val)) {
|
||||
gutil_int_array_append(array, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -395,45 +395,7 @@ enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
struct ril_cell_info_gsm {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
|
||||
int arfcn; /* 16-bit GSM Absolute RF channel number */
|
||||
int bsic; /* 6-bit Base Station Identity Code */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
int timingAdvance; /* Timing Advance. 1 period = 48/13 us */
|
||||
};
|
||||
|
||||
struct ril_cell_info_wcdma {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
|
||||
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
|
||||
int uarfcn; /* 16-bit UMTS Absolute RF Channel Number */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct ril_cell_info_lte {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int ci; /* Cell Identity */
|
||||
int pci; /* Physical cell id (0..503) */
|
||||
int tac; /* Tracking area code */
|
||||
int earfcn; /* 18-bit LTE Absolute RC Channel Number */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
|
||||
int rsrp; /* Reference Signal Receive Power TS 36.133 */
|
||||
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
|
||||
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
|
||||
int cqi; /* Channel Quality Indicator TS 36.101 */
|
||||
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
|
||||
};
|
||||
|
||||
/* RIL Request Messages */
|
||||
/* RIL Request Messages, ofono -> rild */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK 3
|
||||
@@ -568,7 +530,7 @@ struct ril_cell_info_lte {
|
||||
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
|
||||
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
|
||||
|
||||
/* RIL Unsolicited Messages */
|
||||
/* RIL Unsolicited Messages, rild -> ofono */
|
||||
#define RIL_UNSOL_RESPONSE_BASE 1000
|
||||
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
|
||||
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
|
||||
@@ -616,6 +578,9 @@ struct ril_cell_info_lte {
|
||||
#define RIL_UNSOL_ON_SS 1043
|
||||
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
|
||||
|
||||
/* A special request, ofono -> rild */
|
||||
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ struct ril_data_priv {
|
||||
struct ril_network *network;
|
||||
struct ril_data_manager *dm;
|
||||
enum ril_data_priv_flags flags;
|
||||
struct ril_vendor_hook *vendor_hook;
|
||||
|
||||
struct ril_data_request *req_queue;
|
||||
struct ril_data_request *pending_req;
|
||||
@@ -535,11 +536,18 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
struct ril_data *self = RIL_DATA(user_data);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* Only RIL_E_SUCCESS and RIL_E_RADIO_NOT_AVAILABLE are expected here,
|
||||
* all other errors are filtered out by ril_voicecall_clcc_retry()
|
||||
*/
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format));
|
||||
} else {
|
||||
/* RADIO_NOT_AVAILABLE == no calls */
|
||||
ril_data_set_calls(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,6 +1170,18 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_data_poll_call_state_retry(GRilIoRequest* req,
|
||||
int ril_status, const void* resp_data, guint resp_len, void* user_data)
|
||||
{
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_data_poll_call_state(struct ril_data *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
@@ -1171,6 +1191,8 @@ void ril_data_poll_call_state(struct ril_data *self)
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_retry_func(req,
|
||||
ril_data_poll_call_state_retry);
|
||||
priv->query_id =
|
||||
grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_DATA_CALL_LIST,
|
||||
@@ -1227,8 +1249,7 @@ static void ril_data_power_update(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (priv->pending_req || priv->req_queue ||
|
||||
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
|
||||
if (priv->pending_req || priv->req_queue) {
|
||||
ril_radio_power_on(priv->radio, self);
|
||||
} else {
|
||||
ril_radio_power_off(priv->radio, self);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
#include "mtu-watch.h"
|
||||
|
||||
@@ -63,7 +64,7 @@ static char *ril_gprs_context_netmask(const char *bits)
|
||||
const char* str;
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||
((1 << nbits)-1) << (32-nbits));
|
||||
((1u << nbits)-1) << (32-nbits));
|
||||
str = inet_ntoa(in);
|
||||
if (str) {
|
||||
return g_strdup(str);
|
||||
@@ -444,7 +445,7 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
/* Let's make sure that we aren't connecting when roaming not allowed */
|
||||
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
|
||||
if (!ofono_gprs_get_roaming_allowed(gprs) &&
|
||||
if (!__ofono_gprs_get_roaming_allowed(gprs) &&
|
||||
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_error error;
|
||||
|
||||
@@ -308,16 +308,18 @@ static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ril_radio *radio = md->modem.radio;
|
||||
struct ril_modem_online_request *req;
|
||||
|
||||
DBG("%s going %sline", ofono_modem_get_path(modem),
|
||||
online ? "on" : "off");
|
||||
|
||||
ril_radio_set_online(radio, online);
|
||||
if (online) {
|
||||
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_online;
|
||||
} else {
|
||||
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_power_off(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_offline;
|
||||
}
|
||||
|
||||
@@ -390,8 +392,8 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_cell_info_unref(modem->cell_info);
|
||||
ril_data_unref(modem->data);
|
||||
sailfish_cell_info_unref(modem->cell_info);
|
||||
grilio_channel_unref(modem->io);
|
||||
grilio_queue_cancel_all(md->q, FALSE);
|
||||
grilio_queue_unref(md->q);
|
||||
@@ -408,7 +410,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_cell_info *cell_info)
|
||||
struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
struct ofono_modem *ofono = ofono_modem_create(path + 1,
|
||||
@@ -438,7 +440,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
modem->sim_settings = ril_sim_settings_ref(settings);
|
||||
modem->cell_info = ril_cell_info_ref(cell_info);
|
||||
modem->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,15 +14,16 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
struct ril_netmon {
|
||||
struct ofono_netmon *netmon;
|
||||
struct ril_cell_info *cell_info;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
guint register_id;
|
||||
};
|
||||
|
||||
@@ -39,7 +40,7 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
if (mcc >= 0 && mcc <= 999) {
|
||||
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
|
||||
if (mnc >= 0 && mnc <= 999) {
|
||||
const int mnclen = mnclength(mcc, mnc);
|
||||
const unsigned int mnclen = mnclength(mcc, mnc);
|
||||
const char *format[] = { "%d", "%02d", "%03d" };
|
||||
const char *fmt = (mnclen > 0 &&
|
||||
mnclen <= G_N_ELEMENTS(format)) ?
|
||||
@@ -50,7 +51,7 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
const struct ril_cell_info_gsm *gsm)
|
||||
const struct sailfish_cell_info_gsm *gsm)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
@@ -68,7 +69,7 @@ static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
const struct ril_cell_info_wcdma *wcdma)
|
||||
const struct sailfish_cell_info_wcdma *wcdma)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
@@ -87,7 +88,7 @@ static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||
const struct ril_cell_info_lte *lte)
|
||||
const struct sailfish_cell_info_lte *lte)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
@@ -111,19 +112,19 @@ static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
GSList *l;
|
||||
|
||||
for (l = nm->cell_info->cells; l; l = l->next) {
|
||||
const struct ril_cell *cell = l->data;
|
||||
const struct sailfish_cell *cell = l->data;
|
||||
|
||||
if (cell->registered) {
|
||||
switch (cell->type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
ril_netmon_notify_gsm(netmon,
|
||||
&cell->info.gsm);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
ril_netmon_notify_wcdma(netmon,
|
||||
&cell->info.wcdma);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
ril_netmon_notify_lte(netmon,
|
||||
&cell->info.lte);
|
||||
break;
|
||||
@@ -156,7 +157,7 @@ static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
|
||||
if (modem->cell_info) {
|
||||
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
|
||||
|
||||
nm->cell_info = ril_cell_info_ref(modem->cell_info);
|
||||
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
|
||||
nm->netmon = netmon;
|
||||
|
||||
ofono_netmon_set_data(netmon, nm);
|
||||
@@ -182,7 +183,7 @@ static void ril_netmon_remove(struct ofono_netmon *netmon)
|
||||
g_source_remove(nm->register_id);
|
||||
}
|
||||
|
||||
ril_cell_info_unref(nm->cell_info);
|
||||
sailfish_cell_info_unref(nm->cell_info);
|
||||
g_slice_free(struct ril_netmon, nm);
|
||||
}
|
||||
|
||||
|
||||
@@ -499,7 +499,7 @@ 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);
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
DBG("%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
@@ -43,11 +41,6 @@ enum ril_network_timer {
|
||||
TIMER_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_watch_events {
|
||||
WATCH_EVENT_ONLINE,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_radio_event {
|
||||
RADIO_EVENT_STATE_CHANGED,
|
||||
RADIO_EVENT_ONLINE_CHANGED,
|
||||
@@ -65,8 +58,6 @@ struct ril_network_priv {
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct sailfish_watch *watch;
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
int rat;
|
||||
char *log_prefix;
|
||||
guint operator_poll_id;
|
||||
@@ -217,8 +208,14 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
|
||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
||||
if (!ril_parse_int(slac, 16, ®->lac)) {
|
||||
reg->lac = -1;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(sci, 16, ®->ci)) {
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
||||
@@ -487,7 +484,7 @@ static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
return priv->watch->online && ril_sim_card_ready(priv->sim_card);
|
||||
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
|
||||
}
|
||||
|
||||
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
@@ -762,7 +759,7 @@ static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_online_cb(struct sailfish_watch *watch, void *data)
|
||||
static void ril_network_radio_online_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
@@ -825,7 +822,6 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
self->settings = ril_sim_settings_ref(settings);
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->watch = sailfish_watch_new(path);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
@@ -842,9 +838,9 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
|
||||
ril_radio_add_state_changed_handler(priv->radio,
|
||||
ril_network_radio_state_cb, self);
|
||||
priv->watch_event_id[WATCH_EVENT_ONLINE] =
|
||||
sailfish_watch_add_modem_changed_handler(priv->watch,
|
||||
ril_network_online_cb, self);
|
||||
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
|
||||
ril_radio_add_online_changed_handler(priv->radio,
|
||||
ril_network_radio_online_cb, self);
|
||||
priv->settings_event_id =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(settings,
|
||||
ril_network_pref_mode_changed_cb, self);
|
||||
@@ -901,6 +897,7 @@ static void ril_network_finalize(GObject *object)
|
||||
enum ril_network_timer tid;
|
||||
|
||||
DBG_(self, "");
|
||||
|
||||
for (tid=0; tid<TIMER_COUNT; tid++) {
|
||||
ril_network_stop_timer(self, tid);
|
||||
}
|
||||
@@ -911,8 +908,6 @@ static void ril_network_finalize(GObject *object)
|
||||
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
|
||||
sailfish_watch_unref(priv->watch);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_handler(priv->sim_card,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,12 +51,12 @@ struct ril_modem {
|
||||
const char *log_prefix;
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
struct ril_cell_info *cell_info;
|
||||
struct ril_slot_config config;
|
||||
};
|
||||
|
||||
@@ -65,18 +65,13 @@ struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
const char *log_prefix);
|
||||
void ril_oem_raw_free(struct ril_oem_raw *raw);
|
||||
|
||||
struct ril_cell_info_dbus;
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info);
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_cell_info *cell_info);
|
||||
struct sailfish_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
|
||||
|
||||
@@ -50,12 +50,14 @@ struct ril_radio_priv {
|
||||
|
||||
enum ril_radio_signal {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_ONLINE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define POWER_RETRY_SECS (1)
|
||||
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
|
||||
#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
|
||||
|
||||
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
@@ -75,7 +77,8 @@ static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
return !priv->power_cycle && g_hash_table_size(priv->req_table) > 0;
|
||||
return self->online && !priv->power_cycle &&
|
||||
g_hash_table_size(priv->req_table) > 0;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
@@ -280,6 +283,19 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_set_online(struct ril_radio *self, gboolean online)
|
||||
{
|
||||
if (G_LIKELY(self) && self->online != online) {
|
||||
gboolean on, was_on = ril_radio_power_should_be_on(self);
|
||||
self->online = online;
|
||||
on = ril_radio_power_should_be_on(self);
|
||||
if (was_on != on) {
|
||||
ril_radio_power_request(self, on, FALSE);
|
||||
}
|
||||
ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
@@ -287,6 +303,13 @@ gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
|
||||
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
@@ -424,6 +447,7 @@ static void ril_radio_class_init(RilRadioClass *klass)
|
||||
object_class->finalize = ril_radio_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
|
||||
NEW_SIGNAL(klass, STATE);
|
||||
NEW_SIGNAL(klass, ONLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -22,6 +22,7 @@ struct ril_radio {
|
||||
GObject object;
|
||||
struct ril_radio_priv *priv;
|
||||
enum ril_radio_state state;
|
||||
gboolean online;
|
||||
};
|
||||
|
||||
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
|
||||
@@ -34,8 +35,11 @@ void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_cycle(struct ril_radio *radio);
|
||||
void ril_radio_confirm_power_on(struct ril_radio *radio);
|
||||
void ril_radio_set_online(struct ril_radio *radio, gboolean online);
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
|
||||
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
|
||||
|
||||
@@ -221,8 +221,7 @@ static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
||||
|
||||
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
|
||||
{
|
||||
int selected_app = -1;
|
||||
guint i;
|
||||
int i, selected_app = -1;
|
||||
|
||||
for (i = 0; i < status->num_apps; i++) {
|
||||
const int type = status->apps[i].app_type;
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_SIM_INFO_H
|
||||
#define RIL_SIM_INFO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_sim_info {
|
||||
GObject object;
|
||||
struct ril_sim_info_priv *priv;
|
||||
const char *iccid;
|
||||
const char *imsi;
|
||||
const char *spn;
|
||||
};
|
||||
|
||||
struct ofono_sim;
|
||||
typedef void (*ril_sim_info_cb_t)(struct ril_sim_info *info, void *arg);
|
||||
|
||||
struct ril_sim_info *ril_sim_info_new(const char *log_prefix);
|
||||
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *info);
|
||||
void ril_sim_info_unref(struct ril_sim_info *si);
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *si, struct ofono_sim *sim);
|
||||
void ril_sim_info_set_network(struct ril_sim_info *si, struct ril_network *net);
|
||||
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *si,
|
||||
ril_sim_info_cb_t cb, void *arg);
|
||||
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *si,
|
||||
ril_sim_info_cb_t cb, void *arg);
|
||||
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *si,
|
||||
ril_sim_info_cb_t cb, void *arg);
|
||||
void ril_sim_info_remove_handler(struct ril_sim_info *si, gulong id);
|
||||
|
||||
#endif /* RIL_SIM_INFO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -20,9 +20,6 @@
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define RIL_PREF_MODE_DEFAULT(self) (\
|
||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
|
||||
OFONO_RADIO_ACCESS_MODE_LTE : \
|
||||
@@ -41,7 +38,6 @@ enum sailfish_watch_events {
|
||||
struct ril_sim_settings_priv {
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
struct sailfish_watch *watch;
|
||||
GKeyFile *storage;
|
||||
char *imsi;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
enum ofono_radio_access_mode techs);
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *s,
|
||||
struct ofono_sim *sim);
|
||||
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *s,
|
||||
enum ofono_radio_access_mode mode);
|
||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *s,
|
||||
|
||||
@@ -471,7 +471,7 @@ static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
|
||||
|
||||
static void ril_sms_remove(struct ofono_sms *sms)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
|
||||
DBG("");
|
||||
|
||||
@@ -268,7 +268,7 @@ static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
|
||||
static void ril_stk_remove(struct ofono_stk *stk)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
DBG("");
|
||||
ofono_stk_set_data(stk, NULL);
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
#
|
||||
#EmptyConfig=false
|
||||
|
||||
# User and group for the ofono process. RIL clients are typically
|
||||
# expected to run under radio:radio.
|
||||
#
|
||||
# Default is radio:radio
|
||||
#
|
||||
#Identity=radio:radio
|
||||
|
||||
# If the phone has more than one SIM slot, the 3G/LTE module may be
|
||||
# shared by all modems, meaning that only one of the slots can use
|
||||
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
|
||||
@@ -176,3 +183,22 @@ socket=/dev/socket/rild
|
||||
# Default true
|
||||
#
|
||||
#enableVoicecall=true
|
||||
|
||||
# Timeout for the modem to show up, in milliseconds. Those that don't
|
||||
# show up before this timeout expires, will be dropped (ignored).
|
||||
#
|
||||
# In some fairly rare cases it makes sense to shorten this timeout for
|
||||
# optional modems (which may or may not be available), to speed up the
|
||||
# boot up process.
|
||||
#
|
||||
# The default is 20000 (20 seconds)
|
||||
#
|
||||
#startTimeout=20000
|
||||
|
||||
# This allows to use deprecated RIL_REQUEST_GET_IMEI instead of
|
||||
# RIL_REQUEST_DEVICE_IDENTITY to query IMEI from the modem. Some
|
||||
# RILs (e.g. MTK) still don't understand RIL_REQUEST_DEVICE_IDENTITY.
|
||||
#
|
||||
# Default is false (use RIL_REQUEST_DEVICE_IDENTITY)
|
||||
#
|
||||
#legacyImeiQuery=false
|
||||
|
||||
@@ -45,7 +45,6 @@ struct ril_modem;
|
||||
struct ril_radio;
|
||||
struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_cell_info;
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "netreg.h"
|
||||
@@ -233,6 +235,8 @@ const char *ril_request_to_string(guint request)
|
||||
RIL_REQUEST_(SHUTDOWN);
|
||||
RIL_REQUEST_(GET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(SET_RADIO_CAPABILITY);
|
||||
case RIL_RESPONSE_ACKNOWLEDGEMENT:
|
||||
return "RESPONSE_ACK";
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "RIL_REQUEST_%d", request);
|
||||
return unknown;
|
||||
@@ -322,8 +326,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
int access_tech = -1;
|
||||
int tech = -1;
|
||||
if (stech && stech[0]) {
|
||||
tech = atoi(stech);
|
||||
if (ril_parse_int(stech, 0, &tech)) {
|
||||
switch (tech) {
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
@@ -380,8 +383,8 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
|
||||
if (i == OFONO_MAX_MCC_LENGTH) {
|
||||
/* Usually 2 but sometimes 3 digit network code */
|
||||
for (i=0;
|
||||
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mnc[i] = *ptr++;
|
||||
}
|
||||
@@ -408,6 +411,26 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_parse_int(const char *str, int base, int *value)
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (str && str[0]) {
|
||||
char *str2 = g_strstrip(g_strdup(str));
|
||||
char *end = str2;
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(str2, &end, base);
|
||||
ok = !*end && errno != ERANGE && l >= INT_MIN && l <= INT_MAX;
|
||||
if (ok && value) {
|
||||
*value = (int)l;
|
||||
}
|
||||
g_free(str2);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -26,6 +26,7 @@ const char *ril_unsol_event_to_string(guint event);
|
||||
const char *ril_radio_state_to_string(int radio_state);
|
||||
int ril_parse_tech(const char *stech, int *ril_tech);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
gboolean ril_parse_int(const char *str, int base, int *value);
|
||||
|
||||
#define ril_error_init_ok(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
||||
|
||||
@@ -306,7 +306,8 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
case CALL_FAIL_ERROR_UNSPECIFIED:
|
||||
call_status = ril_voicecall_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
call_status == CALL_STATUS_ALERTING ||
|
||||
call_status == CALL_STATUS_INCOMING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
}
|
||||
break;
|
||||
@@ -334,14 +335,18 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
GASSERT(vd->clcc_poll_id);
|
||||
vd->clcc_poll_id = 0;
|
||||
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("We are polling CLCC and received an error");
|
||||
ofono_error("All bets are off for call management");
|
||||
return;
|
||||
/*
|
||||
* Only RIL_E_SUCCESS and RIL_E_RADIO_NOT_AVAILABLE are expected here,
|
||||
* all other errors are filtered out by ril_voicecall_clcc_retry()
|
||||
*/
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
calls = ril_voicecall_parse_clcc(data, len);
|
||||
} else {
|
||||
/* RADIO_NOT_AVAILABLE == no calls */
|
||||
GASSERT(status == RIL_E_RADIO_NOT_AVAILABLE);
|
||||
calls = NULL;
|
||||
}
|
||||
|
||||
calls = ril_voicecall_parse_clcc(data, len);
|
||||
|
||||
n = calls;
|
||||
o = vd->calls;
|
||||
|
||||
@@ -435,12 +440,25 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
vd->calls = calls;
|
||||
}
|
||||
|
||||
static gboolean ril_voicecall_clcc_retry(GRilIoRequest* req, int ril_status,
|
||||
const void* response_data, guint response_len, void* user_data)
|
||||
{
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
{
|
||||
GASSERT(vd);
|
||||
if (!vd->clcc_poll_id) {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_request_set_retry_func(req, ril_voicecall_clcc_retry);
|
||||
vd->clcc_poll_id = grilio_queue_send_request_full(vd->q,
|
||||
req, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||
ril_voicecall_clcc_poll_cb, NULL, vd);
|
||||
|
||||
158
ofono/drivers/rilmodem/lte.c
Normal file
158
ofono/drivers/rilmodem/lte.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.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 <gril/gril.h>
|
||||
#include <gril/grilutil.h>
|
||||
|
||||
#include "rilmodem.h"
|
||||
|
||||
struct ril_lte_data {
|
||||
GRil *ril;
|
||||
};
|
||||
|
||||
static void ril_lte_set_default_attach_info_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
struct ofono_lte *lte = cbd->user;
|
||||
struct ril_lte_data *ld = ofono_lte_get_data(lte);
|
||||
DBG("");
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
g_ril_print_response_no_args(ld->ril, message);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
} else {
|
||||
ofono_error("%s: RIL error %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_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 ril_lte_data *ld = ofono_lte_get_data(lte);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, (struct ofono_lte *)lte);
|
||||
struct parcel rilp;
|
||||
char buf[OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||
|
||||
DBG("%s", info->apn);
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 5);
|
||||
|
||||
if (strlen(info->apn) > 0) {
|
||||
sprintf(buf, "%s", info->apn);
|
||||
parcel_w_string(&rilp, buf);
|
||||
} else
|
||||
parcel_w_string(&rilp, ""); /* apn */
|
||||
|
||||
parcel_w_string(&rilp, "ip"); /* protocol */
|
||||
parcel_w_int32(&rilp, 0); /* auth type */
|
||||
parcel_w_string(&rilp, ""); /* username */
|
||||
parcel_w_string(&rilp, ""); /* password */
|
||||
|
||||
if (g_ril_send(ld->ril, RIL_REQUEST_SET_INITIAL_ATTACH_APN, &rilp,
|
||||
ril_lte_set_default_attach_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static gboolean lte_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_lte_register(lte);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_lte_probe(struct ofono_lte *lte, void *user_data)
|
||||
{
|
||||
GRil *ril = user_data;
|
||||
struct ril_lte_data *ld;
|
||||
|
||||
DBG("");
|
||||
|
||||
ld = g_try_new0(struct ril_lte_data, 1);
|
||||
if (ld == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ld->ril = g_ril_clone(ril);
|
||||
|
||||
ofono_lte_set_data(lte, ld);
|
||||
|
||||
g_idle_add(lte_delayed_register, lte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct ril_lte_data *ld = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
g_ril_unref(ld->ril);
|
||||
g_free(ld);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = RILMODEM,
|
||||
.probe = ril_lte_probe,
|
||||
.remove = ril_lte_remove,
|
||||
.set_default_attach_info = ril_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void ril_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ril_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -111,7 +111,7 @@ static void ril_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, rs);
|
||||
struct parcel rilp;
|
||||
int pref = PREF_NET_TYPE_GSM_WCDMA;
|
||||
int pref = PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
|
||||
@@ -54,6 +54,7 @@ static int rilmodem_init(void)
|
||||
ril_netmon_init();
|
||||
ril_stk_init();
|
||||
ril_cbs_init();
|
||||
ril_lte_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -78,6 +79,7 @@ static void rilmodem_exit(void)
|
||||
ril_netmon_exit();
|
||||
ril_stk_exit();
|
||||
ril_cbs_exit();
|
||||
ril_lte_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,
|
||||
|
||||
@@ -78,3 +78,6 @@ extern void ril_stk_exit(void);
|
||||
|
||||
extern void ril_cbs_init(void);
|
||||
extern void ril_cbs_exit(void);
|
||||
|
||||
extern void ril_lte_init(void);
|
||||
extern void ril_lte_exit(void);
|
||||
|
||||
@@ -183,6 +183,24 @@ static void ril_stk_session_end_notify(struct ril_msg *message,
|
||||
ofono_stk_proactive_session_end_notify(stk);
|
||||
}
|
||||
|
||||
static void ril_stk_initialize_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_stk *stk = user_data;
|
||||
struct stk_data *sd = ofono_stk_get_data(stk);
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(sd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
ofono_stk_remove(stk);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_stk_register(stk);
|
||||
}
|
||||
|
||||
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor,
|
||||
void *user)
|
||||
{
|
||||
@@ -204,7 +222,8 @@ static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor,
|
||||
g_ril_register(ril, RIL_UNSOL_STK_EVENT_NOTIFY,
|
||||
ril_stk_event_notify, stk);
|
||||
|
||||
ofono_stk_register(stk);
|
||||
g_ril_send(data->ril, RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, NULL,
|
||||
ril_stk_initialize_cb, stk, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
482
ofono/drivers/telitmodem/gprs-context-ncm.c
Normal file
482
ofono/drivers/telitmodem/gprs-context-ncm.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Piotr Haber. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "telitmodem.h"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
||||
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||
|
||||
enum state {
|
||||
STATE_IDLE,
|
||||
STATE_ENABLING,
|
||||
STATE_DISABLING,
|
||||
STATE_ACTIVE,
|
||||
};
|
||||
|
||||
enum auth_method {
|
||||
AUTH_METHOD_NONE,
|
||||
AUTH_METHOD_PAP,
|
||||
AUTH_METHOD_CHAP,
|
||||
};
|
||||
|
||||
struct gprs_context_data {
|
||||
GAtChat *chat;
|
||||
unsigned int active_context;
|
||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||
enum auth_method auth_method;
|
||||
enum state state;
|
||||
enum ofono_gprs_proto proto;
|
||||
char address[64];
|
||||
char netmask[64];
|
||||
char gateway[64];
|
||||
char dns1[64];
|
||||
char dns2[64];
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static void failed_setup(struct ofono_gprs_context *gc,
|
||||
GAtResult *result, gboolean deactivate)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
struct ofono_error error;
|
||||
char buf[64];
|
||||
|
||||
DBG("deactivate %d", deactivate);
|
||||
|
||||
if (deactivate == TRUE) {
|
||||
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
||||
g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
if (result == NULL) {
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
return;
|
||||
}
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
gcd->cb(&error, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void session_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);
|
||||
struct ofono_modem *modem;
|
||||
const char *interface;
|
||||
const char *dns[3];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("Failed to establish session");
|
||||
failed_setup(gc, result, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
gcd->state = STATE_ACTIVE;
|
||||
|
||||
dns[0] = gcd->dns1;
|
||||
dns[1] = gcd->dns2;
|
||||
dns[2] = 0;
|
||||
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
|
||||
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 contrdp_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];
|
||||
int cid, bearer_id;
|
||||
const char *apn, *ip_mask, *gw;
|
||||
const char *dns1, *dns2;
|
||||
GAtResultIter iter;
|
||||
gboolean found = FALSE;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("Unable to get context dynamic paramerers");
|
||||
failed_setup(gc, result, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
|
||||
if (!g_at_result_iter_next_number(&iter, &cid))
|
||||
goto error;
|
||||
if (!g_at_result_iter_next_number(&iter, &bearer_id))
|
||||
goto error;
|
||||
if (!g_at_result_iter_next_string(&iter, &apn))
|
||||
goto error;
|
||||
if (!g_at_result_iter_next_string(&iter, &ip_mask))
|
||||
goto error;
|
||||
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||
goto error;
|
||||
if (!g_at_result_iter_next_string(&iter, &dns1))
|
||||
goto error;
|
||||
if (!g_at_result_iter_next_string(&iter, &dns2))
|
||||
goto error;
|
||||
|
||||
if ((unsigned int) cid == gcd->active_context) {
|
||||
found = TRUE;
|
||||
|
||||
if (strcmp(gcd->address, "") != 0)
|
||||
strncpy(gcd->netmask,
|
||||
&ip_mask[strlen(gcd->address) + 1],
|
||||
sizeof(gcd->netmask));
|
||||
|
||||
strncpy(gcd->gateway, gw, sizeof(gcd->gateway));
|
||||
strncpy(gcd->dns1, dns1, sizeof(gcd->dns1));
|
||||
strncpy(gcd->dns2, dns2, sizeof(gcd->dns2));
|
||||
}
|
||||
}
|
||||
|
||||
if (found == FALSE)
|
||||
goto error;
|
||||
|
||||
ofono_info("IP: %s", gcd->address);
|
||||
ofono_info("MASK: %s", gcd->netmask);
|
||||
ofono_info("GW: %s", gcd->gateway);
|
||||
ofono_info("DNS: %s, %s", gcd->dns1, gcd->dns2);
|
||||
|
||||
sprintf(buf, "AT+CGDATA=\"M-RAW_IP\",%d", gcd->active_context);
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
session_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void address_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);
|
||||
int cid;
|
||||
const char *address;
|
||||
char buf[64];
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("Unable to get context address");
|
||||
failed_setup(gc, result, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CGPADDR:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &cid))
|
||||
goto error;
|
||||
|
||||
if ((unsigned int) cid != gcd->active_context)
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &address))
|
||||
goto error;
|
||||
|
||||
strncpy(gcd->address, address, sizeof(gcd->address));
|
||||
|
||||
sprintf(buf, "AT+CGCONTRDP=%d", gcd->active_context);
|
||||
if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
|
||||
contrdp_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("Unable to activate context");
|
||||
failed_setup(gc, result, FALSE);
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("Failed to setup context");
|
||||
failed_setup(gc, result, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gcd->username[0] && gcd->password[0])
|
||||
sprintf(buf, "AT#PDPAUTH=%u,%u,\"%s\",\"%s\"",
|
||||
gcd->active_context, gcd->auth_method,
|
||||
gcd->username, gcd->password);
|
||||
else
|
||||
sprintf(buf, "AT#PDPAUTH=%u,0", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL) == 0)
|
||||
goto error;
|
||||
|
||||
sprintf(buf, "AT#NCM=1,%u", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL) == 0)
|
||||
goto error;
|
||||
|
||||
sprintf(buf, "AT+CGACT=1,%u", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
activate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
failed_setup(gc, NULL, FALSE);
|
||||
}
|
||||
|
||||
static void telitncm_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[OFONO_GPRS_MAX_APN_LENGTH + 128];
|
||||
int len = 0;
|
||||
|
||||
DBG("cid %u", ctx->cid);
|
||||
|
||||
gcd->active_context = ctx->cid;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
memcpy(gcd->username, ctx->username, sizeof(ctx->username));
|
||||
memcpy(gcd->password, ctx->password, sizeof(ctx->password));
|
||||
gcd->state = STATE_ENABLING;
|
||||
gcd->proto = ctx->proto;
|
||||
|
||||
/* We only support CHAP and PAP */
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
gcd->auth_method = AUTH_METHOD_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
gcd->auth_method = AUTH_METHOD_PAP;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (ctx->proto) {
|
||||
case OFONO_GPRS_PROTO_IP:
|
||||
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"",
|
||||
ctx->cid);
|
||||
break;
|
||||
case OFONO_GPRS_PROTO_IPV6:
|
||||
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IPV6\"",
|
||||
ctx->cid);
|
||||
break;
|
||||
case OFONO_GPRS_PROTO_IPV4V6:
|
||||
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IPV4V6\"",
|
||||
ctx->cid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx->apn)
|
||||
snprintf(buf + len, sizeof(buf) - len - 3,
|
||||
",\"%s\"", ctx->apn);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
setup_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void deactivate_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);
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void telitncm_gprs_deactivate_primary(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);
|
||||
char buf[64];
|
||||
|
||||
DBG("cid %u", cid);
|
||||
|
||||
gcd->state = STATE_DISABLING;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
}
|
||||
|
||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
const char *event;
|
||||
int cid;
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CGEV:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_unquoted_string(&iter, &event))
|
||||
return;
|
||||
|
||||
if (g_str_has_prefix(event, "NW DEACT") == FALSE)
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &cid))
|
||||
return;
|
||||
|
||||
DBG("cid %d", cid);
|
||||
|
||||
if ((unsigned int) cid != gcd->active_context)
|
||||
return;
|
||||
|
||||
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
||||
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
}
|
||||
|
||||
static int telitncm_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct gprs_context_data *gcd;
|
||||
|
||||
DBG("");
|
||||
|
||||
gcd = g_try_new0(struct gprs_context_data, 1);
|
||||
if (gcd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gcd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void telitncm_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
g_at_chat_unref(gcd->chat);
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
static struct ofono_gprs_context_driver driver = {
|
||||
.name = "telitncmmodem",
|
||||
.probe = telitncm_gprs_context_probe,
|
||||
.remove = telitncm_gprs_context_remove,
|
||||
.activate_primary = telitncm_gprs_activate_primary,
|
||||
.deactivate_primary = telitncm_gprs_deactivate_primary,
|
||||
};
|
||||
|
||||
void telitncm_gprs_context_init(void)
|
||||
{
|
||||
ofono_gprs_context_driver_register(&driver);
|
||||
}
|
||||
|
||||
void telitncm_gprs_context_exit(void)
|
||||
{
|
||||
ofono_gprs_context_driver_unregister(&driver);
|
||||
}
|
||||
@@ -35,6 +35,7 @@
|
||||
static int telitmodem_init(void)
|
||||
{
|
||||
telit_location_reporting_init();
|
||||
telitncm_gprs_context_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -42,6 +43,7 @@ static int telitmodem_init(void)
|
||||
static void telitmodem_exit(void)
|
||||
{
|
||||
telit_location_reporting_exit();
|
||||
telitncm_gprs_context_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(telitmodem, "Telit modem driver", VERSION,
|
||||
|
||||
@@ -23,3 +23,5 @@
|
||||
|
||||
extern void telit_location_reporting_init();
|
||||
extern void telit_location_reporting_exit();
|
||||
extern void telitncm_gprs_context_init();
|
||||
extern void telitncm_gprs_context_exit();
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||
static const char *uipaddr_prefix[] = { "+UIPADDR:", NULL };
|
||||
|
||||
struct gprs_context_data {
|
||||
GAtChat *chat;
|
||||
@@ -51,6 +52,44 @@ struct gprs_context_data {
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static void uipaddr_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);
|
||||
GAtResultIter iter;
|
||||
|
||||
const char *gw = NULL;
|
||||
const char *netmask = NULL;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+UIPADDR:")) {
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &netmask))
|
||||
break;
|
||||
}
|
||||
|
||||
if (gw)
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, gw);
|
||||
|
||||
if (netmask)
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, netmask);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||
* of "a.b.c.d.m.m.m.m" for IPv4. IPv6 is not supported so we ignore it.
|
||||
@@ -113,6 +152,7 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
const char *laddrnetmask = NULL;
|
||||
const char *gw = NULL;
|
||||
const char *dns[3] = { NULL, NULL, NULL };
|
||||
char buf[64];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
@@ -159,6 +199,17 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
if (dns[0])
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
/*
|
||||
* Some older versions of Toby L2 need to issue AT+UIPADDR to get the
|
||||
* the correct gateway and netmask. The newer version will return an
|
||||
* empty ok reply.
|
||||
*/
|
||||
snprintf(buf, sizeof(buf), "AT+UIPADDR=%u", gcd->active_context);
|
||||
if (g_at_chat_send(gcd->chat, buf, uipaddr_prefix,
|
||||
uipaddr_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
/* Even if UIPADDR failed, we still have enough data. */
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
@@ -443,6 +494,7 @@ static void ublox_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
g_at_chat_unref(gcd->chat);
|
||||
|
||||
memset(gcd, 0, sizeof(*gcd));
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
static struct ofono_gprs_context_driver driver = {
|
||||
|
||||
142
ofono/drivers/ubloxmodem/lte.c
Normal file
142
ofono/drivers/ubloxmodem/lte.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 Endocode AG. 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 "ubloxmodem.h"
|
||||
|
||||
static const char *ucgdflt_prefix[] = { "+UCGDFLT:", NULL };
|
||||
|
||||
struct lte_driver_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void ucgdflt_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 ublox_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+UCGDFLT=0,\"IP\",\"%s\"",
|
||||
info->apn);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "AT+UCGDFLT=0");
|
||||
|
||||
/* We can't do much in case of failure so don't check response. */
|
||||
if (g_at_chat_send(ldd->chat, buf, ucgdflt_prefix,
|
||||
ucgdflt_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 ublox_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct lte_driver_data *ldd;
|
||||
|
||||
DBG("ublox 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 ublox_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("ublox lte remove");
|
||||
|
||||
g_at_chat_unref(ldd->chat);
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = UBLOXMODEM,
|
||||
.probe = ublox_lte_probe,
|
||||
.remove = ublox_lte_remove,
|
||||
.set_default_attach_info = ublox_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void ublox_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ublox_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
354
ofono/drivers/ubloxmodem/netmon.c
Normal file
354
ofono/drivers/ubloxmodem/netmon.c
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 EndoCode AG. 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/netreg.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "ubloxmodem.h"
|
||||
#include "drivers/atmodem/vendor.h"
|
||||
|
||||
static const char *cops_prefix[] = { "+COPS:", NULL };
|
||||
static const char *cesq_prefix[] = { "+CESQ:", NULL };
|
||||
|
||||
struct netmon_driver_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
struct req_cb_data {
|
||||
gint ref_count; /* Ref count */
|
||||
|
||||
struct ofono_netmon *netmon;
|
||||
|
||||
ofono_netmon_cb_t cb;
|
||||
void *data;
|
||||
|
||||
struct ofono_network_operator op;
|
||||
|
||||
int rxlev; /* CESQ: Received Signal Strength Indication */
|
||||
int ber; /* CESQ: Bit Error Rate */
|
||||
int rscp; /* CESQ: Received Signal Code Powe */
|
||||
int rsrp; /* CESQ: Reference Signal Received Power */
|
||||
int ecn0; /* CESQ: Received Energy Ratio */
|
||||
int rsrq; /* CESQ: Reference Signal Received Quality */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the appropriate radio access technology.
|
||||
*
|
||||
* If we can not resolve to a specific radio access technolgy
|
||||
* we return OFONO_NETMON_CELL_TYPE_GSM by default.
|
||||
*/
|
||||
static int ublox_map_radio_access_technology(int tech)
|
||||
{
|
||||
switch (tech) {
|
||||
case ACCESS_TECHNOLOGY_GSM:
|
||||
case ACCESS_TECHNOLOGY_GSM_COMPACT:
|
||||
return OFONO_NETMON_CELL_TYPE_GSM;
|
||||
case ACCESS_TECHNOLOGY_UTRAN:
|
||||
case ACCESS_TECHNOLOGY_UTRAN_HSDPA:
|
||||
case ACCESS_TECHNOLOGY_UTRAN_HSUPA:
|
||||
case ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA:
|
||||
return OFONO_NETMON_CELL_TYPE_UMTS;
|
||||
case ACCESS_TECHNOLOGY_EUTRAN:
|
||||
return OFONO_NETMON_CELL_TYPE_LTE;
|
||||
}
|
||||
|
||||
return OFONO_NETMON_CELL_TYPE_GSM;
|
||||
}
|
||||
|
||||
static inline struct req_cb_data *req_cb_data_new0(void *cb, void *data,
|
||||
void *user)
|
||||
{
|
||||
struct req_cb_data *ret = g_new0(struct req_cb_data, 1);
|
||||
|
||||
ret->ref_count = 1;
|
||||
ret->cb = cb;
|
||||
ret->data = data;
|
||||
ret->netmon = user;
|
||||
ret->rxlev = -1;
|
||||
ret->ber = -1;
|
||||
ret->rscp = -1;
|
||||
ret->rsrp = -1;
|
||||
ret->ecn0 = -1;
|
||||
ret->rsrq = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct req_cb_data *req_cb_data_ref(struct req_cb_data *cbd)
|
||||
{
|
||||
if (cbd == NULL)
|
||||
return NULL;
|
||||
|
||||
g_atomic_int_inc(&cbd->ref_count);
|
||||
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void req_cb_data_unref(gpointer user_data)
|
||||
{
|
||||
gboolean is_zero;
|
||||
struct req_cb_data *cbd = user_data;
|
||||
|
||||
if (cbd == NULL)
|
||||
return;
|
||||
|
||||
is_zero = g_atomic_int_dec_and_test(&cbd->ref_count);
|
||||
|
||||
if (is_zero == TRUE)
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static gboolean ublox_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_netmon *netmon = user_data;
|
||||
|
||||
ofono_netmon_register(netmon);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ublox_netmon_finish_success(struct req_cb_data *cbd)
|
||||
{
|
||||
struct ofono_netmon *nm = cbd->netmon;
|
||||
|
||||
ofono_netmon_serving_cell_notify(nm,
|
||||
cbd->op.tech,
|
||||
OFONO_NETMON_INFO_RXLEV, cbd->rxlev,
|
||||
OFONO_NETMON_INFO_BER, cbd->ber,
|
||||
OFONO_NETMON_INFO_RSCP, cbd->rscp,
|
||||
OFONO_NETMON_INFO_ECN0, cbd->ecn0,
|
||||
OFONO_NETMON_INFO_RSRQ, cbd->rsrq,
|
||||
OFONO_NETMON_INFO_RSRP, cbd->rsrp,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
|
||||
}
|
||||
|
||||
static void cesq_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
enum cesq_ofono_netmon_info {
|
||||
CESQ_RXLEV,
|
||||
CESQ_BER,
|
||||
CESQ_RSCP,
|
||||
CESQ_ECN0,
|
||||
CESQ_RSRQ,
|
||||
CESQ_RSRP,
|
||||
_MAX,
|
||||
};
|
||||
|
||||
struct req_cb_data *cbd = user_data;
|
||||
struct ofono_error error;
|
||||
GAtResultIter iter;
|
||||
int idx, number;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CESQ:")) {
|
||||
DBG(" CESQ: no result ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < _MAX; idx++) {
|
||||
ok = g_at_result_iter_next_number(&iter, &number);
|
||||
|
||||
if (!ok) {
|
||||
/* Ignore and do not fail */
|
||||
DBG(" CESQ: error parsing idx: %d ", idx);
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (idx) {
|
||||
case CESQ_RXLEV:
|
||||
cbd->rxlev = number != 99 ? number:cbd->rxlev;
|
||||
break;
|
||||
case CESQ_BER:
|
||||
cbd->ber = number != 99 ? number:cbd->ber;
|
||||
break;
|
||||
case CESQ_RSCP:
|
||||
cbd->rscp = number != 255 ? number:cbd->rscp;
|
||||
break;
|
||||
case CESQ_ECN0:
|
||||
cbd->ecn0 = number != 255 ? number:cbd->ecn0;
|
||||
break;
|
||||
case CESQ_RSRQ:
|
||||
cbd->rsrq = number != 255 ? number:cbd->rsrq;
|
||||
break;
|
||||
case CESQ_RSRP:
|
||||
cbd->rsrp = number != 255 ? number:cbd->rsrp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DBG(" RXLEV %d ", cbd->rxlev);
|
||||
DBG(" BER %d ", cbd->ber);
|
||||
DBG(" RSCP %d ", cbd->rscp);
|
||||
DBG(" ECN0 %d ", cbd->ecn0);
|
||||
DBG(" RSRQ %d ", cbd->rsrq);
|
||||
DBG(" RSRP %d ", cbd->rsrp);
|
||||
|
||||
/*
|
||||
* We never fail at this point we always send what we collected so
|
||||
* far
|
||||
*/
|
||||
out:
|
||||
ublox_netmon_finish_success(cbd);
|
||||
}
|
||||
|
||||
static void cops_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct req_cb_data *cbd = user_data;
|
||||
struct ofono_netmon *nm = cbd->netmon;
|
||||
struct netmon_driver_data *nmd = ofono_netmon_get_data(nm);
|
||||
struct ofono_error error;
|
||||
GAtResultIter iter;
|
||||
int tech;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
/* Do not fail */
|
||||
if (!g_at_result_iter_next(&iter, "+COPS:")) {
|
||||
CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
/* Default to GSM */
|
||||
if (g_at_result_iter_next_number(&iter, &tech) == FALSE)
|
||||
cbd->op.tech = OFONO_NETMON_CELL_TYPE_GSM;
|
||||
else
|
||||
cbd->op.tech = ublox_map_radio_access_technology(tech);
|
||||
|
||||
cbd = req_cb_data_ref(cbd);
|
||||
if (g_at_chat_send(nmd->chat, "AT+CESQ", cesq_prefix,
|
||||
cesq_cb, cbd, req_cb_data_unref) == 0) {
|
||||
CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
|
||||
req_cb_data_unref(cbd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ublox_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb, void *data)
|
||||
{
|
||||
struct netmon_driver_data *nmd = ofono_netmon_get_data(netmon);
|
||||
struct req_cb_data *cbd;
|
||||
|
||||
DBG("ublox netmon request update");
|
||||
|
||||
cbd = req_cb_data_new0(cb, data, netmon);
|
||||
|
||||
if (g_at_chat_send(nmd->chat, "AT+COPS?", cops_prefix,
|
||||
cops_cb, cbd, req_cb_data_unref) == 0) {
|
||||
CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
|
||||
req_cb_data_unref(cbd);
|
||||
}
|
||||
}
|
||||
|
||||
static int ublox_netmon_probe(struct ofono_netmon *netmon,
|
||||
unsigned int vendor, void *user)
|
||||
{
|
||||
GAtChat *chat = user;
|
||||
struct netmon_driver_data *nmd;
|
||||
|
||||
DBG("ublox netmon probe");
|
||||
|
||||
nmd = g_try_new0(struct netmon_driver_data, 1);
|
||||
if (nmd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
nmd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_netmon_set_data(netmon, nmd);
|
||||
|
||||
g_idle_add(ublox_delayed_register, netmon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ublox_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct netmon_driver_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
DBG("ublox netmon remove");
|
||||
|
||||
g_at_chat_unref(nmd->chat);
|
||||
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
|
||||
g_free(nmd);
|
||||
}
|
||||
|
||||
static struct ofono_netmon_driver driver = {
|
||||
.name = UBLOXMODEM,
|
||||
.probe = ublox_netmon_probe,
|
||||
.remove = ublox_netmon_remove,
|
||||
.request_update = ublox_netmon_request_update,
|
||||
};
|
||||
|
||||
void ublox_netmon_init(void)
|
||||
{
|
||||
ofono_netmon_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ublox_netmon_exit(void)
|
||||
{
|
||||
ofono_netmon_driver_unregister(&driver);
|
||||
}
|
||||
@@ -29,12 +29,15 @@
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/modem.h>
|
||||
|
||||
#include "ubloxmodem.h"
|
||||
|
||||
static int ubloxmodem_init(void)
|
||||
{
|
||||
ublox_gprs_context_init();
|
||||
ublox_netmon_init();
|
||||
ublox_lte_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -42,6 +45,8 @@ static int ubloxmodem_init(void)
|
||||
static void ubloxmodem_exit(void)
|
||||
{
|
||||
ublox_gprs_context_exit();
|
||||
ublox_netmon_exit();
|
||||
ublox_lte_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(ubloxmodem, "U-Blox Toby L2 high speed modem driver",
|
||||
|
||||
@@ -21,5 +21,13 @@
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
|
||||
#define UBLOXMODEM "ubloxmodem"
|
||||
|
||||
extern void ublox_gprs_context_init(void);
|
||||
extern void ublox_gprs_context_exit(void);
|
||||
|
||||
extern void ublox_netmon_init(void);
|
||||
extern void ublox_netmon_exit(void);
|
||||
|
||||
extern void ublox_lte_init(void);
|
||||
extern void ublox_lte_exit(void);
|
||||
|
||||
@@ -116,66 +116,109 @@ static inline void debug(GAtMux *mux, const char *format, ...)
|
||||
|
||||
static void dispatch_sources(GAtMuxChannel *channel, GIOCondition condition)
|
||||
{
|
||||
GAtMuxWatch *source;
|
||||
GSList *c;
|
||||
GSList *p;
|
||||
GSList *t;
|
||||
GSList *refs;
|
||||
|
||||
/*
|
||||
* Don't reference destroyed sources, they may have zero reference
|
||||
* count if this function is invoked from the source's finalize
|
||||
* callback, in which case incrementing and then decrementing
|
||||
* the count would result in double free (first when we decrement
|
||||
* the reference count and then when we return from the finalize
|
||||
* callback).
|
||||
*/
|
||||
|
||||
p = NULL;
|
||||
refs = NULL;
|
||||
|
||||
for (c = channel->sources; c; c = c->next) {
|
||||
GSource *s = c->data;
|
||||
|
||||
if (!g_source_is_destroyed(s)) {
|
||||
GSList *l = g_slist_append(NULL, g_source_ref(s));
|
||||
|
||||
if (p)
|
||||
p->next = l;
|
||||
else
|
||||
refs = l;
|
||||
|
||||
p = l;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep the references to all sources for the duration of the loop.
|
||||
* Callbacks may add and remove the sources, i.e. channel->sources
|
||||
* may keep changing during the loop.
|
||||
*/
|
||||
|
||||
for (c = refs; c; c = c->next) {
|
||||
GAtMuxWatch *w = c->data;
|
||||
GSource *s = &w->source;
|
||||
|
||||
if (g_source_is_destroyed(s))
|
||||
continue;
|
||||
|
||||
debug(channel->mux, "checking source: %p", s);
|
||||
|
||||
if (condition & w->condition) {
|
||||
gpointer user_data = NULL;
|
||||
GSourceFunc callback = NULL;
|
||||
GSourceCallbackFuncs *cb_funcs = s->callback_funcs;
|
||||
gpointer cb_data = s->callback_data;
|
||||
gboolean destroy;
|
||||
|
||||
debug(channel->mux, "dispatching source: %p", s);
|
||||
|
||||
if (cb_funcs) {
|
||||
cb_funcs->ref(cb_data);
|
||||
cb_funcs->get(cb_data, s, &callback,
|
||||
&user_data);
|
||||
}
|
||||
|
||||
destroy = !s->source_funcs->dispatch(s, callback,
|
||||
user_data);
|
||||
|
||||
if (cb_funcs)
|
||||
cb_funcs->unref(cb_data);
|
||||
|
||||
if (destroy) {
|
||||
debug(channel->mux, "removing source: %p", s);
|
||||
g_source_destroy(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove destroyed sources from channel->sources. During this
|
||||
* loop we are not invoking any callbacks, so the consistency is
|
||||
* guaranteed.
|
||||
*/
|
||||
|
||||
p = NULL;
|
||||
c = channel->sources;
|
||||
|
||||
while (c) {
|
||||
gboolean destroy = FALSE;
|
||||
|
||||
source = c->data;
|
||||
|
||||
debug(channel->mux, "checking source: %p", source);
|
||||
|
||||
if (condition & source->condition) {
|
||||
gpointer user_data = NULL;
|
||||
GSourceFunc callback = NULL;
|
||||
GSourceCallbackFuncs *cb_funcs;
|
||||
gpointer cb_data;
|
||||
gboolean (*dispatch) (GSource *, GSourceFunc, gpointer);
|
||||
|
||||
debug(channel->mux, "dispatching source: %p", source);
|
||||
|
||||
dispatch = source->source.source_funcs->dispatch;
|
||||
cb_funcs = source->source.callback_funcs;
|
||||
cb_data = source->source.callback_data;
|
||||
|
||||
if (cb_funcs)
|
||||
cb_funcs->ref(cb_data);
|
||||
|
||||
if (cb_funcs)
|
||||
cb_funcs->get(cb_data, (GSource *) source,
|
||||
&callback, &user_data);
|
||||
|
||||
destroy = !dispatch((GSource *) source, callback,
|
||||
user_data);
|
||||
|
||||
if (cb_funcs)
|
||||
cb_funcs->unref(cb_data);
|
||||
}
|
||||
|
||||
if (destroy) {
|
||||
debug(channel->mux, "removing source: %p", source);
|
||||
|
||||
g_source_destroy((GSource *) source);
|
||||
GSList *n = c->next;
|
||||
GSource *s = c->data;
|
||||
|
||||
if (g_source_is_destroyed(s)) {
|
||||
if (p)
|
||||
p->next = c->next;
|
||||
p->next = n;
|
||||
else
|
||||
channel->sources = c->next;
|
||||
channel->sources = n;
|
||||
|
||||
t = c;
|
||||
c = c->next;
|
||||
g_slist_free_1(t);
|
||||
g_slist_free_1(c);
|
||||
} else {
|
||||
p = c;
|
||||
c = c->next;
|
||||
}
|
||||
|
||||
c = n;
|
||||
}
|
||||
|
||||
/* Release temporary references */
|
||||
g_slist_free_full(refs, (GDestroyNotify) g_source_unref);
|
||||
}
|
||||
|
||||
static gboolean received_data(GIOChannel *channel, GIOCondition cond,
|
||||
@@ -422,7 +465,9 @@ static gboolean watch_dispatch(GSource *source, GSourceFunc callback,
|
||||
static void watch_finalize(GSource *source)
|
||||
{
|
||||
GAtMuxWatch *watch = (GAtMuxWatch *) source;
|
||||
GAtMuxChannel *dlc = (GAtMuxChannel *) watch->channel;
|
||||
|
||||
dlc->sources = g_slist_remove(dlc->sources, watch);
|
||||
g_io_channel_unref(watch->channel);
|
||||
}
|
||||
|
||||
@@ -639,6 +684,9 @@ gboolean g_at_mux_shutdown(GAtMux *mux)
|
||||
if (mux->read_watch > 0)
|
||||
g_source_remove(mux->read_watch);
|
||||
|
||||
if (mux->write_watch > 0)
|
||||
g_source_remove(mux->write_watch);
|
||||
|
||||
for (i = 0; i < MAX_CHANNELS; i++) {
|
||||
if (mux->dlcs[i] == NULL)
|
||||
continue;
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include "crc-ccitt.h"
|
||||
#include "ppp.h"
|
||||
|
||||
#define DEFAULT_MRU 1500
|
||||
#define DEFAULT_MTU 1500
|
||||
|
||||
#define PPP_ADDR_FIELD 0xff
|
||||
@@ -66,7 +65,6 @@ struct _GAtPPP {
|
||||
struct ppp_chap *chap;
|
||||
struct ppp_pap *pap;
|
||||
GAtHDLC *hdlc;
|
||||
gint mru;
|
||||
gint mtu;
|
||||
char username[256];
|
||||
char password[256];
|
||||
@@ -830,7 +828,6 @@ static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
|
||||
ppp->fd = -1;
|
||||
|
||||
/* set options to defaults */
|
||||
ppp->mru = DEFAULT_MRU;
|
||||
ppp->mtu = DEFAULT_MTU;
|
||||
|
||||
/* initialize the lcp state */
|
||||
|
||||
@@ -309,6 +309,12 @@ static GAtSyntaxResult gsm_permissive_feed(GAtSyntax *syntax,
|
||||
case GSM_PERMISSIVE_STATE_RESPONSE_STRING:
|
||||
if (byte == '"')
|
||||
syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
|
||||
else if (byte == '\r') {
|
||||
syntax->state = GSM_PERMISSIVE_STATE_IDLE;
|
||||
i += 1;
|
||||
res = G_AT_SYNTAX_RESULT_LINE;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case GSM_PERMISSIVE_STATE_GUESS_PDU:
|
||||
|
||||
@@ -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_LTE_INTERFACE OFONO_SERVICE ".LongTermEvolution"
|
||||
|
||||
/* CDMA Interfaces */
|
||||
#define OFONO_CDMA_VOICECALL_MANAGER_INTERFACE "org.ofono.cdma.VoiceCallManager"
|
||||
|
||||
@@ -80,7 +80,6 @@ void ofono_gprs_set_cid_range(struct ofono_gprs *gprs,
|
||||
void ofono_gprs_add_context(struct ofono_gprs *gprs,
|
||||
struct ofono_gprs_context *gc);
|
||||
|
||||
ofono_bool_t ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs);
|
||||
void ofono_gprs_cid_activated(struct ofono_gprs *gprs, unsigned int cid,
|
||||
const char *apn);
|
||||
|
||||
|
||||
67
ofono/include/lte.h
Normal file
67
ofono/include/lte.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 Endocode AG. 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_LTE_H
|
||||
#define __OFONO_LTE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_lte;
|
||||
|
||||
struct ofono_lte_default_attach_info {
|
||||
char apn[OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||
};
|
||||
|
||||
typedef void (*ofono_lte_cb_t)(const struct ofono_error *error, void *data);
|
||||
|
||||
struct ofono_lte_driver {
|
||||
const char *name;
|
||||
int (*probe)(struct ofono_lte *lte, void *data);
|
||||
void (*remove)(struct ofono_lte *lte);
|
||||
void (*set_default_attach_info)(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data);
|
||||
};
|
||||
|
||||
int ofono_lte_driver_register(const struct ofono_lte_driver *d);
|
||||
|
||||
void ofono_lte_driver_unregister(const struct ofono_lte_driver *d);
|
||||
|
||||
struct ofono_lte *ofono_lte_create(struct ofono_modem *modem,
|
||||
const char *driver, void *data);
|
||||
|
||||
void ofono_lte_register(struct ofono_lte *lte);
|
||||
|
||||
void ofono_lte_remove(struct ofono_lte *lte);
|
||||
|
||||
void ofono_lte_set_data(struct ofono_lte *lte, void *data);
|
||||
|
||||
void *ofono_lte_get_data(const struct ofono_lte *lte);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -29,6 +29,7 @@ extern "C" {
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
|
||||
enum ofono_modem_type {
|
||||
OFONO_MODEM_TYPE_HARDWARE = 0,
|
||||
@@ -80,6 +81,7 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
|
||||
const char *interface);
|
||||
|
||||
const char *ofono_modem_get_path(struct ofono_modem *modem);
|
||||
struct ofono_sim *ofono_modem_get_sim(struct ofono_modem *modem);
|
||||
|
||||
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
|
||||
void *ofono_modem_get_data(struct ofono_modem *modem);
|
||||
|
||||
@@ -59,6 +59,13 @@ enum ofono_netmon_info {
|
||||
OFONO_NETMON_INFO_RSSI, /* int */
|
||||
OFONO_NETMON_INFO_TIMING_ADVANCE, /* int */
|
||||
OFONO_NETMON_INFO_PSC, /* int */
|
||||
OFONO_NETMON_INFO_RSCP, /* int */
|
||||
OFONO_NETMON_INFO_ECN0, /* int */
|
||||
OFONO_NETMON_INFO_RSRQ, /* int */
|
||||
OFONO_NETMON_INFO_RSRP, /* int */
|
||||
OFONO_NETMON_INFO_EARFCN, /* int */
|
||||
OFONO_NETMON_INFO_EBAND, /* int */
|
||||
OFONO_NETMON_INFO_CQI, /* int */
|
||||
OFONO_NETMON_INFO_INVALID,
|
||||
};
|
||||
|
||||
|
||||
114
ofono/include/sailfish_cell_info.h
Normal file
114
ofono/include/sailfish_cell_info.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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 SAILFISH_CELL_INFO_H
|
||||
#define SAILFISH_CELL_INFO_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
enum sailfish_cell_type {
|
||||
SAILFISH_CELL_TYPE_GSM,
|
||||
SAILFISH_CELL_TYPE_WCDMA,
|
||||
SAILFISH_CELL_TYPE_LTE
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_gsm {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
|
||||
int arfcn; /* 16-bit GSM Absolute RF channel number */
|
||||
int bsic; /* 6-bit Base Station Identity Code */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
int timingAdvance; /* Timing Advance. 1 period = 48/13 us */
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_wcdma {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
|
||||
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
|
||||
int uarfcn; /* 16-bit UMTS Absolute RF Channel Number */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_lte {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int ci; /* Cell Identity */
|
||||
int pci; /* Physical cell id (0..503) */
|
||||
int tac; /* Tracking area code */
|
||||
int earfcn; /* 18-bit LTE Absolute RC Channel Number */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
|
||||
int rsrp; /* Reference Signal Receive Power TS 36.133 */
|
||||
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
|
||||
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
|
||||
int cqi; /* Channel Quality Indicator TS 36.101 */
|
||||
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
|
||||
};
|
||||
|
||||
struct sailfish_cell {
|
||||
enum sailfish_cell_type type;
|
||||
gboolean registered;
|
||||
union {
|
||||
struct sailfish_cell_info_gsm gsm;
|
||||
struct sailfish_cell_info_wcdma wcdma;
|
||||
struct sailfish_cell_info_lte lte;
|
||||
} info;
|
||||
};
|
||||
|
||||
struct sailfish_cell_info {
|
||||
const struct sailfish_cell_info_proc *proc;
|
||||
GSList *cells;
|
||||
};
|
||||
|
||||
typedef void (*sailfish_cell_info_cb_t)(struct sailfish_cell_info *info,
|
||||
void *arg);
|
||||
|
||||
struct sailfish_cell_info_proc {
|
||||
void (*ref)(struct sailfish_cell_info *info);
|
||||
void (*unref)(struct sailfish_cell_info *info);
|
||||
gulong (*add_cells_changed_handler)(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg);
|
||||
void (*remove_handler)(struct sailfish_cell_info *info, gulong id);
|
||||
};
|
||||
|
||||
/* Utilities */
|
||||
gint sailfish_cell_compare_func(gconstpointer v1, gconstpointer v2);
|
||||
gint sailfish_cell_compare_location(const struct sailfish_cell *c1,
|
||||
const struct sailfish_cell *c2);
|
||||
|
||||
/* Cell info object API */
|
||||
struct sailfish_cell_info *sailfish_cell_info_ref
|
||||
(struct sailfish_cell_info *info);
|
||||
void sailfish_cell_info_unref(struct sailfish_cell_info *info);
|
||||
gulong sailfish_cell_info_add_cells_changed_handler
|
||||
(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg);
|
||||
void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
|
||||
gulong id);
|
||||
|
||||
#endif /* SAILFISH_CELINFO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -13,8 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef SAILFISHOS_MANAGER_H
|
||||
#define SAILFISHOS_MANAGER_H
|
||||
#ifndef SAILFISH_MANAGER_H
|
||||
#define SAILFISH_MANAGER_H
|
||||
|
||||
struct ofono_modem;
|
||||
|
||||
@@ -30,6 +30,8 @@ struct sailfish_slot_driver;
|
||||
struct sailfish_slot_driver_reg;
|
||||
struct sailfish_slot_manager;
|
||||
struct sailfish_slot_manager_impl;
|
||||
struct sailfish_cell_info;
|
||||
|
||||
typedef void (*sailfish_slot_manager_impl_cb_t)
|
||||
(struct sailfish_slot_manager_impl *impl, void *user_data);
|
||||
|
||||
@@ -81,14 +83,16 @@ struct sailfish_slot *sailfish_manager_slot_add
|
||||
enum sailfish_sim_state sim_state);
|
||||
void sailfish_manager_imei_obtained(struct sailfish_slot *s, const char *imei);
|
||||
void sailfish_manager_imeisv_obtained(struct sailfish_slot *s,
|
||||
const char *imeisv);
|
||||
const char *imeisv);
|
||||
void sailfish_manager_set_sim_state(struct sailfish_slot *s,
|
||||
enum sailfish_sim_state state);
|
||||
enum sailfish_sim_state state);
|
||||
void sailfish_slot_manager_started(struct sailfish_slot_manager *m);
|
||||
void sailfish_manager_slot_error(struct sailfish_slot *s, const char *key,
|
||||
const char *message);
|
||||
const char *message);
|
||||
void sailfish_manager_error(struct sailfish_slot_manager *m, const char *key,
|
||||
const char *message);
|
||||
const char *message);
|
||||
void sailfish_manager_set_cell_info(struct sailfish_slot *s,
|
||||
struct sailfish_cell_info *ci);
|
||||
|
||||
/* Callbacks provided by slot plugins */
|
||||
struct sailfish_slot_driver {
|
||||
@@ -110,7 +114,7 @@ struct sailfish_slot_driver {
|
||||
void (*slot_free)(struct sailfish_slot_impl *s);
|
||||
};
|
||||
|
||||
#endif /* SAILFISHOS_MANAGER_H */
|
||||
#endif /* SAILFISH_MANAGER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
|
||||
184
ofono/include/sms-filter.h
Normal file
184
ofono/include/sms-filter.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_SMS_FILTER_H
|
||||
#define __OFONO_SMS_FILTER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
|
||||
/* 23.040 Section 9.1.2.5 */
|
||||
enum ofono_sms_number_type {
|
||||
OFONO_SMS_NUMBER_TYPE_UNKNOWN = 0,
|
||||
OFONO_SMS_NUMBER_TYPE_INTERNATIONAL = 1,
|
||||
OFONO_SMS_NUMBER_TYPE_NATIONAL = 2,
|
||||
OFONO_SMS_NUMBER_TYPE_NETWORK_SPECIFIC = 3,
|
||||
OFONO_SMS_NUMBER_TYPE_SUBSCRIBER = 4,
|
||||
OFONO_SMS_NUMBER_TYPE_ALPHANUMERIC = 5,
|
||||
OFONO_SMS_NUMBER_TYPE_ABBREVIATED = 6,
|
||||
OFONO_SMS_NUMBER_TYPE_RESERVED = 7
|
||||
};
|
||||
|
||||
/* 23.040 Section 9.1.2.5 */
|
||||
enum ofono_sms_numbering_plan {
|
||||
OFONO_SMS_NUMBERING_PLAN_UNKNOWN = 0,
|
||||
OFONO_SMS_NUMBERING_PLAN_ISDN = 1,
|
||||
OFONO_SMS_NUMBERING_PLAN_DATA = 3,
|
||||
OFONO_SMS_NUMBERING_PLAN_TELEX = 4,
|
||||
OFONO_SMS_NUMBERING_PLAN_SC1 = 5,
|
||||
OFONO_SMS_NUMBERING_PLAN_SC2 = 6,
|
||||
OFONO_SMS_NUMBERING_PLAN_NATIONAL = 8,
|
||||
OFONO_SMS_NUMBERING_PLAN_PRIVATE = 9,
|
||||
OFONO_SMS_NUMBERING_PLAN_ERMES = 10,
|
||||
OFONO_SMS_NUMBERING_PLAN_RESERVED = 15
|
||||
};
|
||||
|
||||
enum ofono_sms_class {
|
||||
OFONO_SMS_CLASS_0 = 0,
|
||||
OFONO_SMS_CLASS_1 = 1,
|
||||
OFONO_SMS_CLASS_2 = 2,
|
||||
OFONO_SMS_CLASS_3 = 3,
|
||||
OFONO_SMS_CLASS_UNSPECIFIED = 4,
|
||||
};
|
||||
|
||||
struct ofono_sms_address {
|
||||
enum ofono_sms_number_type number_type;
|
||||
enum ofono_sms_numbering_plan numbering_plan;
|
||||
/*
|
||||
* An alphanum TP-OA is 10 7-bit coded octets, which can carry
|
||||
* 11 8-bit characters. 22 bytes + terminator in UTF-8.
|
||||
*/
|
||||
char address[23];
|
||||
};
|
||||
|
||||
struct ofono_sms_scts {
|
||||
unsigned char year;
|
||||
unsigned char month;
|
||||
unsigned char day;
|
||||
unsigned char hour;
|
||||
unsigned char minute;
|
||||
unsigned char second;
|
||||
ofono_bool_t has_timezone;
|
||||
unsigned char timezone;
|
||||
};
|
||||
|
||||
enum ofono_sms_filter_result {
|
||||
OFONO_SMS_FILTER_DROP, /* Stop processing and drop the message */
|
||||
OFONO_SMS_FILTER_CONTINUE /* Run the next filter */
|
||||
};
|
||||
|
||||
typedef void (*ofono_sms_filter_send_text_cb_t)
|
||||
(enum ofono_sms_filter_result result,
|
||||
const struct ofono_sms_address *addr,
|
||||
const char *message,
|
||||
void *data);
|
||||
|
||||
typedef void (*ofono_sms_filter_send_datagram_cb_t)
|
||||
(enum ofono_sms_filter_result result,
|
||||
const struct ofono_sms_address *addr,
|
||||
int dst_port, int src_port,
|
||||
const unsigned char *buf, unsigned int len,
|
||||
void *data);
|
||||
|
||||
typedef void (*ofono_sms_filter_recv_text_cb_t)
|
||||
(enum ofono_sms_filter_result result,
|
||||
const struct ofono_uuid *uuid,
|
||||
const char *message,
|
||||
enum ofono_sms_class cls,
|
||||
const struct ofono_sms_address *addr,
|
||||
const struct ofono_sms_scts *scts,
|
||||
void *data);
|
||||
|
||||
typedef void (*ofono_sms_filter_recv_datagram_cb_t)
|
||||
(enum ofono_sms_filter_result result,
|
||||
const struct ofono_uuid *uuid,
|
||||
int dst_port, int src_port,
|
||||
const unsigned char *buf, unsigned int len,
|
||||
const struct ofono_sms_address *addr,
|
||||
const struct ofono_sms_scts *scts,
|
||||
void *data);
|
||||
|
||||
#define OFONO_SMS_FILTER_PRIORITY_LOW (-100)
|
||||
#define OFONO_SMS_FILTER_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_SMS_FILTER_PRIORITY_HIGH (100)
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* The pointers passed to the filter callbacks are guaranteed to be
|
||||
* valid until the filter calls the completion callback. The completion
|
||||
* callback is never NULL.
|
||||
*
|
||||
* Please avoid making blocking D-Bus calls from the filter callbacks.
|
||||
*/
|
||||
struct ofono_sms_filter {
|
||||
const char *name;
|
||||
int priority;
|
||||
unsigned int (*filter_send_text)(struct ofono_modem *modem,
|
||||
const struct ofono_sms_address *addr,
|
||||
const char *message,
|
||||
ofono_sms_filter_send_text_cb_t cb,
|
||||
void *data);
|
||||
unsigned int (*filter_send_datagram)(struct ofono_modem *modem,
|
||||
const struct ofono_sms_address *addr,
|
||||
int dst_port, int src_port,
|
||||
const unsigned char *buf, unsigned int len,
|
||||
ofono_sms_filter_send_datagram_cb_t cb,
|
||||
void *data);
|
||||
unsigned int (*filter_recv_text)(struct ofono_modem *modem,
|
||||
const struct ofono_uuid *uuid,
|
||||
const char *message,
|
||||
enum ofono_sms_class cls,
|
||||
const struct ofono_sms_address *addr,
|
||||
const struct ofono_sms_scts *scts,
|
||||
ofono_sms_filter_recv_text_cb_t cb,
|
||||
void *data);
|
||||
unsigned int (*filter_recv_datagram)(struct ofono_modem *modem,
|
||||
const struct ofono_uuid *uuid,
|
||||
int dst_port, int src_port,
|
||||
const unsigned char *buf, unsigned int len,
|
||||
const struct ofono_sms_address *addr,
|
||||
const struct ofono_sms_scts *scts,
|
||||
ofono_sms_filter_recv_datagram_cb_t cb,
|
||||
void *data);
|
||||
void (*cancel)(unsigned int id);
|
||||
};
|
||||
|
||||
int ofono_sms_filter_register(const struct ofono_sms_filter *filter);
|
||||
void ofono_sms_filter_unregister(const struct ofono_sms_filter *filter);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_SMS_FILTER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -155,8 +155,10 @@ void bt_unregister_profile(DBusConnection *conn, const char *object)
|
||||
return;
|
||||
}
|
||||
|
||||
dbus_pending_call_set_notify(c, unregister_profile_cb, NULL, NULL);
|
||||
dbus_pending_call_unref(c);
|
||||
if (c) {
|
||||
dbus_pending_call_set_notify(c, unregister_profile_cb, NULL, NULL);
|
||||
dbus_pending_call_unref(c);
|
||||
}
|
||||
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
175
ofono/plugins/file-provision.c
Normal file
175
ofono/plugins/file-provision.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Kerlink SA.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-provision.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/plugin.h>
|
||||
|
||||
/* STORAGEDIR may need to be redefined in unit tests */
|
||||
#ifndef STORAGEDIR
|
||||
# define STORAGEDIR DEFAULT_STORAGEDIR
|
||||
#endif
|
||||
|
||||
#define CONFIG_FILE STORAGEDIR "/provisioning"
|
||||
|
||||
static int config_file_provision_get_settings(const char *mcc,
|
||||
const char *mnc, const char *spn,
|
||||
struct ofono_gprs_provision_data **settings,
|
||||
int *count)
|
||||
{
|
||||
int result = 0;
|
||||
GKeyFile *key_file = NULL;
|
||||
char *setting_group = NULL;
|
||||
char *value;
|
||||
|
||||
DBG("Finding settings for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
|
||||
|
||||
*count = 0;
|
||||
*settings = NULL;
|
||||
|
||||
key_file = g_key_file_new();
|
||||
|
||||
if (!g_key_file_load_from_file(key_file, CONFIG_FILE, 0, NULL)) {
|
||||
result = -ENOENT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
setting_group = g_try_malloc(strlen("operator:") + strlen(mcc) +
|
||||
strlen(mnc) + 2);
|
||||
if (setting_group == NULL) {
|
||||
result = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
sprintf(setting_group, "operator:%s,%s", mcc, mnc);
|
||||
|
||||
value = g_key_file_get_string(key_file, setting_group,
|
||||
"internet.AccessPointName", NULL);
|
||||
|
||||
if (value == NULL)
|
||||
goto error;
|
||||
|
||||
*settings = g_try_new0(struct ofono_gprs_provision_data, 1);
|
||||
if (*settings == NULL) {
|
||||
result = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*count = 1;
|
||||
|
||||
(*settings)[0].type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
|
||||
(*settings)[0].apn = value;
|
||||
|
||||
value = g_key_file_get_string(key_file, setting_group,
|
||||
"internet.Username", NULL);
|
||||
|
||||
if (value != NULL)
|
||||
(*settings)[0].username = value;
|
||||
|
||||
value = g_key_file_get_string(key_file, setting_group,
|
||||
"internet.Password", NULL);
|
||||
|
||||
if (value != NULL)
|
||||
(*settings)[0].password = value;
|
||||
|
||||
(*settings)[0].auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
|
||||
value = g_key_file_get_string(key_file, setting_group,
|
||||
"internet.AuthenticationMethod", NULL);
|
||||
|
||||
if (value != NULL) {
|
||||
if (g_strcmp0(value, "chap") == 0)
|
||||
(*settings)[0].auth_method =
|
||||
OFONO_GPRS_AUTH_METHOD_CHAP;
|
||||
else if (g_strcmp0(value, "pap") == 0)
|
||||
(*settings)[0].auth_method =
|
||||
OFONO_GPRS_AUTH_METHOD_PAP;
|
||||
else
|
||||
DBG("Unknown auth method: %s", value);
|
||||
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
(*settings)[0].proto = OFONO_GPRS_PROTO_IP;
|
||||
value = g_key_file_get_string(key_file, setting_group,
|
||||
"internet.Protocol", NULL);
|
||||
|
||||
if (value != NULL) {
|
||||
DBG("CRO value:%s", value);
|
||||
if (g_strcmp0(value, "ip") == 0) {
|
||||
DBG("CRO value=ip");
|
||||
(*settings)[0].proto = OFONO_GPRS_PROTO_IP;
|
||||
} else if (g_strcmp0(value, "ipv6") == 0) {
|
||||
DBG("CRO value=ipv6");
|
||||
(*settings)[0].proto = OFONO_GPRS_PROTO_IPV6;
|
||||
} else if (g_strcmp0(value, "dual") == 0)
|
||||
(*settings)[0].proto = OFONO_GPRS_PROTO_IPV4V6;
|
||||
else
|
||||
DBG("Unknown protocol: %s", value);
|
||||
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
error:
|
||||
if (key_file != NULL)
|
||||
g_key_file_free(key_file);
|
||||
|
||||
if (setting_group != NULL)
|
||||
g_free(setting_group);
|
||||
|
||||
if (result == 0 && *count > 0)
|
||||
DBG("Found. APN:%s, proto:%d, auth_method:%d",
|
||||
(*settings)[0].apn, (*settings)[0].proto,
|
||||
(*settings)[0].auth_method);
|
||||
else
|
||||
DBG("Not found. Result:%d", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct ofono_gprs_provision_driver config_file_provision_driver = {
|
||||
.name = "GPRS context provisioning",
|
||||
.get_settings = config_file_provision_get_settings,
|
||||
};
|
||||
|
||||
static int config_file_provision_init(void)
|
||||
{
|
||||
return ofono_gprs_provision_driver_register(
|
||||
&config_file_provision_driver);
|
||||
}
|
||||
|
||||
static void config_file_provision_exit(void)
|
||||
{
|
||||
ofono_gprs_provision_driver_unregister(
|
||||
&config_file_provision_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(file_provision, "Gprs Provisioning Plugin",
|
||||
VERSION, OFONO_PLUGIN_PRIORITY_HIGH,
|
||||
config_file_provision_init,
|
||||
config_file_provision_exit)
|
||||
313
ofono/plugins/gemalto.c
Normal file
313
ofono/plugins/gemalto.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Vincent Cesson. 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 <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/phonebook.h>
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/sms.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct gemalto_data {
|
||||
GAtChat *app;
|
||||
GAtChat *mdm;
|
||||
struct ofono_sim *sim;
|
||||
gboolean have_sim;
|
||||
struct at_util_sim_state_query *sim_state_query;
|
||||
};
|
||||
|
||||
static int gemalto_probe(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data;
|
||||
|
||||
data = g_try_new0(struct gemalto_data, 1);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ofono_modem_set_data(modem, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gemalto_remove(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
/* Cleanup potential SIM state polling */
|
||||
at_util_sim_state_query_free(data->sim_state_query);
|
||||
ofono_modem_set_data(modem, NULL);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void gemalto_debug(const char *str, void *user_data)
|
||||
{
|
||||
const char *prefix = user_data;
|
||||
|
||||
ofono_info("%s%s", prefix, str);
|
||||
}
|
||||
|
||||
static GAtChat *open_device(const char *device)
|
||||
{
|
||||
GAtSyntax *syntax;
|
||||
GIOChannel *channel;
|
||||
GAtChat *chat;
|
||||
|
||||
DBG("Opening device %s", device);
|
||||
|
||||
channel = g_at_tty_open(device, NULL);
|
||||
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;
|
||||
|
||||
return chat;
|
||||
}
|
||||
|
||||
static void sim_state_cb(gboolean present, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
at_util_sim_state_query_free(data->sim_state_query);
|
||||
data->sim_state_query = NULL;
|
||||
|
||||
data->have_sim = present;
|
||||
ofono_modem_set_powered(modem, TRUE);
|
||||
}
|
||||
|
||||
static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
if (!ok) {
|
||||
g_at_chat_unref(data->app);
|
||||
data->app = NULL;
|
||||
|
||||
g_at_chat_unref(data->mdm);
|
||||
data->mdm = NULL;
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
data->sim_state_query = at_util_sim_state_query_new(data->app,
|
||||
2, 20, sim_state_cb, modem,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int gemalto_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
const char *app, *mdm;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
app = ofono_modem_get_string(modem, "Application");
|
||||
mdm = ofono_modem_get_string(modem, "Modem");
|
||||
|
||||
if (app == NULL || mdm == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Open devices */
|
||||
data->app = open_device(app);
|
||||
if (data->app == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
data->mdm = open_device(mdm);
|
||||
if (data->mdm == NULL) {
|
||||
g_at_chat_unref(data->app);
|
||||
data->app = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (getenv("OFONO_AT_DEBUG")) {
|
||||
g_at_chat_set_debug(data->app, gemalto_debug, "App");
|
||||
g_at_chat_set_debug(data->mdm, gemalto_debug, "Mdm");
|
||||
}
|
||||
|
||||
g_at_chat_send(data->mdm, "ATE0", none_prefix, NULL, NULL, NULL);
|
||||
g_at_chat_send(data->app, "ATE0 +CMEE=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
g_at_chat_send(data->mdm, "AT&C0", none_prefix, NULL, NULL, NULL);
|
||||
g_at_chat_send(data->app, "AT&C0", none_prefix, NULL, NULL, NULL);
|
||||
|
||||
g_at_chat_send(data->app, "AT+CFUN=4", none_prefix,
|
||||
cfun_enable, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void gemalto_smso_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("");
|
||||
|
||||
g_at_chat_unref(data->mdm);
|
||||
data->mdm = NULL;
|
||||
g_at_chat_unref(data->app);
|
||||
data->app = NULL;
|
||||
|
||||
if (ok)
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
}
|
||||
|
||||
static int gemalto_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_cancel_all(data->app);
|
||||
g_at_chat_unregister_all(data->app);
|
||||
|
||||
/* Shutdown the modem */
|
||||
g_at_chat_send(data->app, "AT^SMSO", none_prefix, gemalto_smso_cb,
|
||||
modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
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 gemalto_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *user_data)
|
||||
{
|
||||
struct gemalto_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->app, command, NULL, set_online_cb, cbd, g_free))
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void gemalto_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
struct ofono_sim *sim;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_devinfo_create(modem, 0, "atmodem", data->app);
|
||||
ofono_location_reporting_create(modem, 0, "gemaltomodem", data->app);
|
||||
sim = ofono_sim_create(modem, 0, "atmodem", data->app);
|
||||
|
||||
if (sim && data->have_sim == TRUE)
|
||||
ofono_sim_inserted_notify(sim, TRUE);
|
||||
}
|
||||
|
||||
static void gemalto_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_phonebook_create(modem, 0, "atmodem", data->app);
|
||||
|
||||
ofono_sms_create(modem, OFONO_VENDOR_CINTERION, "atmodem", data->app);
|
||||
|
||||
gprs = ofono_gprs_create(modem, 0, "atmodem", data->app);
|
||||
gc = ofono_gprs_context_create(modem, 0, "atmodem", data->mdm);
|
||||
|
||||
if (gprs && gc)
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
|
||||
static void gemalto_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct gemalto_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_netreg_create(modem, OFONO_VENDOR_CINTERION, "atmodem", data->app);
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver gemalto_driver = {
|
||||
.name = "gemalto",
|
||||
.probe = gemalto_probe,
|
||||
.remove = gemalto_remove,
|
||||
.enable = gemalto_enable,
|
||||
.disable = gemalto_disable,
|
||||
.set_online = gemalto_set_online,
|
||||
.pre_sim = gemalto_pre_sim,
|
||||
.post_sim = gemalto_post_sim,
|
||||
.post_online = gemalto_post_online,
|
||||
};
|
||||
|
||||
static int gemalto_init(void)
|
||||
{
|
||||
return ofono_modem_driver_register(&gemalto_driver);
|
||||
}
|
||||
|
||||
static void gemalto_exit(void)
|
||||
{
|
||||
ofono_modem_driver_unregister(&gemalto_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(gemalto, "Gemalto modem plugin", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, gemalto_init, gemalto_exit)
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#include <drivers/qmimodem/qmi.h>
|
||||
#include <drivers/qmimodem/dms.h>
|
||||
#include <drivers/qmimodem/wda.h>
|
||||
#include <drivers/qmimodem/util.h>
|
||||
|
||||
#define GOBI_DMS (1 << 0)
|
||||
@@ -60,6 +61,7 @@
|
||||
#define GOBI_CAT (1 << 7)
|
||||
#define GOBI_CAT_OLD (1 << 8)
|
||||
#define GOBI_VOICE (1 << 9)
|
||||
#define GOBI_WDA (1 << 10)
|
||||
|
||||
struct gobi_data {
|
||||
struct qmi_device *device;
|
||||
@@ -168,6 +170,16 @@ static void get_oper_mode_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
data->oper_mode = mode;
|
||||
|
||||
/*
|
||||
* Telit QMI LTE modem must remain online. If powered down, it also
|
||||
* powers down the sim card, and QMI interface has no way to bring
|
||||
* it back alive.
|
||||
*/
|
||||
if (ofono_modem_get_boolean(modem, "AlwaysOnline")) {
|
||||
ofono_modem_set_powered(modem, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (data->oper_mode) {
|
||||
case QMI_DMS_OPER_MODE_ONLINE:
|
||||
param = qmi_param_new_uint8(QMI_DMS_PARAM_OPER_MODE,
|
||||
@@ -250,7 +262,8 @@ static void discover_cb(uint8_t count, const struct qmi_version *list,
|
||||
DBG("");
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DBG("%s %d.%d", list[i].name, list[i].major, list[i].minor);
|
||||
DBG("%s %d.%d - %d", list[i].name, list[i].major, list[i].minor,
|
||||
list[i].type);
|
||||
|
||||
switch (list[i].type) {
|
||||
case QMI_SERVICE_DMS:
|
||||
@@ -265,6 +278,9 @@ static void discover_cb(uint8_t count, const struct qmi_version *list,
|
||||
case QMI_SERVICE_WDS:
|
||||
data->features |= GOBI_WDS;
|
||||
break;
|
||||
case QMI_SERVICE_WDA:
|
||||
data->features |= GOBI_WDA;
|
||||
break;
|
||||
case QMI_SERVICE_PDS:
|
||||
data->features |= GOBI_PDS;
|
||||
break;
|
||||
@@ -353,6 +369,14 @@ static int gobi_disable(struct ofono_modem *modem)
|
||||
qmi_service_cancel_all(data->dms);
|
||||
qmi_service_unregister_all(data->dms);
|
||||
|
||||
/*
|
||||
* Telit QMI modem must remain online. If powered down, it also
|
||||
* powers down the sim card, and QMI interface has no way to bring
|
||||
* it back alive.
|
||||
*/
|
||||
if (ofono_modem_get_boolean(modem, "AlwaysOnline"))
|
||||
goto out;
|
||||
|
||||
param = qmi_param_new_uint8(QMI_DMS_PARAM_OPER_MODE,
|
||||
QMI_DMS_OPER_MODE_PERSIST_LOW_POWER);
|
||||
if (!param)
|
||||
@@ -362,6 +386,7 @@ static int gobi_disable(struct ofono_modem *modem)
|
||||
power_disable_cb, modem, NULL) > 0)
|
||||
return -EINPROGRESS;
|
||||
|
||||
out:
|
||||
shutdown_device(modem);
|
||||
|
||||
return -EINPROGRESS;
|
||||
|
||||
@@ -1,407 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2014 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/call-barring.h>
|
||||
#include <ofono/call-forwarding.h>
|
||||
#include <ofono/call-meter.h>
|
||||
#include <ofono/call-settings.h>
|
||||
#include <ofono/devinfo.h>
|
||||
#include <ofono/message-waiting.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/phonebook.h>
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/sms.h>
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/voicecall.h>
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *qss_prefix[] = { "#QSS:", NULL };
|
||||
|
||||
struct he910_data {
|
||||
GAtChat *chat; /* AT chat */
|
||||
GAtChat *modem; /* Data port */
|
||||
struct ofono_sim *sim;
|
||||
ofono_bool_t have_sim;
|
||||
ofono_bool_t sms_phonebook_added;
|
||||
};
|
||||
|
||||
static void he910_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, he910_debug, debug);
|
||||
|
||||
return chat;
|
||||
}
|
||||
|
||||
static void switch_sim_state_status(struct ofono_modem *modem, int status)
|
||||
{
|
||||
struct he910_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p, SIM status: %d", modem, status);
|
||||
|
||||
switch (status) {
|
||||
case 0: /* SIM not inserted */
|
||||
if (data->have_sim == TRUE) {
|
||||
ofono_sim_inserted_notify(data->sim, FALSE);
|
||||
data->have_sim = FALSE;
|
||||
data->sms_phonebook_added = FALSE;
|
||||
}
|
||||
break;
|
||||
case 1: /* SIM inserted */
|
||||
case 2: /* SIM inserted and PIN unlocked */
|
||||
if (data->have_sim == FALSE) {
|
||||
ofono_sim_inserted_notify(data->sim, TRUE);
|
||||
data->have_sim = TRUE;
|
||||
}
|
||||
break;
|
||||
case 3: /* SIM inserted, SMS and phonebook ready */
|
||||
if (data->sms_phonebook_added == FALSE) {
|
||||
ofono_phonebook_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_sms_create(modem, 0, "atmodem", data->chat);
|
||||
data->sms_phonebook_added = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ofono_warn("Unknown SIM state %d received", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void he910_qss_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
int status;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "#QSS:"))
|
||||
return;
|
||||
|
||||
g_at_result_iter_next_number(&iter, &status);
|
||||
|
||||
switch_sim_state_status(modem, status);
|
||||
}
|
||||
|
||||
static void qss_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
int status, mode;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "#QSS:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &status))
|
||||
return;
|
||||
|
||||
switch_sim_state_status(modem, status);
|
||||
}
|
||||
|
||||
static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct he910_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok) {
|
||||
g_at_chat_unref(data->chat);
|
||||
data->chat = NULL;
|
||||
|
||||
g_at_chat_unref(data->modem);
|
||||
data->modem = NULL;
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch data carrier detect signal off.
|
||||
* When the DCD is disabled the modem does not hangup anymore
|
||||
* after the data connection.
|
||||
*/
|
||||
g_at_chat_send(data->chat, "AT&C0", NULL, NULL, NULL, NULL);
|
||||
|
||||
data->have_sim = FALSE;
|
||||
data->sms_phonebook_added = FALSE;
|
||||
|
||||
ofono_modem_set_powered(modem, TRUE);
|
||||
|
||||
/*
|
||||
* Tell the modem not to automatically initiate auto-attach
|
||||
* proceedures on its own.
|
||||
*/
|
||||
g_at_chat_send(data->chat, "AT#AUTOATT=0", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
/* Follow sim state */
|
||||
g_at_chat_register(data->chat, "#QSS:", he910_qss_notify,
|
||||
FALSE, modem, NULL);
|
||||
|
||||
/* Enable sim state notification */
|
||||
g_at_chat_send(data->chat, "AT#QSS=2", none_prefix, NULL, NULL, NULL);
|
||||
|
||||
g_at_chat_send(data->chat, "AT#QSS?", qss_prefix,
|
||||
qss_query_cb, modem, NULL);
|
||||
}
|
||||
|
||||
static int he910_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct he910_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
data->modem = open_device(modem, "Modem", "Modem: ");
|
||||
if (data->modem == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
data->chat = open_device(modem, "Aux", "Aux: ");
|
||||
if (data->chat == NULL) {
|
||||
g_at_chat_unref(data->modem);
|
||||
data->modem = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
g_at_chat_set_slave(data->modem, data->chat);
|
||||
|
||||
/*
|
||||
* 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=1", none_prefix,
|
||||
cfun_enable_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct he910_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 he910_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct he910_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_cancel_all(data->modem);
|
||||
g_at_chat_unregister_all(data->modem);
|
||||
g_at_chat_unref(data->modem);
|
||||
data->modem = NULL;
|
||||
|
||||
g_at_chat_cancel_all(data->chat);
|
||||
g_at_chat_unregister_all(data->chat);
|
||||
|
||||
/* Power down modem */
|
||||
g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix,
|
||||
cfun_disable_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void he910_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct he910_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_devinfo_create(modem, 0, "atmodem", data->chat);
|
||||
data->sim = ofono_sim_create(modem, OFONO_VENDOR_TELIT, "atmodem",
|
||||
data->chat);
|
||||
ofono_location_reporting_create(modem, 0, "telitmodem", data->chat);
|
||||
}
|
||||
|
||||
static void he910_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct he910_data *data = ofono_modem_get_data(modem);
|
||||
struct ofono_message_waiting *mw;
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_voicecall_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_netreg_create(modem, OFONO_VENDOR_TELIT, "atmodem", data->chat);
|
||||
ofono_ussd_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_forwarding_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_settings_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_meter_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_barring_create(modem, 0, "atmodem", data->chat);
|
||||
|
||||
mw = ofono_message_waiting_create(modem);
|
||||
if (mw)
|
||||
ofono_message_waiting_register(mw);
|
||||
|
||||
gprs = ofono_gprs_create(modem, OFONO_VENDOR_TELIT, "atmodem",
|
||||
data->chat);
|
||||
gc = ofono_gprs_context_create(modem, 0, "atmodem", data->modem);
|
||||
|
||||
if (gprs && gc)
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
|
||||
static int he910_probe(struct ofono_modem *modem)
|
||||
{
|
||||
struct he910_data *data;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
data = g_try_new0(struct he910_data, 1);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ofono_modem_set_data(modem, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void he910_remove(struct ofono_modem *modem)
|
||||
{
|
||||
struct he910_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_modem_set_data(modem, NULL);
|
||||
|
||||
/* Cleanup after hot-unplug */
|
||||
g_at_chat_unref(data->chat);
|
||||
g_at_chat_unref(data->modem);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver he910_driver = {
|
||||
.name = "he910",
|
||||
.probe = he910_probe,
|
||||
.remove = he910_remove,
|
||||
.enable = he910_enable,
|
||||
.disable = he910_disable,
|
||||
.pre_sim = he910_pre_sim,
|
||||
.post_online = he910_post_online,
|
||||
};
|
||||
|
||||
static int he910_init(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
return ofono_modem_driver_register(&he910_driver);
|
||||
}
|
||||
|
||||
static void he910_exit(void)
|
||||
{
|
||||
ofono_modem_driver_unregister(&he910_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(he910, "Telit HE910 driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, he910_init, he910_exit)
|
||||
@@ -177,11 +177,42 @@ static int service_level_connection(struct ofono_modem *modem,
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static struct ofono_modem *modem_register(const char *device,
|
||||
const char *device_address, const char *alias)
|
||||
static void modem_removed(GDBusProxy *proxy, void *user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
|
||||
ofono_modem_remove(modem);
|
||||
}
|
||||
|
||||
static void alias_changed(GDBusProxy *proxy, const char *name,
|
||||
DBusMessageIter *iter, void *user_data)
|
||||
{
|
||||
const char *alias;
|
||||
struct ofono_modem *modem = user_data;
|
||||
|
||||
if (g_str_equal("Alias", name) == FALSE)
|
||||
return;
|
||||
|
||||
dbus_message_iter_get_basic(iter, &alias);
|
||||
ofono_modem_set_name(modem, alias);
|
||||
}
|
||||
|
||||
static struct ofono_modem *modem_register(const char *device, GDBusProxy *proxy)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
char *path;
|
||||
DBusMessageIter iter;
|
||||
const char *alias, *remote;
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == FALSE)
|
||||
return NULL;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &alias);
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
|
||||
return NULL;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &remote);
|
||||
|
||||
path = g_strconcat("hfp", device, NULL);
|
||||
|
||||
@@ -192,12 +223,15 @@ static struct ofono_modem *modem_register(const char *device,
|
||||
if (modem == NULL)
|
||||
return NULL;
|
||||
|
||||
ofono_modem_set_string(modem, "Remote", device_address);
|
||||
ofono_modem_set_string(modem, "Remote", remote);
|
||||
ofono_modem_set_string(modem, "DevicePath", device);
|
||||
|
||||
ofono_modem_set_name(modem, alias);
|
||||
ofono_modem_register(modem);
|
||||
|
||||
g_dbus_proxy_set_property_watch(proxy, alias_changed, modem);
|
||||
g_dbus_proxy_set_removed_watch(proxy, modem_removed, modem);
|
||||
|
||||
return modem;
|
||||
}
|
||||
|
||||
@@ -500,6 +534,71 @@ static int get_version(DBusMessageIter *iter, uint16_t *version)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static gboolean has_hfp_ag_uuid(DBusMessageIter *array)
|
||||
{
|
||||
DBusMessageIter value;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
|
||||
return FALSE;
|
||||
|
||||
dbus_message_iter_recurse(array, &value);
|
||||
|
||||
while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
|
||||
const char *uuid;
|
||||
|
||||
dbus_message_iter_get_basic(&value, &uuid);
|
||||
|
||||
if (g_str_equal(uuid, HFP_AG_UUID) == TRUE)
|
||||
return TRUE;
|
||||
|
||||
dbus_message_iter_next(&value);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void modem_unregister(struct ofono_modem *modem, GDBusProxy *proxy)
|
||||
{
|
||||
ofono_modem_remove(modem);
|
||||
g_dbus_proxy_set_removed_watch(proxy, NULL, NULL);
|
||||
g_dbus_proxy_set_property_watch(proxy, NULL, NULL);
|
||||
}
|
||||
|
||||
static void *device_changed(GDBusProxy *proxy, const char *path)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
dbus_bool_t paired;
|
||||
struct ofono_modem *modem;
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == FALSE)
|
||||
return NULL;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &paired);
|
||||
|
||||
modem = ofono_modem_find(device_path_compare, (void *) path);
|
||||
|
||||
if (paired == FALSE) {
|
||||
if (modem != NULL)
|
||||
modem_unregister(modem, proxy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE ||
|
||||
has_hfp_ag_uuid(&iter) == FALSE) {
|
||||
if (modem != NULL)
|
||||
modem_unregister(modem, proxy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Skip if modem already registered */
|
||||
if (modem)
|
||||
return modem;
|
||||
|
||||
modem = modem_register(path, proxy);
|
||||
|
||||
return modem;
|
||||
}
|
||||
|
||||
static DBusMessage *profile_new_connection(DBusConnection *conn,
|
||||
DBusMessage *msg, void *user_data)
|
||||
{
|
||||
@@ -542,10 +641,18 @@ static DBusMessage *profile_new_connection(DBusConnection *conn,
|
||||
|
||||
modem = ofono_modem_find(device_path_compare, (void *) device);
|
||||
if (modem == NULL) {
|
||||
close(fd);
|
||||
return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE
|
||||
".Rejected",
|
||||
"Unknown Bluetooth device");
|
||||
GDBusProxy *proxy;
|
||||
|
||||
proxy = g_dbus_proxy_new(bluez, device, BLUEZ_DEVICE_INTERFACE);
|
||||
modem = modem_register(device, proxy);
|
||||
g_dbus_proxy_unref(proxy);
|
||||
|
||||
if (!modem) {
|
||||
close(fd);
|
||||
return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE
|
||||
".Rejected",
|
||||
"Unknown Bluetooth device");
|
||||
}
|
||||
}
|
||||
|
||||
err = service_level_connection(modem, fd, version);
|
||||
@@ -687,93 +794,6 @@ static void connect_handler(DBusConnection *conn, void *user_data)
|
||||
HFP_EXT_PROFILE_PATH, NULL, features);
|
||||
}
|
||||
|
||||
static gboolean has_hfp_ag_uuid(DBusMessageIter *array)
|
||||
{
|
||||
DBusMessageIter value;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
|
||||
return FALSE;
|
||||
|
||||
dbus_message_iter_recurse(array, &value);
|
||||
|
||||
while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
|
||||
const char *uuid;
|
||||
|
||||
dbus_message_iter_get_basic(&value, &uuid);
|
||||
|
||||
if (g_str_equal(uuid, HFP_AG_UUID) == TRUE)
|
||||
return TRUE;
|
||||
|
||||
dbus_message_iter_next(&value);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void modem_removed(GDBusProxy *proxy, void *user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
|
||||
ofono_modem_remove(modem);
|
||||
}
|
||||
|
||||
static void alias_changed(GDBusProxy *proxy, const char *name,
|
||||
DBusMessageIter *iter, void *user_data)
|
||||
{
|
||||
const char *alias;
|
||||
struct ofono_modem *modem = user_data;
|
||||
|
||||
if (g_str_equal("Alias", name) == FALSE)
|
||||
return;
|
||||
|
||||
dbus_message_iter_get_basic(iter, &alias);
|
||||
ofono_modem_set_name(modem, alias);
|
||||
}
|
||||
|
||||
static void modem_register_from_proxy(GDBusProxy *proxy, const char *path)
|
||||
{
|
||||
const char *alias, *remote;
|
||||
DBusMessageIter iter;
|
||||
dbus_bool_t paired;
|
||||
struct ofono_modem *modem;
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == FALSE)
|
||||
return;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &paired);
|
||||
|
||||
if (paired == FALSE) {
|
||||
modem = ofono_modem_find(device_path_compare, (void *) path);
|
||||
|
||||
if (modem != NULL) {
|
||||
ofono_modem_remove(modem);
|
||||
g_dbus_proxy_set_removed_watch(proxy, NULL, NULL);
|
||||
g_dbus_proxy_set_property_watch(proxy, NULL, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
|
||||
return;
|
||||
|
||||
if (has_hfp_ag_uuid(&iter) == FALSE)
|
||||
return;
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == FALSE)
|
||||
return;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &alias);
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
|
||||
return;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &remote);
|
||||
|
||||
modem = modem_register(path, remote, alias);
|
||||
g_dbus_proxy_set_property_watch(proxy, alias_changed, modem);
|
||||
g_dbus_proxy_set_removed_watch(proxy, modem_removed, modem);
|
||||
}
|
||||
|
||||
static void proxy_added(GDBusProxy *proxy, void *user_data)
|
||||
{
|
||||
const char *interface, *path;
|
||||
@@ -784,7 +804,7 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
|
||||
if (g_str_equal(BLUEZ_DEVICE_INTERFACE, interface) == FALSE)
|
||||
return;
|
||||
|
||||
modem_register_from_proxy(proxy, path);
|
||||
device_changed(proxy, path);
|
||||
}
|
||||
|
||||
static void property_changed(GDBusProxy *proxy, const char *name,
|
||||
@@ -798,10 +818,11 @@ static void property_changed(GDBusProxy *proxy, const char *name,
|
||||
if (g_str_equal(BLUEZ_DEVICE_INTERFACE, interface) == FALSE)
|
||||
return;
|
||||
|
||||
if (g_str_equal("Paired", name) != TRUE)
|
||||
if (g_str_equal("Paired", name) != TRUE &&
|
||||
g_str_equal("ServicesResolved", name) != TRUE)
|
||||
return;
|
||||
|
||||
modem_register_from_proxy(proxy, path);
|
||||
device_changed(proxy, path);
|
||||
}
|
||||
|
||||
static int hfp_init(void)
|
||||
|
||||
@@ -78,6 +78,8 @@ enum {
|
||||
struct huawei_data {
|
||||
GAtChat *modem;
|
||||
GAtChat *pcui;
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
gboolean have_sim;
|
||||
int sim_state;
|
||||
guint sysinfo_poll_source;
|
||||
@@ -584,6 +586,48 @@ static GAtChat *open_device(struct ofono_modem *modem,
|
||||
return chat;
|
||||
}
|
||||
|
||||
static void modem_disconnect(gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct huawei_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
if (data == NULL) {
|
||||
DBG("Modem has already been removed");
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_warn("Modem channel disconnected");
|
||||
|
||||
/* clean and close modem device */
|
||||
g_at_chat_cancel_all(data->modem);
|
||||
g_at_chat_unregister_all(data->modem);
|
||||
g_at_chat_unref(data->modem);
|
||||
data->modem = NULL;
|
||||
|
||||
/* close gprs context driver */
|
||||
ofono_gprs_context_remove(data->gc);
|
||||
|
||||
/* reopen modem channel */
|
||||
data->modem = open_device(modem, "Modem", "Modem: ");
|
||||
|
||||
if (data->modem == NULL) {
|
||||
DBG("Can't reopen device");
|
||||
return;
|
||||
}
|
||||
|
||||
/* configure modem channel */
|
||||
g_at_chat_set_disconnect_function(data->modem, modem_disconnect, modem);
|
||||
g_at_chat_set_slave(data->modem, data->pcui);
|
||||
g_at_chat_send(data->modem, "ATE0 +CMEE=1", NULL, NULL, NULL, NULL);
|
||||
|
||||
/* reopen gprs context driver */
|
||||
data->gc = ofono_gprs_context_create(modem, OFONO_VENDOR_HUAWEI,
|
||||
"atmodem", data->modem);
|
||||
|
||||
if (data->gprs && data->gc)
|
||||
ofono_gprs_add_context(data->gprs, data->gc);
|
||||
}
|
||||
|
||||
static int huawei_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct huawei_data *data = ofono_modem_get_data(modem);
|
||||
@@ -594,6 +638,8 @@ static int huawei_enable(struct ofono_modem *modem)
|
||||
if (data->modem == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
g_at_chat_set_disconnect_function(data->modem, modem_disconnect, modem);
|
||||
|
||||
data->pcui = open_device(modem, "Pcui", "PCUI: ");
|
||||
if (data->pcui == NULL) {
|
||||
g_at_chat_unref(data->modem);
|
||||
@@ -820,9 +866,6 @@ static void huawei_post_sim(struct ofono_modem *modem)
|
||||
}
|
||||
|
||||
if (data->have_gsm == TRUE) {
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
ofono_phonebook_create(modem, 0, "atmodem", data->pcui);
|
||||
ofono_radio_settings_create(modem, 0,
|
||||
"huaweimodem", data->pcui);
|
||||
@@ -830,13 +873,13 @@ static void huawei_post_sim(struct ofono_modem *modem)
|
||||
ofono_sms_create(modem, OFONO_VENDOR_HUAWEI,
|
||||
"atmodem", data->pcui);
|
||||
|
||||
gprs = ofono_gprs_create(modem, OFONO_VENDOR_HUAWEI,
|
||||
data->gprs = ofono_gprs_create(modem, OFONO_VENDOR_HUAWEI,
|
||||
"atmodem", data->pcui);
|
||||
gc = ofono_gprs_context_create(modem, 0,
|
||||
data->gc = ofono_gprs_context_create(modem, 0,
|
||||
"atmodem", data->modem);
|
||||
|
||||
if (gprs && gc)
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
if (data->gprs && data->gc)
|
||||
ofono_gprs_add_context(data->gprs, data->gc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,15 @@
|
||||
#include <ofono/gprs-provision.h>
|
||||
|
||||
#ifndef MBPI_DATABASE
|
||||
#define MBPI_DATABASE "/usr/share/mobile-broadband-provider-info/" \
|
||||
# ifdef PROVIDER_DATABASE
|
||||
/* This one is pulled from mobile-broadband-provider-info.pc
|
||||
* by the configure script, we should trust it. */
|
||||
# define MBPI_DATABASE PROVIDER_DATABASE
|
||||
# else
|
||||
/* The default one */
|
||||
# define MBPI_DATABASE "/usr/share/mobile-broadband-provider-info/" \
|
||||
"serviceproviders.xml"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "mbpi.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change", GOTO="ofono_end"
|
||||
ACTION!="add", GOTO="ofono_end"
|
||||
|
||||
# ISI/Phonet drivers
|
||||
SUBSYSTEM!="net", GOTO="ofono_isi_end"
|
||||
|
||||
@@ -130,10 +130,15 @@ static void ril_radio_state_changed(struct ril_msg *message,
|
||||
static int ril_probe(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_data *rd;
|
||||
ofono_bool_t lte_cap;
|
||||
|
||||
DBG("");
|
||||
|
||||
rd = g_new0(struct ril_data, 1);
|
||||
|
||||
lte_cap = getenv("OFONO_RIL_RAT_LTE") ? TRUE : FALSE;
|
||||
ofono_modem_set_boolean(modem, MODEM_PROP_LTE_CAPABLE, lte_cap);
|
||||
|
||||
ofono_modem_set_data(modem, rd);
|
||||
|
||||
return 0;
|
||||
@@ -437,7 +442,10 @@ static void ril_post_sim(struct ofono_modem *modem)
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
ofono_sms_create(modem, OFONO_RIL_VENDOR_IMC_SOFIA3GR,
|
||||
if (ofono_modem_get_boolean(modem, MODEM_PROP_LTE_CAPABLE))
|
||||
ofono_sms_create(modem, 0, "rilmodem", rd->ril);
|
||||
else
|
||||
ofono_sms_create(modem, OFONO_RIL_VENDOR_IMC_SOFIA3GR,
|
||||
"rilmodem", rd->ril);
|
||||
|
||||
gprs = ofono_gprs_create(modem, 0, "rilmodem", rd->ril);
|
||||
@@ -448,6 +456,11 @@ static void ril_post_sim(struct ofono_modem *modem)
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
|
||||
if (ofono_modem_get_boolean(modem, MODEM_PROP_LTE_CAPABLE))
|
||||
ofono_lte_create(modem, "rilmodem", rd->ril);
|
||||
|
||||
ofono_stk_create(modem, 0, "rilmodem", rd->ril);
|
||||
}
|
||||
|
||||
static void ril_post_online(struct ofono_modem *modem)
|
||||
@@ -455,8 +468,13 @@ static void ril_post_online(struct ofono_modem *modem)
|
||||
struct ril_data *rd = ofono_modem_get_data(modem);
|
||||
|
||||
ofono_netreg_create(modem, 0, "rilmodem", rd->ril);
|
||||
ofono_radio_settings_create(modem, OFONO_RIL_VENDOR_IMC_SOFIA3GR,
|
||||
"rilmodem", rd->ril);
|
||||
|
||||
if (ofono_modem_get_boolean(modem, MODEM_PROP_LTE_CAPABLE))
|
||||
ofono_radio_settings_create(modem, 0, "rilmodem", rd->ril);
|
||||
else
|
||||
ofono_radio_settings_create(modem, OFONO_RIL_VENDOR_IMC_SOFIA3GR,
|
||||
"rilmodem", rd->ril);
|
||||
|
||||
ofono_ussd_create(modem, 0, "rilmodem", rd->ril);
|
||||
ofono_netmon_create(modem, 0, "rilmodem", rd->ril);
|
||||
}
|
||||
@@ -528,7 +546,7 @@ static int ril_enable(struct ofono_modem *modem)
|
||||
g_ril_set_trace(rd->ril, TRUE);
|
||||
|
||||
if (getenv("OFONO_RIL_HEX_TRACE"))
|
||||
g_ril_set_debugf(rd->ril, ril_debug, "Sofia3GR:");
|
||||
g_ril_set_debugf(rd->ril, ril_debug, "IntelModem:");
|
||||
|
||||
g_ril_register(rd->ril, RIL_UNSOL_RIL_CONNECTED,
|
||||
ril_connected, modem);
|
||||
@@ -581,7 +599,7 @@ static int ril_disable(struct ofono_modem *modem)
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver ril_driver = {
|
||||
.name = "ril_sofia3gr",
|
||||
.name = "ril_intel",
|
||||
.probe = ril_probe,
|
||||
.remove = ril_remove,
|
||||
.enable = ril_enable,
|
||||
@@ -602,5 +620,5 @@ static void ril_exit(void)
|
||||
ofono_modem_driver_unregister(&ril_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(ril_sofia3gr, "SoFiA 3GR RIL-based modem driver", VERSION,
|
||||
OFONO_PLUGIN_DEFINE(ril_intel, "Intel RIL-based modem driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, ril_init, ril_exit)
|
||||
@@ -1,8 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,10 +18,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/log.h>
|
||||
#include "src/ofono.h"
|
||||
|
||||
#include <dbuslog_server_dbus.h>
|
||||
#include <gutil_log.h>
|
||||
@@ -113,13 +109,13 @@ static gboolean debuglog_match(const char* s1, const char* s2)
|
||||
return s1 && s2 && !strcmp(s1, s2);
|
||||
}
|
||||
|
||||
static void debuglog_update_flags(const char* name, guint set, guint clear)
|
||||
static void debuglog_update_flags_range(struct ofono_debug_desc *start,
|
||||
struct ofono_debug_desc *stop, const char* name,
|
||||
guint set, guint clear)
|
||||
{
|
||||
const guint flags = set | clear;
|
||||
struct ofono_debug_desc *start = __start___debug;
|
||||
struct ofono_debug_desc *stop = __stop___debug;
|
||||
|
||||
if (start && stop) {
|
||||
if (start && stop && start < stop) {
|
||||
struct ofono_debug_desc *desc;
|
||||
|
||||
for (desc = start; desc < stop; desc++) {
|
||||
@@ -142,7 +138,44 @@ static void debuglog_update_flags(const char* name, guint set, guint clear)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct debuglog_update_flags_data {
|
||||
const char* name;
|
||||
guint set;
|
||||
guint clear;
|
||||
};
|
||||
|
||||
static void debuglog_update_flags_plugin(struct ofono_plugin_desc *desc,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
/*
|
||||
* We are only interested in the external plugins here because
|
||||
* they don't fall into __start___debug .. __stop___debug range.
|
||||
*/
|
||||
if (!(flags & OFONO_PLUGIN_FLAG_BUILTIN) &&
|
||||
desc->debug_start && desc->debug_stop) {
|
||||
const struct debuglog_update_flags_data *update = user_data;
|
||||
|
||||
debuglog_update_flags_range(desc->debug_start,
|
||||
desc->debug_stop, update->name,
|
||||
update->set, update->clear);
|
||||
}
|
||||
}
|
||||
|
||||
static void debuglog_update_flags(const char* name, guint set, guint clear)
|
||||
{
|
||||
struct debuglog_update_flags_data update;
|
||||
|
||||
/* Builtin plugins */
|
||||
debuglog_update_flags_range(__start___debug, __stop___debug, name,
|
||||
set, clear);
|
||||
|
||||
/* External plugins */
|
||||
update.name = name;
|
||||
update.set = set;
|
||||
update.clear = clear;
|
||||
__ofono_plugin_foreach(debuglog_update_flags_plugin, &update);
|
||||
}
|
||||
|
||||
static void debuglog_category_enabled(DBusLogServer* server,
|
||||
@@ -189,15 +222,10 @@ static guint debuglog_translate_flags(unsigned int ofono_flags)
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int debuglog_init(void)
|
||||
static void debuglog_add_categories(const struct ofono_debug_desc *start,
|
||||
const struct ofono_debug_desc *stop)
|
||||
{
|
||||
const struct ofono_debug_desc *start = __start___debug;
|
||||
const struct ofono_debug_desc *stop = __stop___debug;
|
||||
|
||||
debuglog_server = dbus_log_server_new(ofono_dbus_get_connection(),
|
||||
DEBUGLOG_PATH);
|
||||
|
||||
if (start && stop) {
|
||||
if (start && stop && start < stop) {
|
||||
const struct ofono_debug_desc *desc;
|
||||
GHashTable *hash = NULL;
|
||||
|
||||
@@ -221,19 +249,50 @@ static int debuglog_init(void)
|
||||
|
||||
g_hash_table_destroy(hash);
|
||||
}
|
||||
|
||||
debuglog_event_id[DEBUG_EVENT_CATEGORY_ENABLED] =
|
||||
dbus_log_server_add_category_enabled_handler(
|
||||
debuglog_server, debuglog_category_enabled,
|
||||
NULL);
|
||||
debuglog_event_id[DEBUG_EVENT_CATEGORY_DISABLED] =
|
||||
dbus_log_server_add_category_disabled_handler(
|
||||
debuglog_server, debuglog_category_disabled,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void debuglog_add_external_plugin(struct ofono_plugin_desc *desc,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
/*
|
||||
* We are only interested in the external plugins here because
|
||||
* they don't fall into __start___debug .. __stop___debug range.
|
||||
*/
|
||||
if (!(flags & OFONO_PLUGIN_FLAG_BUILTIN)) {
|
||||
if (desc->debug_start && desc->debug_stop) {
|
||||
DBG("Adding \"%s\" plugin", desc->name);
|
||||
debuglog_add_categories(desc->debug_start,
|
||||
desc->debug_stop);
|
||||
} else {
|
||||
DBG("No debug descriptors for \"%s\" plugin",
|
||||
desc->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int debuglog_init(void)
|
||||
{
|
||||
debuglog_server = dbus_log_server_new(ofono_dbus_get_connection(),
|
||||
DEBUGLOG_PATH);
|
||||
|
||||
/*
|
||||
* First handle the executable and the builtin plugins (including
|
||||
* this one) then the external plugins.
|
||||
*/
|
||||
debuglog_add_categories(__start___debug, __stop___debug);
|
||||
__ofono_plugin_foreach(debuglog_add_external_plugin, NULL);
|
||||
|
||||
debuglog_event_id[DEBUG_EVENT_CATEGORY_ENABLED] =
|
||||
dbus_log_server_add_category_enabled_handler(debuglog_server,
|
||||
debuglog_category_enabled, NULL);
|
||||
debuglog_event_id[DEBUG_EVENT_CATEGORY_DISABLED] =
|
||||
dbus_log_server_add_category_disabled_handler(debuglog_server,
|
||||
debuglog_category_disabled, NULL);
|
||||
|
||||
debuglog_default_log_proc = gutil_log_func2;
|
||||
gutil_log_func2 = debuglog_gutil_log_func;
|
||||
gutil_log_func = gutil_log_syslog;
|
||||
ofono_log_hook = debuglog_ofono_log_hook;
|
||||
|
||||
dbus_log_server_set_default_level(debuglog_server, DBUSLOG_LEVEL_DEBUG);
|
||||
@@ -251,5 +310,5 @@ static void debuglog_exit(void)
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(debuglog, "Debug log interface",
|
||||
VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
VERSION, OFONO_PLUGIN_PRIORITY_HIGH,
|
||||
debuglog_init, debuglog_exit)
|
||||
|
||||
129
ofono/plugins/sailfish_manager/sailfish_cell_info.c
Normal file
129
ofono/plugins/sailfish_manager/sailfish_cell_info.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
gint sailfish_cell_compare_location(const struct sailfish_cell *c1,
|
||||
const struct sailfish_cell *c2)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
if (c1->type != c2->type) {
|
||||
return c1->type - c2->type;
|
||||
} else if (c1->type == SAILFISH_CELL_TYPE_GSM) {
|
||||
const struct sailfish_cell_info_gsm *g1;
|
||||
const struct sailfish_cell_info_gsm *g2;
|
||||
|
||||
g1 = &c1->info.gsm;
|
||||
g2 = &c2->info.gsm;
|
||||
if (g1->mcc != g2->mcc) {
|
||||
return g1->mcc - g2->mcc;
|
||||
} else if (g1->mnc != g2->mnc) {
|
||||
return g1->mnc - g2->mnc;
|
||||
} else if (g1->lac != g2->lac) {
|
||||
return g1->lac - g2->lac;
|
||||
} else {
|
||||
return g1->cid - g2->cid;
|
||||
}
|
||||
} else if (c2->type == SAILFISH_CELL_TYPE_WCDMA) {
|
||||
const struct sailfish_cell_info_wcdma *w1;
|
||||
const struct sailfish_cell_info_wcdma *w2;
|
||||
|
||||
w1 = &c1->info.wcdma;
|
||||
w2 = &c2->info.wcdma;
|
||||
if (w1->mcc != w2->mcc) {
|
||||
return w1->mcc - w2->mcc;
|
||||
} else if (w1->mnc != w2->mnc) {
|
||||
return w1->mnc - w2->mnc;
|
||||
} else if (w1->lac != w2->lac) {
|
||||
return w1->lac - w2->lac;
|
||||
} else {
|
||||
return w1->cid - w2->cid;
|
||||
}
|
||||
} else {
|
||||
const struct sailfish_cell_info_lte *l1 =
|
||||
&c1->info.lte;
|
||||
const struct sailfish_cell_info_lte *l2 =
|
||||
&c2->info.lte;
|
||||
|
||||
GASSERT(c1->type == SAILFISH_CELL_TYPE_LTE);
|
||||
l1 = &c1->info.lte;
|
||||
l2 = &c2->info.lte;
|
||||
if (l1->mcc != l2->mcc) {
|
||||
return l1->mcc - l2->mcc;
|
||||
} else if (l1->mnc != l2->mnc) {
|
||||
return l1->mnc - l2->mnc;
|
||||
} else if (l1->ci != l2->ci) {
|
||||
return l1->ci - l2->ci;
|
||||
} else if (l1->pci != l2->pci) {
|
||||
return l1->pci - l2->pci;
|
||||
} else {
|
||||
return l1->tac - l2->tac;
|
||||
}
|
||||
}
|
||||
} else if (c1) {
|
||||
return 1;
|
||||
} else if (c2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
gint sailfish_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
return sailfish_cell_compare_location(v1, v2);
|
||||
}
|
||||
|
||||
struct sailfish_cell_info *sailfish_cell_info_ref
|
||||
(struct sailfish_cell_info *info)
|
||||
{
|
||||
if (info) {
|
||||
info->proc->ref(info);
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sailfish_cell_info_unref(struct sailfish_cell_info *info)
|
||||
{
|
||||
if (info) {
|
||||
info->proc->unref(info);
|
||||
}
|
||||
}
|
||||
|
||||
gulong sailfish_cell_info_add_cells_changed_handler
|
||||
(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
return info ? info->proc->add_cells_changed_handler(info, cb, arg) : 0;
|
||||
}
|
||||
|
||||
void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
|
||||
gulong id)
|
||||
{
|
||||
if (info) {
|
||||
info->proc->remove_handler(info, id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
598
ofono/plugins/sailfish_manager/sailfish_cell_info_dbus.c
Normal file
598
ofono/plugins/sailfish_manager/sailfish_cell_info_dbus.c
Normal file
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "sailfish_cell_info_dbus.h"
|
||||
#include "sailfish_cell_info.h"
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
struct sailfish_cell_entry {
|
||||
guint cell_id;
|
||||
char *path;
|
||||
struct sailfish_cell cell;
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_dbus {
|
||||
struct sailfish_cell_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
};
|
||||
|
||||
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
|
||||
#define CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
#define CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
|
||||
#define CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define CELL_DBUS_REMOVED_SIGNAL "Removed"
|
||||
|
||||
struct sailfish_cell_property {
|
||||
const char *name;
|
||||
glong off;
|
||||
int flag;
|
||||
};
|
||||
|
||||
#define CELL_GSM_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_gsm,name), value }
|
||||
#define CELL_WCDMA_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_wcdma,name), value }
|
||||
#define CELL_LTE_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_lte,name), value }
|
||||
|
||||
static const struct sailfish_cell_property sailfish_cell_gsm_properties [] = {
|
||||
CELL_GSM_PROPERTY(0x001,mcc),
|
||||
CELL_GSM_PROPERTY(0x002,mnc),
|
||||
CELL_GSM_PROPERTY(0x004,lac),
|
||||
CELL_GSM_PROPERTY(0x008,cid),
|
||||
CELL_GSM_PROPERTY(0x010,arfcn),
|
||||
CELL_GSM_PROPERTY(0x020,bsic),
|
||||
CELL_GSM_PROPERTY(0x040,signalStrength),
|
||||
CELL_GSM_PROPERTY(0x080,bitErrorRate),
|
||||
CELL_GSM_PROPERTY(0x100,timingAdvance)
|
||||
};
|
||||
|
||||
static const struct sailfish_cell_property sailfish_cell_wcdma_properties [] = {
|
||||
CELL_WCDMA_PROPERTY(0x01,mcc),
|
||||
CELL_WCDMA_PROPERTY(0x02,mnc),
|
||||
CELL_WCDMA_PROPERTY(0x04,lac),
|
||||
CELL_WCDMA_PROPERTY(0x08,cid),
|
||||
CELL_WCDMA_PROPERTY(0x10,psc),
|
||||
CELL_WCDMA_PROPERTY(0x20,uarfcn),
|
||||
CELL_WCDMA_PROPERTY(0x40,signalStrength),
|
||||
CELL_WCDMA_PROPERTY(0x80,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct sailfish_cell_property sailfish_cell_lte_properties [] = {
|
||||
CELL_LTE_PROPERTY(0x001,mcc),
|
||||
CELL_LTE_PROPERTY(0x002,mnc),
|
||||
CELL_LTE_PROPERTY(0x004,ci),
|
||||
CELL_LTE_PROPERTY(0x008,pci),
|
||||
CELL_LTE_PROPERTY(0x010,tac),
|
||||
CELL_LTE_PROPERTY(0x020,earfcn),
|
||||
CELL_LTE_PROPERTY(0x040,signalStrength),
|
||||
CELL_LTE_PROPERTY(0x080,rsrp),
|
||||
CELL_LTE_PROPERTY(0x100,rsrq),
|
||||
CELL_LTE_PROPERTY(0x200,rssnr),
|
||||
CELL_LTE_PROPERTY(0x400,cqi),
|
||||
CELL_LTE_PROPERTY(0x800,timingAdvance)
|
||||
};
|
||||
|
||||
#define SAILFISH_CELL_PROPERTY_REGISTERED 0x1000
|
||||
|
||||
typedef void (*sailfish_cell_info_dbus_append_fn)(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry);
|
||||
|
||||
static const char *sailfish_cell_info_dbus_cell_type_str
|
||||
(enum sailfish_cell_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
return "gsm";
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
return "wcdma";
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
return "lte";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
static const struct sailfish_cell_property *
|
||||
sailfish_cell_info_dbus_cell_properties(
|
||||
enum sailfish_cell_type type, int *count)
|
||||
{
|
||||
switch (type) {
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
*count = G_N_ELEMENTS(sailfish_cell_gsm_properties);
|
||||
return sailfish_cell_gsm_properties;
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
*count = G_N_ELEMENTS(sailfish_cell_wcdma_properties);
|
||||
return sailfish_cell_wcdma_properties;
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
*count = G_N_ELEMENTS(sailfish_cell_lte_properties);
|
||||
return sailfish_cell_lte_properties;
|
||||
default:
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static void sailfish_cell_info_destroy_entry(struct sailfish_cell_entry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
g_free(entry->path);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_reply(DBusMessage *msg,
|
||||
const struct sailfish_cell_entry *entry,
|
||||
sailfish_cell_info_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
append(&it, entry);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_version(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
dbus_int32_t version = CELL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
const char *type =
|
||||
sailfish_cell_info_dbus_cell_type_str(entry->cell.type);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
int i, n;
|
||||
DBusMessageIter dict;
|
||||
const struct sailfish_cell *cell = &entry->cell;
|
||||
const struct sailfish_cell_property *prop =
|
||||
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
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) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_close_container(it, &dict);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_all(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
sailfish_cell_info_dbus_append_version(it, entry);
|
||||
sailfish_cell_info_dbus_append_type(it, entry);
|
||||
sailfish_cell_info_dbus_append_registered(it, entry);
|
||||
sailfish_cell_info_dbus_append_properties(it, entry);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_all
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_version
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_type
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_type);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_registered
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_registered);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_properties
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_properties);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable sailfish_cell_info_dbus_cell_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll", NULL,
|
||||
GDBUS_ARGS({ "version", "i" },
|
||||
{ "type", "s" },
|
||||
{ "registered", "b" },
|
||||
{ "properties", "a{sv}" }),
|
||||
sailfish_cell_info_dbus_cell_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
|
||||
GDBUS_ARGS({ "version", "i" }),
|
||||
sailfish_cell_info_dbus_cell_get_version) },
|
||||
{ GDBUS_METHOD("GetType", NULL,
|
||||
GDBUS_ARGS({ "type", "s" }),
|
||||
sailfish_cell_info_dbus_cell_get_type) },
|
||||
{ GDBUS_METHOD("GetRegistered", NULL,
|
||||
GDBUS_ARGS({ "registered", "b" }),
|
||||
sailfish_cell_info_dbus_cell_get_registered) },
|
||||
{ GDBUS_METHOD("GetProperties", NULL,
|
||||
GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
sailfish_cell_info_dbus_cell_get_properties) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable sailfish_cell_info_dbus_cell_signals[] = {
|
||||
{ GDBUS_SIGNAL(CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "registered", "b" })) },
|
||||
{ GDBUS_SIGNAL(CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL(CELL_DBUS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
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) {
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
if (entry->cell_id == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint sailfish_cell_info_dbus_next_cell_id
|
||||
(struct sailfish_cell_info_dbus *dbus)
|
||||
{
|
||||
while (sailfish_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
|
||||
dbus->next_cell_id++;
|
||||
}
|
||||
return dbus->next_cell_id++;
|
||||
}
|
||||
|
||||
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_cell
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const struct sailfish_cell *cell)
|
||||
{
|
||||
if (cell) {
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
if (!sailfish_cell_compare_location(&entry->cell,
|
||||
cell)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_emit_path_list
|
||||
(struct sailfish_cell_info_dbus *dbus, const char *name,
|
||||
GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
|
||||
const struct sailfish_cell *c2)
|
||||
{
|
||||
if (c1->type == c2->type) {
|
||||
int i, n, mask = 0;
|
||||
const struct sailfish_cell_property *prop =
|
||||
sailfish_cell_info_dbus_cell_properties(c1->type, &n);
|
||||
|
||||
if (c1->registered != c2->registered) {
|
||||
mask |= SAILFISH_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const glong offset = prop[i].off;
|
||||
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
|
||||
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
|
||||
if (v1 != v2) {
|
||||
mask |= prop[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_property_changed
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const struct sailfish_cell_entry *entry, int mask)
|
||||
{
|
||||
int i, n;
|
||||
const struct sailfish_cell *cell = &entry->cell;
|
||||
const struct sailfish_cell_property *prop =
|
||||
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
mask &= ~SAILFISH_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_update_entries
|
||||
(struct sailfish_cell_info_dbus *dbus, gboolean emit_signals)
|
||||
{
|
||||
GSList *l;
|
||||
GPtrArray* added = NULL;
|
||||
GPtrArray* removed = NULL;
|
||||
|
||||
/* Remove non-existent cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
|
||||
sailfish_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE);
|
||||
if (emit_signals) {
|
||||
if (!removed) {
|
||||
removed =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_free);
|
||||
}
|
||||
/* Steal the path */
|
||||
g_ptr_array_add(removed, entry->path);
|
||||
entry->path = NULL;
|
||||
}
|
||||
sailfish_cell_info_destroy_entry(entry);
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
|
||||
/* Add new cells */
|
||||
for (l = dbus->info->cells; l; l = l->next) {
|
||||
const struct sailfish_cell *cell = l->data;
|
||||
struct sailfish_cell_entry *entry =
|
||||
sailfish_cell_info_dbus_find_cell(dbus, cell);
|
||||
|
||||
if (entry) {
|
||||
if (emit_signals) {
|
||||
int diff = sailfish_cell_info_dbus_compare(cell,
|
||||
&entry->cell);
|
||||
entry->cell = *cell;
|
||||
sailfish_cell_info_dbus_property_changed(dbus,
|
||||
entry, diff);
|
||||
} else {
|
||||
entry->cell = *cell;
|
||||
}
|
||||
} else {
|
||||
entry = g_new0(struct sailfish_cell_entry, 1);
|
||||
entry->cell = *cell;
|
||||
entry->cell_id =
|
||||
sailfish_cell_info_dbus_next_cell_id(dbus);
|
||||
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
|
||||
entry->cell_id);
|
||||
dbus->entries = g_slist_append(dbus->entries, entry);
|
||||
DBG("%s added", entry->path);
|
||||
g_dbus_register_interface(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
sailfish_cell_info_dbus_cell_methods,
|
||||
sailfish_cell_info_dbus_cell_signals, NULL,
|
||||
entry, NULL);
|
||||
if (emit_signals) {
|
||||
if (!added) {
|
||||
added = g_ptr_array_new();
|
||||
}
|
||||
g_ptr_array_add(added, entry->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
sailfish_cell_info_dbus_emit_path_list(dbus,
|
||||
CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
|
||||
g_ptr_array_free(removed, TRUE);
|
||||
}
|
||||
|
||||
if (added) {
|
||||
sailfish_cell_info_dbus_emit_path_list(dbus,
|
||||
CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
|
||||
g_ptr_array_free(added, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_cells_changed_cb
|
||||
(struct sailfish_cell_info *info, void *arg)
|
||||
{
|
||||
DBG("");
|
||||
sailfish_cell_info_dbus_update_entries
|
||||
((struct sailfish_cell_info_dbus *)arg, TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct sailfish_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable sailfish_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
sailfish_cell_info_dbus_get_cells) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable sailfish_cell_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
(struct ofono_modem *modem, struct sailfish_cell_info *info)
|
||||
{
|
||||
if (modem && info) {
|
||||
struct sailfish_cell_info_dbus *dbus =
|
||||
g_new0(struct sailfish_cell_info_dbus, 1);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
dbus->path = g_strdup(ofono_modem_get_path(modem));
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->info = sailfish_cell_info_ref(info);
|
||||
dbus->handler_id =
|
||||
sailfish_cell_info_add_cells_changed_handler(info,
|
||||
sailfish_cell_info_dbus_cells_changed_cb, dbus);
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE,
|
||||
sailfish_cell_info_dbus_methods,
|
||||
sailfish_cell_info_dbus_signals,
|
||||
NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(modem,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
sailfish_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
sailfish_cell_info_dbus_free(dbus);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
/* Unregister cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE);
|
||||
sailfish_cell_info_destroy_entry(entry);
|
||||
l = l->next;
|
||||
}
|
||||
g_slist_free(dbus->entries);
|
||||
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
sailfish_cell_info_remove_handler(dbus->info, dbus->handler_id);
|
||||
sailfish_cell_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
36
ofono/plugins/sailfish_manager/sailfish_cell_info_dbus.h
Normal file
36
ofono/plugins/sailfish_manager/sailfish_cell_info_dbus.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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 SAILFISH_CELL_INFO_DBUS_H
|
||||
#define SAILFISH_CELL_INFO_DBUS_H
|
||||
|
||||
struct ofono_modem;
|
||||
|
||||
struct sailfish_cell_info;
|
||||
struct sailfish_cell_info_dbus;
|
||||
|
||||
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
(struct ofono_modem *modem, struct sailfish_cell_info *info);
|
||||
void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus);
|
||||
|
||||
#endif /* SAILFISH_CELL_INFO_DBUS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -27,7 +27,10 @@
|
||||
#include "storage.h"
|
||||
|
||||
#include <sailfish_manager.h>
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
#include "sailfish_manager_dbus.h"
|
||||
#include "sailfish_cell_info_dbus.h"
|
||||
#include "sailfish_sim_info.h"
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
@@ -84,6 +87,8 @@ struct sailfish_slot_priv {
|
||||
struct sailfish_watch *watch;
|
||||
struct sailfish_sim_info *siminfo;
|
||||
struct sailfish_sim_info_dbus *siminfo_dbus;
|
||||
struct sailfish_cell_info *cellinfo;
|
||||
struct sailfish_cell_info_dbus *cellinfo_dbus;
|
||||
enum sailfish_sim_state sim_state;
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
char *imei;
|
||||
@@ -148,14 +153,33 @@ static void sailfish_manager_update_modem_paths_full
|
||||
}
|
||||
|
||||
/*
|
||||
* sailfish_manager_foreach_slot() terminates the loop and returns
|
||||
* TRUE if the callback returns TRUE. If all callbacks return FALSE, it
|
||||
* returns FALSE. It there are no slots, it returns FALSE too.
|
||||
* sailfish_manager_foreach_driver() and sailfish_manager_foreach_slot()
|
||||
* terminate the loop and return TRUE if the callback returns TRUE. If all
|
||||
* callbacks return FALSE, they returns FALSE. It there are no drivers/slots,
|
||||
* they return FALSE too.
|
||||
*/
|
||||
|
||||
#define SF_LOOP_CONTINUE (FALSE)
|
||||
#define SF_LOOP_DONE (TRUE)
|
||||
|
||||
static gboolean sailfish_manager_foreach_driver(struct sailfish_manager_priv *p,
|
||||
gboolean (*fn)(struct sailfish_slot_driver_reg *r, void *user_data),
|
||||
void *user_data)
|
||||
{
|
||||
struct sailfish_slot_driver_reg *r = p->drivers;
|
||||
gboolean done = FALSE;
|
||||
|
||||
while (r && !done) {
|
||||
struct sailfish_slot_driver_reg *rnext = r->next;
|
||||
|
||||
/* The callback returns TRUE to terminate the loop */
|
||||
done = fn(r, user_data);
|
||||
r = rnext;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_foreach_slot
|
||||
(struct sailfish_manager_priv *p,
|
||||
gboolean (*fn)(struct sailfish_slot_priv *s, void *user_data),
|
||||
@@ -189,12 +213,31 @@ static gboolean sailfish_manager_foreach_slot
|
||||
return done;
|
||||
}
|
||||
|
||||
static void sailfish_manager_slot_update_cell_info_dbus
|
||||
(struct sailfish_slot_priv *s)
|
||||
{
|
||||
struct ofono_modem *modem = s->watch->modem;
|
||||
|
||||
if (modem && s->cellinfo) {
|
||||
if (!s->cellinfo_dbus) {
|
||||
s->cellinfo_dbus = sailfish_cell_info_dbus_new(modem,
|
||||
s->cellinfo);
|
||||
}
|
||||
} else {
|
||||
if (s->cellinfo_dbus) {
|
||||
sailfish_cell_info_dbus_free(s->cellinfo_dbus);
|
||||
s->cellinfo_dbus = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_manager_slot_modem_changed(struct sailfish_watch *w,
|
||||
void *user_data)
|
||||
{
|
||||
struct sailfish_slot_priv *s = user_data;
|
||||
struct sailfish_manager_priv *p = s->manager->plugin;
|
||||
|
||||
sailfish_manager_slot_update_cell_info_dbus(s);
|
||||
sailfish_manager_update_modem_paths_full(p);
|
||||
sailfish_manager_update_ready(p);
|
||||
}
|
||||
@@ -382,6 +425,8 @@ static void sailfish_slot_free(struct sailfish_slot_priv *s)
|
||||
}
|
||||
sailfish_sim_info_unref(s->siminfo);
|
||||
sailfish_sim_info_dbus_free(s->siminfo_dbus);
|
||||
sailfish_cell_info_dbus_free(s->cellinfo_dbus);
|
||||
sailfish_cell_info_unref(s->cellinfo);
|
||||
sailfish_watch_remove_all_handlers(s->watch, s->watch_event_id);
|
||||
sailfish_watch_unref(s->watch);
|
||||
g_free(s->imei);
|
||||
@@ -392,6 +437,55 @@ static void sailfish_slot_free(struct sailfish_slot_priv *s)
|
||||
sailfish_manager_reindex_slots(p);
|
||||
}
|
||||
|
||||
void sailfish_manager_set_cell_info(struct sailfish_slot *s,
|
||||
struct sailfish_cell_info *info)
|
||||
{
|
||||
if (s) {
|
||||
struct sailfish_slot_priv *slot = sailfish_slot_priv_cast(s);
|
||||
|
||||
if (slot->cellinfo != info) {
|
||||
sailfish_cell_info_dbus_free(slot->cellinfo_dbus);
|
||||
sailfish_cell_info_unref(slot->cellinfo);
|
||||
slot->cellinfo = sailfish_cell_info_ref(info);
|
||||
slot->cellinfo_dbus = NULL;
|
||||
sailfish_manager_slot_update_cell_info_dbus(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_update_dbus_block_proc
|
||||
(struct sailfish_slot_driver_reg *r, void *data)
|
||||
{
|
||||
enum sailfish_manager_dbus_block *block = data;
|
||||
struct sailfish_slot_manager *m;
|
||||
struct sailfish_slot_priv *s;
|
||||
|
||||
if (r->init_id) {
|
||||
/* Driver is being initialized */
|
||||
(*block) |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
|
||||
return SF_LOOP_DONE;
|
||||
}
|
||||
|
||||
m = r->manager;
|
||||
if (!m) {
|
||||
return SF_LOOP_CONTINUE;
|
||||
}
|
||||
|
||||
if (!m->started) {
|
||||
/* Slots are being initialized */
|
||||
(*block) |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
|
||||
return SF_LOOP_DONE;
|
||||
}
|
||||
|
||||
for (s = m->slots; s && s->imei; s = s->next);
|
||||
if (s) {
|
||||
/* IMEI is not available (yet) */
|
||||
(*block) |= SAILFISH_MANAGER_DBUS_BLOCK_IMEI;
|
||||
}
|
||||
|
||||
return SF_LOOP_CONTINUE;
|
||||
}
|
||||
|
||||
static void sailfish_manager_update_dbus_block(struct sailfish_manager_priv *p)
|
||||
{
|
||||
enum sailfish_manager_dbus_block block =
|
||||
@@ -401,35 +495,8 @@ static void sailfish_manager_update_dbus_block(struct sailfish_manager_priv *p)
|
||||
/* Plugin is being initialized */
|
||||
block |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
|
||||
} else {
|
||||
struct sailfish_slot_driver_reg *r;
|
||||
|
||||
for (r = p->drivers; r; r = r->next) {
|
||||
struct sailfish_slot_manager *m;
|
||||
struct sailfish_slot_priv *s;
|
||||
|
||||
if (r->init_id) {
|
||||
/* Driver is being initialized */
|
||||
block |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
m = r->manager;
|
||||
if (!m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!m->started) {
|
||||
/* Slots are being initialized */
|
||||
block |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
for (s = m->slots; s && s->imei; s = s->next);
|
||||
if (s) {
|
||||
/* IMEI is not available (yet) */
|
||||
block |= SAILFISH_MANAGER_DBUS_BLOCK_IMEI;
|
||||
}
|
||||
}
|
||||
sailfish_manager_foreach_driver(p,
|
||||
sailfish_manager_update_dbus_block_proc, &block);
|
||||
}
|
||||
|
||||
sailfish_manager_dbus_set_block(p->dbus, block);
|
||||
@@ -437,16 +504,14 @@ static void sailfish_manager_update_dbus_block(struct sailfish_manager_priv *p)
|
||||
|
||||
static void sailfish_manager_set_config_string
|
||||
(struct sailfish_manager_priv *p, const char *key,
|
||||
const char *value, gboolean sync)
|
||||
const char *value)
|
||||
{
|
||||
if (value) {
|
||||
g_key_file_set_string(p->storage, SF_STORE_GROUP, key, value);
|
||||
} else {
|
||||
g_key_file_remove_key(p->storage, SF_STORE_GROUP, key, NULL);
|
||||
}
|
||||
if (sync) {
|
||||
storage_sync(NULL, SF_STORE, p->storage);
|
||||
}
|
||||
storage_sync(NULL, SF_STORE, p->storage);
|
||||
}
|
||||
|
||||
struct sailfish_manager_slot_imsi_data {
|
||||
@@ -640,8 +705,22 @@ static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
|
||||
return mask;
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_update_ready_proc
|
||||
(struct sailfish_slot_priv *s, void *unused)
|
||||
static gboolean sailfish_manager_update_ready_driver_proc
|
||||
(struct sailfish_slot_driver_reg *r, void *unused)
|
||||
{
|
||||
struct sailfish_slot_manager *m = r->manager;
|
||||
|
||||
if (!m || m->started) {
|
||||
/* This one is either missing or ready */
|
||||
return SF_LOOP_CONTINUE;
|
||||
} else {
|
||||
/* This one is not */
|
||||
return SF_LOOP_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_update_ready_slot_proc
|
||||
(struct sailfish_slot_priv *s, void *unused)
|
||||
{
|
||||
if (s->imei && s->sim_state != SAILFISH_SIM_STATE_UNKNOWN) {
|
||||
/* This one is ready */
|
||||
@@ -655,11 +734,14 @@ static gboolean sailfish_manager_update_ready_proc
|
||||
static gboolean sailfish_manager_update_ready(struct sailfish_manager_priv *p)
|
||||
{
|
||||
/*
|
||||
* sailfish_manager_foreach_slot() returns FALSE if either all
|
||||
* callbacks returned FALSE (SF_LOOP_CONTINUE) or there are no
|
||||
* slots. In either case we are ready. */
|
||||
const gboolean ready = !sailfish_manager_foreach_slot(p,
|
||||
sailfish_manager_update_ready_proc, NULL);
|
||||
* sailfish_manager_foreach_driver and sailfish_manager_foreach_slot
|
||||
* return FALSE if either all callbacks returned SF_LOOP_CONTINUE or
|
||||
* there are no drivers/slots. In either case we are ready. */
|
||||
const gboolean ready =
|
||||
!sailfish_manager_foreach_driver
|
||||
(p,sailfish_manager_update_ready_driver_proc, NULL) &&
|
||||
!sailfish_manager_foreach_slot
|
||||
(p, sailfish_manager_update_ready_slot_proc, NULL);
|
||||
|
||||
if (p->pub.ready != ready) {
|
||||
p->pub.ready = ready;
|
||||
@@ -827,7 +909,7 @@ static void sailfish_manager_set_enabled_slots(struct sailfish_manager *m,
|
||||
* default behavior. */
|
||||
if (data.all_enabled) {
|
||||
sailfish_manager_set_config_string(p,
|
||||
SF_STORE_ENABLED_SLOTS, NULL, TRUE);
|
||||
SF_STORE_ENABLED_SLOTS, NULL);
|
||||
} else {
|
||||
const char *value;
|
||||
char *tmp;
|
||||
@@ -841,7 +923,7 @@ static void sailfish_manager_set_enabled_slots(struct sailfish_manager *m,
|
||||
}
|
||||
|
||||
sailfish_manager_set_config_string(p,
|
||||
SF_STORE_ENABLED_SLOTS, value, TRUE);
|
||||
SF_STORE_ENABLED_SLOTS, value);
|
||||
g_free(tmp);
|
||||
}
|
||||
g_strfreev(new_slots);
|
||||
@@ -864,7 +946,7 @@ static void sailfish_manager_set_default_voice_imsi(struct sailfish_manager *m,
|
||||
m->default_voice_imsi =
|
||||
p->default_voice_imsi = g_strdup(imsi);
|
||||
sailfish_manager_set_config_string(p,
|
||||
SF_STORE_DEFAULT_VOICE_SIM, imsi, TRUE);
|
||||
SF_STORE_DEFAULT_VOICE_SIM, imsi);
|
||||
sailfish_manager_dbus_signal(p->dbus,
|
||||
SAILFISH_MANAGER_SIGNAL_VOICE_IMSI |
|
||||
sailfish_manager_update_modem_paths(p));
|
||||
@@ -882,7 +964,7 @@ static void sailfish_manager_set_default_data_imsi(struct sailfish_manager *m,
|
||||
m->default_data_imsi =
|
||||
p->default_data_imsi = g_strdup(imsi);
|
||||
sailfish_manager_set_config_string(p,
|
||||
SF_STORE_DEFAULT_DATA_SIM, imsi, TRUE);
|
||||
SF_STORE_DEFAULT_DATA_SIM, imsi);
|
||||
sailfish_manager_dbus_signal(p->dbus,
|
||||
SAILFISH_MANAGER_SIGNAL_DATA_IMSI |
|
||||
sailfish_manager_update_modem_paths(p));
|
||||
@@ -964,6 +1046,7 @@ void sailfish_manager_slot_error(struct sailfish_slot *s, const char *key,
|
||||
struct sailfish_slot_priv *priv = sailfish_slot_priv_cast(s);
|
||||
/* slot->path always starts with a slash, skip it */
|
||||
const char *section = s->path + 1;
|
||||
|
||||
priv->errors = sailfish_manager_inc_error_count(priv->errors,
|
||||
section, key);
|
||||
sailfish_manager_dbus_signal_modem_error
|
||||
@@ -1154,7 +1237,9 @@ static gboolean sailfish_manager_priv_init(gpointer user_data)
|
||||
if (!p->init_countdown) {
|
||||
p->init_id = 0;
|
||||
DBG("done with registrations");
|
||||
sailfish_manager_update_dbus_block(p);
|
||||
if (!sailfish_manager_update_ready(p)) {
|
||||
sailfish_manager_update_dbus_block(p);
|
||||
}
|
||||
return G_SOURCE_REMOVE;
|
||||
} else {
|
||||
/* Keep on waiting */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2008-2014 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
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <ofono/call-settings.h>
|
||||
#include <ofono/devinfo.h>
|
||||
#include <ofono/message-waiting.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/phonebook.h>
|
||||
#include <ofono/sim.h>
|
||||
@@ -58,10 +59,41 @@
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
#include "bluez4.h"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *rsen_prefix[]= { "#RSEN:", NULL };
|
||||
static const char *qss_prefix[] = { "#QSS:", NULL };
|
||||
|
||||
enum modem_model {
|
||||
HE910 = 1,
|
||||
UE910,
|
||||
LE910,
|
||||
UC864,
|
||||
UE866,
|
||||
};
|
||||
|
||||
static struct {
|
||||
enum modem_model model;
|
||||
const char *variant;
|
||||
gboolean has_voice;
|
||||
gboolean has_gps;
|
||||
} variants_list[] = {
|
||||
{ HE910, NULL, FALSE, FALSE },
|
||||
{ HE910, "G", TRUE, TRUE },
|
||||
{ HE910, "GL", TRUE, FALSE },
|
||||
{ HE910, "EUR", TRUE, FALSE },
|
||||
{ HE910, "NAR", TRUE, FALSE },
|
||||
{ HE910, "DG", FALSE, TRUE },
|
||||
{ HE910, "EUG", FALSE, TRUE },
|
||||
{ HE910, "NAG", FALSE, TRUE },
|
||||
{ UE910, NULL, FALSE, FALSE },
|
||||
{ UE910, "EUR", TRUE, FALSE },
|
||||
{ UE910, "NAR", TRUE, FALSE },
|
||||
{ LE910, NULL, FALSE, FALSE },
|
||||
{ UC864, NULL, TRUE, FALSE },
|
||||
{ UC864, "G", TRUE, TRUE },
|
||||
{ UC864, "WD", FALSE, FALSE },
|
||||
{ UE866, NULL, FALSE, FALSE },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct telit_data {
|
||||
GAtChat *chat; /* AT chat */
|
||||
@@ -69,11 +101,9 @@ struct telit_data {
|
||||
struct ofono_sim *sim;
|
||||
ofono_bool_t have_sim;
|
||||
ofono_bool_t sms_phonebook_added;
|
||||
struct ofono_modem *sap_modem;
|
||||
GIOChannel *bt_io;
|
||||
GIOChannel *hw_io;
|
||||
guint bt_watch;
|
||||
guint hw_watch;
|
||||
enum modem_model model;
|
||||
gboolean has_voice;
|
||||
gboolean has_gps;
|
||||
};
|
||||
|
||||
static void telit_debug(const char *str, void *user_data)
|
||||
@@ -83,102 +113,6 @@ static void telit_debug(const char *str, void *user_data)
|
||||
ofono_info("%s%s", prefix, str);
|
||||
}
|
||||
|
||||
static void sap_close_io(struct ofono_modem *modem)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
if (data->bt_io != NULL) {
|
||||
int sk = g_io_channel_unix_get_fd(data->bt_io);
|
||||
shutdown(sk, SHUT_RDWR);
|
||||
|
||||
g_io_channel_unref(data->bt_io);
|
||||
data->bt_io = NULL;
|
||||
}
|
||||
|
||||
if (data->bt_watch > 0)
|
||||
g_source_remove(data->bt_watch);
|
||||
|
||||
g_io_channel_unref(data->hw_io);
|
||||
data->hw_io = NULL;
|
||||
|
||||
if (data->hw_watch > 0)
|
||||
g_source_remove(data->hw_watch);
|
||||
}
|
||||
|
||||
static void bt_watch_remove(gpointer userdata)
|
||||
{
|
||||
struct ofono_modem *modem = userdata;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
|
||||
data->bt_watch = 0;
|
||||
}
|
||||
|
||||
static gboolean bt_event_cb(GIOChannel *bt_io, GIOCondition condition,
|
||||
gpointer userdata)
|
||||
{
|
||||
struct ofono_modem *modem = userdata;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
if (condition & G_IO_IN) {
|
||||
GIOStatus status;
|
||||
gsize bytes_read, bytes_written;
|
||||
gchar buf[300];
|
||||
|
||||
status = g_io_channel_read_chars(bt_io, buf, 300,
|
||||
&bytes_read, NULL);
|
||||
|
||||
if (bytes_read > 0)
|
||||
g_io_channel_write_chars(data->hw_io, buf,
|
||||
bytes_read, &bytes_written, NULL);
|
||||
|
||||
if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void hw_watch_remove(gpointer userdata)
|
||||
{
|
||||
struct ofono_modem *modem = userdata;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
|
||||
data->hw_watch = 0;
|
||||
}
|
||||
|
||||
static gboolean hw_event_cb(GIOChannel *hw_io, GIOCondition condition,
|
||||
gpointer userdata)
|
||||
{
|
||||
struct ofono_modem *modem = userdata;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
if (condition & G_IO_IN) {
|
||||
GIOStatus status;
|
||||
gsize bytes_read, bytes_written;
|
||||
gchar buf[300];
|
||||
|
||||
status = g_io_channel_read_chars(hw_io, buf, 300,
|
||||
&bytes_read, NULL);
|
||||
|
||||
if (bytes_read > 0)
|
||||
g_io_channel_write_chars(data->bt_io, buf,
|
||||
bytes_read, &bytes_written, NULL);
|
||||
|
||||
if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GAtChat *open_device(struct ofono_modem *modem,
|
||||
const char *key, char *debug)
|
||||
{
|
||||
@@ -199,15 +133,13 @@ static GAtChat *open_device(struct ofono_modem *modem,
|
||||
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_gsmv1();
|
||||
syntax = g_at_syntax_new_gsm_permissive();
|
||||
chat = g_at_chat_new(channel, syntax);
|
||||
g_at_syntax_unref(syntax);
|
||||
g_io_channel_unref(channel);
|
||||
@@ -243,6 +175,11 @@ static void switch_sim_state_status(struct ofono_modem *modem, int status)
|
||||
}
|
||||
break;
|
||||
case 3: /* SIM inserted, SMS and phonebook ready */
|
||||
if (data->have_sim == FALSE) {
|
||||
ofono_sim_inserted_notify(data->sim, TRUE);
|
||||
data->have_sim = TRUE;
|
||||
}
|
||||
|
||||
if (data->sms_phonebook_added == FALSE) {
|
||||
ofono_phonebook_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_sms_create(modem, 0, "atmodem", data->chat);
|
||||
@@ -273,33 +210,61 @@ static void telit_qss_notify(GAtResult *result, gpointer user_data)
|
||||
switch_sim_state_status(modem, status);
|
||||
}
|
||||
|
||||
static void qss_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
int status, mode;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "#QSS:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &status))
|
||||
return;
|
||||
|
||||
switch_sim_state_status(modem, status);
|
||||
}
|
||||
|
||||
static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
struct ofono_modem *m = data->sap_modem ? : modem;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok) {
|
||||
g_at_chat_unref(data->chat);
|
||||
data->chat = NULL;
|
||||
ofono_modem_set_powered(m, FALSE);
|
||||
sap_close_io(modem);
|
||||
|
||||
g_at_chat_unref(data->modem);
|
||||
data->modem = NULL;
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch data carrier detect signal off.
|
||||
* When the DCD is disabled the modem does not hangup anymore
|
||||
* after the data connection.
|
||||
* after the data connection. We need to do that on both channels.
|
||||
*/
|
||||
g_at_chat_send(data->chat, "AT&C0", NULL, NULL, NULL, NULL);
|
||||
g_at_chat_send(data->modem, "AT&C0", NULL, NULL, NULL, NULL);
|
||||
|
||||
data->have_sim = FALSE;
|
||||
data->sms_phonebook_added = FALSE;
|
||||
|
||||
ofono_modem_set_powered(m, TRUE);
|
||||
ofono_modem_set_powered(modem, TRUE);
|
||||
|
||||
/*
|
||||
* Tell the modem not to automatically initiate auto-attach
|
||||
@@ -314,6 +279,105 @@ static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
/* Enable sim state notification */
|
||||
g_at_chat_send(data->chat, "AT#QSS=2", none_prefix, NULL, NULL, NULL);
|
||||
|
||||
g_at_chat_send(data->chat, "AT#QSS?", qss_prefix,
|
||||
qss_query_cb, modem, NULL);
|
||||
}
|
||||
|
||||
static gboolean find_model_variant(struct ofono_modem *modem,
|
||||
const char * model_variant)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
char model[32];
|
||||
char variant[32];
|
||||
gchar **tokens;
|
||||
int i;
|
||||
|
||||
if (!model_variant || model_variant[0] == '\0')
|
||||
return FALSE;
|
||||
|
||||
DBG("%s", model_variant);
|
||||
|
||||
tokens = g_strsplit(model_variant, "-", 2);
|
||||
|
||||
if (!tokens || !tokens[0] || !tokens[1])
|
||||
return FALSE;
|
||||
|
||||
g_strlcpy(model, tokens[0], sizeof(model));
|
||||
g_strlcpy(variant, tokens[1], sizeof(variant));
|
||||
g_strfreev(tokens);
|
||||
|
||||
if (g_str_equal(model, "HE910"))
|
||||
data->model = HE910;
|
||||
else if (g_str_equal(model, "UE910"))
|
||||
data->model = UE910;
|
||||
else if (g_str_equal(model, "LE910"))
|
||||
data->model = LE910;
|
||||
else if (g_str_equal(model, "UC864"))
|
||||
data->model = UC864;
|
||||
else if (g_str_equal(model, "UE866"))
|
||||
data->model = UE866;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
DBG("Model: %s", model);
|
||||
|
||||
for (i = 0; variants_list[i].model; i++) {
|
||||
if (variants_list[i].model != data->model)
|
||||
continue;
|
||||
|
||||
/* Set model defaults */
|
||||
if (variants_list[i].variant == NULL) {
|
||||
data->has_voice = variants_list[i].has_voice;
|
||||
data->has_gps = variants_list[i].has_gps;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Specific variant match */
|
||||
if (g_str_equal(variant, variants_list[i].variant)) {
|
||||
DBG("Variant: %s", variant);
|
||||
data->has_voice = variants_list[i].has_voice;
|
||||
data->has_gps = variants_list[i].has_gps;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void cfun_gmm_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
const char * model_variant;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
/* Get +GMM response */
|
||||
if (!at_util_parse_attr(result, "", &model_variant))
|
||||
goto error;
|
||||
|
||||
/* Try to find modem model and variant */
|
||||
if (!find_model_variant(modem, model_variant)) {
|
||||
ofono_info("Unknown xE910 model/variant %s", model_variant);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set phone functionality */
|
||||
if (g_at_chat_send(data->chat, "AT+CFUN=1", none_prefix,
|
||||
cfun_enable_cb, modem, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
g_at_chat_unref(data->chat);
|
||||
data->chat = NULL;
|
||||
|
||||
g_at_chat_unref(data->modem);
|
||||
data->modem = NULL;
|
||||
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
}
|
||||
|
||||
static int telit_enable(struct ofono_modem *modem)
|
||||
@@ -341,67 +405,23 @@ static int telit_enable(struct ofono_modem *modem)
|
||||
*/
|
||||
g_at_chat_send(data->chat, "ATE0 +CMEE=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
g_at_chat_send(data->modem, "ATE0", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
/*
|
||||
* Disable sim state notification so that we sure get a notification
|
||||
* when we enable it again later and don't have to query it.
|
||||
*/
|
||||
g_at_chat_send(data->chat, "AT#QSS=0", none_prefix, NULL, NULL, NULL);
|
||||
|
||||
/* Set phone functionality */
|
||||
g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix,
|
||||
cfun_enable_cb, modem, NULL);
|
||||
/* Get modem model and variant */
|
||||
g_at_chat_send(data->chat, "AT+GMM", NULL,
|
||||
cfun_gmm_cb, modem, NULL);
|
||||
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void telit_rsen_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
int status;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "#RSEN:"))
|
||||
return;
|
||||
|
||||
g_at_result_iter_next_number(&iter, &status);
|
||||
|
||||
if (status == 0) {
|
||||
ofono_modem_set_powered(data->sap_modem, FALSE);
|
||||
sap_close_io(modem);
|
||||
return;
|
||||
}
|
||||
|
||||
telit_enable(modem);
|
||||
}
|
||||
|
||||
static void rsen_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
if (!ok) {
|
||||
ofono_modem_set_powered(data->sap_modem, FALSE);
|
||||
sap_close_io(modem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
if(data->sap_modem)
|
||||
modem = data->sap_modem;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_unref(data->chat);
|
||||
@@ -409,13 +429,12 @@ static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
if (ok)
|
||||
ofono_modem_set_powered(modem, FALSE);
|
||||
|
||||
data->sap_modem = NULL;
|
||||
}
|
||||
|
||||
static int telit_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_cancel_all(data->modem);
|
||||
@@ -427,211 +446,66 @@ static int telit_disable(struct ofono_modem *modem)
|
||||
g_at_chat_unregister_all(data->chat);
|
||||
|
||||
/* Power down modem */
|
||||
g_at_chat_send(data->chat, "AT+CFUN=0", none_prefix,
|
||||
g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix,
|
||||
cfun_disable_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void rsen_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
sap_close_io(modem);
|
||||
|
||||
telit_disable(modem);
|
||||
}
|
||||
|
||||
static int telit_sap_open(void)
|
||||
{
|
||||
const char *device = "/dev/ttyUSB4";
|
||||
struct termios ti;
|
||||
int fd;
|
||||
|
||||
DBG("%s", device);
|
||||
|
||||
fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Switch TTY to raw mode */
|
||||
memset(&ti, 0, sizeof(ti));
|
||||
cfmakeraw(&ti);
|
||||
|
||||
ti.c_cflag |= (B115200 | CLOCAL | CREAD);
|
||||
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
if (tcsetattr(fd, TCSANOW, &ti) < 0) {
|
||||
close(fd);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int telit_sap_enable(struct ofono_modem *modem,
|
||||
struct ofono_modem *sap_modem,
|
||||
int bt_fd)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
int fd;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
fd = telit_sap_open();
|
||||
if (fd < 0)
|
||||
goto error;
|
||||
|
||||
data->hw_io = g_io_channel_unix_new(fd);
|
||||
if (data->hw_io == NULL) {
|
||||
close(fd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_io_channel_set_encoding(data->hw_io, NULL, NULL);
|
||||
g_io_channel_set_buffered(data->hw_io, FALSE);
|
||||
g_io_channel_set_close_on_unref(data->hw_io, TRUE);
|
||||
|
||||
data->bt_io = g_io_channel_unix_new(bt_fd);
|
||||
if (data->bt_io == NULL)
|
||||
goto error;
|
||||
|
||||
g_io_channel_set_encoding(data->bt_io, NULL, NULL);
|
||||
g_io_channel_set_buffered(data->bt_io, FALSE);
|
||||
g_io_channel_set_close_on_unref(data->bt_io, TRUE);
|
||||
|
||||
data->hw_watch = g_io_add_watch_full(data->hw_io, G_PRIORITY_DEFAULT,
|
||||
G_IO_HUP | G_IO_ERR | G_IO_NVAL | G_IO_IN,
|
||||
hw_event_cb, modem, hw_watch_remove);
|
||||
|
||||
data->bt_watch = g_io_add_watch_full(data->bt_io, G_PRIORITY_DEFAULT,
|
||||
G_IO_HUP | G_IO_ERR | G_IO_NVAL | G_IO_IN,
|
||||
bt_event_cb, modem, bt_watch_remove);
|
||||
|
||||
data->sap_modem = sap_modem;
|
||||
|
||||
g_at_chat_register(data->chat, "#RSEN:", telit_rsen_notify,
|
||||
FALSE, modem, NULL);
|
||||
|
||||
g_at_chat_send(data->chat, "AT#NOPT=0", NULL, NULL, NULL, NULL);
|
||||
|
||||
/* Set SAP functionality */
|
||||
g_at_chat_send(data->chat, "AT#RSEN=1,1,0,2,0", rsen_prefix,
|
||||
rsen_enable_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
|
||||
error:
|
||||
shutdown(bt_fd, SHUT_RDWR);
|
||||
close(bt_fd);
|
||||
|
||||
sap_close_io(modem);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int telit_sap_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
g_at_chat_send(data->chat, "AT#RSEN=0", rsen_prefix,
|
||||
rsen_disable_cb, modem, NULL);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void telit_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
if (data->sap_modem)
|
||||
modem = data->sap_modem;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_devinfo_create(modem, 0, "atmodem", data->chat);
|
||||
data->sim = ofono_sim_create(modem, OFONO_VENDOR_TELIT, "atmodem",
|
||||
data->chat);
|
||||
ofono_voicecall_create(modem, 0, "atmodem", data->chat);
|
||||
}
|
||||
|
||||
static void telit_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
if (data->sap_modem)
|
||||
modem = data->sap_modem;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
gprs = ofono_gprs_create(modem, OFONO_VENDOR_TELIT, "atmodem",
|
||||
data->chat);
|
||||
gc = ofono_gprs_context_create(modem, 0, "atmodem", data->modem);
|
||||
|
||||
if (gprs && gc)
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
|
||||
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 telit_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *user_data)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
char const *command = online ? "AT+CFUN=1,0" : "AT+CFUN=4,0";
|
||||
|
||||
DBG("modem %p %s", modem, online ? "online" : "offline");
|
||||
|
||||
g_at_chat_send(data->chat, command, none_prefix, set_online_cb,
|
||||
cbd, g_free);
|
||||
if (data->has_gps)
|
||||
ofono_location_reporting_create(modem, 0, "telitmodem",
|
||||
data->chat);
|
||||
}
|
||||
|
||||
static void telit_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct telit_data *data = ofono_modem_get_data(modem);
|
||||
struct ofono_message_waiting *mw;
|
||||
|
||||
if(data->sap_modem)
|
||||
modem = data->sap_modem;
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_netreg_create(modem, OFONO_VENDOR_TELIT, "atmodem", data->chat);
|
||||
ofono_ussd_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_forwarding_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_settings_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_meter_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_barring_create(modem, 0, "atmodem", data->chat);
|
||||
|
||||
mw = ofono_message_waiting_create(modem);
|
||||
if (mw)
|
||||
ofono_message_waiting_register(mw);
|
||||
if (data->has_voice) {
|
||||
struct ofono_message_waiting *mw;
|
||||
|
||||
ofono_voicecall_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_ussd_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_forwarding_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_settings_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_meter_create(modem, 0, "atmodem", data->chat);
|
||||
ofono_call_barring_create(modem, 0, "atmodem", data->chat);
|
||||
|
||||
mw = ofono_message_waiting_create(modem);
|
||||
if (mw)
|
||||
ofono_message_waiting_register(mw);
|
||||
}
|
||||
|
||||
gprs = ofono_gprs_create(modem, OFONO_VENDOR_TELIT, "atmodem",
|
||||
data->chat);
|
||||
|
||||
if (data->model == LE910)
|
||||
gc = ofono_gprs_context_create(modem, OFONO_VENDOR_TELIT,
|
||||
"telitncmmodem", data->modem);
|
||||
else
|
||||
gc = ofono_gprs_context_create(modem, 0, "atmodem",
|
||||
data->modem);
|
||||
|
||||
if (gprs && gc)
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
|
||||
static struct bluetooth_sap_driver sap_driver = {
|
||||
.name = "telit",
|
||||
.enable = telit_sap_enable,
|
||||
.pre_sim = telit_pre_sim,
|
||||
.post_sim = telit_post_sim,
|
||||
.set_online = telit_set_online,
|
||||
.post_online = telit_post_online,
|
||||
.disable = telit_sap_disable,
|
||||
};
|
||||
|
||||
static int telit_probe(struct ofono_modem *modem)
|
||||
{
|
||||
struct telit_data *data;
|
||||
@@ -644,8 +518,6 @@ static int telit_probe(struct ofono_modem *modem)
|
||||
|
||||
ofono_modem_set_data(modem, data);
|
||||
|
||||
bluetooth_sap_client_register(&sap_driver, modem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -655,8 +527,6 @@ static void telit_remove(struct ofono_modem *modem)
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
bluetooth_sap_client_unregister(modem);
|
||||
|
||||
ofono_modem_set_data(modem, NULL);
|
||||
|
||||
/* Cleanup after hot-unplug */
|
||||
@@ -672,14 +542,14 @@ static struct ofono_modem_driver telit_driver = {
|
||||
.remove = telit_remove,
|
||||
.enable = telit_enable,
|
||||
.disable = telit_disable,
|
||||
.set_online = telit_set_online,
|
||||
.pre_sim = telit_pre_sim,
|
||||
.post_sim = telit_post_sim,
|
||||
.post_online = telit_post_online,
|
||||
};
|
||||
|
||||
static int telit_init(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
return ofono_modem_driver_register(&telit_driver);
|
||||
}
|
||||
|
||||
@@ -688,5 +558,5 @@ static void telit_exit(void)
|
||||
ofono_modem_driver_unregister(&telit_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(telit, "telit driver", VERSION,
|
||||
OFONO_PLUGIN_DEFINE(telit, "Telit driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, telit_init, telit_exit)
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/netmon.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
@@ -313,6 +315,8 @@ static void ublox_post_sim(struct ofono_modem *modem)
|
||||
|
||||
--ncontexts;
|
||||
}
|
||||
|
||||
ofono_lte_create(modem, "ubloxmodem", data->aux);
|
||||
}
|
||||
|
||||
static void ublox_post_online(struct ofono_modem *modem)
|
||||
@@ -320,6 +324,8 @@ static void ublox_post_online(struct ofono_modem *modem)
|
||||
struct ublox_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
ofono_netreg_create(modem, data->vendor_family, "atmodem", data->aux);
|
||||
|
||||
ofono_netmon_create(modem, data->vendor_family, "ubloxmodem", data->aux);
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver ublox_driver = {
|
||||
|
||||
@@ -1,545 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 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 <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
static GSList *modem_list = NULL;
|
||||
static GHashTable *devpath_list = NULL;
|
||||
|
||||
static struct ofono_modem *find_modem(const char *devpath)
|
||||
{
|
||||
GSList *list;
|
||||
|
||||
for (list = modem_list; list; list = list->next) {
|
||||
struct ofono_modem *modem = list->data;
|
||||
const char *path = ofono_modem_get_string(modem, "Path");
|
||||
|
||||
if (g_strcmp0(devpath, path) == 0)
|
||||
return modem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *get_property(struct udev_device *device,
|
||||
char const *property_name)
|
||||
{
|
||||
struct udev_list_entry *entry;
|
||||
|
||||
entry = udev_device_get_properties_list_entry(device);
|
||||
while (entry) {
|
||||
const char *name = udev_list_entry_get_name(entry);
|
||||
|
||||
if (g_strcmp0(name, property_name) == 0)
|
||||
return udev_list_entry_get_value(entry);
|
||||
|
||||
entry = udev_list_entry_get_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *get_driver(struct udev_device *udev_device)
|
||||
{
|
||||
return get_property(udev_device, "OFONO_DRIVER");
|
||||
}
|
||||
|
||||
static const char *get_serial(struct udev_device *udev_device)
|
||||
{
|
||||
const char *serial;
|
||||
|
||||
serial = get_property(udev_device, "ID_SERIAL_SHORT");
|
||||
|
||||
if (serial != NULL) {
|
||||
unsigned int i, len = strlen(serial);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!g_ascii_isalnum(serial[i]))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
static void add_ifx(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
struct udev_list_entry *entry;
|
||||
const char *devnode;
|
||||
|
||||
DBG("modem %p", modem);
|
||||
|
||||
devnode = udev_device_get_devnode(udev_device);
|
||||
ofono_modem_set_string(modem, "Device", devnode);
|
||||
|
||||
entry = udev_device_get_properties_list_entry(udev_device);
|
||||
while (entry) {
|
||||
const char *name = udev_list_entry_get_name(entry);
|
||||
const char *value = udev_list_entry_get_value(entry);
|
||||
|
||||
if (g_str_equal(name, "OFONO_IFX_LDISC") == TRUE)
|
||||
ofono_modem_set_string(modem, "LineDiscipline", value);
|
||||
else if (g_str_equal(name, "OFONO_IFX_AUDIO") == TRUE)
|
||||
ofono_modem_set_string(modem, "AudioSetting", value);
|
||||
else if (g_str_equal(name, "OFONO_IFX_LOOPBACK") == TRUE)
|
||||
ofono_modem_set_string(modem, "AudioLoopback", value);
|
||||
|
||||
entry = udev_list_entry_get_next(entry);
|
||||
}
|
||||
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_isi(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *ifname, *type, *addr;
|
||||
|
||||
DBG("modem %p", modem);
|
||||
|
||||
if (ofono_modem_get_string(modem, "Interface"))
|
||||
return;
|
||||
|
||||
addr = get_property(udev_device, "OFONO_ISI_ADDRESS");
|
||||
if (addr != NULL)
|
||||
ofono_modem_set_integer(modem, "Address", atoi(addr));
|
||||
|
||||
if (g_strcmp0(udev_device_get_subsystem(udev_device), "net") != 0)
|
||||
return;
|
||||
|
||||
type = udev_device_get_sysattr_value(udev_device, "type");
|
||||
if (g_strcmp0(type, "820") != 0)
|
||||
return;
|
||||
|
||||
ifname = udev_device_get_sysname(udev_device);
|
||||
ofono_modem_set_string(modem, "Interface", ifname);
|
||||
|
||||
DBG("interface %s", ifname);
|
||||
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_calypso(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *devnode;
|
||||
|
||||
DBG("modem %p", modem);
|
||||
|
||||
devnode = udev_device_get_devnode(udev_device);
|
||||
ofono_modem_set_string(modem, "Device", devnode);
|
||||
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_wavecom(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *devnode;
|
||||
struct udev_list_entry *entry;
|
||||
|
||||
DBG("modem %p", modem);
|
||||
|
||||
devnode = udev_device_get_devnode(udev_device);
|
||||
ofono_modem_set_string(modem, "Device", devnode);
|
||||
|
||||
entry = udev_device_get_properties_list_entry(udev_device);
|
||||
while (entry) {
|
||||
const char *name = udev_list_entry_get_name(entry);
|
||||
const char *value = udev_list_entry_get_value(entry);
|
||||
|
||||
if (g_str_equal(name, "OFONO_WAVECOM_MODEL") == TRUE)
|
||||
ofono_modem_set_string(modem, "Model", value);
|
||||
|
||||
entry = udev_list_entry_get_next(entry);
|
||||
}
|
||||
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_cinterion(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *devnode;
|
||||
|
||||
DBG("modem %p", modem);
|
||||
|
||||
devnode = udev_device_get_devnode(udev_device);
|
||||
ofono_modem_set_string(modem, "Device", devnode);
|
||||
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_nokiacdma(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *devnode;
|
||||
|
||||
DBG("modem %p", modem);
|
||||
|
||||
devnode = udev_device_get_devnode(udev_device);
|
||||
ofono_modem_set_string(modem, "Device", devnode);
|
||||
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_sim900(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *devnode;
|
||||
|
||||
DBG("modem %p", modem);
|
||||
|
||||
devnode = udev_device_get_devnode(udev_device);
|
||||
ofono_modem_set_string(modem, "Device", devnode);
|
||||
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_modem(struct udev_device *udev_device)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
struct udev_device *parent;
|
||||
const char *devpath, *curpath, *driver;
|
||||
|
||||
driver = get_driver(udev_device);
|
||||
if (driver != NULL) {
|
||||
devpath = udev_device_get_devpath(udev_device);
|
||||
if (devpath == NULL)
|
||||
return;
|
||||
|
||||
if(g_strcmp0(driver, "tc65") == 0)
|
||||
driver = "cinterion";
|
||||
if(g_strcmp0(driver, "ehs6") == 0)
|
||||
driver = "cinterion";
|
||||
|
||||
modem = ofono_modem_create(NULL, driver);
|
||||
if (modem == NULL)
|
||||
return;
|
||||
|
||||
ofono_modem_set_string(modem, "Path", devpath);
|
||||
|
||||
modem_list = g_slist_prepend(modem_list, modem);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
parent = udev_device_get_parent(udev_device);
|
||||
if (parent == NULL)
|
||||
return;
|
||||
|
||||
driver = get_driver(parent);
|
||||
if (driver == NULL) {
|
||||
parent = udev_device_get_parent(parent);
|
||||
driver = get_driver(parent);
|
||||
if (driver == NULL) {
|
||||
parent = udev_device_get_parent(parent);
|
||||
driver = get_driver(parent);
|
||||
if (driver == NULL)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
devpath = udev_device_get_devpath(parent);
|
||||
if (devpath == NULL)
|
||||
return;
|
||||
|
||||
modem = find_modem(devpath);
|
||||
if (modem == NULL) {
|
||||
const char *serial = get_serial(parent);
|
||||
|
||||
modem = ofono_modem_create(serial, driver);
|
||||
if (modem == NULL)
|
||||
return;
|
||||
|
||||
ofono_modem_set_string(modem, "Path", devpath);
|
||||
ofono_modem_set_integer(modem, "Registered", 0);
|
||||
|
||||
modem_list = g_slist_prepend(modem_list, modem);
|
||||
}
|
||||
|
||||
done:
|
||||
curpath = udev_device_get_devpath(udev_device);
|
||||
if (curpath == NULL)
|
||||
return;
|
||||
|
||||
DBG("%s (%s)", curpath, driver);
|
||||
|
||||
g_hash_table_insert(devpath_list, g_strdup(curpath), g_strdup(devpath));
|
||||
|
||||
if (g_strcmp0(driver, "ifx") == 0)
|
||||
add_ifx(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "u8500") == 0)
|
||||
add_isi(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "n900") == 0)
|
||||
add_isi(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "calypso") == 0)
|
||||
add_calypso(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "cinterion") == 0)
|
||||
add_cinterion(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "nokiacdma") == 0)
|
||||
add_nokiacdma(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "sim900") == 0)
|
||||
add_sim900(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "wavecom") == 0)
|
||||
add_wavecom(modem, udev_device);
|
||||
}
|
||||
|
||||
static gboolean devpath_remove(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
const char *path = value;
|
||||
const char *devpath = user_data;
|
||||
|
||||
DBG("%s -> %s", path, devpath);
|
||||
|
||||
return g_str_equal(path, devpath);
|
||||
}
|
||||
|
||||
static void remove_modem(struct udev_device *udev_device)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
const char *curpath = udev_device_get_devpath(udev_device);
|
||||
char *devpath, *remove;
|
||||
|
||||
if (curpath == NULL)
|
||||
return;
|
||||
|
||||
DBG("%s", curpath);
|
||||
|
||||
devpath = g_hash_table_lookup(devpath_list, curpath);
|
||||
if (devpath == NULL)
|
||||
return;
|
||||
|
||||
modem = find_modem(devpath);
|
||||
if (modem == NULL)
|
||||
return;
|
||||
|
||||
modem_list = g_slist_remove(modem_list, modem);
|
||||
|
||||
ofono_modem_remove(modem);
|
||||
|
||||
DBG("%s", devpath);
|
||||
|
||||
remove = g_strdup(devpath);
|
||||
|
||||
g_hash_table_foreach_remove(devpath_list, devpath_remove, remove);
|
||||
|
||||
g_free(remove);
|
||||
}
|
||||
|
||||
static void enumerate_devices(struct udev *context)
|
||||
{
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *entry;
|
||||
|
||||
enumerate = udev_enumerate_new(context);
|
||||
if (enumerate == NULL)
|
||||
return;
|
||||
|
||||
udev_enumerate_add_match_subsystem(enumerate, "tty");
|
||||
udev_enumerate_add_match_subsystem(enumerate, "net");
|
||||
udev_enumerate_add_match_subsystem(enumerate, "hsi");
|
||||
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
entry = udev_enumerate_get_list_entry(enumerate);
|
||||
while (entry) {
|
||||
const char *syspath = udev_list_entry_get_name(entry);
|
||||
struct udev_device *device;
|
||||
|
||||
device = udev_device_new_from_syspath(context, syspath);
|
||||
if (device != NULL) {
|
||||
const char *subsystem;
|
||||
|
||||
subsystem = udev_device_get_subsystem(device);
|
||||
|
||||
if (g_strcmp0(subsystem, "tty") == 0 ||
|
||||
g_strcmp0(subsystem, "net") == 0 ||
|
||||
g_strcmp0(subsystem, "hsi") == 0)
|
||||
add_modem(device);
|
||||
|
||||
udev_device_unref(device);
|
||||
}
|
||||
|
||||
entry = udev_list_entry_get_next(entry);
|
||||
}
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
}
|
||||
|
||||
static struct udev *udev_ctx;
|
||||
static struct udev_monitor *udev_mon;
|
||||
static guint udev_watch = 0;
|
||||
|
||||
static gboolean udev_event(GIOChannel *channel, GIOCondition cond,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct udev_device *device;
|
||||
const char *subsystem, *action;
|
||||
|
||||
if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
|
||||
ofono_warn("Error with udev monitor channel");
|
||||
udev_watch = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
device = udev_monitor_receive_device(udev_mon);
|
||||
if (device == NULL)
|
||||
return TRUE;
|
||||
|
||||
subsystem = udev_device_get_subsystem(device);
|
||||
if (subsystem == NULL)
|
||||
goto done;
|
||||
|
||||
action = udev_device_get_action(device);
|
||||
if (action == NULL)
|
||||
goto done;
|
||||
|
||||
DBG("subsystem %s %s", subsystem, action);
|
||||
|
||||
if (g_str_equal(action, "add") == TRUE) {
|
||||
if (g_strcmp0(subsystem, "tty") == 0 ||
|
||||
g_strcmp0(subsystem, "net") == 0 ||
|
||||
g_strcmp0(subsystem, "hsi") == 0)
|
||||
add_modem(device);
|
||||
} else if (g_str_equal(action, "remove") == TRUE) {
|
||||
if (g_strcmp0(subsystem, "tty") == 0 ||
|
||||
g_strcmp0(subsystem, "net") == 0 ||
|
||||
g_strcmp0(subsystem, "hsi") == 0)
|
||||
remove_modem(device);
|
||||
}
|
||||
|
||||
DBG("subsystem %s finished", subsystem);
|
||||
|
||||
done:
|
||||
udev_device_unref(device);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void udev_start(void)
|
||||
{
|
||||
GIOChannel *channel;
|
||||
int fd;
|
||||
|
||||
if (udev_monitor_enable_receiving(udev_mon) < 0) {
|
||||
ofono_error("Failed to enable udev monitor");
|
||||
return;
|
||||
}
|
||||
|
||||
enumerate_devices(udev_ctx);
|
||||
|
||||
fd = udev_monitor_get_fd(udev_mon);
|
||||
|
||||
channel = g_io_channel_unix_new(fd);
|
||||
if (channel == NULL)
|
||||
return;
|
||||
|
||||
udev_watch = g_io_add_watch(channel,
|
||||
G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
|
||||
udev_event, NULL);
|
||||
|
||||
g_io_channel_unref(channel);
|
||||
}
|
||||
|
||||
static int udev_init(void)
|
||||
{
|
||||
devpath_list = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
if (devpath_list == NULL) {
|
||||
ofono_error("Failed to create udev path list");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
udev_ctx = udev_new();
|
||||
if (udev_ctx == NULL) {
|
||||
ofono_error("Failed to create udev context");
|
||||
g_hash_table_destroy(devpath_list);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
|
||||
if (udev_mon == NULL) {
|
||||
ofono_error("Failed to create udev monitor");
|
||||
g_hash_table_destroy(devpath_list);
|
||||
udev_unref(udev_ctx);
|
||||
udev_ctx = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "tty", NULL);
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "net", NULL);
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "hsi", NULL);
|
||||
|
||||
udev_monitor_filter_update(udev_mon);
|
||||
|
||||
udev_start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void udev_exit(void)
|
||||
{
|
||||
GSList *list;
|
||||
|
||||
if (udev_watch > 0)
|
||||
g_source_remove(udev_watch);
|
||||
|
||||
for (list = modem_list; list; list = list->next) {
|
||||
struct ofono_modem *modem = list->data;
|
||||
|
||||
ofono_modem_remove(modem);
|
||||
}
|
||||
|
||||
g_slist_free(modem_list);
|
||||
modem_list = NULL;
|
||||
|
||||
g_hash_table_destroy(devpath_list);
|
||||
devpath_list = NULL;
|
||||
|
||||
if (udev_ctx == NULL)
|
||||
return;
|
||||
|
||||
udev_monitor_filter_remove(udev_mon);
|
||||
|
||||
udev_monitor_unref(udev_mon);
|
||||
udev_unref(udev_ctx);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(udev, "udev hardware detection", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, udev_init, udev_exit)
|
||||
@@ -37,13 +37,22 @@
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
enum modem_type {
|
||||
MODEM_TYPE_USB,
|
||||
MODEM_TYPE_SERIAL,
|
||||
};
|
||||
|
||||
struct modem_info {
|
||||
char *syspath;
|
||||
char *devname;
|
||||
char *driver;
|
||||
char *vendor;
|
||||
char *model;
|
||||
GSList *devices;
|
||||
enum modem_type type;
|
||||
union {
|
||||
GSList *devices;
|
||||
struct serial_device_info* serial;
|
||||
};
|
||||
struct ofono_modem *modem;
|
||||
const char *sysattr;
|
||||
};
|
||||
@@ -58,6 +67,13 @@ struct device_info {
|
||||
char *subsystem;
|
||||
};
|
||||
|
||||
struct serial_device_info {
|
||||
char *devpath;
|
||||
char *devnode;
|
||||
char *subsystem;
|
||||
struct udev_device* dev;
|
||||
};
|
||||
|
||||
static gboolean setup_isi(struct modem_info *modem)
|
||||
{
|
||||
const char *node = NULL;
|
||||
@@ -188,20 +204,31 @@ static gboolean setup_gobi(struct modem_info *modem)
|
||||
for (list = modem->devices; list; list = list->next) {
|
||||
struct device_info *info = list->data;
|
||||
|
||||
DBG("%s %s %s %s", info->devnode, info->interface,
|
||||
info->number, info->label);
|
||||
DBG("%s %s %s %s %s %s", info->devnode, info->interface,
|
||||
info->number, info->label,
|
||||
info->sysattr, info->subsystem);
|
||||
|
||||
if (g_strcmp0(info->interface, "255/255/255") == 0) {
|
||||
if (info->number == NULL)
|
||||
qmi = info->devnode;
|
||||
else if (g_strcmp0(info->number, "00") == 0)
|
||||
net = info->devnode;
|
||||
else if (g_strcmp0(info->number, "01") == 0)
|
||||
diag = info->devnode;
|
||||
else if (g_strcmp0(info->number, "02") == 0)
|
||||
mdm = info->devnode;
|
||||
else if (g_strcmp0(info->number, "03") == 0)
|
||||
gps = info->devnode;
|
||||
if (g_strcmp0(info->subsystem, "usbmisc") == 0) /* cdc-wdm */
|
||||
qmi = info->devnode;
|
||||
else if (g_strcmp0(info->subsystem, "net") == 0) /* wwan */
|
||||
net = info->devnode;
|
||||
else if (g_strcmp0(info->subsystem, "tty") == 0) {
|
||||
if (g_strcmp0(info->interface, "255/255/255") == 0) {
|
||||
if (g_strcmp0(info->number, "00") == 0)
|
||||
diag = info->devnode; /* ec20 */
|
||||
else if (g_strcmp0(info->number, "01") == 0)
|
||||
diag = info->devnode; /* gobi */
|
||||
else if (g_strcmp0(info->number, "02") == 0)
|
||||
mdm = info->devnode; /* gobi */
|
||||
else if (g_strcmp0(info->number, "03") == 0)
|
||||
gps = info->devnode; /* gobi */
|
||||
} else if (g_strcmp0(info->interface, "255/0/0") == 0) {
|
||||
if (g_strcmp0(info->number, "01") == 0)
|
||||
gps = info->devnode; /* ec20 */
|
||||
if (g_strcmp0(info->number, "02") == 0)
|
||||
mdm = info->devnode; /* ec20 */
|
||||
/* ignore the 3rd device second AT/mdm iface */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,8 +279,6 @@ static gboolean setup_sierra(struct modem_info *modem)
|
||||
|
||||
if (qmi != NULL && net != NULL) {
|
||||
ofono_modem_set_driver(modem->modem, "gobi");
|
||||
/* Fixup SIM interface for Sierra QMI devices */
|
||||
ofono_modem_set_boolean(modem->modem, "ForceSimLegacy", TRUE);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -272,42 +297,6 @@ done:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_option(struct modem_info *modem)
|
||||
{
|
||||
const char *aux = NULL, *mdm = NULL, *diag = NULL;
|
||||
GSList *list;
|
||||
|
||||
DBG("%s", modem->syspath);
|
||||
|
||||
for (list = modem->devices; list; list = list->next) {
|
||||
struct device_info *info = list->data;
|
||||
|
||||
DBG("%s %s %s %s", info->devnode, info->interface,
|
||||
info->number, info->label);
|
||||
|
||||
if (g_strcmp0(info->interface, "255/255/255") == 0) {
|
||||
if (g_strcmp0(info->number, "00") == 0)
|
||||
mdm = info->devnode;
|
||||
else if (g_strcmp0(info->number, "01") == 0)
|
||||
diag = info->devnode;
|
||||
else if (g_strcmp0(info->number, "02") == 0)
|
||||
aux = info->devnode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (aux == NULL || mdm == NULL)
|
||||
return FALSE;
|
||||
|
||||
DBG("aux=%s modem=%s diag=%s", aux, mdm, diag);
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Aux", aux);
|
||||
ofono_modem_set_string(modem->modem, "Modem", mdm);
|
||||
ofono_modem_set_string(modem->modem, "Diag", diag);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_huawei(struct modem_info *modem)
|
||||
{
|
||||
const char *qmi = NULL, *mdm = NULL, *net = NULL;
|
||||
@@ -613,7 +602,7 @@ static gboolean setup_nokia(struct modem_info *modem)
|
||||
|
||||
static gboolean setup_telit(struct modem_info *modem)
|
||||
{
|
||||
const char *mdm = NULL, *aux = NULL, *gps = NULL, *diag = NULL;
|
||||
const char *mdm = NULL, *aux = NULL, *gps = NULL, *net = NULL;
|
||||
GSList *list;
|
||||
|
||||
DBG("%s", modem->syspath);
|
||||
@@ -635,30 +624,41 @@ static gboolean setup_telit(struct modem_info *modem)
|
||||
} else if (g_strcmp0(info->interface, "255/255/255") == 0) {
|
||||
if (g_strcmp0(info->number, "00") == 0)
|
||||
mdm = info->devnode;
|
||||
else if (g_strcmp0(info->number, "01") == 0)
|
||||
diag = info->devnode;
|
||||
else if (g_strcmp0(info->number, "02") == 0)
|
||||
gps = info->devnode;
|
||||
else if (g_strcmp0(info->number, "03") == 0)
|
||||
aux = info->devnode;
|
||||
} else if (g_strcmp0(info->interface, "2/2/1") == 0) {
|
||||
if (g_strcmp0(info->number, "00") == 0)
|
||||
mdm = info->devnode;
|
||||
else if (g_strcmp0(info->number, "06") == 0)
|
||||
aux = info->devnode;
|
||||
else if (g_strcmp0(info->number, "0a") == 0)
|
||||
gps = info->devnode;
|
||||
} else if (info->sysattr && (g_str_has_suffix(info->sysattr,
|
||||
"CDC NCM") == TRUE)) {
|
||||
net = info->devnode;
|
||||
}
|
||||
}
|
||||
|
||||
if (aux == NULL || mdm == NULL)
|
||||
return FALSE;
|
||||
|
||||
DBG("modem=%s aux=%s gps=%s diag=%s", mdm, aux, gps, diag);
|
||||
DBG("modem=%s aux=%s gps=%s net=%s", mdm, aux, gps, net);
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Modem", mdm);
|
||||
ofono_modem_set_string(modem->modem, "Aux", aux);
|
||||
ofono_modem_set_string(modem->modem, "GPS", gps);
|
||||
|
||||
if (net != NULL)
|
||||
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_he910(struct modem_info *modem)
|
||||
static gboolean setup_telitqmi(struct modem_info *modem)
|
||||
{
|
||||
const char *mdm = NULL, *aux = NULL, *gps = NULL;
|
||||
const char *qmi = NULL, *net = NULL;
|
||||
GSList *list;
|
||||
|
||||
DBG("%s", modem->syspath);
|
||||
@@ -666,27 +666,29 @@ static gboolean setup_he910(struct modem_info *modem)
|
||||
for (list = modem->devices; list; list = list->next) {
|
||||
struct device_info *info = list->data;
|
||||
|
||||
DBG("%s %s %s %s", info->devnode, info->interface,
|
||||
info->number, info->label);
|
||||
DBG("%s %s %s %s %s", info->devnode, info->interface,
|
||||
info->number, info->label, info->subsystem);
|
||||
|
||||
if (g_strcmp0(info->interface, "2/2/1") == 0) {
|
||||
if (g_strcmp0(info->number, "00") == 0)
|
||||
mdm = info->devnode;
|
||||
else if (g_strcmp0(info->number, "06") == 0)
|
||||
aux = info->devnode;
|
||||
else if (g_strcmp0(info->number, "0a") == 0)
|
||||
gps = info->devnode;
|
||||
if (g_strcmp0(info->interface, "255/255/255") == 0 &&
|
||||
g_strcmp0(info->number, "02") == 0) {
|
||||
if (g_strcmp0(info->subsystem, "net") == 0)
|
||||
net = info->devnode;
|
||||
else if (g_strcmp0(info->subsystem, "usbmisc") == 0)
|
||||
qmi = info->devnode;
|
||||
}
|
||||
}
|
||||
|
||||
if (aux == NULL || mdm == NULL)
|
||||
if (qmi == NULL || net == NULL)
|
||||
return FALSE;
|
||||
|
||||
DBG("modem=%s aux=%s gps=%s", mdm, aux, gps);
|
||||
DBG("qmi=%s net=%s", qmi, net);
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Modem", mdm);
|
||||
ofono_modem_set_string(modem->modem, "Aux", aux);
|
||||
ofono_modem_set_string(modem->modem, "GPS", gps);
|
||||
ofono_modem_set_string(modem->modem, "Device", qmi);
|
||||
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
|
||||
|
||||
ofono_modem_set_boolean(modem->modem, "ForceSimLegacy", TRUE);
|
||||
ofono_modem_set_boolean(modem->modem, "AlwaysOnline", TRUE);
|
||||
ofono_modem_set_driver(modem->modem, "gobi");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -856,6 +858,143 @@ static gboolean setup_quectel(struct modem_info *modem)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_quectelqmi(struct modem_info *modem)
|
||||
{
|
||||
const char *qmi = NULL, *net = NULL, *gps = NULL;
|
||||
GSList *list;
|
||||
|
||||
DBG("%s", modem->syspath);
|
||||
|
||||
for (list = modem->devices; list; list = g_slist_next(list)) {
|
||||
struct device_info *info = list->data;
|
||||
|
||||
DBG("%s %s %s %s %s", info->devnode, info->interface,
|
||||
info->number, info->label, info->subsystem);
|
||||
|
||||
if (g_strcmp0(info->interface, "255/255/255") == 0 &&
|
||||
g_strcmp0(info->number, "04") == 0) {
|
||||
if (g_strcmp0(info->subsystem, "net") == 0)
|
||||
net = info->devnode;
|
||||
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) {
|
||||
gps = info->devnode;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("qmi=%s net=%s", qmi, net);
|
||||
|
||||
if (qmi == NULL || net == NULL)
|
||||
return FALSE;
|
||||
|
||||
DBG("qmi=%s net=%s", qmi, net);
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Device", qmi);
|
||||
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
|
||||
|
||||
if (gps)
|
||||
ofono_modem_set_string(modem->modem, "GPS", gps);
|
||||
|
||||
ofono_modem_set_driver(modem->modem, "gobi");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_serial_modem(struct modem_info* modem)
|
||||
{
|
||||
struct serial_device_info* info;
|
||||
|
||||
info = modem->serial;
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Device", info->devnode);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_tc65(struct modem_info* modem)
|
||||
{
|
||||
ofono_modem_set_driver(modem->modem, "cinterion");
|
||||
|
||||
return setup_serial_modem(modem);
|
||||
}
|
||||
|
||||
static gboolean setup_ehs6(struct modem_info* modem)
|
||||
{
|
||||
ofono_modem_set_driver(modem->modem, "cinterion");
|
||||
|
||||
return setup_serial_modem(modem);
|
||||
}
|
||||
|
||||
static gboolean setup_ifx(struct modem_info* modem)
|
||||
{
|
||||
struct serial_device_info* info;
|
||||
const char *value;
|
||||
|
||||
info = modem->serial;
|
||||
|
||||
value = udev_device_get_property_value(info->dev, "OFONO_IFX_LDISC");
|
||||
if (value)
|
||||
ofono_modem_set_string(modem->modem, "LineDiscipline", value);
|
||||
|
||||
value = udev_device_get_property_value(info->dev, "OFONO_IFX_AUDIO");
|
||||
if (value)
|
||||
ofono_modem_set_string(modem->modem, "AudioSetting", value);
|
||||
|
||||
value = udev_device_get_property_value(info->dev, "OFONO_IFX_LOOPBACK");
|
||||
if (value)
|
||||
ofono_modem_set_string(modem->modem, "AudioLoopback", value);
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Device", info->devnode);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_wavecom(struct modem_info* modem)
|
||||
{
|
||||
struct serial_device_info* info;
|
||||
const char *value;
|
||||
|
||||
info = modem->serial;
|
||||
|
||||
value = udev_device_get_property_value(info->dev,
|
||||
"OFONO_WAVECOM_MODEL");
|
||||
if (value)
|
||||
ofono_modem_set_string(modem->modem, "Model", value);
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Device", info->devnode);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_isi_serial(struct modem_info* modem)
|
||||
{
|
||||
struct serial_device_info* info;
|
||||
const char *value;
|
||||
|
||||
info = modem->serial;
|
||||
|
||||
if (g_strcmp0(udev_device_get_subsystem(info->dev), "net") != 0)
|
||||
return FALSE;
|
||||
|
||||
value = udev_device_get_sysattr_value(info->dev, "type");
|
||||
if (g_strcmp0(value, "820") != 0)
|
||||
return FALSE;
|
||||
|
||||
/* OK, we want this device to be a modem */
|
||||
value = udev_device_get_sysname(info->dev);
|
||||
if (value)
|
||||
ofono_modem_set_string(modem->modem, "Interface", value);
|
||||
|
||||
value = udev_device_get_property_value(info->dev, "OFONO_ISI_ADDRESS");
|
||||
if (value)
|
||||
ofono_modem_set_integer(modem->modem, "Address", atoi(value));
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Device", info->devnode);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_ublox(struct modem_info *modem)
|
||||
{
|
||||
const char *aux = NULL, *mdm = NULL, *net = NULL;
|
||||
@@ -915,6 +1054,50 @@ static gboolean setup_ublox(struct modem_info *modem)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean setup_gemalto(struct modem_info* modem)
|
||||
{
|
||||
const char *app = NULL, *gps = NULL, *mdm = NULL,
|
||||
*net = NULL, *qmi = NULL;
|
||||
|
||||
GSList *list;
|
||||
|
||||
DBG("%s", modem->syspath);
|
||||
|
||||
for (list = modem->devices; list; list = list->next) {
|
||||
struct device_info *info = list->data;
|
||||
|
||||
DBG("%s %s %s %s %s", info->devnode, info->interface,
|
||||
info->number, info->label, info->subsystem);
|
||||
|
||||
if (g_strcmp0(info->interface, "255/255/255") == 0) {
|
||||
if (g_strcmp0(info->number, "01") == 0)
|
||||
gps = info->devnode;
|
||||
else if (g_strcmp0(info->number, "02") == 0)
|
||||
app = info->devnode;
|
||||
else if (g_strcmp0(info->number, "03") == 0)
|
||||
mdm = info->devnode;
|
||||
else if (g_strcmp0(info->subsystem, "net") == 0)
|
||||
net = info->devnode;
|
||||
else if (g_strcmp0(info->subsystem, "usbmisc") == 0)
|
||||
qmi = info->devnode;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("application=%s gps=%s modem=%s network=%s qmi=%s",
|
||||
app, gps, mdm, net, qmi);
|
||||
|
||||
if (app == NULL || mdm == NULL)
|
||||
return FALSE;
|
||||
|
||||
ofono_modem_set_string(modem->modem, "Application", app);
|
||||
ofono_modem_set_string(modem->modem, "GPS", gps);
|
||||
ofono_modem_set_string(modem->modem, "Modem", mdm);
|
||||
ofono_modem_set_string(modem->modem, "Device", qmi);
|
||||
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
gboolean (*setup)(struct modem_info *modem);
|
||||
@@ -925,7 +1108,6 @@ static struct {
|
||||
{ "hso", setup_hso, "hsotype" },
|
||||
{ "gobi", setup_gobi },
|
||||
{ "sierra", setup_sierra },
|
||||
{ "option", setup_option },
|
||||
{ "huawei", setup_huawei },
|
||||
{ "speedupcdma",setup_speedup },
|
||||
{ "speedup", setup_speedup },
|
||||
@@ -933,14 +1115,27 @@ static struct {
|
||||
{ "alcatel", setup_alcatel },
|
||||
{ "novatel", setup_novatel },
|
||||
{ "nokia", setup_nokia },
|
||||
{ "telit", setup_telit },
|
||||
{ "he910", setup_he910 },
|
||||
{ "telit", setup_telit, "device/interface" },
|
||||
{ "telitqmi", setup_telitqmi },
|
||||
{ "simcom", setup_simcom },
|
||||
{ "zte", setup_zte },
|
||||
{ "icera", setup_icera },
|
||||
{ "samsung", setup_samsung },
|
||||
{ "quectel", setup_quectel },
|
||||
{ "quectelqmi", setup_quectelqmi},
|
||||
{ "ublox", setup_ublox },
|
||||
{ "gemalto", setup_gemalto },
|
||||
/* Following are non-USB modems */
|
||||
{ "ifx", setup_ifx },
|
||||
{ "u8500", setup_isi_serial },
|
||||
{ "n900", setup_isi_serial },
|
||||
{ "calypso", setup_serial_modem },
|
||||
{ "cinterion", setup_serial_modem },
|
||||
{ "nokiacdma", setup_serial_modem },
|
||||
{ "sim900", setup_serial_modem },
|
||||
{ "wavecom", setup_wavecom },
|
||||
{ "tc65", setup_tc65 },
|
||||
{ "ehs6", setup_ehs6 },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -958,6 +1153,27 @@ static const char *get_sysattr(const char *driver)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void device_info_free(struct device_info* info)
|
||||
{
|
||||
g_free(info->devpath);
|
||||
g_free(info->devnode);
|
||||
g_free(info->interface);
|
||||
g_free(info->number);
|
||||
g_free(info->label);
|
||||
g_free(info->sysattr);
|
||||
g_free(info->subsystem);
|
||||
g_free(info);
|
||||
}
|
||||
|
||||
static void serial_device_info_free(struct serial_device_info* info)
|
||||
{
|
||||
g_free(info->devpath);
|
||||
g_free(info->devnode);
|
||||
g_free(info->subsystem);
|
||||
udev_device_unref(info->dev);
|
||||
g_free(info);
|
||||
}
|
||||
|
||||
static void destroy_modem(gpointer data)
|
||||
{
|
||||
struct modem_info *modem = data;
|
||||
@@ -967,25 +1183,22 @@ static void destroy_modem(gpointer data)
|
||||
|
||||
ofono_modem_remove(modem->modem);
|
||||
|
||||
for (list = modem->devices; list; list = list->next) {
|
||||
struct device_info *info = list->data;
|
||||
switch (modem->type) {
|
||||
case MODEM_TYPE_USB:
|
||||
for (list = modem->devices; list; list = list->next) {
|
||||
struct device_info *info = list->data;
|
||||
|
||||
DBG("%s", info->devnode);
|
||||
DBG("%s", info->devnode);
|
||||
device_info_free(info);
|
||||
}
|
||||
|
||||
g_free(info->devpath);
|
||||
g_free(info->devnode);
|
||||
g_free(info->interface);
|
||||
g_free(info->number);
|
||||
g_free(info->label);
|
||||
g_free(info->sysattr);
|
||||
g_free(info->subsystem);
|
||||
g_free(info);
|
||||
|
||||
list->data = NULL;
|
||||
g_slist_free(modem->devices);
|
||||
break;
|
||||
case MODEM_TYPE_SERIAL:
|
||||
serial_device_info_free(modem->serial);
|
||||
break;
|
||||
}
|
||||
|
||||
g_slist_free(modem->devices);
|
||||
|
||||
g_free(modem->syspath);
|
||||
g_free(modem->devname);
|
||||
g_free(modem->driver);
|
||||
@@ -1032,11 +1245,103 @@ static gint compare_device(gconstpointer a, gconstpointer b)
|
||||
return g_strcmp0(info1->number, info2->number);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we try to find the "modem device".
|
||||
*
|
||||
* In this variant we identify the "modem device" as simply the device
|
||||
* that has the OFONO_DRIVER property. If the device node doesn't
|
||||
* have this property itself, then we do a brute force search for it
|
||||
* through the device hierarchy.
|
||||
*
|
||||
*/
|
||||
static struct udev_device* get_serial_modem_device(struct udev_device *dev)
|
||||
{
|
||||
const char* driver;
|
||||
|
||||
while (dev) {
|
||||
driver = udev_device_get_property_value(dev, "OFONO_DRIVER");
|
||||
if (driver)
|
||||
return dev;
|
||||
|
||||
dev = udev_device_get_parent(dev);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add 'legacy' device
|
||||
*
|
||||
* The term legacy is a bit misleading, but this adds devices according
|
||||
* to the original ofono model.
|
||||
*
|
||||
* - We cannot assume that these are USB devices
|
||||
* - The modem consists of only a single interface
|
||||
* - The device must have an OFONO_DRIVER property from udev
|
||||
*/
|
||||
static void add_serial_device(struct udev_device *dev)
|
||||
{
|
||||
const char *syspath, *devpath, *devname, *devnode;
|
||||
struct modem_info *modem;
|
||||
struct serial_device_info *info;
|
||||
const char *subsystem;
|
||||
struct udev_device* mdev;
|
||||
const char* driver;
|
||||
|
||||
mdev = get_serial_modem_device(dev);
|
||||
if (!mdev) {
|
||||
DBG("Device is missing required OFONO_DRIVER property");
|
||||
return;
|
||||
}
|
||||
|
||||
driver = udev_device_get_property_value(mdev, "OFONO_DRIVER");
|
||||
|
||||
syspath = udev_device_get_syspath(mdev);
|
||||
devname = udev_device_get_devnode(mdev);
|
||||
devpath = udev_device_get_devpath(mdev);
|
||||
|
||||
devnode = udev_device_get_devnode(dev);
|
||||
|
||||
if (!syspath || !devname || !devpath || !devnode)
|
||||
return;
|
||||
|
||||
modem = g_hash_table_lookup(modem_list, syspath);
|
||||
if (modem == NULL) {
|
||||
modem = g_try_new0(struct modem_info, 1);
|
||||
if (modem == NULL)
|
||||
return;
|
||||
|
||||
modem->type = MODEM_TYPE_SERIAL;
|
||||
modem->syspath = g_strdup(syspath);
|
||||
modem->devname = g_strdup(devname);
|
||||
modem->driver = g_strdup("legacy");
|
||||
|
||||
g_hash_table_replace(modem_list, modem->syspath, modem);
|
||||
}
|
||||
|
||||
subsystem = udev_device_get_subsystem(dev);
|
||||
|
||||
DBG("%s", syspath);
|
||||
DBG("%s", devpath);
|
||||
DBG("%s (%s)", devnode, driver);
|
||||
|
||||
info = g_try_new0(struct serial_device_info, 1);
|
||||
if (info == NULL)
|
||||
return;
|
||||
|
||||
info->devpath = g_strdup(devpath);
|
||||
info->devnode = g_strdup(devnode);
|
||||
info->subsystem = g_strdup(subsystem);
|
||||
info->dev = udev_device_ref(dev);
|
||||
|
||||
modem->devices = g_slist_append(modem->devices, info);
|
||||
}
|
||||
|
||||
static void add_device(const char *syspath, const char *devname,
|
||||
const char *driver, const char *vendor,
|
||||
const char *model, struct udev_device *device)
|
||||
{
|
||||
struct udev_device *intf;
|
||||
struct udev_device *usb_interface;
|
||||
const char *devpath, *devnode, *interface, *number;
|
||||
const char *label, *sysattr, *subsystem;
|
||||
struct modem_info *modem;
|
||||
@@ -1054,9 +1359,9 @@ static void add_device(const char *syspath, const char *devname,
|
||||
return;
|
||||
}
|
||||
|
||||
intf = udev_device_get_parent_with_subsystem_devtype(device,
|
||||
usb_interface = udev_device_get_parent_with_subsystem_devtype(device,
|
||||
"usb", "usb_interface");
|
||||
if (intf == NULL)
|
||||
if (usb_interface == NULL)
|
||||
return;
|
||||
|
||||
modem = g_hash_table_lookup(modem_list, syspath);
|
||||
@@ -1065,6 +1370,7 @@ static void add_device(const char *syspath, const char *devname,
|
||||
if (modem == NULL)
|
||||
return;
|
||||
|
||||
modem->type = MODEM_TYPE_USB;
|
||||
modem->syspath = g_strdup(syspath);
|
||||
modem->devname = g_strdup(devname);
|
||||
modem->driver = g_strdup(driver);
|
||||
@@ -1076,7 +1382,7 @@ static void add_device(const char *syspath, const char *devname,
|
||||
g_hash_table_replace(modem_list, modem->syspath, modem);
|
||||
}
|
||||
|
||||
interface = udev_device_get_property_value(intf, "INTERFACE");
|
||||
interface = udev_device_get_property_value(usb_interface, "INTERFACE");
|
||||
number = udev_device_get_property_value(device, "ID_USB_INTERFACE_NUM");
|
||||
|
||||
/* If environment variable is not set, get value from attributes (or parent's ones) */
|
||||
@@ -1092,6 +1398,10 @@ static void add_device(const char *syspath, const char *devname,
|
||||
}
|
||||
|
||||
label = udev_device_get_property_value(device, "OFONO_LABEL");
|
||||
if (!label)
|
||||
label = udev_device_get_property_value(usb_interface,
|
||||
"OFONO_LABEL");
|
||||
|
||||
subsystem = udev_device_get_subsystem(device);
|
||||
|
||||
if (modem->sysattr != NULL)
|
||||
@@ -1171,15 +1481,26 @@ static struct {
|
||||
{ "simcom", "option", "05c6", "9000" },
|
||||
{ "telit", "usbserial", "1bc7" },
|
||||
{ "telit", "option", "1bc7" },
|
||||
{ "he910", "cdc_acm", "1bc7", "0021" },
|
||||
{ "telit", "cdc_acm", "1bc7", "0021" },
|
||||
{ "telitqmi", "qmi_wwan", "1bc7", "1201" },
|
||||
{ "telitqmi", "option", "1bc7", "1201" },
|
||||
{ "nokia", "option", "0421", "060e" },
|
||||
{ "nokia", "option", "0421", "0623" },
|
||||
{ "samsung", "option", "04e8", "6889" },
|
||||
{ "samsung", "kalmia" },
|
||||
{ "quectel", "option", "05c6", "9090" },
|
||||
{ "quectelqmi", "qmi_wwan", "2c7c", "0121" },
|
||||
{ "quectelqmi", "qcserial", "2c7c", "0121" },
|
||||
{ "quectelqmi", "qmi_wwan", "2c7c", "0125" },
|
||||
{ "quectelqmi", "qcserial", "2c7c", "0125" },
|
||||
{ "ublox", "cdc_acm", "1546", "1102" },
|
||||
{ "ublox", "rndis_host", "1546", "1146" },
|
||||
{ "ublox", "cdc_acm", "1546", "1146" },
|
||||
{ "gemalto", "option", "1e2d", "0053" },
|
||||
{ "gemalto", "cdc_wdm", "1e2d", "0053" },
|
||||
{ "gemalto", "qmi_wwan", "1e2d", "0053" },
|
||||
{ "telit", "cdc_ncm", "1bc7", "0036" },
|
||||
{ "telit", "cdc_acm", "1bc7", "0036" },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -1202,9 +1523,22 @@ static void check_usb_device(struct udev_device *device)
|
||||
if (devname == NULL)
|
||||
return;
|
||||
|
||||
vendor = udev_device_get_property_value(usb_device, "ID_VENDOR_ID");
|
||||
model = udev_device_get_property_value(usb_device, "ID_MODEL_ID");
|
||||
|
||||
driver = udev_device_get_property_value(usb_device, "OFONO_DRIVER");
|
||||
if (!driver) {
|
||||
struct udev_device *usb_interface =
|
||||
udev_device_get_parent_with_subsystem_devtype(
|
||||
device, "usb", "usb_interface");
|
||||
|
||||
if (usb_interface)
|
||||
driver = udev_device_get_property_value(
|
||||
usb_interface, "OFONO_DRIVER");
|
||||
}
|
||||
|
||||
if (driver == NULL) {
|
||||
const char *drv, *vid, *pid;
|
||||
const char *drv;
|
||||
unsigned int i;
|
||||
|
||||
drv = udev_device_get_property_value(device, "ID_USB_DRIVER");
|
||||
@@ -1223,40 +1557,24 @@ static void check_usb_device(struct udev_device *device)
|
||||
}
|
||||
}
|
||||
|
||||
vid = udev_device_get_property_value(device, "ID_VENDOR_ID");
|
||||
pid = udev_device_get_property_value(device, "ID_MODEL_ID");
|
||||
|
||||
DBG("%s [%s:%s]", drv, vid, pid);
|
||||
DBG("%s [%s:%s]", drv, vendor, model);
|
||||
|
||||
for (i = 0; vendor_list[i].driver; i++) {
|
||||
if (g_str_equal(vendor_list[i].drv, drv) == FALSE)
|
||||
continue;
|
||||
|
||||
if (vendor_list[i].vid == NULL) {
|
||||
driver = vendor_list[i].driver;
|
||||
vendor = vid;
|
||||
model = pid;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vid == NULL || pid == NULL)
|
||||
continue;
|
||||
|
||||
if (g_str_equal(vendor_list[i].vid, vid) == TRUE) {
|
||||
if (vendor_list[i].pid == NULL) {
|
||||
driver = vendor_list[i].driver;
|
||||
vendor = vid;
|
||||
model = pid;
|
||||
if (vendor_list[i].vid) {
|
||||
if (!g_str_equal(vendor_list[i].vid, vendor))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_strcmp0(vendor_list[i].pid, pid) == 0) {
|
||||
driver = vendor_list[i].driver;
|
||||
vendor = vid;
|
||||
model = pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vendor_list[i].pid) {
|
||||
if (!g_str_equal(vendor_list[i].pid, model))
|
||||
continue;
|
||||
}
|
||||
|
||||
driver = vendor_list[i].driver;
|
||||
}
|
||||
|
||||
if (driver == NULL)
|
||||
@@ -1280,6 +1598,9 @@ static void check_device(struct udev_device *device)
|
||||
if ((g_str_equal(bus, "usb") == TRUE) ||
|
||||
(g_str_equal(bus, "usbmisc") == TRUE))
|
||||
check_usb_device(device);
|
||||
else
|
||||
add_serial_device(device);
|
||||
|
||||
}
|
||||
|
||||
static gboolean create_modem(gpointer key, gpointer value, gpointer user_data)
|
||||
@@ -1330,6 +1651,7 @@ static void enumerate_devices(struct udev *context)
|
||||
udev_enumerate_add_match_subsystem(enumerate, "usb");
|
||||
udev_enumerate_add_match_subsystem(enumerate, "usbmisc");
|
||||
udev_enumerate_add_match_subsystem(enumerate, "net");
|
||||
udev_enumerate_add_match_subsystem(enumerate, "hsi");
|
||||
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
@@ -1454,6 +1776,7 @@ static int detect_init(void)
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
|
||||
"usbmisc", NULL);
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "net", NULL);
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "hsi", NULL);
|
||||
|
||||
udev_monitor_filter_update(udev_mon);
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
/* 27.007 Section 7.3 <AcT> */
|
||||
enum access_technology {
|
||||
ACCESS_TECHNOLOGY_GSM = 0,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user