mirror of
https://github.com/sailfishos/ofono
synced 2025-12-02 15:41:03 +08:00
Compare commits
354 Commits
mer/1.19+g
...
upgrade-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bede136cc | ||
|
|
b3380c6eca | ||
|
|
f98e9a2193 | ||
|
|
9faf27ec28 | ||
|
|
32c26c5a35 | ||
|
|
79fb591342 | ||
|
|
f6e46f78e3 | ||
|
|
7c587772d1 | ||
|
|
0d0728593b | ||
|
|
fd3916b2c7 | ||
|
|
c35557c2ed | ||
|
|
bb07543dd6 | ||
|
|
d346f1289c | ||
|
|
e170b6df4c | ||
|
|
761cd320bb | ||
|
|
60bc47aea2 | ||
|
|
183e4dab4b | ||
|
|
d6cdfc92ad | ||
|
|
b68752640c | ||
|
|
a53fc6ea7e | ||
|
|
63fe971077 | ||
|
|
011f3b74d1 | ||
|
|
4d2e314ad6 | ||
|
|
d846618057 | ||
|
|
38115199f7 | ||
|
|
f88c7ce919 | ||
|
|
9d6b3ec124 | ||
|
|
6dcf5cebc1 | ||
|
|
0e87392c90 | ||
|
|
dab76692db | ||
|
|
21bc90f638 | ||
|
|
d8707d52be | ||
|
|
fa0abf892d | ||
|
|
8a28d4eea8 | ||
|
|
4f0be99683 | ||
|
|
95933beb2d | ||
|
|
018a712e29 | ||
|
|
e6777f1ecc | ||
|
|
a58e1a5e9b | ||
|
|
61be41240f | ||
|
|
dbb40560c6 | ||
|
|
9bf50bb3e3 | ||
|
|
d2353c46a8 | ||
|
|
6701b53737 | ||
|
|
6612bfa1da | ||
|
|
c732d5192d | ||
|
|
6815772b17 | ||
|
|
e4766ef2c4 | ||
|
|
7aa396636b | ||
|
|
096cd04044 | ||
|
|
5eabe96602 | ||
|
|
05dec021c0 | ||
|
|
6f7209b045 | ||
|
|
a766281a02 | ||
|
|
13b4802bec | ||
|
|
e1547fdaf4 | ||
|
|
08c36b2885 | ||
|
|
0180c9febf | ||
|
|
49034cfc69 | ||
|
|
4685e3f0de | ||
|
|
72be5bdff2 | ||
|
|
79c1abfdd3 | ||
|
|
c88cffaa2e | ||
|
|
17e66090ec | ||
|
|
100cf7df1d | ||
|
|
280ed19215 | ||
|
|
ae0f5b0ff6 | ||
|
|
dbfc642eb3 | ||
|
|
e5e5108913 | ||
|
|
9035db3129 | ||
|
|
81391a4101 | ||
|
|
60d449c01d | ||
|
|
b0ccc39866 | ||
|
|
bd2aa28405 | ||
|
|
67e31bb519 | ||
|
|
b848827976 | ||
|
|
ab6764dcc0 | ||
|
|
da42039c80 | ||
|
|
392c00c65e | ||
|
|
7a0fe98d95 | ||
|
|
d508a2f2bb | ||
|
|
8f070cf583 | ||
|
|
d2d8117723 | ||
|
|
6897e57353 | ||
|
|
6a8c2aa9c1 | ||
|
|
076e388d45 | ||
|
|
bcafe0dc3d | ||
|
|
9272075f55 | ||
|
|
526072d7a3 | ||
|
|
0680063527 | ||
|
|
4e08680e5f | ||
|
|
1d85caa7f9 | ||
|
|
db0ef91c81 | ||
|
|
54d8c78a50 | ||
|
|
905c886269 | ||
|
|
f0c7a373ae | ||
|
|
4673da16d5 | ||
|
|
0dc2acee4e | ||
|
|
f749284029 | ||
|
|
778b9f08aa | ||
|
|
40db3f7067 | ||
|
|
e198cf04c0 | ||
|
|
fbd59ba56f | ||
|
|
cff9ded7e6 | ||
|
|
c74386b5e6 | ||
|
|
028f54c26f | ||
|
|
c066f34ea1 | ||
|
|
b1c79d5cae | ||
|
|
0cc61dcfe8 | ||
|
|
5852bebda0 | ||
|
|
768c028a11 | ||
|
|
6b93ea0cc6 | ||
|
|
4a485a7aa0 | ||
|
|
f6fb277cf4 | ||
|
|
03f150838b | ||
|
|
9731ca1a87 | ||
|
|
a09f4c070d | ||
|
|
f018f5a255 | ||
|
|
286396bf91 | ||
|
|
5d6baccced | ||
|
|
514f4cf9cc | ||
|
|
ff8408e6dd | ||
|
|
df1294d77c | ||
|
|
2323ebacb3 | ||
|
|
c780eff0ce | ||
|
|
373248a35b | ||
|
|
fe219b648d | ||
|
|
33f55c569f | ||
|
|
d6cf954354 | ||
|
|
d8e852cb5e | ||
|
|
83e3ec0e98 | ||
|
|
e35f537f72 | ||
|
|
c7daf5aa43 | ||
|
|
490a9c06f4 | ||
|
|
320b3f4605 | ||
|
|
e35dae17d9 | ||
|
|
f4522f4a00 | ||
|
|
ce85c94426 | ||
|
|
4027bdc04e | ||
|
|
c57f99bf01 | ||
|
|
54d610ce6a | ||
|
|
f7f9e32743 | ||
|
|
8c9e370486 | ||
|
|
19b80236f6 | ||
|
|
2ec6fc749d | ||
|
|
0a3bdd20f4 | ||
|
|
284919e76a | ||
|
|
ddcbb89fa1 | ||
|
|
5ec6b8e7ec | ||
|
|
f94681f6f6 | ||
|
|
de8edc84fa | ||
|
|
90faf1b3a5 | ||
|
|
2b139b6974 | ||
|
|
168f193efb | ||
|
|
32d8b5ccfc | ||
|
|
f400ceff80 | ||
|
|
2186c60630 | ||
|
|
d5fb195e2f | ||
|
|
cbb08079d2 | ||
|
|
0583a831fb | ||
|
|
a8a0758e90 | ||
|
|
9e267487f4 | ||
|
|
c8a774dfee | ||
|
|
b88518d0f3 | ||
|
|
b223ccc675 | ||
|
|
947a41a5fc | ||
|
|
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 |
61
.gitignore
vendored
61
.gitignore
vendored
@@ -1,61 +0,0 @@
|
|||||||
*.o
|
|
||||||
*.lo
|
|
||||||
*.la
|
|
||||||
.deps
|
|
||||||
.libs
|
|
||||||
.dirstamp
|
|
||||||
Makefile
|
|
||||||
Makefile.in
|
|
||||||
aclocal.m4
|
|
||||||
config.guess
|
|
||||||
config.h
|
|
||||||
config.h.in
|
|
||||||
config.log
|
|
||||||
config.status
|
|
||||||
config.sub
|
|
||||||
configure
|
|
||||||
depcomp
|
|
||||||
compile
|
|
||||||
install-sh
|
|
||||||
libtool
|
|
||||||
ltmain.sh
|
|
||||||
missing
|
|
||||||
stamp-h1
|
|
||||||
autom4te.cache
|
|
||||||
test-driver
|
|
||||||
test-suite.log
|
|
||||||
|
|
||||||
ofono.pc
|
|
||||||
include/ofono
|
|
||||||
include/version.h
|
|
||||||
src/builtin.h
|
|
||||||
src/ofonod
|
|
||||||
src/ofono.service
|
|
||||||
dundee/dundee
|
|
||||||
dundee/dundee.service
|
|
||||||
|
|
||||||
unit/test-common
|
|
||||||
unit/test-util
|
|
||||||
unit/test-idmap
|
|
||||||
unit/test-sms
|
|
||||||
unit/test-sms-root
|
|
||||||
unit/test-simutil
|
|
||||||
unit/test-mux
|
|
||||||
unit/test-caif
|
|
||||||
unit/test-stkutil
|
|
||||||
unit/test-cdmasms
|
|
||||||
unit/test-*.log
|
|
||||||
unit/test-*.trs
|
|
||||||
|
|
||||||
tools/huawei-audio
|
|
||||||
tools/auto-enable
|
|
||||||
tools/get-location
|
|
||||||
tools/lookup-apn
|
|
||||||
tools/lookup-provider-name
|
|
||||||
tools/tty-redirector
|
|
||||||
tools/qmi
|
|
||||||
tools/stktest
|
|
||||||
|
|
||||||
gatchat/gsmdial
|
|
||||||
gatchat/test-server
|
|
||||||
gatchat/test-qcdm
|
|
||||||
7
.mailmap
7
.mailmap
@@ -1,7 +0,0 @@
|
|||||||
Luiz Augusto von Dentz <luiz.dentz-von@nokia.com> <luiz.dentz-von@nokia.com>
|
|
||||||
Zhenhua Zhang <zhenhua.zhang@intel.com> <zhenhua.zhang@intel.com>
|
|
||||||
Pekka Pessi <pekka.pessi@nokia.com> <Pekka.Pessi@nokia.com>
|
|
||||||
Pekka Pessi <pekka.pessi@nokia.com> <ppessi@hamsa.research.nokia.com>
|
|
||||||
Lasse Kunnasluoto <lasse.kunnasluoto@tieto.com> <Lasse.Kunnasluoto@tieto.com>
|
|
||||||
Syam Sidhardhan <s.syam@samsung.com> <syamsidhardh@gmail.com>
|
|
||||||
Michael Dietrich <mdt@emdete.de> <mdt@emdete.de>
|
|
||||||
7
ofono/.gitignore
vendored
7
ofono/.gitignore
vendored
@@ -42,13 +42,20 @@ unit/test-mux
|
|||||||
unit/test-caif
|
unit/test-caif
|
||||||
unit/test-stkutil
|
unit/test-stkutil
|
||||||
unit/test-cdmasms
|
unit/test-cdmasms
|
||||||
|
unit/test-dbus-queue
|
||||||
|
unit/test-gprs-filter
|
||||||
|
unit/test-ril_config
|
||||||
|
unit/test-ril_util
|
||||||
unit/test-rilmodem-cb
|
unit/test-rilmodem-cb
|
||||||
unit/test-rilmodem-cs
|
unit/test-rilmodem-cs
|
||||||
unit/test-rilmodem-gprs
|
unit/test-rilmodem-gprs
|
||||||
unit/test-rilmodem-sms
|
unit/test-rilmodem-sms
|
||||||
unit/test-sailfish_cell_info
|
unit/test-sailfish_cell_info
|
||||||
|
unit/test-sailfish_cell_info_dbus
|
||||||
unit/test-sailfish_manager
|
unit/test-sailfish_manager
|
||||||
unit/test-sailfish_sim_info
|
unit/test-sailfish_sim_info
|
||||||
|
unit/test-sailfish_sim_info_dbus
|
||||||
|
unit/test-sailfish_watch
|
||||||
unit/test-sms-filter
|
unit/test-sms-filter
|
||||||
unit/test-*.log
|
unit/test-*.log
|
||||||
unit/test-*.trs
|
unit/test-*.trs
|
||||||
|
|||||||
@@ -116,3 +116,13 @@ Martin Chaplet <m.chaplet@kerlink.fr>
|
|||||||
Suman Mallela <suman.m@intel.com>
|
Suman Mallela <suman.m@intel.com>
|
||||||
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
|
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
|
||||||
Antoine Aubert <a.aubert@overkiz.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>
|
||||||
|
Matthijs Kooijman <matthijs@stdin.nl>
|
||||||
|
Clayton Craft <clayton@craftyguy.net>
|
||||||
|
Joey Hewitt <joey@joeyhewitt.com>
|
||||||
|
|||||||
@@ -1,3 +1,36 @@
|
|||||||
|
ver 1.21:
|
||||||
|
Fix issue with USSD notification received handling.
|
||||||
|
Fix issue with crashing SIM filesystem notifications.
|
||||||
|
Fix issue with LTE bearer reporting and Huawei modems.
|
||||||
|
Fix issue with invalid memory access and QMI.
|
||||||
|
Add support for QMI SIM writing functionality.
|
||||||
|
Add support for RAT selection for QMI modems.
|
||||||
|
Add support for network monitor agent interface.
|
||||||
|
Add support for Cinterion Hardware Monitor interface.
|
||||||
|
Add support for LTE atom driver for Huawei modems.
|
||||||
|
Add support for LTE atom driver for AT modems.
|
||||||
|
Add support for Intel xmm7xxx series modems.
|
||||||
|
|
||||||
|
ver 1.20:
|
||||||
|
Fix issue with context removal before activation.
|
||||||
|
Fix issue with update during GPRS context activation.
|
||||||
|
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:
|
ver 1.19:
|
||||||
Fix issue with DHCP parsing and Huawei modems.
|
Fix issue with DHCP parsing and Huawei modems.
|
||||||
Fix issue with detecting Huawei E3372 modem.
|
Fix issue with detecting Huawei E3372 modem.
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
|||||||
include/cdma-provision.h include/handsfree.h \
|
include/cdma-provision.h include/handsfree.h \
|
||||||
include/sim-mnclength.h \
|
include/sim-mnclength.h \
|
||||||
include/handsfree-audio.h include/siri.h \
|
include/handsfree-audio.h include/siri.h \
|
||||||
include/sms-filter.h \
|
include/sms-filter.h include/gprs-filter.h \
|
||||||
include/netmon.h
|
include/netmon.h include/lte.h \
|
||||||
|
include/storage.h \
|
||||||
|
gdbus/gdbus.h
|
||||||
|
|
||||||
nodist_pkginclude_HEADERS = include/version.h
|
nodist_pkginclude_HEADERS = include/version.h
|
||||||
|
|
||||||
@@ -113,8 +115,6 @@ gril_sources = gril/gril.h gril/gril.c \
|
|||||||
btio_sources = btio/btio.h btio/btio.c
|
btio_sources = btio/btio.h btio/btio.c
|
||||||
|
|
||||||
if UDEV
|
if UDEV
|
||||||
builtin_modules += udev
|
|
||||||
builtin_sources += plugins/udev.c
|
|
||||||
builtin_cflags += @UDEV_CFLAGS@
|
builtin_cflags += @UDEV_CFLAGS@
|
||||||
builtin_libadd += @UDEV_LIBS@
|
builtin_libadd += @UDEV_LIBS@
|
||||||
|
|
||||||
@@ -166,8 +166,12 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
|||||||
drivers/ril/ril_stk.c \
|
drivers/ril/ril_stk.c \
|
||||||
drivers/ril/ril_ussd.c \
|
drivers/ril/ril_ussd.c \
|
||||||
drivers/ril/ril_util.c \
|
drivers/ril/ril_util.c \
|
||||||
|
drivers/ril/ril_vendor.c \
|
||||||
drivers/ril/ril_voicecall.c
|
drivers/ril/ril_voicecall.c
|
||||||
|
|
||||||
|
# Vendor specific extensions
|
||||||
|
builtin_sources += drivers/ril/ril_vendor_mtk.c
|
||||||
|
|
||||||
if DATAFILES
|
if DATAFILES
|
||||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||||
endif
|
endif
|
||||||
@@ -185,8 +189,8 @@ builtin_sources += plugins/ril.c plugins/ril.h
|
|||||||
builtin_modules += infineon
|
builtin_modules += infineon
|
||||||
builtin_sources += plugins/infineon.c
|
builtin_sources += plugins/infineon.c
|
||||||
|
|
||||||
builtin_modules += ril_sofia3gr
|
builtin_modules += ril_intel
|
||||||
builtin_sources += plugins/ril_sofia3gr.c
|
builtin_sources += plugins/ril_intel.c
|
||||||
|
|
||||||
builtin_modules += rilmodem
|
builtin_modules += rilmodem
|
||||||
builtin_sources += drivers/rilmodem/rilmodem.h \
|
builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||||
@@ -211,7 +215,8 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
|||||||
drivers/rilmodem/netmon.c \
|
drivers/rilmodem/netmon.c \
|
||||||
drivers/rilmodem/stk.c \
|
drivers/rilmodem/stk.c \
|
||||||
drivers/rilmodem/cbs.c \
|
drivers/rilmodem/cbs.c \
|
||||||
drivers/infineonmodem/infineon_constants.h
|
drivers/infineonmodem/infineon_constants.h \
|
||||||
|
drivers/rilmodem/lte.c
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -270,11 +275,13 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
|
|||||||
drivers/qmimodem/ctl.h \
|
drivers/qmimodem/ctl.h \
|
||||||
drivers/qmimodem/dms.h \
|
drivers/qmimodem/dms.h \
|
||||||
drivers/qmimodem/nas.h \
|
drivers/qmimodem/nas.h \
|
||||||
|
drivers/qmimodem/nas.c \
|
||||||
drivers/qmimodem/uim.h \
|
drivers/qmimodem/uim.h \
|
||||||
drivers/qmimodem/wms.h \
|
drivers/qmimodem/wms.h \
|
||||||
drivers/qmimodem/wds.h \
|
drivers/qmimodem/wds.h \
|
||||||
drivers/qmimodem/pds.h \
|
drivers/qmimodem/pds.h \
|
||||||
drivers/qmimodem/common.h
|
drivers/qmimodem/common.h \
|
||||||
|
drivers/qmimodem/wda.h
|
||||||
|
|
||||||
builtin_modules += qmimodem
|
builtin_modules += qmimodem
|
||||||
builtin_sources += $(qmi_sources) \
|
builtin_sources += $(qmi_sources) \
|
||||||
@@ -291,7 +298,8 @@ builtin_sources += $(qmi_sources) \
|
|||||||
drivers/qmimodem/gprs.c \
|
drivers/qmimodem/gprs.c \
|
||||||
drivers/qmimodem/gprs-context.c \
|
drivers/qmimodem/gprs-context.c \
|
||||||
drivers/qmimodem/radio-settings.c \
|
drivers/qmimodem/radio-settings.c \
|
||||||
drivers/qmimodem/location-reporting.c
|
drivers/qmimodem/location-reporting.c \
|
||||||
|
drivers/qmimodem/netmon.c
|
||||||
|
|
||||||
builtin_modules += gobi
|
builtin_modules += gobi
|
||||||
builtin_sources += plugins/gobi.c
|
builtin_sources += plugins/gobi.c
|
||||||
@@ -322,7 +330,8 @@ builtin_sources += drivers/atmodem/atmodem.h \
|
|||||||
drivers/atmodem/gprs.c \
|
drivers/atmodem/gprs.c \
|
||||||
drivers/atmodem/gprs-context.c \
|
drivers/atmodem/gprs-context.c \
|
||||||
drivers/atmodem/sim-auth.c \
|
drivers/atmodem/sim-auth.c \
|
||||||
drivers/atmodem/gnss.c
|
drivers/atmodem/gnss.c \
|
||||||
|
drivers/atmodem/lte.c
|
||||||
|
|
||||||
builtin_modules += nwmodem
|
builtin_modules += nwmodem
|
||||||
builtin_sources += drivers/atmodem/atutil.h \
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
@@ -379,7 +388,8 @@ builtin_modules += telitmodem
|
|||||||
builtin_sources += drivers/atmodem/atutil.h \
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
drivers/telitmodem/telitmodem.h \
|
drivers/telitmodem/telitmodem.h \
|
||||||
drivers/telitmodem/telitmodem.c \
|
drivers/telitmodem/telitmodem.c \
|
||||||
drivers/telitmodem/location-reporting.c
|
drivers/telitmodem/location-reporting.c \
|
||||||
|
drivers/telitmodem/gprs-context-ncm.c
|
||||||
|
|
||||||
builtin_modules += hsomodem
|
builtin_modules += hsomodem
|
||||||
builtin_sources += drivers/atmodem/atutil.h \
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
@@ -441,9 +451,23 @@ builtin_modules += ubloxmodem
|
|||||||
builtin_sources += drivers/atmodem/atutil.h \
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
drivers/ubloxmodem/ubloxmodem.h \
|
drivers/ubloxmodem/ubloxmodem.h \
|
||||||
drivers/ubloxmodem/ubloxmodem.c \
|
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
|
||||||
|
|
||||||
|
builtin_modules += xmm7modem
|
||||||
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
|
drivers/xmm7modem/xmm7modem.h \
|
||||||
|
drivers/xmm7modem/xmm7modem.c \
|
||||||
|
drivers/xmm7modem/radio-settings.c
|
||||||
|
|
||||||
if PHONESIM
|
if PHONESIM
|
||||||
builtin_modules += phonesim
|
builtin_modules += phonesim
|
||||||
builtin_sources += plugins/phonesim.c
|
builtin_sources += plugins/phonesim.c
|
||||||
@@ -508,6 +532,9 @@ builtin_sources += plugins/caif.c
|
|||||||
builtin_modules += cinterion
|
builtin_modules += cinterion
|
||||||
builtin_sources += plugins/cinterion.c
|
builtin_sources += plugins/cinterion.c
|
||||||
|
|
||||||
|
builtin_modules += gemalto
|
||||||
|
builtin_sources += plugins/gemalto.c
|
||||||
|
|
||||||
builtin_modules += nokia
|
builtin_modules += nokia
|
||||||
builtin_sources += plugins/nokia.c
|
builtin_sources += plugins/nokia.c
|
||||||
|
|
||||||
@@ -535,24 +562,30 @@ builtin_sources += plugins/samsung.c
|
|||||||
builtin_modules += sim900
|
builtin_modules += sim900
|
||||||
builtin_sources += plugins/sim900.c
|
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_modules += quectel
|
||||||
builtin_sources += plugins/quectel.c
|
builtin_sources += plugins/quectel.c
|
||||||
|
|
||||||
builtin_modules += ublox
|
builtin_modules += ublox
|
||||||
builtin_sources += plugins/ublox.c
|
builtin_sources += plugins/ublox.c
|
||||||
|
|
||||||
builtin_modules += he910
|
builtin_modules += xmm7xxx
|
||||||
builtin_sources += plugins/he910.c
|
builtin_sources += plugins/xmm7xxx.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
builtin_modules += connman
|
builtin_modules += connman
|
||||||
builtin_sources += plugins/connman.c
|
builtin_sources += plugins/connman.c
|
||||||
|
|
||||||
|
builtin_modules += mnclength
|
||||||
|
builtin_sources += plugins/mnclength.c
|
||||||
|
|
||||||
if BLUETOOTH
|
if BLUETOOTH
|
||||||
if BLUEZ4
|
if BLUEZ4
|
||||||
builtin_modules += telit
|
|
||||||
builtin_sources += plugins/telit.c plugins/bluez4.h
|
|
||||||
|
|
||||||
builtin_modules += sap
|
builtin_modules += sap
|
||||||
builtin_sources += plugins/sap.c plugins/bluez4.h
|
builtin_sources += plugins/sap.c plugins/bluez4.h
|
||||||
|
|
||||||
@@ -629,8 +662,9 @@ builtin_sources += plugins/provision.h
|
|||||||
builtin_modules += cdma_provision
|
builtin_modules += cdma_provision
|
||||||
builtin_sources += plugins/cdma-provision.c
|
builtin_sources += plugins/cdma-provision.c
|
||||||
|
|
||||||
builtin_modules += mnclength
|
builtin_modules += file_provision
|
||||||
builtin_sources += plugins/mnclength.c
|
builtin_sources += plugins/file-provision.c
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if MAINTAINER_MODE
|
if MAINTAINER_MODE
|
||||||
@@ -702,9 +736,10 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
|||||||
src/cdma-provision.c src/handsfree.c \
|
src/cdma-provision.c src/handsfree.c \
|
||||||
src/handsfree-audio.c src/bluetooth.h \
|
src/handsfree-audio.c src/bluetooth.h \
|
||||||
src/sim-mnclength.c src/voicecallagent.c \
|
src/sim-mnclength.c src/voicecallagent.c \
|
||||||
src/sms-filter.c \
|
src/sms-filter.c src/gprs-filter.c src/dbus-queue.c \
|
||||||
src/hfp.h src/siri.c \
|
src/hfp.h src/siri.c \
|
||||||
src/netmon.c
|
src/netmon.c src/lte.c \
|
||||||
|
src/netmonagent.c src/netmonagent.h
|
||||||
|
|
||||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||||
@@ -752,7 +787,9 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
|||||||
doc/certification.txt doc/siri-api.txt \
|
doc/certification.txt doc/siri-api.txt \
|
||||||
doc/telit-modem.txt \
|
doc/telit-modem.txt \
|
||||||
doc/networkmonitor-api.txt \
|
doc/networkmonitor-api.txt \
|
||||||
doc/allowed-apns-api.txt
|
doc/allowed-apns-api.txt \
|
||||||
|
doc/lte-api.txt \
|
||||||
|
doc/cinterion-hardware-monitor-api.txt
|
||||||
|
|
||||||
|
|
||||||
test_scripts = test/backtrace \
|
test_scripts = test/backtrace \
|
||||||
@@ -859,7 +896,10 @@ test_scripts = test/backtrace \
|
|||||||
test/get-serving-cell-info \
|
test/get-serving-cell-info \
|
||||||
test/list-allowed-access-points \
|
test/list-allowed-access-points \
|
||||||
test/enable-throttling \
|
test/enable-throttling \
|
||||||
test/disable-throttling
|
test/disable-throttling \
|
||||||
|
test/set-lte-property \
|
||||||
|
test/test-serving-cell-info
|
||||||
|
|
||||||
|
|
||||||
if TEST
|
if TEST
|
||||||
testdir = $(pkglibdir)/test
|
testdir = $(pkglibdir)/test
|
||||||
@@ -879,19 +919,31 @@ unit_objects =
|
|||||||
|
|
||||||
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
||||||
unit/test-simutil unit/test-stkutil \
|
unit/test-simutil unit/test-stkutil \
|
||||||
unit/test-sms unit/test-cdmasms \
|
unit/test-sms unit/test-cdmasms
|
||||||
unit/test-provision unit/test-sms-filter
|
|
||||||
|
|
||||||
if SAILFISH_MANAGER
|
if SAILFISH_MANAGER
|
||||||
|
|
||||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||||
plugins/sailfish_manager/sailfish_cell_info.c
|
plugins/sailfish_manager/sailfish_cell_info.c
|
||||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||||
-Iplugins/sailfish_cell_info
|
-Iplugins/sailfish_manager
|
||||||
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||||
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
||||||
unit_tests += unit/test-sailfish_cell_info
|
unit_tests += unit/test-sailfish_cell_info
|
||||||
|
|
||||||
|
unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||||
|
unit/test-sailfish_cell_info_dbus.c \
|
||||||
|
unit/fake_sailfish_cell_info.c \
|
||||||
|
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||||
|
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||||
|
gdbus/object.c \
|
||||||
|
src/dbus.c src/log.c
|
||||||
|
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||||
|
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager
|
||||||
|
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
|
||||||
|
unit_tests += unit/test-sailfish_cell_info_dbus
|
||||||
|
|
||||||
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||||
unit/fake_sailfish_watch.c \
|
unit/fake_sailfish_watch.c \
|
||||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||||
@@ -902,6 +954,19 @@ unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
|||||||
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||||
unit_tests += unit/test-sailfish_sim_info
|
unit_tests += unit/test-sailfish_sim_info
|
||||||
|
|
||||||
|
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
|
||||||
|
unit/test-dbus.c unit/fake_sailfish_watch.c \
|
||||||
|
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||||
|
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||||
|
gdbus/object.c \
|
||||||
|
src/dbus.c src/storage.c src/watch.c src/log.c
|
||||||
|
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||||
|
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
|
||||||
|
-Iplugins/sailfish_manager
|
||||||
|
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
|
||||||
|
unit_tests += unit/test-sailfish_sim_info_dbus
|
||||||
|
|
||||||
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||||
unit/fake_sailfish_watch.c \
|
unit/fake_sailfish_watch.c \
|
||||||
plugins/sailfish_manager/sailfish_manager.c \
|
plugins/sailfish_manager/sailfish_manager.c \
|
||||||
@@ -914,11 +979,35 @@ unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
|||||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||||
unit_tests += unit/test-sailfish_manager
|
unit_tests += unit/test-sailfish_manager
|
||||||
|
|
||||||
|
unit_test_sailfish_watch_SOURCES = unit/test-sailfish_watch.c \
|
||||||
|
plugins/sailfish_manager/sailfish_watch.c \
|
||||||
|
src/log.c src/watch.c
|
||||||
|
unit_test_sailfish_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||||
|
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||||
|
unit_test_sailfish_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_sailfish_watch_OBJECTS)
|
||||||
|
unit_tests += unit/test-sailfish_watch
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if RILMODEM
|
if RILMODEM
|
||||||
if SAILFISH_RILMODEM
|
if SAILFISH_RILMODEM
|
||||||
|
|
||||||
|
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
|
||||||
|
drivers/ril/ril_config.c src/log.c
|
||||||
|
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
|
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_ril_config_OBJECTS)
|
||||||
|
unit_tests += unit/test-ril_config
|
||||||
|
|
||||||
|
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||||
|
src/log.c
|
||||||
|
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
|
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_tests += unit/test-rilmodem-cs \
|
||||||
unit/test-rilmodem-cs \
|
unit/test-rilmodem-cs \
|
||||||
unit/test-rilmodem-sms \
|
unit/test-rilmodem-sms \
|
||||||
@@ -987,6 +1076,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
|||||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_caif_OBJECTS)
|
unit_objects += $(unit_test_caif_OBJECTS)
|
||||||
|
|
||||||
|
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||||
|
src/dbus-queue.c gdbus/object.c \
|
||||||
|
src/dbus.c src/log.c
|
||||||
|
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
|
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_dbus_queue_OBJECTS)
|
||||||
|
unit_tests += unit/test-dbus-queue
|
||||||
|
|
||||||
unit_test_provision_SOURCES = unit/test-provision.c \
|
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||||
plugins/provision.h plugins/mbpi.c \
|
plugins/provision.h plugins/mbpi.c \
|
||||||
plugins/sailfish_provision.c \
|
plugins/sailfish_provision.c \
|
||||||
@@ -994,12 +1091,21 @@ unit_test_provision_SOURCES = unit/test-provision.c \
|
|||||||
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||||
unit_objects += $(unit_test_provision_OBJECTS)
|
unit_objects += $(unit_test_provision_OBJECTS)
|
||||||
|
unit_tests += unit/test-provision
|
||||||
|
|
||||||
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
|
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
|
||||||
src/sms-filter.c src/log.c
|
src/sms-filter.c src/log.c
|
||||||
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
unit_test_sms_filter_LDADD = @GLIB_LIBS@ -ldl
|
unit_test_sms_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||||
unit_objects += $(unit_test_sms_filter_OBJECTS)
|
unit_objects += $(unit_test_sms_filter_OBJECTS)
|
||||||
|
unit_tests += unit/test-sms-filter
|
||||||
|
|
||||||
|
unit_test_gprs_filter_SOURCES = unit/test-gprs-filter.c \
|
||||||
|
src/gprs-filter.c src/log.c
|
||||||
|
unit_test_gprs_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
|
unit_test_gprs_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_gprs_filter_OBJECTS)
|
||||||
|
unit_tests += unit/test-gprs-filter
|
||||||
|
|
||||||
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
|
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
|
||||||
gatchat/ringbuffer.h gatchat/ringbuffer.c \
|
gatchat/ringbuffer.h gatchat/ringbuffer.c \
|
||||||
@@ -1064,13 +1170,6 @@ tools_lookup_provider_name_LDADD = @GLIB_LIBS@
|
|||||||
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
||||||
tools_tty_redirector_LDADD = @GLIB_LIBS@
|
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
|
if MAINTAINER_MODE
|
||||||
noinst_PROGRAMS += tools/stktest
|
noinst_PROGRAMS += tools/stktest
|
||||||
|
|
||||||
@@ -1139,6 +1238,10 @@ include/ofono/version.h: include/version.h
|
|||||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||||
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
|
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
|
||||||
|
|
||||||
|
include/ofono/gdbus.h: $(abs_top_srcdir)/gdbus/gdbus.h
|
||||||
|
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||||
|
$(AM_V_GEN)$(LN_S) $< $@
|
||||||
|
|
||||||
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
|
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
|
||||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||||
$(AM_V_GEN)$(LN_S) $< $@
|
$(AM_V_GEN)$(LN_S) $< $@
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ AC_DEFUN([COMPILER_FLAGS], [
|
|||||||
CFLAGS="$CFLAGS -Wmissing-declarations"
|
CFLAGS="$CFLAGS -Wmissing-declarations"
|
||||||
CFLAGS="$CFLAGS -Wredundant-decls"
|
CFLAGS="$CFLAGS -Wredundant-decls"
|
||||||
CFLAGS="$CFLAGS -Wcast-align"
|
CFLAGS="$CFLAGS -Wcast-align"
|
||||||
|
CFLAGS="$CFLAGS -Wno-format-truncation"
|
||||||
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
|
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.60)
|
AC_PREREQ(2.60)
|
||||||
AC_INIT(ofono, 1.19)
|
AC_INIT(ofono, 1.21)
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
@@ -184,8 +184,8 @@ AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
|||||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||||
|
|
||||||
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.18, dummy=yes,
|
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.21, dummy=yes,
|
||||||
AC_MSG_ERROR(libgrilio >= 1.0.18 is required))
|
AC_MSG_ERROR(libgrilio >= 1.0.21 is required))
|
||||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
||||||
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
||||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||||
@@ -202,6 +202,13 @@ AC_ARG_ENABLE(sailfish-manager,
|
|||||||
[enable_sailfish_manager=${enableval}])
|
[enable_sailfish_manager=${enableval}])
|
||||||
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
|
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
|
||||||
|
|
||||||
|
if (test "${enable_sailfish_manager}" = "yes"); then
|
||||||
|
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
|
||||||
|
AC_MSG_ERROR(dbus-glib is required by unit tests))
|
||||||
|
AC_SUBST(DBUS_GLIB_CFLAGS)
|
||||||
|
AC_SUBST(DBUS_GLIB_LIBS)
|
||||||
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
|
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
|
||||||
[don't allow to add or remove connection context over D-Bus]), [
|
[don't allow to add or remove connection context over D-Bus]), [
|
||||||
if (test "${enableval}" = "no"); then
|
if (test "${enableval}" = "no"); then
|
||||||
|
|||||||
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
HardwareMonitor hierarchy
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Service org.ofono
|
||||||
|
Interface org.ofono.cinterion.HardwareMonitor
|
||||||
|
Object path /{device0,device1,...}
|
||||||
|
|
||||||
|
Methods array{string,variant} GetStatistics
|
||||||
|
|
||||||
|
Returns an array of dict entries representing the
|
||||||
|
current temperature and supply voltage of the modem.
|
||||||
|
|
||||||
|
Units:
|
||||||
|
Temperature: Celsius
|
||||||
|
Voltage: mV
|
||||||
@@ -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
|
Some of them are mandatory (marked as 'M'), while some others are optional
|
||||||
(marked as 'O'), but generally preferred.
|
(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
|
There should be a blank line before if statement unless the if is nested and
|
||||||
not preceded by an expression or variable declaration.
|
not preceded by an expression or variable declaration.
|
||||||
|
|||||||
@@ -76,6 +76,22 @@ Methods dict GetProperties()
|
|||||||
[service].Error.NotImplemented
|
[service].Error.NotImplemented
|
||||||
[service].Error.NotAllowed
|
[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)
|
Signals PropertyChanged(string name, variant value)
|
||||||
|
|
||||||
This signal indicates a changed value of the given
|
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.
|
||||||
@@ -22,6 +22,34 @@ Methods a{sv} GetServingCellInformation()
|
|||||||
are available, their valid value ranges and
|
are available, their valid value ranges and
|
||||||
applicability to different cell types.
|
applicability to different cell types.
|
||||||
|
|
||||||
|
void RegisterAgent(object path)
|
||||||
|
|
||||||
|
Registers an agent which will be called whenever the
|
||||||
|
modem registers to or moves to a new cell.
|
||||||
|
|
||||||
|
void UnregisterAgent(object path)
|
||||||
|
|
||||||
|
Unregisters an agent.
|
||||||
|
|
||||||
|
NetworkMonitorAgent Hierarchy [experimental]
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Service unique name
|
||||||
|
Interface org.ofono.NetworkMonitorAgent
|
||||||
|
Object path freely definable
|
||||||
|
|
||||||
|
Methods void ServingCellInformationChanged(a{sv}) [noreply]
|
||||||
|
|
||||||
|
This method is called whenever the serving cell
|
||||||
|
information has been updated.
|
||||||
|
|
||||||
|
Possible Errors: None
|
||||||
|
|
||||||
|
void Release() [noreply]
|
||||||
|
|
||||||
|
Agent is being released, possibly because of oFono
|
||||||
|
terminating, NetworkMonitor interface is being torn
|
||||||
|
down or modem off. No UnregisterAgent call is needed.
|
||||||
|
|
||||||
Network Monitor Property Types
|
Network Monitor Property Types
|
||||||
==============================
|
==============================
|
||||||
@@ -77,7 +105,46 @@ byte TimingAdvance [optional, gsm]
|
|||||||
|
|
||||||
Contains the Timing Advance. Valid range of values is 0-219.
|
Contains the Timing Advance. Valid range of values is 0-219.
|
||||||
|
|
||||||
byte Strength [optional, gsm, umts]
|
byte Strength [optional, gsm, umts, lte]
|
||||||
|
|
||||||
Contains the signal strength. Valid values are 0-31. Refer to <rssi>
|
Contains the signal strength. Valid values are 0-31. Refer to <rssi>
|
||||||
in 27.007, Section 8.5.
|
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.
|
After setting the configuration, a power cycle is required.
|
||||||
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
|
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
|
||||||
can be checked using 'AT+CGMR'.
|
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.
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ static int atmodem_init(void)
|
|||||||
at_gprs_context_init();
|
at_gprs_context_init();
|
||||||
at_sim_auth_init();
|
at_sim_auth_init();
|
||||||
at_gnss_init();
|
at_gnss_init();
|
||||||
|
at_lte_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -76,6 +77,7 @@ static void atmodem_exit(void)
|
|||||||
at_gprs_exit();
|
at_gprs_exit();
|
||||||
at_gprs_context_exit();
|
at_gprs_context_exit();
|
||||||
at_gnss_exit();
|
at_gnss_exit();
|
||||||
|
at_lte_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
||||||
|
|||||||
@@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void);
|
|||||||
|
|
||||||
extern void at_gnss_init(void);
|
extern void at_gnss_init(void);
|
||||||
extern void at_gnss_exit(void);
|
extern void at_gnss_exit(void);
|
||||||
|
|
||||||
|
extern void at_lte_init(void);
|
||||||
|
extern void at_lte_exit(void);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <gatchat.h>
|
#include <gatchat.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||||
#include <ofono/log.h>
|
#include <ofono/log.h>
|
||||||
@@ -614,3 +615,42 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req)
|
|||||||
|
|
||||||
g_free(req);
|
g_free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||||
|
* of "a.b.c.d.m.m.m.m" for IPv4.
|
||||||
|
* address/netmask must be able to hold
|
||||||
|
* 255.255.255.255 + null = 16 characters
|
||||||
|
*/
|
||||||
|
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||||
|
char *address, char *netmask)
|
||||||
|
{
|
||||||
|
const char *s = addrnetmask;
|
||||||
|
const char *net = NULL;
|
||||||
|
|
||||||
|
int ret = -EINVAL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Count 7 dots for ipv4, less or more means error. */
|
||||||
|
for (i = 0; i < 9; i++, s++) {
|
||||||
|
s = strchr(s, '.');
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == 3) {
|
||||||
|
/* set netmask ptr and break the string */
|
||||||
|
net = s + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 7) {
|
||||||
|
memcpy(address, addrnetmask, net - addrnetmask);
|
||||||
|
address[net - addrnetmask - 1] = '\0';
|
||||||
|
strcpy(netmask, net);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ struct at_util_sim_state_query *at_util_sim_state_query_new(GAtChat *chat,
|
|||||||
GDestroyNotify destroy);
|
GDestroyNotify destroy);
|
||||||
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
||||||
|
|
||||||
|
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||||
|
char *address, char *netmask);
|
||||||
|
|
||||||
struct cb_data {
|
struct cb_data {
|
||||||
void *cb;
|
void *cb;
|
||||||
void *data;
|
void *data;
|
||||||
|
|||||||
@@ -43,10 +43,11 @@
|
|||||||
#include "atmodem.h"
|
#include "atmodem.h"
|
||||||
#include "vendor.h"
|
#include "vendor.h"
|
||||||
|
|
||||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
#define TUN_DEV "/dev/net/tun"
|
||||||
|
|
||||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||||
|
|
||||||
|
static const char *cgdata_prefix[] = { "+CGDATA:", NULL };
|
||||||
static const char *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
|
|
||||||
enum state {
|
enum state {
|
||||||
@@ -67,6 +68,7 @@ struct gprs_context_data {
|
|||||||
ofono_gprs_context_cb_t cb;
|
ofono_gprs_context_cb_t cb;
|
||||||
void *cb_data; /* Callback data */
|
void *cb_data; /* Callback data */
|
||||||
unsigned int vendor;
|
unsigned int vendor;
|
||||||
|
gboolean use_atd99;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ppp_debug(const char *str, void *data)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gcd->vendor == OFONO_VENDOR_SIMCOM_SIM900)
|
if (gcd->use_atd99)
|
||||||
sprintf(buf, "ATD*99***%u#", gcd->active_context);
|
sprintf(buf, "ATD*99***%u#", gcd->active_context);
|
||||||
else
|
else
|
||||||
sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
|
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);
|
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,
|
static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||||
unsigned int vendor, void *data)
|
unsigned int vendor, void *data)
|
||||||
{
|
{
|
||||||
@@ -391,7 +430,7 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
if (stat(TUN_DEV, &st) < 0) {
|
||||||
ofono_error("Missing support for TUN/TAP devices");
|
ofono_error("Missing support for TUN/TAP devices");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@@ -409,6 +448,15 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
|||||||
if (chat == NULL)
|
if (chat == NULL)
|
||||||
return 0;
|
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);
|
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ struct gprs_data {
|
|||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
unsigned int vendor;
|
unsigned int vendor;
|
||||||
unsigned int last_auto_context_id;
|
unsigned int last_auto_context_id;
|
||||||
|
gboolean telit_try_reattach;
|
||||||
|
int attached;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
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);
|
snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
|
||||||
|
|
||||||
if (g_at_chat_send(gd->chat, buf, none_prefix,
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
|
|
||||||
@@ -194,6 +198,28 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
|
|||||||
NULL, NULL, NULL, gd->vendor) == FALSE)
|
NULL, NULL, NULL, gd->vendor) == FALSE)
|
||||||
return;
|
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);
|
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") ||
|
if (g_str_equal(event, "NW DETACH") ||
|
||||||
g_str_equal(event, "ME 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);
|
ofono_gprs_detached_notify(gprs);
|
||||||
return;
|
return;
|
||||||
} else if (g_str_has_prefix(event, "ME PDN ACT")) {
|
} else if (g_str_has_prefix(event, "ME PDN ACT")) {
|
||||||
@@ -296,6 +327,26 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
|||||||
ofono_gprs_bearer_notify(gprs, bearer);
|
ofono_gprs_bearer_notify(gprs, bearer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs *gprs = user_data;
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *mode;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strcmp("LTE", mode))
|
||||||
|
ofono_gprs_bearer_notify(gprs, 7); /* LTE */
|
||||||
|
|
||||||
|
/* in other modes, notification ^MODE is used */
|
||||||
|
}
|
||||||
|
|
||||||
static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs *gprs = user_data;
|
struct ofono_gprs *gprs = user_data;
|
||||||
@@ -323,6 +374,9 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
|||||||
case 3:
|
case 3:
|
||||||
bearer = 5; /* HSDPA */
|
bearer = 5; /* HSDPA */
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
bearer = 7; /* LTE */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
bearer = 0;
|
bearer = 0;
|
||||||
break;
|
break;
|
||||||
@@ -398,6 +452,8 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
case OFONO_VENDOR_HUAWEI:
|
case OFONO_VENDOR_HUAWEI:
|
||||||
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
||||||
FALSE, gprs, NULL);
|
FALSE, gprs, NULL);
|
||||||
|
g_at_chat_register(gd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||||
|
FALSE, gprs, NULL);
|
||||||
break;
|
break;
|
||||||
case OFONO_VENDOR_UBLOX:
|
case OFONO_VENDOR_UBLOX:
|
||||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||||
@@ -411,6 +467,7 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
FALSE, gprs, NULL);
|
FALSE, gprs, NULL);
|
||||||
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
|
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
|
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
|
||||||
FALSE, gprs, NULL);
|
FALSE, gprs, NULL);
|
||||||
@@ -522,7 +579,7 @@ static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
|
|||||||
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
|
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!g_at_result_iter_close_list(&iter))
|
if (!g_at_result_iter_skip_next(&iter))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (g_at_result_iter_open_list(&iter))
|
if (g_at_result_iter_open_list(&iter))
|
||||||
|
|||||||
142
ofono/drivers/atmodem/lte.c
Normal file
142
ofono/drivers/atmodem/lte.c
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
#include <ofono/gprs-context.h>
|
||||||
|
#include <ofono/log.h>
|
||||||
|
#include <ofono/lte.h>
|
||||||
|
|
||||||
|
#include "gatchat.h"
|
||||||
|
#include "gatresult.h"
|
||||||
|
|
||||||
|
#include "atmodem.h"
|
||||||
|
|
||||||
|
struct lte_driver_data {
|
||||||
|
GAtChat *chat;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_lte_cb_t cb = cbd->cb;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
cb(&error, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||||
|
const struct ofono_lte_default_attach_info *info,
|
||||||
|
ofono_lte_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||||
|
char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
|
DBG("LTE config with APN: %s", info->apn);
|
||||||
|
|
||||||
|
if (strlen(info->apn) > 0)
|
||||||
|
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"",
|
||||||
|
info->apn);
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\"");
|
||||||
|
|
||||||
|
/* We can't do much in case of failure so don't check response. */
|
||||||
|
if (g_at_chat_send(ldd->chat, buf, NULL,
|
||||||
|
at_lte_set_default_attach_info_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean lte_delayed_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_lte *lte = user_data;
|
||||||
|
|
||||||
|
ofono_lte_register(lte);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int at_lte_probe(struct ofono_lte *lte, void *data)
|
||||||
|
{
|
||||||
|
GAtChat *chat = data;
|
||||||
|
struct lte_driver_data *ldd;
|
||||||
|
|
||||||
|
DBG("at lte probe");
|
||||||
|
|
||||||
|
ldd = g_try_new0(struct lte_driver_data, 1);
|
||||||
|
if (!ldd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ldd->chat = g_at_chat_clone(chat);
|
||||||
|
|
||||||
|
ofono_lte_set_data(lte, ldd);
|
||||||
|
|
||||||
|
g_idle_add(lte_delayed_register, lte);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void at_lte_remove(struct ofono_lte *lte)
|
||||||
|
{
|
||||||
|
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||||
|
|
||||||
|
DBG("at lte remove");
|
||||||
|
|
||||||
|
g_at_chat_unref(ldd->chat);
|
||||||
|
|
||||||
|
ofono_lte_set_data(lte, NULL);
|
||||||
|
|
||||||
|
g_free(ldd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ofono_lte_driver driver = {
|
||||||
|
.name = "atmodem",
|
||||||
|
.probe = at_lte_probe,
|
||||||
|
.remove = at_lte_remove,
|
||||||
|
.set_default_attach_info = at_lte_set_default_attach_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
void at_lte_init(void)
|
||||||
|
{
|
||||||
|
ofono_lte_driver_register(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void at_lte_exit(void)
|
||||||
|
{
|
||||||
|
ofono_lte_driver_unregister(&driver);
|
||||||
|
}
|
||||||
@@ -1088,6 +1088,27 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_netreg *netreg = user_data;
|
||||||
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *mode;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strcmp("LTE", mode))
|
||||||
|
nd->tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||||
|
|
||||||
|
/* for other technologies, notification ^MODE is used */
|
||||||
|
}
|
||||||
|
|
||||||
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
|
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_netreg *netreg = user_data;
|
struct ofono_netreg *netreg = user_data;
|
||||||
@@ -1896,6 +1917,10 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
|
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
|
||||||
FALSE, netreg, NULL);
|
FALSE, netreg, NULL);
|
||||||
|
|
||||||
|
/* Register for 4G system mode reports */
|
||||||
|
g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||||
|
FALSE, netreg, NULL);
|
||||||
|
|
||||||
/* Register for network time reports */
|
/* Register for network time reports */
|
||||||
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
||||||
FALSE, netreg, NULL);
|
FALSE, netreg, NULL);
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ struct sim_data {
|
|||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
unsigned int vendor;
|
unsigned int vendor;
|
||||||
guint ready_id;
|
guint ready_id;
|
||||||
|
guint passwd_type_mask;
|
||||||
struct at_util_sim_state_query *sim_state_query;
|
struct at_util_sim_state_query *sim_state_query;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1459,9 +1460,8 @@ static void at_pin_enable(struct ofono_sim *sim,
|
|||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[64];
|
char buf[64];
|
||||||
int ret;
|
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;
|
goto error;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
||||||
@@ -1490,10 +1490,8 @@ static void at_change_passwd(struct ofono_sim *sim,
|
|||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[64];
|
char buf[64];
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
|
||||||
|
|
||||||
if (passwd_type >= len ||
|
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||||
at_clck_cpwd_fac[passwd_type] == NULL)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
||||||
@@ -1550,9 +1548,8 @@ static void at_query_clck(struct ofono_sim *sim,
|
|||||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[64];
|
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;
|
goto error;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
||||||
@@ -1568,13 +1565,42 @@ error:
|
|||||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
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 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);
|
ofono_sim_register(sim);
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||||
@@ -1582,6 +1608,7 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
|||||||
{
|
{
|
||||||
GAtChat *chat = data;
|
GAtChat *chat = data;
|
||||||
struct sim_data *sd;
|
struct sim_data *sd;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
sd = g_new0(struct sim_data, 1);
|
sd = g_new0(struct sim_data, 1);
|
||||||
sd->chat = g_at_chat_clone(chat);
|
sd->chat = g_at_chat_clone(chat);
|
||||||
@@ -1591,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);
|
g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
ofono_sim_set_data(sim, sd);
|
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)
|
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");
|
"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)
|
static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||||
{
|
{
|
||||||
struct sms_data *data = ofono_sms_get_data(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("");
|
DBG("");
|
||||||
|
|
||||||
/* We must acknowledge the PDU using CNMA */
|
/* We must acknowledge the PDU using CNMA */
|
||||||
if (data->cnma_ack_pdu)
|
if (data->cnma_ack_pdu) {
|
||||||
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
switch (data->vendor) {
|
||||||
data->cnma_ack_pdu_len, data->cnma_ack_pdu);
|
case OFONO_VENDOR_CINTERION:
|
||||||
else /* Should be a safe fallback */
|
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");
|
snprintf(buf, sizeof(buf), "AT+CNMA=0");
|
||||||
|
}
|
||||||
|
|
||||||
g_at_chat_send(data->chat, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
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 ofono_sms *sms = user_data;
|
||||||
struct sms_data *data = ofono_sms_get_data(sms);
|
struct sms_data *data = ofono_sms_get_data(sms);
|
||||||
|
GAtResultIter iter;
|
||||||
const char *hexpdu;
|
const char *hexpdu;
|
||||||
|
unsigned char pdu[176];
|
||||||
long pdu_len;
|
long pdu_len;
|
||||||
int tpdu_len;
|
int tpdu_len;
|
||||||
unsigned char pdu[176];
|
|
||||||
|
|
||||||
if (!at_parse_cmt(result, &hexpdu, &tpdu_len)) {
|
g_at_result_iter_init(&iter, result);
|
||||||
ofono_error("Unable to parse CMT notification");
|
|
||||||
return;
|
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) {
|
if (strlen(hexpdu) > sizeof(pdu) * 2) {
|
||||||
ofono_error("Bad PDU length in CMT notification");
|
ofono_error("Bad PDU length in CMT notification");
|
||||||
return;
|
return;
|
||||||
@@ -431,6 +439,9 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
if (data->vendor != OFONO_VENDOR_SIMCOM)
|
if (data->vendor != OFONO_VENDOR_SIMCOM)
|
||||||
at_ack_delivery(sms);
|
at_ack_delivery(sms);
|
||||||
|
|
||||||
|
err:
|
||||||
|
ofono_error("Unable to parse CMT notification");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void at_cmgr_notify(GAtResult *result, gpointer user_data)
|
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)
|
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");
|
" please submit patches to support this hardware");
|
||||||
|
|
||||||
ofono_sms_remove(sms);
|
ofono_sms_remove(sms);
|
||||||
|
|||||||
@@ -47,4 +47,5 @@ enum ofono_vendor {
|
|||||||
OFONO_VENDOR_UBLOX,
|
OFONO_VENDOR_UBLOX,
|
||||||
OFONO_VENDOR_UBLOX_TOBY_L2,
|
OFONO_VENDOR_UBLOX_TOBY_L2,
|
||||||
OFONO_VENDOR_CINTERION,
|
OFONO_VENDOR_CINTERION,
|
||||||
|
OFONO_VENDOR_XMM,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
#include "cdmamodem.h"
|
#include "cdmamodem.h"
|
||||||
#include "drivers/atmodem/vendor.h"
|
#include "drivers/atmodem/vendor.h"
|
||||||
|
|
||||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
#define TUN_DEV "/dev/net/tun"
|
||||||
|
|
||||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ static int cdma_connman_probe(struct ofono_cdma_connman *cm,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
if (stat(TUN_DEV, &st) < 0) {
|
||||||
ofono_error("Missing support for TUN/TAP devices");
|
ofono_error("Missing support for TUN/TAP devices");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|||||||
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
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -19,11 +19,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#include <drivers/atmodem/atutil.h>
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
extern void gemalto_location_reporting_init();
|
||||||
{
|
extern void gemalto_location_reporting_exit();
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
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);
|
||||||
|
}
|
||||||
@@ -42,11 +42,13 @@
|
|||||||
|
|
||||||
static const char *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
|
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
|
||||||
|
static const char *syscfgex_prefix[] = { "^SYSCFGEX:", NULL };
|
||||||
|
|
||||||
#define HUAWEI_BAND_ANY 0x3FFFFFFF
|
#define HUAWEI_BAND_ANY 0x3FFFFFFF
|
||||||
|
|
||||||
struct radio_settings_data {
|
struct radio_settings_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
|
ofono_bool_t syscfgex_cap;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct huawei_band_gsm_table {
|
static const struct huawei_band_gsm_table {
|
||||||
@@ -176,20 +178,76 @@ error:
|
|||||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void syscfgex_query_mode_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||||
|
enum ofono_radio_access_mode mode;
|
||||||
|
struct ofono_error error;
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *acqorder;
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
cb(&error, -1, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (g_at_result_iter_next(&iter, "^SYSCFGEX:") == FALSE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (g_at_result_iter_next_string(&iter, &acqorder) == FALSE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if ((strcmp(acqorder, "00") == 0) ||
|
||||||
|
(strstr(acqorder, "01") &&
|
||||||
|
strstr(acqorder, "02") &&
|
||||||
|
strstr(acqorder, "03")))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||||
|
else if (strstr(acqorder, "03"))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
else if (strstr(acqorder, "02"))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
else if (strstr(acqorder, "01"))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
cb(&error, mode, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
|
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
|
||||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||||
{
|
{
|
||||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
if (g_at_chat_send(rsd->chat, "AT^SYSCFG?", syscfg_prefix,
|
if (rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFGEX?",
|
||||||
syscfg_query_mode_cb, cbd, g_free) == 0) {
|
syscfgex_prefix,
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
syscfgex_query_mode_cb,
|
||||||
g_free(cbd);
|
cbd, g_free) > 0)
|
||||||
}
|
return;
|
||||||
|
|
||||||
|
if (!rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFG?",
|
||||||
|
syscfg_prefix,
|
||||||
|
syscfg_query_mode_cb,
|
||||||
|
cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
static void syscfgxx_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
@@ -200,12 +258,11 @@ static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
|||||||
cb(&error, cbd->data);
|
cb(&error, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
static void syscfg_set_rat_mode(struct radio_settings_data *rsd,
|
||||||
enum ofono_radio_access_mode mode,
|
enum ofono_radio_access_mode mode,
|
||||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[40];
|
char buf[40];
|
||||||
unsigned int value = 2, acq_order = 0;
|
unsigned int value = 2, acq_order = 0;
|
||||||
@@ -231,7 +288,7 @@ static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
|||||||
value, acq_order);
|
value, acq_order);
|
||||||
|
|
||||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
syscfg_modify_mode_cb, cbd, g_free) > 0)
|
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -239,7 +296,55 @@ error:
|
|||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
static void syscfgex_set_rat_mode(struct radio_settings_data *rsd,
|
||||||
|
enum ofono_radio_access_mode mode,
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
char buf[50];
|
||||||
|
char *atcmd = "AT^SYSCFGEX=\"%s\",40000000,2,4,40000000,,";
|
||||||
|
char *acqorder = "030201";
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||||
|
acqorder = "00";
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||||
|
acqorder = "01";
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||||
|
acqorder = "02";
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||||
|
acqorder = "03";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), atcmd, acqorder);
|
||||||
|
|
||||||
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
|
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
enum ofono_radio_access_mode mode,
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
if (rsd->syscfgex_cap)
|
||||||
|
syscfgex_set_rat_mode(rsd, mode, cb, data);
|
||||||
|
else
|
||||||
|
syscfg_set_rat_mode(rsd, mode, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syscfgxx_modify_band_cb(gboolean ok, GAtResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
@@ -250,13 +355,54 @@ static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
|||||||
cb(&error, cbd->data);
|
cb(&error, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
static void syscfgex_set_band(struct radio_settings_data *rsd,
|
||||||
|
enum ofono_radio_band_gsm band_gsm,
|
||||||
|
enum ofono_radio_band_umts band_umts,
|
||||||
|
ofono_radio_settings_band_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
char buf[50];
|
||||||
|
char *atcmd = "AT^SYSCFGEX=\"99\",%x,2,4,40000000,,";
|
||||||
|
unsigned int huawei_band;
|
||||||
|
|
||||||
|
if (band_gsm == OFONO_RADIO_BAND_GSM_ANY
|
||||||
|
&& band_umts == OFONO_RADIO_BAND_UMTS_ANY) {
|
||||||
|
huawei_band = HUAWEI_BAND_ANY;
|
||||||
|
} else {
|
||||||
|
unsigned int huawei_band_gsm;
|
||||||
|
unsigned int huawei_band_umts;
|
||||||
|
|
||||||
|
huawei_band_gsm = band_gsm_to_huawei(band_gsm);
|
||||||
|
|
||||||
|
if (!huawei_band_gsm)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
huawei_band_umts = band_umts_to_huawei(band_umts);
|
||||||
|
|
||||||
|
if (!huawei_band_umts)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
huawei_band = huawei_band_gsm | huawei_band_umts;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), atcmd, huawei_band);
|
||||||
|
|
||||||
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
|
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syscfg_set_band(struct radio_settings_data *rsd,
|
||||||
enum ofono_radio_band_gsm band_gsm,
|
enum ofono_radio_band_gsm band_gsm,
|
||||||
enum ofono_radio_band_umts band_umts,
|
enum ofono_radio_band_umts band_umts,
|
||||||
ofono_radio_settings_band_set_cb_t cb,
|
ofono_radio_settings_band_set_cb_t cb,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[40];
|
char buf[40];
|
||||||
unsigned int huawei_band;
|
unsigned int huawei_band;
|
||||||
@@ -284,7 +430,7 @@ static void huawei_set_band(struct ofono_radio_settings *rs,
|
|||||||
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
|
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
|
||||||
|
|
||||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
syscfg_modify_band_cb, cbd, g_free) > 0)
|
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -292,6 +438,20 @@ error:
|
|||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||||
|
enum ofono_radio_band_gsm band_gsm,
|
||||||
|
enum ofono_radio_band_umts band_umts,
|
||||||
|
ofono_radio_settings_band_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
if (rsd->syscfgex_cap)
|
||||||
|
syscfgex_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||||
|
else
|
||||||
|
syscfg_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
|
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
@@ -364,6 +524,21 @@ static void syscfg_support_cb(gboolean ok, GAtResult *result,
|
|||||||
ofono_radio_settings_register(rs);
|
ofono_radio_settings_register(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void syscfgex_support_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_radio_settings *rs = user_data;
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||||
|
syscfg_support_cb, rs, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
rsd->syscfgex_cap = 1;
|
||||||
|
ofono_radio_settings_register(rs);
|
||||||
|
}
|
||||||
|
|
||||||
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||||
unsigned int vendor, void *data)
|
unsigned int vendor, void *data)
|
||||||
{
|
{
|
||||||
@@ -378,8 +553,8 @@ static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
|||||||
|
|
||||||
ofono_radio_settings_set_data(rs, rsd);
|
ofono_radio_settings_set_data(rs, rsd);
|
||||||
|
|
||||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
g_at_chat_send(rsd->chat, "AT^SYSCFGEX=?", syscfgex_prefix,
|
||||||
syscfg_support_cb, rs, NULL);
|
syscfgex_support_cb, rs, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -400,8 +575,8 @@ static struct ofono_radio_settings_driver driver = {
|
|||||||
.remove = huawei_radio_settings_remove,
|
.remove = huawei_radio_settings_remove,
|
||||||
.query_rat_mode = huawei_query_rat_mode,
|
.query_rat_mode = huawei_query_rat_mode,
|
||||||
.set_rat_mode = huawei_set_rat_mode,
|
.set_rat_mode = huawei_set_rat_mode,
|
||||||
.query_band = huawei_query_band,
|
.query_band = huawei_query_band,
|
||||||
.set_band = huawei_set_band,
|
.set_band = huawei_set_band,
|
||||||
};
|
};
|
||||||
|
|
||||||
void huawei_radio_settings_init(void)
|
void huawei_radio_settings_init(void)
|
||||||
|
|||||||
@@ -42,13 +42,14 @@
|
|||||||
|
|
||||||
#include "ifxmodem.h"
|
#include "ifxmodem.h"
|
||||||
|
|
||||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
#define TUN_DEV "/dev/net/tun"
|
||||||
|
|
||||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||||
|
|
||||||
static const char *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
static const char *xdns_prefix[] = { "+XDNS:", NULL };
|
static const char *xdns_prefix[] = { "+XDNS:", NULL };
|
||||||
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
||||||
|
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||||
|
|
||||||
enum state {
|
enum state {
|
||||||
STATE_IDLE,
|
STATE_IDLE,
|
||||||
@@ -59,17 +60,20 @@ enum state {
|
|||||||
|
|
||||||
struct gprs_context_data {
|
struct gprs_context_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
|
unsigned int vendor;
|
||||||
unsigned int active_context;
|
unsigned int active_context;
|
||||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||||
GAtRawIP *rawip;
|
GAtRawIP *rawip;
|
||||||
enum state state;
|
enum state state;
|
||||||
enum ofono_gprs_proto proto;
|
enum ofono_gprs_proto proto;
|
||||||
char address[32];
|
char address[64];
|
||||||
char dns1[32];
|
char gateway[64];
|
||||||
char dns2[32];
|
char netmask[64];
|
||||||
|
char dns1[64];
|
||||||
|
char dns2[64];
|
||||||
ofono_gprs_context_cb_t cb;
|
ofono_gprs_context_cb_t cb;
|
||||||
void *cb_data; /* Callback data */
|
void *cb_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void rawip_debug(const char *str, void *data)
|
static void rawip_debug(const char *str, void *data)
|
||||||
@@ -257,11 +261,136 @@ error:
|
|||||||
failed_setup(gc, NULL, TRUE);
|
failed_setup(gc, NULL, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs_context *gc = user_data;
|
||||||
|
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
|
||||||
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
|
GAtResultIter iter;
|
||||||
|
|
||||||
|
const char *laddrnetmask = NULL;
|
||||||
|
const char *gw = NULL;
|
||||||
|
const char *interface;
|
||||||
|
const char *dns[3];
|
||||||
|
|
||||||
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
gcd->cb(&error, gcd->cb_data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
|
||||||
|
/* skip cid, bearer_id, apn */
|
||||||
|
g_at_result_iter_skip_next(&iter);
|
||||||
|
g_at_result_iter_skip_next(&iter);
|
||||||
|
g_at_result_iter_skip_next(&iter);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &laddrnetmask))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &dns[0]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &dns[1]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(gcd->dns1, dns[0], sizeof(gcd->dns1));
|
||||||
|
strncpy(gcd->dns2, dns[1], sizeof(gcd->dns2));
|
||||||
|
dns[2] = 0;
|
||||||
|
|
||||||
|
DBG("DNS: %s, %s\n", gcd->dns1, gcd->dns2);
|
||||||
|
|
||||||
|
if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
|
||||||
|
gcd->address, gcd->netmask) < 0) {
|
||||||
|
failed_setup(gc, NULL, TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gw)
|
||||||
|
strncpy(gcd->gateway, gw, sizeof(gcd->gateway));
|
||||||
|
|
||||||
|
gcd->state = STATE_ACTIVE;
|
||||||
|
|
||||||
|
DBG("address: %s\n", gcd->address);
|
||||||
|
DBG("netmask: %s\n", gcd->netmask);
|
||||||
|
DBG("DNS1: %s\n", gcd->dns1);
|
||||||
|
DBG("DNS2: %s\n", gcd->dns2);
|
||||||
|
DBG("Gateway: %s\n", gcd->gateway);
|
||||||
|
|
||||||
|
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||||
|
|
||||||
|
ofono_gprs_context_set_interface(gc, interface);
|
||||||
|
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
|
||||||
|
|
||||||
|
if (gcd->netmask[0])
|
||||||
|
ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
|
||||||
|
|
||||||
|
if (gcd->gateway[0])
|
||||||
|
ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
|
||||||
|
|
||||||
|
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ifx_read_settings(struct ofono_gprs_context *gc)
|
||||||
|
{
|
||||||
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
gcd->address[0] = '\0';
|
||||||
|
gcd->gateway[0] = '\0';
|
||||||
|
gcd->netmask[0] = '\0';
|
||||||
|
gcd->dns1[0] = '\0';
|
||||||
|
gcd->dns2[0] = '\0';
|
||||||
|
|
||||||
|
/* read IP configuration info */
|
||||||
|
if(gcd->vendor == OFONO_VENDOR_XMM) {
|
||||||
|
snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%u",
|
||||||
|
gcd->active_context);
|
||||||
|
|
||||||
|
if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
|
||||||
|
cgcontrdp_cb, gc, NULL) > 0)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||||
|
|
||||||
|
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||||
|
address_cb, gc, NULL) > 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
failed_setup(gc, NULL, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ifx_gprs_read_settings(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int cid,
|
||||||
|
ofono_gprs_context_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
|
DBG("cid %u", cid);
|
||||||
|
|
||||||
|
gcd->active_context = cid;
|
||||||
|
gcd->cb = cb;
|
||||||
|
gcd->cb_data = data;
|
||||||
|
|
||||||
|
ifx_read_settings(gc);
|
||||||
|
}
|
||||||
|
|
||||||
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs_context *gc = 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);
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
@@ -271,19 +400,14 @@ static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
ifx_read_settings(gc);
|
||||||
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)
|
static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs_context *gc = user_data;
|
struct ofono_gprs_context *gc = user_data;
|
||||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
char buf[128];
|
char buf[384];
|
||||||
|
|
||||||
DBG("ok %d", ok);
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
@@ -387,7 +511,8 @@ static void deactivate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
gcd->active_context = 0;
|
gcd->active_context = 0;
|
||||||
gcd->state = STATE_IDLE;
|
gcd->state = STATE_IDLE;
|
||||||
|
|
||||||
g_at_chat_resume(gcd->chat);
|
if (gcd->vendor != OFONO_VENDOR_XMM)
|
||||||
|
g_at_chat_resume(gcd->chat);
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||||
}
|
}
|
||||||
@@ -409,11 +534,25 @@ static void ifx_gprs_deactivate_primary(struct ofono_gprs_context *gc,
|
|||||||
g_at_rawip_shutdown(gcd->rawip);
|
g_at_rawip_shutdown(gcd->rawip);
|
||||||
|
|
||||||
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
||||||
if (g_at_chat_send(chat, buf, none_prefix,
|
|
||||||
deactivate_cb, gc, NULL) > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, data);
|
if (gcd->vendor == OFONO_VENDOR_XMM) {
|
||||||
|
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||||
|
deactivate_cb, gc, NULL) > 0)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (g_at_chat_send(chat, buf, none_prefix,
|
||||||
|
deactivate_cb, gc, NULL) > 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ifx_gprs_detach_shutdown(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int cid)
|
||||||
|
{
|
||||||
|
DBG("");
|
||||||
|
ifx_gprs_deactivate_primary(gc, cid, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||||
@@ -451,14 +590,13 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
g_at_rawip_unref(gcd->rawip);
|
g_at_rawip_unref(gcd->rawip);
|
||||||
gcd->rawip = NULL;
|
gcd->rawip = NULL;
|
||||||
|
g_at_chat_resume(gcd->chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
||||||
|
|
||||||
gcd->active_context = 0;
|
gcd->active_context = 0;
|
||||||
gcd->state = STATE_IDLE;
|
gcd->state = STATE_IDLE;
|
||||||
|
|
||||||
g_at_chat_resume(gcd->chat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||||
@@ -470,23 +608,27 @@ static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
if (stat(TUN_DEV, &st) < 0) {
|
||||||
ofono_error("Missing support for TUN/TAP devices");
|
ofono_error("Missing support for TUN/TAP devices");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_at_chat_get_slave(chat) == NULL)
|
if (vendor != OFONO_VENDOR_XMM) {
|
||||||
return -EINVAL;
|
if (g_at_chat_get_slave(chat) == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
gcd = g_try_new0(struct gprs_context_data, 1);
|
gcd = g_try_new0(struct gprs_context_data, 1);
|
||||||
if (gcd == NULL)
|
if (gcd == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gcd->vendor = vendor;
|
||||||
gcd->chat = g_at_chat_clone(chat);
|
gcd->chat = g_at_chat_clone(chat);
|
||||||
|
|
||||||
ofono_gprs_context_set_data(gc, gcd);
|
ofono_gprs_context_set_data(gc, gcd);
|
||||||
|
|
||||||
chat = g_at_chat_get_slave(gcd->chat);
|
if (vendor != OFONO_VENDOR_XMM)
|
||||||
|
chat = g_at_chat_get_slave(gcd->chat);
|
||||||
|
|
||||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||||
|
|
||||||
@@ -516,6 +658,8 @@ static struct ofono_gprs_context_driver driver = {
|
|||||||
.remove = ifx_gprs_context_remove,
|
.remove = ifx_gprs_context_remove,
|
||||||
.activate_primary = ifx_gprs_activate_primary,
|
.activate_primary = ifx_gprs_activate_primary,
|
||||||
.deactivate_primary = ifx_gprs_deactivate_primary,
|
.deactivate_primary = ifx_gprs_deactivate_primary,
|
||||||
|
.read_settings = ifx_gprs_read_settings,
|
||||||
|
.detach_shutdown = ifx_gprs_detach_shutdown
|
||||||
};
|
};
|
||||||
|
|
||||||
void ifx_gprs_context_init(void)
|
void ifx_gprs_context_init(void)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <drivers/atmodem/atutil.h>
|
#include <drivers/atmodem/atutil.h>
|
||||||
|
#include <drivers/atmodem/vendor.h>
|
||||||
|
|
||||||
extern void ifx_voicecall_init(void);
|
extern void ifx_voicecall_init(void);
|
||||||
extern void ifx_voicecall_exit(void);
|
extern void ifx_voicecall_exit(void);
|
||||||
|
|||||||
@@ -646,8 +646,31 @@ error:
|
|||||||
/* ISI callback: PIN state (enabled/disabled) query */
|
/* ISI callback: PIN state (enabled/disabled) query */
|
||||||
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
||||||
{
|
{
|
||||||
check_sec_response(msg, opaque, SEC_CODE_STATE_OK_RESP,
|
struct isi_cb_data *cbd = opaque;
|
||||||
SEC_CODE_STATE_FAIL_RESP);
|
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
||||||
|
int locked;
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
|
||||||
|
!g_isi_msg_data_get_byte(msg, 1, &status))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (state != SEC_CODE_STATE_OK_RESP)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (status == SEC_CODE_ENABLE)
|
||||||
|
locked = 1;
|
||||||
|
else if (status == SEC_CODE_DISABLE)
|
||||||
|
locked = 0;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, locked, cbd->data);
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isi_query_locked(struct ofono_sim *sim,
|
static void isi_query_locked(struct ofono_sim *sim,
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <ofono/log.h>
|
#include <ofono/log.h>
|
||||||
#include <ofono/modem.h>
|
#include <ofono/modem.h>
|
||||||
#include <ofono/devinfo.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);
|
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);
|
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
|||||||
@@ -24,18 +24,22 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include <ofono/log.h>
|
#include <ofono/log.h>
|
||||||
#include <ofono/modem.h>
|
#include <ofono/modem.h>
|
||||||
#include <ofono/gprs-context.h>
|
#include <ofono/gprs-context.h>
|
||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
|
#include "wda.h"
|
||||||
#include "wds.h"
|
#include "wds.h"
|
||||||
|
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
|
|
||||||
struct gprs_context_data {
|
struct gprs_context_data {
|
||||||
struct qmi_service *wds;
|
struct qmi_service *wds;
|
||||||
|
struct qmi_service *wda;
|
||||||
|
struct qmi_device *dev;
|
||||||
unsigned int active_context;
|
unsigned int active_context;
|
||||||
uint32_t pkt_handle;
|
uint32_t pkt_handle;
|
||||||
};
|
};
|
||||||
@@ -61,8 +65,12 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
|
|||||||
|
|
||||||
switch (status->status) {
|
switch (status->status) {
|
||||||
case QMI_WDS_CONN_STATUS_DISCONNECTED:
|
case QMI_WDS_CONN_STATUS_DISCONNECTED:
|
||||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
if (data->pkt_handle) {
|
||||||
data->active_context = 0;
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,18 +83,68 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
|
|||||||
struct ofono_modem *modem;
|
struct ofono_modem *modem;
|
||||||
const char *interface;
|
const char *interface;
|
||||||
uint8_t pdp_type, ip_family;
|
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("");
|
DBG("");
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL))
|
if (qmi_result_set_error(result, NULL))
|
||||||
goto done;
|
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))
|
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_PDP_TYPE, &pdp_type))
|
||||||
DBG("PDP type %d", pdp_type);
|
DBG("PDP type %d", pdp_type);
|
||||||
|
|
||||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
|
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
|
||||||
DBG("IP family %d", 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:
|
done:
|
||||||
modem = ofono_gprs_context_get_modem(gc);
|
modem = ofono_gprs_context_get_modem(gc);
|
||||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||||
@@ -94,8 +152,6 @@ done:
|
|||||||
ofono_gprs_context_set_interface(gc, interface);
|
ofono_gprs_context_set_interface(gc, interface);
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
|
||||||
g_free(cbd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_net_cb(struct qmi_result *result, void *user_data)
|
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;
|
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,
|
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;
|
return;
|
||||||
|
|
||||||
modem = ofono_gprs_context_get_modem(gc);
|
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);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
|
||||||
g_free(cbd);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
data->active_context = 0;
|
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);
|
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 cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
struct qmi_param *param;
|
struct qmi_param *param;
|
||||||
uint8_t ip_family;
|
uint8_t ip_family;
|
||||||
|
uint8_t auth;
|
||||||
|
|
||||||
DBG("cid %u", ctx->cid);
|
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);
|
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,
|
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;
|
return;
|
||||||
|
|
||||||
qmi_param_free(param);
|
qmi_param_free(param);
|
||||||
@@ -202,17 +313,19 @@ static void stop_net_cb(struct qmi_result *result, void *user_data)
|
|||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL)) {
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
if (cb)
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->active_context = 0;
|
|
||||||
|
|
||||||
data->pkt_handle = 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,
|
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;
|
goto error;
|
||||||
|
|
||||||
if (qmi_service_send(data->wds, QMI_WDS_STOP_NET, param,
|
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;
|
return;
|
||||||
|
|
||||||
qmi_param_free(param);
|
qmi_param_free(param);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
if (cb)
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
|
||||||
g_free(cbd);
|
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)
|
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs_context *gc = 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);
|
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,
|
static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||||
unsigned int vendor, void *user_data)
|
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);
|
data = g_new0(struct gprs_context_data, 1);
|
||||||
|
|
||||||
ofono_gprs_context_set_data(gc, data);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -288,9 +474,15 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
|
|||||||
|
|
||||||
ofono_gprs_context_set_data(gc, NULL);
|
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);
|
g_free(data);
|
||||||
}
|
}
|
||||||
@@ -301,6 +493,8 @@ static struct ofono_gprs_context_driver driver = {
|
|||||||
.remove = qmi_gprs_context_remove,
|
.remove = qmi_gprs_context_remove,
|
||||||
.activate_primary = qmi_activate_primary,
|
.activate_primary = qmi_activate_primary,
|
||||||
.deactivate_primary = qmi_deactivate_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)
|
void qmi_gprs_context_init(void)
|
||||||
|
|||||||
@@ -30,16 +30,18 @@
|
|||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
#include "nas.h"
|
#include "nas.h"
|
||||||
|
|
||||||
|
#include "src/common.h"
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
|
|
||||||
struct gprs_data {
|
struct gprs_data {
|
||||||
struct qmi_service *nas;
|
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;
|
const struct qmi_nas_serving_system *ss;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
|
int i;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
@@ -47,14 +49,46 @@ static bool extract_ss_info(struct qmi_result *result, int *status)
|
|||||||
if (!ss)
|
if (!ss)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ss->ps_state == QMI_NAS_ATTACH_STATUS_ATTACHED)
|
if (ss->ps_state == QMI_NAS_ATTACH_STATE_ATTACHED)
|
||||||
*status = 0x01;
|
*status = NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||||
else
|
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;
|
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)
|
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs *gprs = 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("");
|
DBG("");
|
||||||
|
|
||||||
if (!extract_ss_info(result, &status))
|
status = handle_ss_info(result, gprs);
|
||||||
return;
|
|
||||||
|
|
||||||
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)
|
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)
|
static void get_ss_info_cb(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
|
struct ofono_gprs *gprs = cbd->user;
|
||||||
ofono_gprs_status_cb_t cb = cbd->cb;
|
ofono_gprs_status_cb_t cb = cbd->cb;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL)) {
|
if (qmi_result_set_error(result, NULL))
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
goto error;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!extract_ss_info(result, &status)) {
|
status = handle_ss_info(result, gprs);
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
|
||||||
return;
|
if (status < 0)
|
||||||
}
|
goto error;
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
|
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,
|
static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||||
@@ -150,6 +188,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
|
cbd->user = gprs;
|
||||||
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||||
get_ss_info_cb, cbd, g_free) > 0)
|
get_ss_info_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
@@ -174,6 +213,13 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
|||||||
|
|
||||||
data->nas = qmi_service_ref(service);
|
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,
|
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||||
ss_info_notify, gprs, NULL);
|
ss_info_notify, gprs, NULL);
|
||||||
|
|
||||||
@@ -194,7 +240,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
|||||||
|
|
||||||
ofono_gprs_set_data(gprs, data);
|
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;
|
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_RESET 0 /* Reset NAS service state variables */
|
||||||
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
|
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
|
||||||
#define QMI_NAS_EVENT 2 /* Connection state report indication */
|
#define QMI_NAS_EVENT 2 /* Connection state report indication */
|
||||||
@@ -33,6 +35,8 @@
|
|||||||
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
|
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
|
||||||
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
|
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
|
||||||
|
|
||||||
|
#define QMI_NAS_SET_SYSTEM_SELECTION_PREF 51
|
||||||
|
#define QMI_NAS_GET_SYSTEM_SELECTION_PREF 52
|
||||||
|
|
||||||
/* Set NAS state report conditions */
|
/* Set NAS state report conditions */
|
||||||
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
|
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
|
||||||
@@ -63,7 +67,7 @@ struct qmi_nas_rf_info {
|
|||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
/* Get the signal strength */
|
/* Get the signal strength */
|
||||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x10
|
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x01
|
||||||
|
|
||||||
/* Scan for visible network */
|
/* Scan for visible network */
|
||||||
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
|
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
|
||||||
@@ -95,6 +99,7 @@ struct qmi_nas_network_rat {
|
|||||||
} __attribute__((__packed__)) info[0];
|
} __attribute__((__packed__)) info[0];
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#define QMI_NAS_NETWORK_RAT_NONE 0x00
|
||||||
#define QMI_NAS_NETWORK_RAT_GSM 0x04
|
#define QMI_NAS_NETWORK_RAT_GSM 0x04
|
||||||
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
|
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
|
||||||
#define QMI_NAS_NETWORK_RAT_LTE 0x08
|
#define QMI_NAS_NETWORK_RAT_LTE 0x08
|
||||||
@@ -140,9 +145,29 @@ struct qmi_nas_current_plmn {
|
|||||||
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
|
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
|
||||||
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
|
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
|
||||||
|
|
||||||
#define QMI_NAS_ATTACH_STATUS_INVALID 0x00
|
/* qmi_nas_serving_system.status */
|
||||||
#define QMI_NAS_ATTACH_STATUS_ATTACHED 0x01
|
#define QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED 0x00
|
||||||
#define QMI_NAS_ATTACH_STATUS_DETACHED 0x02
|
#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
|
||||||
|
|
||||||
|
#define QMI_NAS_RESULT_3GGP_DST 0x1b
|
||||||
|
#define QMI_NAS_RESULT_3GPP_TIME 0x1c
|
||||||
|
struct qmi_nas_3gpp_time {
|
||||||
|
uint16_t year;
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t day;
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t second;
|
||||||
|
uint8_t timezone;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* cs_state/ps_state */
|
||||||
|
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
|
||||||
|
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
|
||||||
|
#define QMI_NAS_ATTACH_STATE_DETACHED 0x02
|
||||||
|
|
||||||
/* Get info about home network */
|
/* Get info about home network */
|
||||||
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
|
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
|
||||||
@@ -152,3 +177,14 @@ struct qmi_nas_home_network {
|
|||||||
uint8_t desc_len;
|
uint8_t desc_len;
|
||||||
char desc[0];
|
char desc[0];
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_ANY (-1)
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_GSM (1 << 2)
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_UMTS (1 << 3)
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_LTE (1 << 4)
|
||||||
|
|
||||||
|
#define QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||||
|
|
||||||
|
#define QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||||
|
|
||||||
|
int qmi_nas_rat_to_tech(uint8_t rat);
|
||||||
|
|||||||
286
ofono/drivers/qmimodem/netmon.c
Normal file
286
ofono/drivers/qmimodem/netmon.c
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/log.h>
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
#include <ofono/netmon.h>
|
||||||
|
|
||||||
|
#include "qmi.h"
|
||||||
|
#include "nas.h"
|
||||||
|
|
||||||
|
#include "qmimodem.h"
|
||||||
|
#include "src/common.h"
|
||||||
|
|
||||||
|
struct netmon_data {
|
||||||
|
struct qmi_service *nas;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void get_rssi_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
struct ofono_netmon *netmon = cbd->user;
|
||||||
|
ofono_netmon_cb_t cb = cbd->cb;
|
||||||
|
struct {
|
||||||
|
enum ofono_netmon_cell_type type;
|
||||||
|
int rssi;
|
||||||
|
int ber;
|
||||||
|
int rsrq;
|
||||||
|
int rsrp;
|
||||||
|
} props;
|
||||||
|
uint16_t len;
|
||||||
|
int16_t rsrp;
|
||||||
|
const struct {
|
||||||
|
int8_t value;
|
||||||
|
int8_t rat;
|
||||||
|
} __attribute__((__packed__)) *rsrq;
|
||||||
|
const struct {
|
||||||
|
uint16_t count;
|
||||||
|
struct {
|
||||||
|
uint8_t rssi;
|
||||||
|
int8_t rat;
|
||||||
|
} __attribute__((__packed__)) info[0];
|
||||||
|
} __attribute__((__packed__)) *rssi;
|
||||||
|
const struct {
|
||||||
|
uint16_t count;
|
||||||
|
struct {
|
||||||
|
uint16_t rate;
|
||||||
|
int8_t rat;
|
||||||
|
} __attribute__((__packed__)) info[0];
|
||||||
|
} __attribute__((__packed__)) *ber;
|
||||||
|
int i;
|
||||||
|
uint16_t num;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSSI */
|
||||||
|
rssi = qmi_result_get(result, 0x11, &len);
|
||||||
|
num = GUINT16_FROM_LE(rssi->count);
|
||||||
|
if (rssi) {
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
DBG("RSSI: %hhu on RAT %hhd",
|
||||||
|
rssi->info[i].rssi,
|
||||||
|
rssi->info[i].rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get cell type from RSSI info... it will be the same
|
||||||
|
* for all the other entries
|
||||||
|
*/
|
||||||
|
props.type = qmi_nas_rat_to_tech(rssi->info[0].rat);
|
||||||
|
switch (rssi->info[0].rat) {
|
||||||
|
case QMI_NAS_NETWORK_RAT_GSM:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_UMTS;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_NETWORK_RAT_LTE:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_LTE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
props.rssi = (rssi->info[0].rssi + 113) / 2;
|
||||||
|
if (props.rssi > 31) props.rssi = 31;
|
||||||
|
if (props.rssi < 0) props.rssi = 0;
|
||||||
|
} else {
|
||||||
|
props.type = QMI_NAS_NETWORK_RAT_GSM;
|
||||||
|
props.rssi = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bit error rate */
|
||||||
|
ber = qmi_result_get(result, 0x15, &len);
|
||||||
|
num = GUINT16_FROM_LE(ber->count);
|
||||||
|
if (ber) {
|
||||||
|
for (i = 0; i < ber->count; i++) {
|
||||||
|
DBG("Bit error rate: %hu on RAT %hhd",
|
||||||
|
GUINT16_FROM_LE(ber->info[i].rate),
|
||||||
|
ber->info[i].rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
props.ber = GUINT16_FROM_LE(ber->info[0].rate);
|
||||||
|
if (props.ber > 7)
|
||||||
|
props.ber = -1;
|
||||||
|
} else {
|
||||||
|
props.ber = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LTE RSRQ */
|
||||||
|
rsrq = qmi_result_get(result, 0x16, &len);
|
||||||
|
if (rsrq) {
|
||||||
|
DBG("RSRQ: %hhd on RAT %hhd",
|
||||||
|
rsrq->value,
|
||||||
|
rsrq->rat);
|
||||||
|
|
||||||
|
if (rsrq->value == 0) {
|
||||||
|
props.rsrq = -1;
|
||||||
|
} else {
|
||||||
|
props.rsrq = (rsrq->value + 19) * 2;
|
||||||
|
if (props.rsrq > 34) props.rsrq = 34;
|
||||||
|
if (props.rsrq < 0) props.rsrq = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.rsrq = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LTE RSRP */
|
||||||
|
if (qmi_result_get_int16(result, 0x18, &rsrp)) {
|
||||||
|
DBG("Got LTE RSRP: %hd", rsrp);
|
||||||
|
|
||||||
|
if (rsrp == 0) {
|
||||||
|
props.rsrp = -1;
|
||||||
|
} else {
|
||||||
|
props.rsrp = rsrp + 140;
|
||||||
|
if (props.rsrp > 97) props.rsrp = 97;
|
||||||
|
if (props.rsrp < 0) props.rsrp = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.rsrp = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_netmon_serving_cell_notify(netmon,
|
||||||
|
props.type,
|
||||||
|
OFONO_NETMON_INFO_RSSI, props.rssi,
|
||||||
|
OFONO_NETMON_INFO_BER, props.ber,
|
||||||
|
OFONO_NETMON_INFO_RSRQ, props.rsrq,
|
||||||
|
OFONO_NETMON_INFO_RSRP, props.rsrp,
|
||||||
|
OFONO_NETMON_INFO_INVALID);
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_netmon_request_update(struct ofono_netmon *netmon,
|
||||||
|
ofono_netmon_cb_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct netmon_data *data = ofono_netmon_get_data(netmon);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
struct qmi_param *param;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
cbd->user = netmon;
|
||||||
|
|
||||||
|
param = qmi_param_new();
|
||||||
|
if (!param)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Request all signal strength items: mask=0xff */
|
||||||
|
qmi_param_append_uint16(param, 0x10, 255);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->nas, QMI_NAS_GET_RSSI, param,
|
||||||
|
get_rssi_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qmi_param_free(param);
|
||||||
|
|
||||||
|
out:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_netmon *netmon = user_data;
|
||||||
|
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
ofono_error("Failed to request NAS service");
|
||||||
|
ofono_netmon_remove(netmon);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nmd->nas = qmi_service_ref(service);
|
||||||
|
|
||||||
|
ofono_netmon_register(netmon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qmi_netmon_probe(struct ofono_netmon *netmon,
|
||||||
|
unsigned int vendor, void *user_data)
|
||||||
|
{
|
||||||
|
struct qmi_device *device = user_data;
|
||||||
|
struct netmon_data *nmd;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
nmd = g_new0(struct netmon_data, 1);
|
||||||
|
|
||||||
|
ofono_netmon_set_data(netmon, nmd);
|
||||||
|
|
||||||
|
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||||
|
create_nas_cb, netmon, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_netmon_remove(struct ofono_netmon *netmon)
|
||||||
|
{
|
||||||
|
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
ofono_netmon_set_data(netmon, NULL);
|
||||||
|
|
||||||
|
qmi_service_unregister_all(nmd->nas);
|
||||||
|
|
||||||
|
qmi_service_unref(nmd->nas);
|
||||||
|
|
||||||
|
g_free(nmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ofono_netmon_driver driver = {
|
||||||
|
.name = "qmimodem",
|
||||||
|
.probe = qmi_netmon_probe,
|
||||||
|
.remove = qmi_netmon_remove,
|
||||||
|
.request_update = qmi_netmon_request_update,
|
||||||
|
};
|
||||||
|
|
||||||
|
void qmi_netmon_init(void)
|
||||||
|
{
|
||||||
|
ofono_netmon_driver_register(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qmi_netmon_exit(void)
|
||||||
|
{
|
||||||
|
ofono_netmon_driver_unregister(&driver);
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <endian.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -43,18 +44,36 @@ struct netreg_data {
|
|||||||
uint8_t current_rat;
|
uint8_t current_rat;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rat_to_tech(uint8_t rat)
|
static bool extract_ss_info_time(
|
||||||
|
struct qmi_result *result,
|
||||||
|
struct ofono_network_time *time)
|
||||||
{
|
{
|
||||||
switch (rat) {
|
const struct qmi_nas_3gpp_time *time_3gpp = NULL;
|
||||||
case QMI_NAS_NETWORK_RAT_GSM:
|
uint8_t dst_3gpp;
|
||||||
return ACCESS_TECHNOLOGY_GSM;
|
bool dst_3gpp_valid;
|
||||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
uint16_t len;
|
||||||
return ACCESS_TECHNOLOGY_UTRAN;
|
|
||||||
case QMI_NAS_NETWORK_RAT_LTE:
|
/* parse 3gpp time & dst */
|
||||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
dst_3gpp_valid = qmi_result_get_uint8(result, QMI_NAS_RESULT_3GGP_DST,
|
||||||
|
&dst_3gpp);
|
||||||
|
|
||||||
|
time_3gpp = qmi_result_get(result, QMI_NAS_RESULT_3GPP_TIME, &len);
|
||||||
|
if (time_3gpp && len == sizeof(struct qmi_nas_3gpp_time) &&
|
||||||
|
dst_3gpp_valid) {
|
||||||
|
time->year = le16toh(time_3gpp->year);
|
||||||
|
time->mon = time_3gpp->month;
|
||||||
|
time->mday = time_3gpp->day;
|
||||||
|
time->hour = time_3gpp->hour;
|
||||||
|
time->min = time_3gpp->minute;
|
||||||
|
time->sec = time_3gpp->second;
|
||||||
|
time->utcoff = time_3gpp->timezone * 15 * 60;
|
||||||
|
time->dst = dst_3gpp;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
/* TODO: 3gpp2 */
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||||
@@ -64,7 +83,7 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
const struct qmi_nas_serving_system *ss;
|
const struct qmi_nas_serving_system *ss;
|
||||||
const struct qmi_nas_current_plmn *plmn;
|
const struct qmi_nas_current_plmn *plmn;
|
||||||
uint8_t i, roaming;
|
uint8_t i, roaming;
|
||||||
uint16_t value16, len;
|
uint16_t value16, len, opname_len;
|
||||||
uint32_t value32;
|
uint32_t value32;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
@@ -82,13 +101,13 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
for (i = 0; i < ss->radio_if_count; i++) {
|
for (i = 0; i < ss->radio_if_count; i++) {
|
||||||
DBG("radio in use %d", ss->radio_if[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,
|
if (qmi_result_get_uint8(result, QMI_NAS_RESULT_ROAMING_STATUS,
|
||||||
&roaming)) {
|
&roaming)) {
|
||||||
if (ss->status == 1 && roaming == 0)
|
if (ss->status == 1 && roaming == 0)
|
||||||
*status = 5;
|
*status = NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!operator)
|
if (!operator)
|
||||||
@@ -100,8 +119,21 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
GUINT16_FROM_LE(plmn->mcc));
|
GUINT16_FROM_LE(plmn->mcc));
|
||||||
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
|
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
|
||||||
GUINT16_FROM_LE(plmn->mnc));
|
GUINT16_FROM_LE(plmn->mnc));
|
||||||
strncpy(operator->name, plmn->desc, plmn->desc_len);
|
opname_len = plmn->desc_len;
|
||||||
operator->name[plmn->desc_len] = '\0';
|
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);
|
DBG("%s (%s:%s)", operator->name, operator->mcc, operator->mnc);
|
||||||
}
|
}
|
||||||
@@ -125,11 +157,15 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_netreg *netreg = user_data;
|
struct ofono_netreg *netreg = user_data;
|
||||||
|
struct ofono_network_time net_time;
|
||||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||||
int status, lac, cellid, tech;
|
int status, lac, cellid, tech;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
|
if (extract_ss_info_time(result, &net_time))
|
||||||
|
ofono_netreg_time_notify(netreg, &net_time);
|
||||||
|
|
||||||
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
|
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
|
||||||
&data->operator))
|
&data->operator))
|
||||||
return;
|
return;
|
||||||
@@ -265,7 +301,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,
|
DBG("%03d:%02d %d", netrat->info[i].mcc, netrat->info[i].mnc,
|
||||||
netrat->info[i].rat);
|
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:
|
done:
|
||||||
@@ -357,7 +393,7 @@ static void qmi_register_manual(struct ofono_netreg *netreg,
|
|||||||
|
|
||||||
info.mcc = atoi(mcc);
|
info.mcc = atoi(mcc);
|
||||||
info.mnc = atoi(mnc);
|
info.mnc = atoi(mnc);
|
||||||
info.rat = data->current_rat;
|
info.rat = QMI_NAS_NETWORK_RAT_NO_CHANGE;
|
||||||
|
|
||||||
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
|
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
|
||||||
sizeof(info), &info);
|
sizeof(info), &info);
|
||||||
@@ -451,10 +487,11 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
|||||||
if (ss) {
|
if (ss) {
|
||||||
int strength;
|
int strength;
|
||||||
|
|
||||||
DBG("signal with %d dBm on %d", ss->dbm, ss->rat);
|
|
||||||
|
|
||||||
strength = dbm_to_strength(ss->dbm);
|
strength = dbm_to_strength(ss->dbm);
|
||||||
|
|
||||||
|
DBG("signal with %d%%(%d dBm) on %d",
|
||||||
|
strength, ss->dbm, ss->rat);
|
||||||
|
|
||||||
ofono_netreg_strength_notify(netreg, strength);
|
ofono_netreg_strength_notify(netreg, strength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,10 +511,17 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
|||||||
static void set_event_cb(struct qmi_result *result, void *user_data)
|
static void set_event_cb(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_netreg *netreg = user_data;
|
struct ofono_netreg *netreg = user_data;
|
||||||
|
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
ofono_netreg_register(netreg);
|
ofono_netreg_register(netreg);
|
||||||
|
|
||||||
|
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||||
|
event_notify, netreg, NULL);
|
||||||
|
|
||||||
|
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||||
|
ss_info_notify, netreg, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||||
@@ -499,12 +543,6 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
|||||||
|
|
||||||
data->nas = qmi_service_ref(service);
|
data->nas = qmi_service_ref(service);
|
||||||
|
|
||||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
|
||||||
event_notify, netreg, NULL);
|
|
||||||
|
|
||||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
|
||||||
ss_info_notify, netreg, NULL);
|
|
||||||
|
|
||||||
param = qmi_param_new();
|
param = qmi_param_new();
|
||||||
if (!param)
|
if (!param)
|
||||||
goto done;
|
goto done;
|
||||||
@@ -543,7 +581,7 @@ static int qmi_netreg_probe(struct ofono_netreg *netreg,
|
|||||||
|
|
||||||
ofono_netreg_set_data(netreg, data);
|
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);
|
create_nas_cb, netreg, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -33,12 +35,18 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/log.h>
|
||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
#include "ctl.h"
|
#include "ctl.h"
|
||||||
|
|
||||||
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
|
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
|
||||||
const void *buffer, void *user_data);
|
const void *buffer, void *user_data);
|
||||||
|
|
||||||
|
struct discovery {
|
||||||
|
qmi_destroy_func_t destroy;
|
||||||
|
};
|
||||||
|
|
||||||
struct qmi_device {
|
struct qmi_device {
|
||||||
int ref_count;
|
int ref_count;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -49,6 +57,7 @@ struct qmi_device {
|
|||||||
GQueue *req_queue;
|
GQueue *req_queue;
|
||||||
GQueue *control_queue;
|
GQueue *control_queue;
|
||||||
GQueue *service_queue;
|
GQueue *service_queue;
|
||||||
|
GQueue *discovery_queue;
|
||||||
uint8_t next_control_tid;
|
uint8_t next_control_tid;
|
||||||
uint16_t next_service_tid;
|
uint16_t next_service_tid;
|
||||||
qmi_debug_func_t debug_func;
|
qmi_debug_func_t debug_func;
|
||||||
@@ -60,6 +69,12 @@ struct qmi_device {
|
|||||||
uint8_t version_count;
|
uint8_t version_count;
|
||||||
GHashTable *service_list;
|
GHashTable *service_list;
|
||||||
unsigned int release_users;
|
unsigned int release_users;
|
||||||
|
qmi_shutdown_func_t shutdown_func;
|
||||||
|
void *shutdown_user_data;
|
||||||
|
qmi_destroy_func_t shutdown_destroy;
|
||||||
|
guint shutdown_source;
|
||||||
|
bool shutting_down : 1;
|
||||||
|
bool destroyed : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qmi_service {
|
struct qmi_service {
|
||||||
@@ -209,6 +224,14 @@ static gint __request_compare(gconstpointer a, gconstpointer b)
|
|||||||
return req->tid - tid;
|
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)
|
static void __notify_free(gpointer data, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct qmi_notify *notify = data;
|
struct qmi_notify *notify = data;
|
||||||
@@ -313,8 +336,12 @@ static const char *__service_type_to_string(uint8_t type)
|
|||||||
return "UIM";
|
return "UIM";
|
||||||
case QMI_SERVICE_PBM:
|
case QMI_SERVICE_PBM:
|
||||||
return "PBM";
|
return "PBM";
|
||||||
|
case QMI_SERVICE_QCHAT:
|
||||||
|
return "QCHAT";
|
||||||
case QMI_SERVICE_RMTFS:
|
case QMI_SERVICE_RMTFS:
|
||||||
return "RMTFS";
|
return "RMTFS";
|
||||||
|
case QMI_SERVICE_TEST:
|
||||||
|
return "TEST";
|
||||||
case QMI_SERVICE_LOC:
|
case QMI_SERVICE_LOC:
|
||||||
return "LOC";
|
return "LOC";
|
||||||
case QMI_SERVICE_SAR:
|
case QMI_SERVICE_SAR:
|
||||||
@@ -326,9 +353,21 @@ static const char *__service_type_to_string(uint8_t type)
|
|||||||
case QMI_SERVICE_TS:
|
case QMI_SERVICE_TS:
|
||||||
return "TS";
|
return "TS";
|
||||||
case QMI_SERVICE_TMD:
|
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:
|
case QMI_SERVICE_PDC:
|
||||||
return "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:
|
case QMI_SERVICE_CAT_OLD:
|
||||||
return "CAT";
|
return "CAT";
|
||||||
case QMI_SERVICE_RMS:
|
case QMI_SERVICE_RMS:
|
||||||
@@ -758,7 +797,7 @@ static void handle_packet(struct qmi_device *device,
|
|||||||
|
|
||||||
tid = GUINT16_FROM_LE(service->transaction);
|
tid = GUINT16_FROM_LE(service->transaction);
|
||||||
|
|
||||||
if (service->type == 0x04 && tid == 0x0000) {
|
if (service->type == 0x04) {
|
||||||
handle_indication(device, hdr->service, hdr->client,
|
handle_indication(device, hdr->service, hdr->client,
|
||||||
message, length, data);
|
message, length, data);
|
||||||
return;
|
return;
|
||||||
@@ -838,6 +877,21 @@ static void read_watch_destroy(gpointer user_data)
|
|||||||
device->read_watch = 0;
|
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)
|
static void service_destroy(gpointer data)
|
||||||
{
|
{
|
||||||
struct qmi_service *service = data;
|
struct qmi_service *service = data;
|
||||||
@@ -891,6 +945,7 @@ struct qmi_device *qmi_device_new(int fd)
|
|||||||
device->req_queue = g_queue_new();
|
device->req_queue = g_queue_new();
|
||||||
device->control_queue = g_queue_new();
|
device->control_queue = g_queue_new();
|
||||||
device->service_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,
|
device->service_list = g_hash_table_new_full(g_direct_hash,
|
||||||
g_direct_equal, NULL, service_destroy);
|
g_direct_equal, NULL, service_destroy);
|
||||||
@@ -927,6 +982,9 @@ void qmi_device_unref(struct qmi_device *device)
|
|||||||
g_queue_foreach(device->req_queue, __request_free, NULL);
|
g_queue_foreach(device->req_queue, __request_free, NULL);
|
||||||
g_queue_free(device->req_queue);
|
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)
|
if (device->write_watch > 0)
|
||||||
g_source_remove(device->write_watch);
|
g_source_remove(device->write_watch);
|
||||||
|
|
||||||
@@ -936,12 +994,18 @@ void qmi_device_unref(struct qmi_device *device)
|
|||||||
if (device->close_on_unref)
|
if (device->close_on_unref)
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
|
|
||||||
|
if (device->shutdown_source)
|
||||||
|
g_source_remove(device->shutdown_source);
|
||||||
|
|
||||||
g_hash_table_destroy(device->service_list);
|
g_hash_table_destroy(device->service_list);
|
||||||
|
|
||||||
g_free(device->version_str);
|
g_free(device->version_str);
|
||||||
g_free(device->version_list);
|
g_free(device->version_list);
|
||||||
|
|
||||||
g_free(device);
|
if (device->shutting_down)
|
||||||
|
device->destroyed = true;
|
||||||
|
else
|
||||||
|
g_free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmi_device_set_debug(struct qmi_device *device,
|
void qmi_device_set_debug(struct qmi_device *device,
|
||||||
@@ -962,6 +1026,23 @@ void qmi_device_set_close_on_unref(struct qmi_device *device, bool do_close)
|
|||||||
device->close_on_unref = do_close;
|
device->close_on_unref = do_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qmi_result_print_tlvs(struct qmi_result *result)
|
||||||
|
{
|
||||||
|
const void *ptr = result->data;
|
||||||
|
uint16_t len = result->length;
|
||||||
|
|
||||||
|
while (len > QMI_TLV_HDR_SIZE) {
|
||||||
|
const struct qmi_tlv_hdr *tlv = ptr;
|
||||||
|
uint16_t tlv_length = GUINT16_FROM_LE(tlv->length);
|
||||||
|
|
||||||
|
DBG("tlv: 0x%02x len 0x%04x", tlv->type, tlv->length);
|
||||||
|
|
||||||
|
ptr += QMI_TLV_HDR_SIZE + tlv_length;
|
||||||
|
len -= QMI_TLV_HDR_SIZE + tlv_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const void *tlv_get(const void *data, uint16_t size,
|
static const void *tlv_get(const void *data, uint16_t size,
|
||||||
uint8_t type, uint16_t *length)
|
uint8_t type, uint16_t *length)
|
||||||
{
|
{
|
||||||
@@ -987,6 +1068,7 @@ static const void *tlv_get(const void *data, uint16_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct discover_data {
|
struct discover_data {
|
||||||
|
struct discovery super;
|
||||||
struct qmi_device *device;
|
struct qmi_device *device;
|
||||||
qmi_discover_func_t func;
|
qmi_discover_func_t func;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
@@ -994,6 +1076,21 @@ struct discover_data {
|
|||||||
guint timeout;
|
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,
|
static void discover_callback(uint16_t message, uint16_t length,
|
||||||
const void *buffer, void *user_data)
|
const void *buffer, void *user_data)
|
||||||
{
|
{
|
||||||
@@ -1007,8 +1104,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
|||||||
uint8_t count;
|
uint8_t count;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
g_source_remove(data->timeout);
|
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
list = NULL;
|
list = NULL;
|
||||||
|
|
||||||
@@ -1079,10 +1174,7 @@ done:
|
|||||||
if (data->func)
|
if (data->func)
|
||||||
data->func(count, list, data->user_data);
|
data->func(count, list, data->user_data);
|
||||||
|
|
||||||
if (data->destroy)
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
data->destroy(data->user_data);
|
|
||||||
|
|
||||||
g_free(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean discover_reply(gpointer user_data)
|
static gboolean discover_reply(gpointer user_data)
|
||||||
@@ -1096,10 +1188,7 @@ static gboolean discover_reply(gpointer user_data)
|
|||||||
data->func(device->version_count,
|
data->func(device->version_count,
|
||||||
device->version_list, data->user_data);
|
device->version_list, data->user_data);
|
||||||
|
|
||||||
if (data->destroy)
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
data->destroy(data->user_data);
|
|
||||||
|
|
||||||
g_free(data);
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1120,13 +1209,15 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
data->super.destroy = discover_data_free;
|
||||||
data->device = device;
|
data->device = device;
|
||||||
data->func = func;
|
data->func = func;
|
||||||
data->user_data = user_data;
|
data->user_data = user_data;
|
||||||
data->destroy = destroy;
|
data->destroy = destroy;
|
||||||
|
|
||||||
if (device->version_list) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1147,6 +1238,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
|||||||
__request_submit(device, req, hdr->transaction);
|
__request_submit(device, req, hdr->transaction);
|
||||||
|
|
||||||
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
||||||
|
__qmi_device_discovery_started(device, &data->super);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1177,63 +1269,256 @@ static void release_client(struct qmi_device *device,
|
|||||||
__request_submit(device, req, hdr->transaction);
|
__request_submit(device, req, hdr->transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct shutdown_data {
|
static void shutdown_destroy(gpointer user_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)
|
|
||||||
{
|
{
|
||||||
struct shutdown_data *data = user_data;
|
struct qmi_device *device = user_data;
|
||||||
|
|
||||||
if (data->func)
|
if (device->shutdown_destroy)
|
||||||
data->func(data->user_data);
|
device->shutdown_destroy(device->shutdown_user_data);
|
||||||
|
|
||||||
g_free(data);
|
device->shutdown_source = 0;
|
||||||
|
|
||||||
return FALSE;
|
if (device->destroyed)
|
||||||
|
g_free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean shutdown_timeout(gpointer user_data)
|
static gboolean shutdown_callback(gpointer user_data)
|
||||||
{
|
{
|
||||||
struct shutdown_data *data = user_data;
|
struct qmi_device *device = user_data;
|
||||||
struct qmi_device *device = data->device;
|
|
||||||
|
|
||||||
if (device->release_users > 0)
|
if (device->release_users > 0)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return shutdown_reply(data);
|
device->shutting_down = true;
|
||||||
|
|
||||||
|
if (device->shutdown_func)
|
||||||
|
device->shutdown_func(device->shutdown_user_data);
|
||||||
|
|
||||||
|
device->shutting_down = true;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||||
void *user_data, qmi_destroy_func_t destroy)
|
void *user_data, qmi_destroy_func_t destroy)
|
||||||
{
|
{
|
||||||
struct shutdown_data *data;
|
|
||||||
|
|
||||||
if (!device)
|
if (!device)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (device->shutdown_source > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
__debug_device(device, "device %p shutdown", device);
|
__debug_device(device, "device %p shutdown", device);
|
||||||
|
|
||||||
data = g_try_new0(struct shutdown_data, 1);
|
device->shutdown_source = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
|
||||||
if (!data)
|
0, shutdown_callback, device,
|
||||||
|
shutdown_destroy);
|
||||||
|
if (device->shutdown_source == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
data->device = device;
|
device->shutdown_func = func;
|
||||||
data->func = func;
|
device->shutdown_user_data = user_data;
|
||||||
data->user_data = user_data;
|
device->shutdown_destroy = destroy;
|
||||||
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);
|
|
||||||
|
|
||||||
return true;
|
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 *qmi_param_new(void)
|
||||||
{
|
{
|
||||||
struct qmi_param *param;
|
struct qmi_param *param;
|
||||||
@@ -1435,6 +1720,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||||
|
int16_t *value)
|
||||||
|
{
|
||||||
|
const unsigned char *ptr;
|
||||||
|
uint16_t len, tmp;
|
||||||
|
|
||||||
|
if (!result || !type)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ptr = tlv_get(result->data, result->length, type, &len);
|
||||||
|
if (!ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(&tmp, ptr, 2);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
*value = GINT16_FROM_LE(tmp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||||
uint16_t *value)
|
uint16_t *value)
|
||||||
{
|
{
|
||||||
@@ -1501,6 +1807,7 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct service_create_data {
|
struct service_create_data {
|
||||||
|
struct discovery super;
|
||||||
struct qmi_device *device;
|
struct qmi_device *device;
|
||||||
bool shared;
|
bool shared;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -1512,16 +1819,29 @@ struct service_create_data {
|
|||||||
guint timeout;
|
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;
|
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)
|
if (data->destroy)
|
||||||
data->destroy(data->user_data);
|
data->destroy(data->user_data);
|
||||||
|
|
||||||
g_free(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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1537,8 +1857,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
|||||||
uint16_t len;
|
uint16_t len;
|
||||||
unsigned int hash_id;
|
unsigned int hash_id;
|
||||||
|
|
||||||
g_source_remove(data->timeout);
|
|
||||||
|
|
||||||
result_code = tlv_get(buffer, length, 0x02, &len);
|
result_code = tlv_get(buffer, length, 0x02, &len);
|
||||||
if (!result_code)
|
if (!result_code)
|
||||||
goto done;
|
goto done;
|
||||||
@@ -1580,13 +1898,9 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
data->func(service, data->user_data);
|
data->func(service, data->user_data);
|
||||||
|
|
||||||
qmi_service_unref(service);
|
qmi_service_unref(service);
|
||||||
|
|
||||||
if (data->destroy)
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
data->destroy(data->user_data);
|
|
||||||
|
|
||||||
g_free(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_create_discover(uint8_t count,
|
static void service_create_discover(uint8_t count,
|
||||||
@@ -1617,7 +1931,9 @@ static void service_create_discover(uint8_t count,
|
|||||||
if (data->timeout > 0)
|
if (data->timeout > 0)
|
||||||
g_source_remove(data->timeout);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1640,6 +1956,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
data->super.destroy = service_create_data_free;
|
||||||
data->device = device;
|
data->device = device;
|
||||||
data->shared = shared;
|
data->shared = shared;
|
||||||
data->type = type;
|
data->type = type;
|
||||||
@@ -1662,6 +1979,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
||||||
|
__qmi_device_discovery_started(device, &data->super);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1680,17 +1998,23 @@ bool qmi_service_create(struct qmi_device *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct service_create_shared_data {
|
struct service_create_shared_data {
|
||||||
|
struct discovery super;
|
||||||
struct qmi_service *service;
|
struct qmi_service *service;
|
||||||
|
struct qmi_device *device;
|
||||||
qmi_create_func_t func;
|
qmi_create_func_t func;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
qmi_destroy_func_t destroy;
|
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;
|
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);
|
qmi_service_unref(data->service);
|
||||||
|
|
||||||
@@ -1698,6 +2022,16 @@ static gboolean service_create_shared_reply(gpointer user_data)
|
|||||||
data->destroy(data->user_data);
|
data->destroy(data->user_data);
|
||||||
|
|
||||||
g_free(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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1724,13 +2058,16 @@ bool qmi_service_create_shared(struct qmi_device *device,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
data->super.destroy = service_create_shared_data_free;
|
||||||
data->service = qmi_service_ref(service);
|
data->service = qmi_service_ref(service);
|
||||||
|
data->device = device;
|
||||||
data->func = func;
|
data->func = func;
|
||||||
data->user_data = user_data;
|
data->user_data = user_data;
|
||||||
data->destroy = destroy;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,18 +35,32 @@
|
|||||||
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
|
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
|
||||||
#define QMI_SERVICE_UIM 11 /* UIM service */
|
#define QMI_SERVICE_UIM 11 /* UIM service */
|
||||||
#define QMI_SERVICE_PBM 12 /* Phonebook 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_RMTFS 14 /* Remote file system service */
|
||||||
|
#define QMI_SERVICE_TEST 15
|
||||||
#define QMI_SERVICE_LOC 16 /* Location service */
|
#define QMI_SERVICE_LOC 16 /* Location service */
|
||||||
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
|
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
|
||||||
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
|
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
|
||||||
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
|
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
|
||||||
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
|
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
|
||||||
#define QMI_SERVICE_TMD 24 /* Thermal mitigation device 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_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_CAT_OLD 224 /* Card application toolkit service */
|
||||||
#define QMI_SERVICE_RMS 225 /* Remote management service */
|
#define QMI_SERVICE_RMS 225 /* Remote management service */
|
||||||
#define QMI_SERVICE_OMA 226 /* OMA device 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 {
|
struct qmi_version {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint16_t major;
|
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,
|
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||||
void *user_data, qmi_destroy_func_t destroy);
|
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;
|
struct qmi_param;
|
||||||
|
|
||||||
@@ -112,13 +130,15 @@ const void *qmi_result_get(struct qmi_result *result, uint8_t type,
|
|||||||
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
|
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
|
||||||
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||||
uint8_t *value);
|
uint8_t *value);
|
||||||
|
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||||
|
int16_t *value);
|
||||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||||
uint16_t *value);
|
uint16_t *value);
|
||||||
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
||||||
uint32_t *value);
|
uint32_t *value);
|
||||||
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||||
uint64_t *value);
|
uint64_t *value);
|
||||||
|
void qmi_result_print_tlvs(struct qmi_result *result);
|
||||||
|
|
||||||
struct qmi_service;
|
struct qmi_service;
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,14 @@ static int qmimodem_init(void)
|
|||||||
qmi_gprs_context_init();
|
qmi_gprs_context_init();
|
||||||
qmi_radio_settings_init();
|
qmi_radio_settings_init();
|
||||||
qmi_location_reporting_init();
|
qmi_location_reporting_init();
|
||||||
|
qmi_netmon_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmimodem_exit(void)
|
static void qmimodem_exit(void)
|
||||||
{
|
{
|
||||||
|
qmi_netmon_exit();
|
||||||
qmi_location_reporting_exit();
|
qmi_location_reporting_exit();
|
||||||
qmi_radio_settings_exit();
|
qmi_radio_settings_exit();
|
||||||
qmi_gprs_context_exit();
|
qmi_gprs_context_exit();
|
||||||
|
|||||||
@@ -53,3 +53,6 @@ extern void qmi_radio_settings_exit(void);
|
|||||||
|
|
||||||
extern void qmi_location_reporting_init(void);
|
extern void qmi_location_reporting_init(void);
|
||||||
extern void qmi_location_reporting_exit(void);
|
extern void qmi_location_reporting_exit(void);
|
||||||
|
|
||||||
|
extern void qmi_netmon_init(void);
|
||||||
|
extern void qmi_netmon_exit(void);
|
||||||
|
|||||||
@@ -29,15 +29,202 @@
|
|||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
#include "nas.h"
|
#include "nas.h"
|
||||||
|
#include "dms.h"
|
||||||
|
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
|
|
||||||
struct settings_data {
|
struct settings_data {
|
||||||
struct qmi_service *nas;
|
struct qmi_service *nas;
|
||||||
|
struct qmi_service *dms;
|
||||||
uint16_t major;
|
uint16_t major;
|
||||||
uint16_t minor;
|
uint16_t minor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void get_system_selection_pref_cb(struct qmi_result *result,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||||
|
enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||||
|
uint16_t pref;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmi_result_get_uint16(result,
|
||||||
|
QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref);
|
||||||
|
|
||||||
|
switch (pref) {
|
||||||
|
case QMI_NAS_RAT_MODE_PREF_GSM:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_RAT_MODE_PREF_UMTS:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_RAT_MODE_PREF_LTE:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_query_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_service_send(data->nas,
|
||||||
|
QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL,
|
||||||
|
get_system_selection_pref_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_system_selection_pref_cb(struct qmi_result *result,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_set_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
enum ofono_radio_access_mode mode,
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||||
|
struct qmi_param *param;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_GSM;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_UMTS;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_LTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
param = qmi_param_new();
|
||||||
|
if (!param) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE,
|
||||||
|
pref);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->nas,
|
||||||
|
QMI_NAS_SET_SYSTEM_SELECTION_PREF, param,
|
||||||
|
set_system_selection_pref_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qmi_param_free(param);
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_caps_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
|
||||||
|
const struct qmi_dms_device_caps *caps;
|
||||||
|
unsigned int available_rats;
|
||||||
|
uint16_t len;
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
|
||||||
|
if (!caps)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
available_rats = 0;
|
||||||
|
for (i = 0; i < caps->radio_if_count; i++) {
|
||||||
|
switch (caps->radio_if[i]) {
|
||||||
|
case QMI_DMS_RADIO_IF_GSM:
|
||||||
|
available_rats |= OFONO_RADIO_ACCESS_MODE_GSM;
|
||||||
|
break;
|
||||||
|
case QMI_DMS_RADIO_IF_UMTS:
|
||||||
|
available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
break;
|
||||||
|
case QMI_DMS_RADIO_IF_LTE:
|
||||||
|
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_query_available_rats(struct ofono_radio_settings *rs,
|
||||||
|
ofono_radio_settings_available_rats_query_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
|
if (!rsd->dms)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL,
|
||||||
|
get_caps_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_free(cbd);
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_radio_settings *rs = user_data;
|
||||||
|
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!service)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data->dms = qmi_service_ref(service);
|
||||||
|
}
|
||||||
|
|
||||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_radio_settings *rs = user_data;
|
struct ofono_radio_settings *rs = user_data;
|
||||||
@@ -74,10 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
|
|||||||
|
|
||||||
ofono_radio_settings_set_data(rs, data);
|
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_DMS,
|
||||||
|
create_dms_cb, rs, NULL);
|
||||||
|
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||||
|
create_nas_cb, rs, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||||
@@ -99,6 +288,9 @@ static struct ofono_radio_settings_driver driver = {
|
|||||||
.name = "qmimodem",
|
.name = "qmimodem",
|
||||||
.probe = qmi_radio_settings_probe,
|
.probe = qmi_radio_settings_probe,
|
||||||
.remove = qmi_radio_settings_remove,
|
.remove = qmi_radio_settings_remove,
|
||||||
|
.set_rat_mode = qmi_set_rat_mode,
|
||||||
|
.query_rat_mode = qmi_query_rat_mode,
|
||||||
|
.query_available_rats = qmi_query_available_rats,
|
||||||
};
|
};
|
||||||
|
|
||||||
void qmi_radio_settings_init(void)
|
void qmi_radio_settings_init(void)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <ofono/sim.h>
|
#include <ofono/sim.h>
|
||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
|
#include "dms.h"
|
||||||
#include "uim.h"
|
#include "uim.h"
|
||||||
|
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
@@ -38,15 +39,36 @@
|
|||||||
#define EF_STATUS_INVALIDATED 0
|
#define EF_STATUS_INVALIDATED 0
|
||||||
#define EF_STATUS_VALID 1
|
#define EF_STATUS_VALID 1
|
||||||
|
|
||||||
struct sim_data {
|
/* max number of retry of commands that can temporary fail */
|
||||||
struct qmi_service *uim;
|
#define MAX_RETRY_COUNT 100
|
||||||
uint32_t event_mask;
|
|
||||||
|
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 card_state;
|
||||||
uint8_t app_type;
|
uint8_t app_type;
|
||||||
uint8_t passwd_state;
|
uint8_t passwd_state;
|
||||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
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,
|
static int create_fileid_data(uint8_t app_type, int fileid,
|
||||||
const unsigned char *path,
|
const unsigned char *path,
|
||||||
unsigned int path_len,
|
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 sim_data *data = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
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];
|
unsigned char fileid_data[9];
|
||||||
int fileid_len;
|
int fileid_len;
|
||||||
struct qmi_param *param;
|
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 sim_data *data = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
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 read_data[4];
|
||||||
unsigned char fileid_data[9];
|
unsigned char fileid_data[9];
|
||||||
int fileid_len;
|
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 sim_data *data = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
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 read_data[4];
|
||||||
unsigned char fileid_data[9];
|
unsigned char fileid_data[9];
|
||||||
int fileid_len;
|
int fileid_len;
|
||||||
@@ -295,76 +317,214 @@ error:
|
|||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
static void write_generic_cb(struct qmi_result *result, void *user_data)
|
||||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
|
||||||
{
|
{
|
||||||
struct sim_data *data = ofono_sim_get_data(sim);
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_sim_write_cb_t cb = cbd->cb;
|
||||||
|
uint16_t len;
|
||||||
|
const uint8_t *card_result;
|
||||||
|
uint8_t sw1, sw2;
|
||||||
|
|
||||||
DBG("passwd state %d", data->passwd_state);
|
card_result = qmi_result_get(result, 0x10, &len);
|
||||||
|
if (card_result == NULL || len != 2) {
|
||||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
DBG("card_result: %p, len: %d", card_result, (int) len);
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_data);
|
sw1 = card_result[0];
|
||||||
}
|
sw2 = card_result[1];
|
||||||
|
|
||||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
DBG("%02x, %02x", sw1, sw2);
|
||||||
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 ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
||||||
|
(sw1 == 0x90 && sw2 != 0x00)) {
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
ofono_error("%s: error sw1 %02x sw2 %02x", __func__, sw1, sw2);
|
||||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
|
||||||
|
error.type = OFONO_ERROR_TYPE_SIM;
|
||||||
|
error.error = (sw1 << 8) | sw2;
|
||||||
|
|
||||||
|
cb(&error, cbd->data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, data->retries, user_data);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void card_setup(const struct qmi_uim_slot_info *slot,
|
static void write_generic(struct ofono_sim *sim,
|
||||||
|
uint16_t qmi_message, int fileid,
|
||||||
|
int start_or_recordnum,
|
||||||
|
int length, const unsigned char *value,
|
||||||
|
const unsigned char *path, unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||||
|
unsigned char write_data[4 + length];
|
||||||
|
unsigned char fileid_data[9];
|
||||||
|
int fileid_len;
|
||||||
|
struct qmi_param *param;
|
||||||
|
|
||||||
|
DBG("file id 0x%04x path len %d", fileid, path_len);
|
||||||
|
|
||||||
|
fileid_len = create_fileid_data(data->app_type, fileid,
|
||||||
|
path, path_len, fileid_data);
|
||||||
|
|
||||||
|
if (fileid_len < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
write_data[0] = start_or_recordnum & 0xff;
|
||||||
|
write_data[1] = (start_or_recordnum & 0xff00) >> 8;
|
||||||
|
write_data[2] = length & 0xff;
|
||||||
|
write_data[3] = (length & 0xff00) >> 8;
|
||||||
|
memcpy(&write_data[4], value, length);
|
||||||
|
|
||||||
|
param = qmi_param_new();
|
||||||
|
if (!param)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
|
||||||
|
qmi_param_append(param, 0x02, fileid_len, fileid_data);
|
||||||
|
qmi_param_append(param, 0x03, 4 + length, write_data);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->uim, qmi_message, param,
|
||||||
|
write_generic_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qmi_param_free(param);
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_write_transparent(struct ofono_sim *sim,
|
||||||
|
int fileid, int start, int length,
|
||||||
|
const unsigned char *value,
|
||||||
|
const unsigned char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
write_generic(sim, QMI_UIM_WRITE_TRANSPARENT, fileid, start,
|
||||||
|
length, value, path, path_len, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_write_linear(struct ofono_sim *sim,
|
||||||
|
int fileid, int record, int length,
|
||||||
|
const unsigned char *value,
|
||||||
|
const unsigned char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, record,
|
||||||
|
length, value, path, path_len, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_write_cyclic(struct ofono_sim *sim,
|
||||||
|
int fileid, int length,
|
||||||
|
const unsigned char *value,
|
||||||
|
const unsigned char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, 0,
|
||||||
|
length, value, path, path_len, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_imsi_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_sim_imsi_cb_t cb = cbd->cb;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMSI);
|
||||||
|
if (!str) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
|
||||||
|
|
||||||
|
qmi_free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_info1 *info1,
|
||||||
const struct qmi_uim_app_info2 *info2,
|
const struct qmi_uim_app_info2 *info2,
|
||||||
struct sim_data *data)
|
struct sim_status *sim_stat)
|
||||||
{
|
{
|
||||||
data->card_state = slot->card_state;
|
bool need_retry = false;
|
||||||
data->app_type = info1->app_type;
|
sim_stat->card_state = slot->card_state;
|
||||||
|
sim_stat->app_type = info1->app_type;
|
||||||
|
|
||||||
switch (info1->app_state) {
|
switch (info1->app_state) {
|
||||||
case 0x02: /* PIN1 or UPIN is required */
|
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;
|
break;
|
||||||
case 0x03: /* PUK1 or PUK for UPIN is required */
|
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;
|
break;
|
||||||
case 0x07: /* Ready */
|
case 0x07: /* Ready */
|
||||||
data->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
sim_stat->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
sim_stat->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_PUK] = info2->puk1_retries;
|
||||||
|
|
||||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
sim_stat->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_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 void *ptr;
|
||||||
const struct qmi_uim_card_status *status;
|
const struct qmi_uim_card_status *status;
|
||||||
uint16_t len, offset;
|
uint16_t len, offset;
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
enum get_card_status_result res = GET_CARD_STATUS_RESULT_ERROR;
|
||||||
DBG("");
|
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL))
|
if (qmi_result_set_error(result, NULL))
|
||||||
goto done;
|
goto done;
|
||||||
@@ -397,15 +557,211 @@ static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
|||||||
|
|
||||||
index = GUINT16_FROM_LE(status->index_gw_pri);
|
index = GUINT16_FROM_LE(status->index_gw_pri);
|
||||||
|
|
||||||
if ((index & 0xff) == i && (index >> 8) == n)
|
if ((index & 0xff) == i && (index >> 8) == n) {
|
||||||
card_setup(slot, info1, info2, data);
|
if (get_card_status(slot, info1, info2,
|
||||||
|
sim_stat))
|
||||||
|
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
|
||||||
|
else
|
||||||
|
res = GET_CARD_STATUS_RESULT_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
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);
|
ofono_sim_register(sim);
|
||||||
|
|
||||||
switch (data->card_state) {
|
switch (sim_stat.card_state) {
|
||||||
case 0x00: /* Absent */
|
case 0x00: /* Absent */
|
||||||
case 0x02: /* Error */
|
case 0x02: /* Error */
|
||||||
break;
|
break;
|
||||||
@@ -465,30 +821,44 @@ static void create_uim_cb(struct qmi_service *service, void *user_data)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
qmi_service_unref(data->uim);
|
|
||||||
|
|
||||||
ofono_sim_remove(sim);
|
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,
|
static int qmi_sim_probe(struct ofono_sim *sim,
|
||||||
unsigned int vendor, void *user_data)
|
unsigned int vendor, void *user_data)
|
||||||
{
|
{
|
||||||
struct qmi_device *device = user_data;
|
struct qmi_device *device = user_data;
|
||||||
struct sim_data *data;
|
struct sim_data *data;
|
||||||
int i;
|
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
data = g_new0(struct sim_data, 1);
|
data = g_new0(struct sim_data, 1);
|
||||||
|
|
||||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
data->qmi_dev = device;
|
||||||
|
|
||||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
||||||
data->retries[i] = -1;
|
|
||||||
|
|
||||||
ofono_sim_set_data(sim, data);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -501,9 +871,18 @@ static void qmi_sim_remove(struct ofono_sim *sim)
|
|||||||
|
|
||||||
ofono_sim_set_data(sim, NULL);
|
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);
|
g_free(data);
|
||||||
}
|
}
|
||||||
@@ -516,8 +895,13 @@ static struct ofono_sim_driver driver = {
|
|||||||
.read_file_transparent = qmi_read_transparent,
|
.read_file_transparent = qmi_read_transparent,
|
||||||
.read_file_linear = qmi_read_record,
|
.read_file_linear = qmi_read_record,
|
||||||
.read_file_cyclic = qmi_read_record,
|
.read_file_cyclic = qmi_read_record,
|
||||||
|
.write_file_transparent = qmi_write_transparent,
|
||||||
|
.write_file_linear = qmi_write_linear,
|
||||||
|
.write_file_cyclic = qmi_write_cyclic,
|
||||||
|
.read_imsi = qmi_read_imsi,
|
||||||
.query_passwd_state = qmi_query_passwd_state,
|
.query_passwd_state = qmi_query_passwd_state,
|
||||||
.query_pin_retries = qmi_query_pin_retries,
|
.query_pin_retries = qmi_query_pin_retries,
|
||||||
|
.send_passwd = qmi_pin_send,
|
||||||
};
|
};
|
||||||
|
|
||||||
void qmi_sim_init(void)
|
void qmi_sim_init(void)
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ static void qmi_bearer_query(struct ofono_sms *sms,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (data->major < 1 && data->minor < 2)
|
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
|
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
|
||||||
@@ -315,7 +315,7 @@ static void qmi_bearer_set(struct ofono_sms *sms, int bearer,
|
|||||||
|
|
||||||
DBG("bearer %d", bearer);
|
DBG("bearer %d", bearer);
|
||||||
|
|
||||||
if (data->major < 1 && data->minor < 2)
|
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
domain = bearer_to_domain(bearer);
|
domain = bearer_to_domain(bearer);
|
||||||
@@ -411,7 +411,7 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
|
|||||||
new_list->count = GUINT16_TO_LE(1);
|
new_list->count = GUINT16_TO_LE(1);
|
||||||
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
|
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
|
||||||
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
|
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
|
||||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NV;
|
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NONE;
|
||||||
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
|
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
|
||||||
|
|
||||||
param = qmi_param_new();
|
param = qmi_param_new();
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
|
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
|
||||||
#define QMI_UIM_GET_FILE_ATTRIBUTES 36 /* Get file attributes */
|
#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_EVENT_REGISTRATION 46 /* Register for indications */
|
||||||
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
|
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
|
||||||
|
|
||||||
@@ -91,3 +93,12 @@ struct qmi_uim_file_attributes {
|
|||||||
uint16_t raw_len;
|
uint16_t raw_len;
|
||||||
uint8_t raw_value[0];
|
uint8_t raw_value[0];
|
||||||
} __attribute__((__packed__));
|
} __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 */
|
/* Start WDS network interface */
|
||||||
#define QMI_WDS_PARAM_APN 0x14 /* string */
|
#define QMI_WDS_PARAM_APN 0x14 /* string */
|
||||||
#define QMI_WDS_PARAM_IP_FAMILY 0x19 /* uint8 */
|
#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 */
|
#define QMI_WDS_RESULT_PKT_HANDLE 0x01 /* uint32 */
|
||||||
|
|
||||||
@@ -51,10 +58,12 @@ struct qmi_wds_notify_conn_status {
|
|||||||
|
|
||||||
/* Get the runtime data session settings */
|
/* Get the runtime data session settings */
|
||||||
#define QMI_WDS_RESULT_PDP_TYPE 0x11 /* uint8 */
|
#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_PRIMARY_DNS 0x15 /* uint32 IPv4 */
|
||||||
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
|
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
|
||||||
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
|
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
|
||||||
#define QMI_WDS_RESULT_GATEWAY 0x20 /* 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_RESULT_IP_FAMILY 0x2b /* uint8 */
|
||||||
|
|
||||||
#define QMI_WDS_PDP_TYPE_IPV4 0x00
|
#define QMI_WDS_PDP_TYPE_IPV4 0x00
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ struct qmi_wms_param_message {
|
|||||||
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
||||||
#define QMI_WMS_STORAGE_TYPE_NV 1
|
#define QMI_WMS_STORAGE_TYPE_NV 1
|
||||||
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
||||||
|
#define QMI_WMS_STORAGE_TYPE_NONE 255
|
||||||
|
|
||||||
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||||
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||||
|
#define MAX_RETRIES (5)
|
||||||
|
|
||||||
typedef GObjectClass RilCellInfoClass;
|
typedef GObjectClass RilCellInfoClass;
|
||||||
typedef struct ril_cell_info RilCellInfo;
|
typedef struct ril_cell_info RilCellInfo;
|
||||||
@@ -105,10 +106,10 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
|||||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||||
|
|
||||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||||
gsm->arfcn = INT_MAX;
|
gsm->arfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||||
gsm->bsic = INT_MAX;
|
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
|
||||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||||
gsm->timingAdvance = INT_MAX;
|
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
|
||||||
/* RIL_CellIdentityGsm */
|
/* RIL_CellIdentityGsm */
|
||||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||||
@@ -144,7 +145,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
|||||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||||
|
|
||||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||||
wcdma->uarfcn = INT_MAX;
|
wcdma->uarfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||||
@@ -175,7 +176,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
|||||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||||
|
|
||||||
/* Optional RIL_CellIdentityLte_v12 part */
|
/* Optional RIL_CellIdentityLte_v12 part */
|
||||||
lte->earfcn = INT_MAX;
|
lte->earfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||||
@@ -296,8 +297,8 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
|||||||
DBG_(self, "");
|
DBG_(self, "");
|
||||||
GASSERT(self->query_id);
|
GASSERT(self->query_id);
|
||||||
self->query_id = 0;
|
self->query_id = 0;
|
||||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
|
||||||
(io->ril_version, data, len));
|
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||||
@@ -314,7 +315,7 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
|||||||
{
|
{
|
||||||
GRilIoRequest *req = grilio_request_new();
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||||
self->query_id = grilio_channel_send_request_full(self->io, req,
|
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||||
@@ -328,7 +329,7 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
|||||||
|
|
||||||
grilio_request_append_int32(req, 1);
|
grilio_request_append_int32(req, 1);
|
||||||
grilio_request_append_int32(req, ms);
|
grilio_request_append_int32(req, ms);
|
||||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||||
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
||||||
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
||||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||||
@@ -338,18 +339,16 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
|||||||
|
|
||||||
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
||||||
{
|
{
|
||||||
ril_cell_info_set_rate(self,
|
if (self->sim_card_ready) {
|
||||||
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
|
ril_cell_info_set_rate(self,
|
||||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
(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)
|
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
|
||||||
{
|
{
|
||||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
|
||||||
|
|
||||||
if (self->sim_card_ready) {
|
|
||||||
ril_cell_info_update_rate(self);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||||
@@ -373,16 +372,11 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
|||||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
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 *self = RIL_CELL_INFO(arg);
|
||||||
const gboolean sim_card_was_ready = self->sim_card_ready;
|
|
||||||
|
|
||||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
|
||||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||||
if (self->sim_card_ready != sim_card_was_ready) {
|
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||||
ril_cell_info_refresh(self);
|
ril_cell_info_refresh(self);
|
||||||
if (self->sim_card_ready) {
|
ril_cell_info_update_rate(self);
|
||||||
ril_cell_info_update_rate(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sailfish_cell_info interface callbacks */
|
/* sailfish_cell_info interface callbacks */
|
||||||
@@ -483,10 +477,8 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
|||||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||||
ril_cell_info_sim_status_cb, self);
|
ril_cell_info_sim_status_cb, self);
|
||||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||||
if (self->sim_card_ready) {
|
ril_cell_info_refresh(self);
|
||||||
ril_cell_info_query(self);
|
ril_cell_info_update_rate(self);
|
||||||
ril_cell_info_update_rate(self);
|
|
||||||
}
|
|
||||||
return &self->info;
|
return &self->info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -14,11 +14,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ril_config.h"
|
#include "ril_config.h"
|
||||||
|
#include "ril_util.h"
|
||||||
#include "ril_log.h"
|
#include "ril_log.h"
|
||||||
|
|
||||||
#include <gutil_intarray.h>
|
#include <gutil_intarray.h>
|
||||||
#include <gutil_ints.h>
|
#include <gutil_ints.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
/* Utilities for parsing ril_subscription.conf */
|
/* Utilities for parsing ril_subscription.conf */
|
||||||
|
|
||||||
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||||
@@ -185,17 +190,24 @@ GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
|||||||
char *value = ril_config_get_string(file, group, key);
|
char *value = ril_config_get_string(file, group, key);
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
char **values = g_strsplit(value, ",", -1);
|
|
||||||
char **ptr = values;
|
|
||||||
GUtilIntArray *array = gutil_int_array_new();
|
GUtilIntArray *array = gutil_int_array_new();
|
||||||
|
char **values, **ptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some people are thinking that # is a comment
|
||||||
|
* anywhere on the line, not just at the beginning
|
||||||
|
*/
|
||||||
|
char *comment = strchr(value, '#');
|
||||||
|
|
||||||
|
if (comment) *comment = 0;
|
||||||
|
values = g_strsplit(value, ",", -1);
|
||||||
|
ptr = values;
|
||||||
|
|
||||||
while (*ptr) {
|
while (*ptr) {
|
||||||
const char *str = *ptr++;
|
int val;
|
||||||
char *end = NULL;
|
|
||||||
long ival = strtol(str, &end, 0);
|
|
||||||
|
|
||||||
if (str[0] && !end[0]) {
|
if (ril_parse_int(*ptr++, 0, &val)) {
|
||||||
gutil_int_array_append(array, ival);
|
gutil_int_array_append(array, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +236,337 @@ char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ril_config_merge_files() function does the following:
|
||||||
|
*
|
||||||
|
* 1. Loads the specified key file (say, "/etc/foo.conf")
|
||||||
|
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
|
||||||
|
* for the files with the same suffix as the main file (e.g. "*.conf")
|
||||||
|
* 3. Sorts the files from the subdirectory (alphabetically)
|
||||||
|
* 4. Merges the contents of the additional files with the main file
|
||||||
|
* according to their sort order.
|
||||||
|
*
|
||||||
|
* When the entries are merged, keys and groups overwrite the exising
|
||||||
|
* ones by default. Keys can be suffixed with special characters to
|
||||||
|
* remove or modify the existing entries instead:
|
||||||
|
*
|
||||||
|
* ':' Sets the (default) value if the key is missing
|
||||||
|
* '+' Appends values to the string list
|
||||||
|
* '?' Appends only new (non-existent) values to the string list
|
||||||
|
* '-' Removes the values from the string list
|
||||||
|
*
|
||||||
|
* Both keys and groups can be prefixed with '!' to remove the entire key
|
||||||
|
* or group.
|
||||||
|
*
|
||||||
|
* For example if we merge these two files:
|
||||||
|
*
|
||||||
|
* /etc/foo.conf:
|
||||||
|
*
|
||||||
|
* [foo]
|
||||||
|
* a=1
|
||||||
|
* b=2,3
|
||||||
|
* c=4
|
||||||
|
* d=5
|
||||||
|
* [bar]
|
||||||
|
* e=5
|
||||||
|
*
|
||||||
|
* /etc/foo.d/bar.conf:
|
||||||
|
*
|
||||||
|
* [foo]
|
||||||
|
* a+=2
|
||||||
|
* b-=2
|
||||||
|
* c=5
|
||||||
|
* !d
|
||||||
|
* [!bar]
|
||||||
|
*
|
||||||
|
* we end up with this:
|
||||||
|
*
|
||||||
|
* [foo]
|
||||||
|
* a=1
|
||||||
|
* b=2,3
|
||||||
|
* c=5
|
||||||
|
*
|
||||||
|
* Not that the list separator is assumed to be ',' (rather than default ';').
|
||||||
|
* The keyfile passed to ril_config_merge_files() should use the same list
|
||||||
|
* separator, because the default values are copied from the config files
|
||||||
|
* as is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static gint ril_config_sort_files(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
/* The comparison function for g_ptr_array_sort() doesn't take
|
||||||
|
* the pointers from the array as arguments, it takes pointers
|
||||||
|
* to the pointers in the array. */
|
||||||
|
return strcmp(*(char**)a, *(char**)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **ril_config_collect_files(const char *path, const char *suffix)
|
||||||
|
{
|
||||||
|
/* Returns sorted list of regular files in the directory,
|
||||||
|
* optionally having the specified suffix (e.g. ".conf").
|
||||||
|
* Returns NULL if nothing appropriate has been found. */
|
||||||
|
char **files = NULL;
|
||||||
|
DIR *d = opendir(path);
|
||||||
|
|
||||||
|
if (d) {
|
||||||
|
GPtrArray *list = g_ptr_array_new();
|
||||||
|
const struct dirent *p;
|
||||||
|
|
||||||
|
while ((p = readdir(d)) != NULL) {
|
||||||
|
/* No need to even stat . and .. */
|
||||||
|
if (strcmp(p->d_name, ".") &&
|
||||||
|
strcmp(p->d_name, "..") && (!suffix ||
|
||||||
|
g_str_has_suffix(p->d_name, suffix))) {
|
||||||
|
struct stat st;
|
||||||
|
char *buf = g_strconcat(path, "/", p->d_name,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
|
||||||
|
g_ptr_array_add(list, buf);
|
||||||
|
} else {
|
||||||
|
g_free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list->len > 0) {
|
||||||
|
g_ptr_array_sort(list, ril_config_sort_files);
|
||||||
|
g_ptr_array_add(list, NULL);
|
||||||
|
files = (char**)g_ptr_array_free(list, FALSE);
|
||||||
|
} else {
|
||||||
|
g_ptr_array_free(list, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(d);
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_config_list_find(char **list, gsize len, const char *value)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (!strcmp(list[i], value)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_list_append(GKeyFile *conf, GKeyFile *k,
|
||||||
|
const char *group, const char *key,
|
||||||
|
char **values, gsize n, gboolean unique)
|
||||||
|
{
|
||||||
|
/* Note: will steal strings from values */
|
||||||
|
if (n > 0) {
|
||||||
|
int i;
|
||||||
|
gsize len = 0;
|
||||||
|
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||||
|
&len, NULL);
|
||||||
|
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
|
||||||
|
|
||||||
|
for (i = 0; i < (int)len; i++) {
|
||||||
|
g_ptr_array_add(newlist, list[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (int)n; i++) {
|
||||||
|
char *val = values[i];
|
||||||
|
|
||||||
|
if (!unique || ril_config_list_find((char**)
|
||||||
|
newlist->pdata, newlist->len, val) < 0) {
|
||||||
|
/* Move the string to the new list */
|
||||||
|
g_ptr_array_add(newlist, val);
|
||||||
|
memmove(values + i, values + i + 1,
|
||||||
|
sizeof(char*) * (n - i));
|
||||||
|
i--;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newlist->len > len) {
|
||||||
|
g_key_file_set_string_list(conf, group, key,
|
||||||
|
(const gchar * const *) newlist->pdata,
|
||||||
|
newlist->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strings are deallocated by GPtrArray */
|
||||||
|
g_ptr_array_free(newlist, TRUE);
|
||||||
|
g_free(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_list_remove(GKeyFile *conf, GKeyFile *k,
|
||||||
|
const char *group, const char *key, char **values, gsize n)
|
||||||
|
{
|
||||||
|
if (n > 0) {
|
||||||
|
gsize len = 0;
|
||||||
|
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||||
|
&len, NULL);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
gsize i;
|
||||||
|
const gsize oldlen = len;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
/* Remove all matching values */
|
||||||
|
while ((pos = ril_config_list_find(list, len,
|
||||||
|
values[i])) >= 0) {
|
||||||
|
g_free(list[pos]);
|
||||||
|
memmove(list + pos, list + pos + 1,
|
||||||
|
sizeof(char*) * (len - pos));
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < oldlen) {
|
||||||
|
g_key_file_set_string_list(conf, group, key,
|
||||||
|
(const gchar * const *) list, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_merge_group(GKeyFile *conf, GKeyFile *k,
|
||||||
|
const char *group)
|
||||||
|
{
|
||||||
|
gsize i, n = 0;
|
||||||
|
char **keys = g_key_file_get_keys(k, group, &n, NULL);
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
char *key = keys[i];
|
||||||
|
|
||||||
|
if (key[0] == '!') {
|
||||||
|
if (key[1]) {
|
||||||
|
g_key_file_remove_key(conf, group, key+1, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const gsize len = strlen(key);
|
||||||
|
const char last = (len > 0) ? key[len-1] : 0;
|
||||||
|
|
||||||
|
if (last == '+' || last == '?') {
|
||||||
|
gsize count = 0;
|
||||||
|
gchar **values = g_key_file_get_string_list(k,
|
||||||
|
group, key, &count, NULL);
|
||||||
|
|
||||||
|
key[len-1] = 0;
|
||||||
|
ril_config_list_append(conf, k, group, key,
|
||||||
|
values, count, last == '?');
|
||||||
|
g_strfreev(values);
|
||||||
|
} else if (last == '-') {
|
||||||
|
gsize count = 0;
|
||||||
|
gchar **values = g_key_file_get_string_list(k,
|
||||||
|
group, key, &count, NULL);
|
||||||
|
|
||||||
|
key[len-1] = 0;
|
||||||
|
ril_config_list_remove(conf, k, group, key,
|
||||||
|
values, count);
|
||||||
|
g_strfreev(values);
|
||||||
|
} else {
|
||||||
|
/* Overwrite the value (it must exist in k) */
|
||||||
|
gchar *value = g_key_file_get_value(k, group,
|
||||||
|
key, NULL);
|
||||||
|
|
||||||
|
if (last == ':') {
|
||||||
|
/* Default value */
|
||||||
|
key[len-1] = 0;
|
||||||
|
if (!g_key_file_has_key(conf,
|
||||||
|
group, key, NULL)) {
|
||||||
|
g_key_file_set_value(conf,
|
||||||
|
group, key, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_key_file_set_value(conf, group, key,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
g_free(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
|
||||||
|
{
|
||||||
|
gsize i, n = 0;
|
||||||
|
char **groups = g_key_file_get_groups(k, &n);
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
const char *group = groups[i];
|
||||||
|
|
||||||
|
if (group[0] == '!') {
|
||||||
|
g_key_file_remove_group(conf, group + 1, NULL);
|
||||||
|
} else {
|
||||||
|
ril_config_merge_group(conf, k, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_merge_file(GKeyFile *conf, const char *file)
|
||||||
|
{
|
||||||
|
GKeyFile *k = g_key_file_new();
|
||||||
|
|
||||||
|
g_key_file_set_list_separator(k, ',');
|
||||||
|
|
||||||
|
if (g_key_file_load_from_file(k, file, 0, NULL)) {
|
||||||
|
ril_config_merge_keyfile(conf, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_key_file_unref(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_config_merge_files(GKeyFile *conf, const char *file)
|
||||||
|
{
|
||||||
|
if (conf && file && file[0]) {
|
||||||
|
char *dot = strrchr(file, '.');
|
||||||
|
const char *suffix;
|
||||||
|
char *dir;
|
||||||
|
char **files;
|
||||||
|
|
||||||
|
if (!dot) {
|
||||||
|
dir = g_strconcat(file, ".d", NULL);
|
||||||
|
suffix = NULL;
|
||||||
|
} else if (!dot[1]) {
|
||||||
|
dir = g_strconcat(file, "d", NULL);
|
||||||
|
suffix = NULL;
|
||||||
|
} else {
|
||||||
|
/* 2 bytes for ".d" and 1 for NULL terminator */
|
||||||
|
dir = g_malloc(dot - file + 3);
|
||||||
|
strncpy(dir, file, dot - file);
|
||||||
|
strcpy(dir + (dot - file), ".d");
|
||||||
|
suffix = dot + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
files = ril_config_collect_files(dir, suffix);
|
||||||
|
g_free(dir);
|
||||||
|
|
||||||
|
/* Load the main config */
|
||||||
|
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
|
||||||
|
DBG("Loading %s", file);
|
||||||
|
ril_config_merge_file(conf, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files) {
|
||||||
|
char **ptr;
|
||||||
|
|
||||||
|
for (ptr = files; *ptr; ptr++) {
|
||||||
|
DBG("Merging %s", *ptr);
|
||||||
|
ril_config_merge_file(conf, *ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* mode: C
|
* mode: C
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||||
|
|
||||||
|
void ril_config_merge_files(GKeyFile *conf, const char *file);
|
||||||
|
|
||||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||||
const char *key);
|
const char *key);
|
||||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "ril_network.h"
|
#include "ril_network.h"
|
||||||
#include "ril_sim_settings.h"
|
#include "ril_sim_settings.h"
|
||||||
#include "ril_util.h"
|
#include "ril_util.h"
|
||||||
|
#include "ril_vendor.h"
|
||||||
#include "ril_log.h"
|
#include "ril_log.h"
|
||||||
|
|
||||||
#include <gutil_strv.h>
|
#include <gutil_strv.h>
|
||||||
@@ -94,6 +95,7 @@ struct ril_data_priv {
|
|||||||
struct ril_network *network;
|
struct ril_network *network;
|
||||||
struct ril_data_manager *dm;
|
struct ril_data_manager *dm;
|
||||||
enum ril_data_priv_flags flags;
|
enum ril_data_priv_flags flags;
|
||||||
|
struct ril_vendor_hook *vendor_hook;
|
||||||
|
|
||||||
struct ril_data_request *req_queue;
|
struct ril_data_request *req_queue;
|
||||||
struct ril_data_request *pending_req;
|
struct ril_data_request *pending_req;
|
||||||
@@ -206,10 +208,15 @@ GRilIoRequest *ril_request_deactivate_data_call_new(int cid)
|
|||||||
* ril_data_call
|
* ril_data_call
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static struct ril_data_call *ril_data_call_new()
|
||||||
|
{
|
||||||
|
return g_new0(struct ril_data_call, 1);
|
||||||
|
}
|
||||||
|
|
||||||
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
|
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
|
||||||
{
|
{
|
||||||
if (call) {
|
if (call) {
|
||||||
struct ril_data_call *dc = g_new0(struct ril_data_call, 1);
|
struct ril_data_call *dc = ril_data_call_new();
|
||||||
dc->cid = call->cid;
|
dc->cid = call->cid;
|
||||||
dc->status = call->status;
|
dc->status = call->status;
|
||||||
dc->active = call->active;
|
dc->active = call->active;
|
||||||
@@ -226,13 +233,18 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_data_call_destroy(struct ril_data_call *call)
|
||||||
|
{
|
||||||
|
g_free(call->ifname);
|
||||||
|
g_strfreev(call->dnses);
|
||||||
|
g_strfreev(call->addresses);
|
||||||
|
g_strfreev(call->gateways);
|
||||||
|
}
|
||||||
|
|
||||||
void ril_data_call_free(struct ril_data_call *call)
|
void ril_data_call_free(struct ril_data_call *call)
|
||||||
{
|
{
|
||||||
if (call) {
|
if (call) {
|
||||||
g_free(call->ifname);
|
ril_data_call_destroy(call);
|
||||||
g_strfreev(call->dnses);
|
|
||||||
g_strfreev(call->addresses);
|
|
||||||
g_strfreev(call->gateways);
|
|
||||||
g_free(call);
|
g_free(call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,7 +262,7 @@ static void ril_data_call_list_free(struct ril_data_call_list *list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
|
static gint ril_data_call_compare(gconstpointer a, gconstpointer b)
|
||||||
{
|
{
|
||||||
const struct ril_data_call *ca = a;
|
const struct ril_data_call *ca = a;
|
||||||
const struct ril_data_call *cb = b;
|
const struct ril_data_call *cb = b;
|
||||||
@@ -264,7 +276,7 @@ static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
|
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
|
||||||
{
|
{
|
||||||
switch (proto) {
|
switch (proto) {
|
||||||
case OFONO_GPRS_PROTO_IPV6:
|
case OFONO_GPRS_PROTO_IPV6:
|
||||||
@@ -278,7 +290,7 @@ static const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ril_data_protocol_to_ofono(gchar *str)
|
int ril_data_protocol_to_ofono(const gchar *str)
|
||||||
{
|
{
|
||||||
if (str) {
|
if (str) {
|
||||||
if (!strcmp(str, PROTO_IPV6_STR)) {
|
if (!strcmp(str, PROTO_IPV6_STR)) {
|
||||||
@@ -292,14 +304,13 @@ static int ril_data_protocol_to_ofono(gchar *str)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ril_data_call *ril_data_call_parse(int version,
|
static gboolean ril_data_call_parse_default(struct ril_data_call *call,
|
||||||
GRilIoParser *rilp)
|
int version, GRilIoParser *rilp)
|
||||||
{
|
{
|
||||||
int prot;
|
int prot;
|
||||||
char *prot_str;
|
char *prot_str;
|
||||||
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
|
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
|
||||||
guint32 active = RIL_DATA_CALL_INACTIVE;
|
guint32 active = RIL_DATA_CALL_INACTIVE;
|
||||||
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
|
|
||||||
|
|
||||||
/* RIL_Data_Call_Response_v6 (see ril.h) */
|
/* RIL_Data_Call_Response_v6 (see ril.h) */
|
||||||
grilio_parser_get_uint32(rilp, &status);
|
grilio_parser_get_uint32(rilp, &status);
|
||||||
@@ -334,13 +345,49 @@ static struct ril_data_call *ril_data_call_parse(int version,
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_free(prot_str);
|
g_free(prot_str);
|
||||||
return call;
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
|
||||||
|
int version, GRilIoParser *parser)
|
||||||
|
{
|
||||||
|
GRilIoParser copy = *parser;
|
||||||
|
struct ril_data_call *call = ril_data_call_new();
|
||||||
|
gboolean parsed = ril_vendor_hook_data_call_parse(hook, call,
|
||||||
|
version, parser);
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
/* Try the default parser */
|
||||||
|
ril_data_call_destroy(call);
|
||||||
|
memset(call, 0, sizeof(*call));
|
||||||
|
*parser = copy;
|
||||||
|
parsed = ril_data_call_parse_default(call, version, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed) {
|
||||||
|
DBG("[status=%d,retry=%d,cid=%d,active=%d,type=%s,ifname=%s,"
|
||||||
|
"mtu=%d,address=%s,dns=%s %s,gateways=%s]",
|
||||||
|
call->status, call->retry_time,
|
||||||
|
call->cid, call->active,
|
||||||
|
ril_data_ofono_protocol_to_ril(call->prot),
|
||||||
|
call->ifname, call->mtu,
|
||||||
|
call->addresses ? call->addresses[0] : NULL,
|
||||||
|
call->dnses ? call->dnses[0] : NULL,
|
||||||
|
(call->dnses && call->dnses[0] &&
|
||||||
|
call->dnses[1]) ? call->dnses[1] : "",
|
||||||
|
call->gateways ? call->gateways[0] : NULL);
|
||||||
|
return call;
|
||||||
|
} else {
|
||||||
|
ril_data_call_free(call);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||||
guint len, enum ril_data_call_format format)
|
guint len, struct ril_vendor_hook *hook,
|
||||||
|
enum ril_data_call_format format)
|
||||||
{
|
{
|
||||||
unsigned int version, n, i;
|
guint32 version, n, i;
|
||||||
GRilIoParser rilp;
|
GRilIoParser rilp;
|
||||||
|
|
||||||
grilio_parser_init(&rilp, data, len);
|
grilio_parser_init(&rilp, data, len);
|
||||||
@@ -358,25 +405,14 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
|
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
|
||||||
struct ril_data_call *call =
|
struct ril_data_call *call = ril_data_call_parse(hook,
|
||||||
ril_data_call_parse(list->version, &rilp);
|
list->version, &rilp);
|
||||||
|
|
||||||
DBG("[status=%d,retry=%d,cid=%d,"
|
if (call) {
|
||||||
"active=%d,type=%s,ifname=%s,mtu=%d,"
|
list->num++;
|
||||||
"address=%s, dns=%s %s,gateways=%s]",
|
list->calls = g_slist_insert_sorted(list->calls,
|
||||||
call->status, call->retry_time,
|
call, ril_data_call_compare);
|
||||||
call->cid, call->active,
|
}
|
||||||
ril_data_ofono_protocol_to_ril(call->prot),
|
|
||||||
call->ifname, call->mtu,
|
|
||||||
call->addresses ? call->addresses[0] : NULL,
|
|
||||||
call->dnses ? call->dnses[0] : NULL,
|
|
||||||
(call->dnses && call->dnses[0] &&
|
|
||||||
call->dnses[1]) ? call->dnses[1] : "",
|
|
||||||
call->gateways ? call->gateways[0] : NULL);
|
|
||||||
|
|
||||||
list->num++;
|
|
||||||
list->calls = g_slist_insert_sorted(list->calls, call,
|
|
||||||
ril_data_call_parse_compare);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list->calls) {
|
if (list->calls) {
|
||||||
@@ -470,7 +506,7 @@ static int ril_data_call_list_move_calls(struct ril_data_call_list *dest,
|
|||||||
dest->num++;
|
dest->num++;
|
||||||
src->calls = g_slist_delete_link(src->calls, l);
|
src->calls = g_slist_delete_link(src->calls, l);
|
||||||
dest->calls = g_slist_insert_sorted(dest->calls,
|
dest->calls = g_slist_insert_sorted(dest->calls,
|
||||||
call, ril_data_call_parse_compare);
|
call, ril_data_call_compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
l = next;
|
l = next;
|
||||||
@@ -526,7 +562,7 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||||
priv->options.data_call_format));
|
priv->vendor_hook, priv->options.data_call_format));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||||
@@ -535,11 +571,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 *self = RIL_DATA(user_data);
|
||||||
struct ril_data_priv *priv = self->priv;
|
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);
|
GASSERT(priv->query_id);
|
||||||
priv->query_id = 0;
|
priv->query_id = 0;
|
||||||
if (ril_status == RIL_E_SUCCESS) {
|
if (ril_status == RIL_E_SUCCESS) {
|
||||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||||
priv->options.data_call_format));
|
priv->vendor_hook, priv->options.data_call_format));
|
||||||
|
} else {
|
||||||
|
/* RADIO_NOT_AVAILABLE == no calls */
|
||||||
|
ril_data_set_calls(self, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,7 +785,7 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
|||||||
|
|
||||||
if (ril_status == RIL_E_SUCCESS) {
|
if (ril_status == RIL_E_SUCCESS) {
|
||||||
list = ril_data_call_list_parse(data, len,
|
list = ril_data_call_list_parse(data, len,
|
||||||
priv->options.data_call_format);
|
priv->vendor_hook, priv->options.data_call_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
@@ -846,19 +889,23 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Give vendor code a chance to build a vendor specific packet */
|
||||||
* TODO: add comments about tethering, other non-public
|
ioreq = ril_vendor_hook_data_call_req(priv->vendor_hook, tech,
|
||||||
* profiles...
|
DATA_PROFILE_DEFAULT_STR, setup->apn, setup->username,
|
||||||
*/
|
setup->password, auth, proto_str);
|
||||||
ioreq = grilio_request_new();
|
|
||||||
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
|
if (!ioreq) {
|
||||||
grilio_request_append_format(ioreq, "%d", tech);
|
/* The default one */
|
||||||
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
|
ioreq = grilio_request_new();
|
||||||
grilio_request_append_utf8(ioreq, setup->apn);
|
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
|
||||||
grilio_request_append_utf8(ioreq, setup->username);
|
grilio_request_append_format(ioreq, "%d", tech);
|
||||||
grilio_request_append_utf8(ioreq, setup->password);
|
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
|
||||||
grilio_request_append_format(ioreq, "%d", auth);
|
grilio_request_append_utf8(ioreq, setup->apn);
|
||||||
grilio_request_append_utf8(ioreq, proto_str);
|
grilio_request_append_utf8(ioreq, setup->username);
|
||||||
|
grilio_request_append_utf8(ioreq, setup->password);
|
||||||
|
grilio_request_append_format(ioreq, "%d", auth);
|
||||||
|
grilio_request_append_utf8(ioreq, proto_str);
|
||||||
|
}
|
||||||
|
|
||||||
GASSERT(!req->pending_id);
|
GASSERT(!req->pending_id);
|
||||||
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
||||||
@@ -1106,7 +1153,8 @@ static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
|
|||||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||||
struct ril_radio *radio, struct ril_network *network,
|
struct ril_radio *radio, struct ril_network *network,
|
||||||
GRilIoChannel *io, const struct ril_data_options *options,
|
GRilIoChannel *io, const struct ril_data_options *options,
|
||||||
const struct ril_slot_config *config)
|
const struct ril_slot_config *config,
|
||||||
|
struct ril_vendor_hook *vendor_hook)
|
||||||
{
|
{
|
||||||
GASSERT(dm);
|
GASSERT(dm);
|
||||||
if (G_LIKELY(dm)) {
|
if (G_LIKELY(dm)) {
|
||||||
@@ -1139,6 +1187,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
|||||||
priv->dm = ril_data_manager_ref(dm);
|
priv->dm = ril_data_manager_ref(dm);
|
||||||
priv->radio = ril_radio_ref(radio);
|
priv->radio = ril_radio_ref(radio);
|
||||||
priv->network = ril_network_ref(network);
|
priv->network = ril_network_ref(network);
|
||||||
|
priv->vendor_hook = ril_vendor_hook_ref(vendor_hook);
|
||||||
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
|
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
|
||||||
ril_data_call_list_changed_cb,
|
ril_data_call_list_changed_cb,
|
||||||
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
|
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
|
||||||
@@ -1162,6 +1211,18 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
|||||||
return NULL;
|
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)
|
void ril_data_poll_call_state(struct ril_data *self)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
@@ -1171,6 +1232,8 @@ void ril_data_poll_call_state(struct ril_data *self)
|
|||||||
GRilIoRequest *req = grilio_request_new();
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
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 =
|
priv->query_id =
|
||||||
grilio_queue_send_request_full(priv->q, req,
|
grilio_queue_send_request_full(priv->q, req,
|
||||||
RIL_REQUEST_DATA_CALL_LIST,
|
RIL_REQUEST_DATA_CALL_LIST,
|
||||||
@@ -1435,6 +1498,7 @@ static void ril_data_finalize(GObject *object)
|
|||||||
ril_network_unref(priv->network);
|
ril_network_unref(priv->network);
|
||||||
ril_data_manager_unref(priv->dm);
|
ril_data_manager_unref(priv->dm);
|
||||||
ril_data_call_list_free(self->data_calls);
|
ril_data_call_list_free(self->data_calls);
|
||||||
|
ril_vendor_hook_unref(priv->vendor_hook);
|
||||||
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
|
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -17,8 +17,11 @@
|
|||||||
#define RIL_DATA_H
|
#define RIL_DATA_H
|
||||||
|
|
||||||
#include "ril_types.h"
|
#include "ril_types.h"
|
||||||
|
|
||||||
#include <ofono/gprs-context.h>
|
#include <ofono/gprs-context.h>
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
enum ril_data_call_active {
|
enum ril_data_call_active {
|
||||||
RIL_DATA_CALL_INACTIVE = 0,
|
RIL_DATA_CALL_INACTIVE = 0,
|
||||||
RIL_DATA_CALL_LINK_DOWN = 1,
|
RIL_DATA_CALL_LINK_DOWN = 1,
|
||||||
@@ -96,7 +99,8 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
|||||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||||
struct ril_radio *radio, struct ril_network *network,
|
struct ril_radio *radio, struct ril_network *network,
|
||||||
GRilIoChannel *io, const struct ril_data_options *options,
|
GRilIoChannel *io, const struct ril_data_options *options,
|
||||||
const struct ril_slot_config *config);
|
const struct ril_slot_config *config,
|
||||||
|
struct ril_vendor_hook *vendor_hook);
|
||||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||||
void ril_data_unref(struct ril_data *data);
|
void ril_data_unref(struct ril_data *data);
|
||||||
gboolean ril_data_allowed(struct ril_data *data);
|
gboolean ril_data_allowed(struct ril_data *data);
|
||||||
@@ -124,6 +128,9 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
|||||||
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||||
int cid);
|
int cid);
|
||||||
|
|
||||||
|
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto);
|
||||||
|
int ril_data_protocol_to_ofono(const gchar *str);
|
||||||
|
|
||||||
/* Constructors of various kinds of RIL requests */
|
/* Constructors of various kinds of RIL requests */
|
||||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Jolla Ltd.
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "ril_types.h"
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
struct ril_ecclist_priv;
|
struct ril_ecclist_priv;
|
||||||
|
|
||||||
struct ril_ecclist {
|
struct ril_ecclist {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ofono.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "mtu-watch.h"
|
#include "mtu-watch.h"
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ static char *ril_gprs_context_netmask(const char *bits)
|
|||||||
const char* str;
|
const char* str;
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||||
((1 << nbits)-1) << (32-nbits));
|
((1u << nbits)-1) << (32-nbits));
|
||||||
str = inet_ntoa(in);
|
str = inet_ntoa(in);
|
||||||
if (str) {
|
if (str) {
|
||||||
return g_strdup(str);
|
return g_strdup(str);
|
||||||
@@ -377,7 +378,7 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
|||||||
ril_gprs_context_set_dns_servers(gc, call);
|
ril_gprs_context_set_dns_servers(gc, call);
|
||||||
}
|
}
|
||||||
|
|
||||||
ofono_gprs_context_signal_change(gc, call->cid);
|
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
|
||||||
ril_data_call_free(prev_call);
|
ril_data_call_free(prev_call);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,6 +396,8 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
|||||||
if (ril_status != RIL_E_SUCCESS) {
|
if (ril_status != RIL_E_SUCCESS) {
|
||||||
ofono_error("GPRS context: Reply failure: %s",
|
ofono_error("GPRS context: Reply failure: %s",
|
||||||
ril_error_to_string(ril_status));
|
ril_error_to_string(ril_status));
|
||||||
|
} else if (!call) {
|
||||||
|
ofono_error("Unexpected data call failure");
|
||||||
} else if (call->status != PDP_FAIL_NONE) {
|
} else if (call->status != PDP_FAIL_NONE) {
|
||||||
ofono_error("Unexpected data call status %d", call->status);
|
ofono_error("Unexpected data call status %d", call->status);
|
||||||
error.type = OFONO_ERROR_TYPE_CMS;
|
error.type = OFONO_ERROR_TYPE_CMS;
|
||||||
@@ -444,7 +447,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 */
|
/* Let's make sure that we aren't connecting when roaming not allowed */
|
||||||
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||||
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
|
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) ==
|
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||||
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||||
struct ofono_error error;
|
struct ofono_error error;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -58,8 +58,6 @@ struct ril_modem_data {
|
|||||||
char *imeisv;
|
char *imeisv;
|
||||||
char *imei;
|
char *imei;
|
||||||
char *ecclist_file;
|
char *ecclist_file;
|
||||||
gboolean pre_sim_done;
|
|
||||||
gboolean allow_data;
|
|
||||||
gulong imsi_event_id;
|
gulong imsi_event_id;
|
||||||
|
|
||||||
guint online_check_id;
|
guint online_check_id;
|
||||||
@@ -249,7 +247,6 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
|
|||||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||||
|
|
||||||
DBG("%s", ofono_modem_get_path(modem));
|
DBG("%s", ofono_modem_get_path(modem));
|
||||||
md->pre_sim_done = TRUE;
|
|
||||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
if (md->modem.config.enable_voicecall) {
|
if (md->modem.config.enable_voicecall) {
|
||||||
@@ -288,8 +285,10 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
|||||||
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
|
||||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||||
|
if (md->modem.config.enable_cbs) {
|
||||||
|
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||||
@@ -469,11 +468,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
|||||||
/*
|
/*
|
||||||
* With some RIL implementations, querying available
|
* With some RIL implementations, querying available
|
||||||
* band modes causes some magic Android properties to
|
* band modes causes some magic Android properties to
|
||||||
* appear. Otherwise this request is pretty harmless
|
* appear.
|
||||||
* and useless.
|
|
||||||
*/
|
*/
|
||||||
grilio_queue_send_request(md->q, NULL,
|
if (config->query_available_band_mode) {
|
||||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
grilio_queue_send_request(md->q, NULL,
|
||||||
|
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
ril_modem_update_radio_settings(md);
|
ril_modem_update_radio_settings(md);
|
||||||
return modem;
|
return modem;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -27,6 +27,14 @@ struct ril_netmon {
|
|||||||
guint register_id;
|
guint register_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This number must be in sync with ril_netmon_notify_ofono: */
|
||||||
|
#define RIL_NETMON_MAX_OFONO_PARAMS (8)
|
||||||
|
|
||||||
|
struct ril_netmon_ofono_param {
|
||||||
|
enum ofono_netmon_info type;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
||||||
{
|
{
|
||||||
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
||||||
@@ -40,7 +48,7 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
|||||||
if (mcc >= 0 && mcc <= 999) {
|
if (mcc >= 0 && mcc <= 999) {
|
||||||
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
|
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
|
||||||
if (mnc >= 0 && mnc <= 999) {
|
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 *format[] = { "%d", "%02d", "%03d" };
|
||||||
const char *fmt = (mnclen > 0 &&
|
const char *fmt = (mnclen > 0 &&
|
||||||
mnclen <= G_N_ELEMENTS(format)) ?
|
mnclen <= G_N_ELEMENTS(format)) ?
|
||||||
@@ -50,58 +58,171 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
|
||||||
|
enum ofono_netmon_cell_type type, int mcc, int mnc,
|
||||||
|
struct ril_netmon_ofono_param *params, int nparams)
|
||||||
|
{
|
||||||
|
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||||
|
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Better not to push uninitialized data to the stack ... */
|
||||||
|
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
|
||||||
|
params[i].type = OFONO_NETMON_INFO_INVALID;
|
||||||
|
params[i].value = SAILFISH_CELL_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
|
||||||
|
ofono_netmon_serving_cell_notify(netmon, type,
|
||||||
|
OFONO_NETMON_INFO_MCC, s_mcc,
|
||||||
|
OFONO_NETMON_INFO_MNC, s_mnc,
|
||||||
|
params[0].type, params[0].value,
|
||||||
|
params[1].type, params[1].value,
|
||||||
|
params[2].type, params[2].value,
|
||||||
|
params[3].type, params[3].value,
|
||||||
|
params[4].type, params[4].value,
|
||||||
|
params[5].type, params[5].value,
|
||||||
|
params[6].type, params[6].value,
|
||||||
|
params[7].type, params[7].value,
|
||||||
|
OFONO_NETMON_INFO_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||||
const struct sailfish_cell_info_gsm *gsm)
|
const struct sailfish_cell_info_gsm *gsm)
|
||||||
{
|
{
|
||||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
int n = 0;
|
||||||
|
|
||||||
ril_netmon_format_mccmnc(mcc, mnc, gsm->mcc, gsm->mnc);
|
if (gsm->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
ofono_netmon_serving_cell_notify(netmon,
|
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||||
OFONO_NETMON_CELL_TYPE_GSM,
|
params[n].value = gsm->lac;
|
||||||
OFONO_NETMON_INFO_MCC, mcc,
|
n++;
|
||||||
OFONO_NETMON_INFO_MNC, mnc,
|
}
|
||||||
OFONO_NETMON_INFO_LAC, gsm->lac,
|
|
||||||
OFONO_NETMON_INFO_CI, gsm->cid,
|
if (gsm->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
OFONO_NETMON_INFO_RSSI, gsm->signalStrength,
|
params[n].type = OFONO_NETMON_INFO_CI;
|
||||||
OFONO_NETMON_INFO_BER, gsm->bitErrorRate,
|
params[n].value = gsm->cid;
|
||||||
OFONO_NETMON_INFO_INVALID);
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gsm->arfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||||
|
params[n].value = gsm->arfcn;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gsm->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||||
|
params[n].value = gsm->signalStrength;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gsm->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_BER;
|
||||||
|
params[n].value = gsm->bitErrorRate;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_GSM,
|
||||||
|
gsm->mcc, gsm->mnc, params, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||||
const struct sailfish_cell_info_wcdma *wcdma)
|
const struct sailfish_cell_info_wcdma *wcdma)
|
||||||
{
|
{
|
||||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
int n = 0;
|
||||||
|
|
||||||
ril_netmon_format_mccmnc(mcc, mnc, wcdma->mcc, wcdma->mnc);
|
if (wcdma->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
ofono_netmon_serving_cell_notify(netmon,
|
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||||
OFONO_NETMON_CELL_TYPE_UMTS,
|
params[n].value = wcdma->lac;
|
||||||
OFONO_NETMON_INFO_MCC, mcc,
|
n++;
|
||||||
OFONO_NETMON_INFO_MNC, mnc,
|
}
|
||||||
OFONO_NETMON_INFO_LAC, wcdma->lac,
|
|
||||||
OFONO_NETMON_INFO_CI, wcdma->cid,
|
if (wcdma->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
OFONO_NETMON_INFO_PSC, wcdma->psc,
|
params[n].type = OFONO_NETMON_INFO_CI;
|
||||||
OFONO_NETMON_INFO_RSSI, wcdma->signalStrength,
|
params[n].value = wcdma->cid;
|
||||||
OFONO_NETMON_INFO_BER, wcdma->bitErrorRate,
|
n++;
|
||||||
OFONO_NETMON_INFO_INVALID);
|
}
|
||||||
|
|
||||||
|
if (wcdma->psc != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_PSC;
|
||||||
|
params[n].value = wcdma->psc;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->uarfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||||
|
params[n].value = wcdma->uarfcn;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||||
|
params[n].value = wcdma->signalStrength;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_BER;
|
||||||
|
params[n].value = wcdma->bitErrorRate;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_UMTS,
|
||||||
|
wcdma->mcc, wcdma->mnc, params, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||||
const struct sailfish_cell_info_lte *lte)
|
const struct sailfish_cell_info_lte *lte)
|
||||||
{
|
{
|
||||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
int n = 0;
|
||||||
|
|
||||||
ril_netmon_format_mccmnc(mcc, mnc, lte->mcc, lte->mnc);
|
if (lte->ci != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
ofono_netmon_serving_cell_notify(netmon,
|
params[n].type = OFONO_NETMON_INFO_CI;
|
||||||
OFONO_NETMON_CELL_TYPE_LTE,
|
params[n].value = lte->ci;
|
||||||
OFONO_NETMON_INFO_MCC, mcc,
|
n++;
|
||||||
OFONO_NETMON_INFO_MNC, mnc,
|
}
|
||||||
OFONO_NETMON_INFO_CI, lte->ci,
|
|
||||||
OFONO_NETMON_INFO_RSSI, lte->signalStrength,
|
if (lte->earfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
OFONO_NETMON_INFO_TIMING_ADVANCE, lte->timingAdvance,
|
params[n].type = OFONO_NETMON_INFO_EARFCN;
|
||||||
OFONO_NETMON_INFO_INVALID);
|
params[n].value = lte->earfcn;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||||
|
params[n].value = lte->signalStrength;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->rsrp != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSRQ;
|
||||||
|
params[n].value = lte->rsrp;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->rsrq != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSRP;
|
||||||
|
params[n].value = lte->rsrq;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->cqi != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_CQI;
|
||||||
|
params[n].value = lte->cqi;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->timingAdvance != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
|
||||||
|
params[n].value = lte->timingAdvance;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_LTE,
|
||||||
|
lte->mcc, lte->mnc, params, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -322,6 +322,7 @@ static int ril_netreg_get_signal_strength(const void *data, guint len)
|
|||||||
{
|
{
|
||||||
GRilIoParser rilp;
|
GRilIoParser rilp;
|
||||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||||
|
int rsrp = 0;
|
||||||
|
|
||||||
grilio_parser_init(&rilp, data, len);
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
|
||||||
@@ -341,23 +342,41 @@ static int ril_netreg_get_signal_strength(const void *data, guint len)
|
|||||||
|
|
||||||
/* LTE_SignalStrength */
|
/* LTE_SignalStrength */
|
||||||
grilio_parser_get_int32(&rilp, <e_signal);
|
grilio_parser_get_int32(&rilp, <e_signal);
|
||||||
grilio_parser_get_int32(&rilp, NULL); /* rsrp */
|
grilio_parser_get_int32(&rilp, &rsrp);
|
||||||
grilio_parser_get_int32(&rilp, NULL); /* rsrq */
|
/* The rest is ignored */
|
||||||
grilio_parser_get_int32(&rilp, NULL); /* rssnr */
|
|
||||||
grilio_parser_get_int32(&rilp, NULL); /* cqi */
|
|
||||||
|
|
||||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
|
if (rsrp == INT_MAX) {
|
||||||
evdo_dbm, lte_signal);
|
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal,
|
||||||
|
cdma_dbm, evdo_dbm, lte_signal);
|
||||||
|
} else {
|
||||||
|
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d", gw_signal,
|
||||||
|
cdma_dbm, evdo_dbm, lte_signal, rsrp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the first valid one */
|
/* Return the first valid one */
|
||||||
if (gw_signal != 99 && gw_signal != -1) {
|
|
||||||
|
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
|
||||||
|
* RSRP value. If we've got zero, don't report it just yet. */
|
||||||
|
if (gw_signal >= 1 && gw_signal <= 31) {
|
||||||
|
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||||
return (gw_signal * 100) / 31;
|
return (gw_signal * 100) / 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lte_signal != 99 && lte_signal != -1) {
|
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||||
|
if (lte_signal >= 0 && lte_signal <= 31) {
|
||||||
return (lte_signal * 100) / 31;
|
return (lte_signal * 100) / 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
|
||||||
|
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||||
|
return 140 - rsrp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we've got zero strength and no valid RSRP, then so be it */
|
||||||
|
if (gw_signal == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* In case of dbm, return the value directly */
|
/* In case of dbm, return the value directly */
|
||||||
if (cdma_dbm != -1) {
|
if (cdma_dbm != -1) {
|
||||||
return MIN(cdma_dbm, 100);
|
return MIN(cdma_dbm, 100);
|
||||||
@@ -417,9 +436,8 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
|||||||
{
|
{
|
||||||
struct ril_netreg *nd = user_data;
|
struct ril_netreg *nd = user_data;
|
||||||
GRilIoParser rilp;
|
GRilIoParser rilp;
|
||||||
struct ofono_network_time time;
|
int year, mon, mday, hour, min, sec, tzi, dst = 0;
|
||||||
int year, mon, mday, hour, min, sec, dst, tzi;
|
char tzs;
|
||||||
char tzs, tz[4];
|
|
||||||
gchar *nitz;
|
gchar *nitz;
|
||||||
|
|
||||||
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
||||||
@@ -428,20 +446,32 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
|||||||
nitz = grilio_parser_get_utf8(&rilp);
|
nitz = grilio_parser_get_utf8(&rilp);
|
||||||
|
|
||||||
DBG("%s", nitz);
|
DBG("%s", nitz);
|
||||||
sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday,
|
|
||||||
&hour, &min, &sec, &tzs, &tzi, &dst);
|
|
||||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
|
||||||
|
|
||||||
time.utcoff = atoi(tz) * 15 * 60;
|
/*
|
||||||
time.dst = dst;
|
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
|
||||||
time.sec = sec;
|
* The ds part is considered optional, initialized to zero.
|
||||||
time.min = min;
|
*/
|
||||||
time.hour = hour;
|
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
|
||||||
time.mday = mday;
|
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
|
||||||
time.mon = mon;
|
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
|
||||||
time.year = 2000 + year;
|
struct ofono_network_time time;
|
||||||
|
char tz[4];
|
||||||
|
|
||||||
|
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||||
|
time.utcoff = atoi(tz) * 15 * 60;
|
||||||
|
time.dst = dst;
|
||||||
|
time.sec = sec;
|
||||||
|
time.min = min;
|
||||||
|
time.hour = hour;
|
||||||
|
time.mday = mday;
|
||||||
|
time.mon = mon;
|
||||||
|
time.year = 2000 + year;
|
||||||
|
|
||||||
|
ofono_netreg_time_notify(nd->netreg, &time);
|
||||||
|
} else {
|
||||||
|
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
|
||||||
|
}
|
||||||
|
|
||||||
ofono_netreg_time_notify(nd->netreg, &time);
|
|
||||||
g_free(nitz);
|
g_free(nitz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,7 +529,7 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
|||||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||||
{
|
{
|
||||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
DBG("%p", netreg);
|
DBG("%p", netreg);
|
||||||
grilio_queue_cancel_all(nd->q, FALSE);
|
grilio_queue_cancel_all(nd->q, FALSE);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -208,8 +208,14 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
|||||||
reg->max_calls = 2;
|
reg->max_calls = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
|
if (!ril_parse_int(slac, 16, ®->lac)) {
|
||||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
reg->lac = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ril_parse_int(sci, 16, ®->ci)) {
|
||||||
|
reg->ci = -1;
|
||||||
|
}
|
||||||
|
|
||||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||||
|
|
||||||
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
||||||
@@ -394,12 +400,25 @@ static void ril_network_poll_state(struct ril_network *self)
|
|||||||
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
||||||
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
||||||
ril_network_poll_operator_cb);
|
ril_network_poll_operator_cb);
|
||||||
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
|
||||||
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
ril_network_query_registration_state(self);
|
||||||
ril_network_poll_voice_state_cb);
|
}
|
||||||
priv->data_poll_id = ril_network_poll_and_retry(self,
|
|
||||||
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
|
void ril_network_query_registration_state(struct ril_network *self)
|
||||||
ril_network_poll_data_state_cb);
|
{
|
||||||
|
if (self) {
|
||||||
|
struct ril_network_priv *priv = self->priv;
|
||||||
|
|
||||||
|
DBG_(self, "");
|
||||||
|
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
||||||
|
priv->voice_poll_id,
|
||||||
|
RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||||
|
ril_network_poll_voice_state_cb);
|
||||||
|
priv->data_poll_id = ril_network_poll_and_retry(self,
|
||||||
|
priv->data_poll_id,
|
||||||
|
RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||||
|
ril_network_poll_data_state_cb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
|
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "ril_types.h"
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
struct ofono_network_operator;
|
struct ofono_network_operator;
|
||||||
|
|
||||||
struct ril_registration_state {
|
struct ril_registration_state {
|
||||||
@@ -54,6 +56,7 @@ void ril_network_set_max_pref_mode(struct ril_network *net,
|
|||||||
enum ofono_radio_access_mode max_pref_mode,
|
enum ofono_radio_access_mode max_pref_mode,
|
||||||
gboolean force_check);
|
gboolean force_check);
|
||||||
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
||||||
|
void ril_network_query_registration_state(struct ril_network *net);
|
||||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||||
ril_network_cb_t cb, void *arg);
|
ril_network_cb_t cb, void *arg);
|
||||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||||
@@ -67,6 +70,9 @@ gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
|
|||||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||||
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||||
|
|
||||||
|
#define ril_network_remove_all_handlers(net, ids) \
|
||||||
|
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||||
|
|
||||||
#endif /* RIL_NETWORK_H */
|
#endif /* RIL_NETWORK_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "ril_radio_caps.h"
|
#include "ril_radio_caps.h"
|
||||||
#include "ril_data.h"
|
#include "ril_data.h"
|
||||||
#include "ril_util.h"
|
#include "ril_util.h"
|
||||||
|
#include "ril_vendor.h"
|
||||||
#include "ril_log.h"
|
#include "ril_log.h"
|
||||||
|
|
||||||
#include <sailfish_manager.h>
|
#include <sailfish_manager.h>
|
||||||
@@ -39,10 +40,14 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||||
#include <ofono/plugin.h>
|
#include <ofono/plugin.h>
|
||||||
#include "ofono.h"
|
#include <ofono/storage.h>
|
||||||
|
|
||||||
#define OFONO_RADIO_ACCESS_MODE_ALL (OFONO_RADIO_ACCESS_MODE_GSM |\
|
#define OFONO_RADIO_ACCESS_MODE_ALL (OFONO_RADIO_ACCESS_MODE_GSM |\
|
||||||
OFONO_RADIO_ACCESS_MODE_UMTS |\
|
OFONO_RADIO_ACCESS_MODE_UMTS |\
|
||||||
@@ -50,16 +55,16 @@
|
|||||||
|
|
||||||
#define RIL_DEVICE_IDENTITY_RETRIES_LAST 2
|
#define RIL_DEVICE_IDENTITY_RETRIES_LAST 2
|
||||||
|
|
||||||
#define RADIO_GID 1001
|
|
||||||
#define RADIO_UID 1001
|
|
||||||
#define RIL_SUB_SIZE 4
|
#define RIL_SUB_SIZE 4
|
||||||
|
|
||||||
#define RILMODEM_CONF_FILE CONFIGDIR "/ril_subscription.conf"
|
#define RILMODEM_CONF_FILE CONFIGDIR "/ril_subscription.conf"
|
||||||
|
#define RILMODEM_DEFAULT_IDENTITY "radio:radio"
|
||||||
#define RILMODEM_DEFAULT_SOCK "/dev/socket/rild"
|
#define RILMODEM_DEFAULT_SOCK "/dev/socket/rild"
|
||||||
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
|
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
|
||||||
#define RILMODEM_DEFAULT_SUB "SUB1"
|
#define RILMODEM_DEFAULT_SUB "SUB1"
|
||||||
#define RILMODEM_DEFAULT_TECHS OFONO_RADIO_ACCESS_MODE_ALL
|
#define RILMODEM_DEFAULT_TECHS OFONO_RADIO_ACCESS_MODE_ALL
|
||||||
#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
|
#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
|
||||||
|
#define RILMODEM_DEFAULT_ENABLE_CBS TRUE
|
||||||
#define RILMODEM_DEFAULT_SLOT 0xffffffff
|
#define RILMODEM_DEFAULT_SLOT 0xffffffff
|
||||||
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
|
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
|
||||||
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
|
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
|
||||||
@@ -70,6 +75,8 @@
|
|||||||
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4
|
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4
|
||||||
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY 200 /* ms */
|
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY 200 /* ms */
|
||||||
#define RILMODEM_DEFAULT_EMPTY_PIN_QUERY TRUE /* optimistic */
|
#define RILMODEM_DEFAULT_EMPTY_PIN_QUERY TRUE /* optimistic */
|
||||||
|
#define RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE TRUE /* Qualcomm */
|
||||||
|
#define RILMODEM_DEFAULT_LEGACY_IMEI_QUERY FALSE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The convention is that the keys which can only appear in the [Settings]
|
* The convention is that the keys which can only appear in the [Settings]
|
||||||
@@ -78,6 +85,7 @@
|
|||||||
* with lower case.
|
* with lower case.
|
||||||
*/
|
*/
|
||||||
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
|
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
|
||||||
|
#define RILCONF_SETTINGS_IDENTITY "Identity"
|
||||||
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
|
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
|
||||||
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
|
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
|
||||||
|
|
||||||
@@ -91,16 +99,19 @@
|
|||||||
#define RILCONF_TIMEOUT "timeout"
|
#define RILCONF_TIMEOUT "timeout"
|
||||||
#define RILCONF_4G "enable4G" /* Deprecated */
|
#define RILCONF_4G "enable4G" /* Deprecated */
|
||||||
#define RILCONF_ENABLE_VOICECALL "enableVoicecall"
|
#define RILCONF_ENABLE_VOICECALL "enableVoicecall"
|
||||||
|
#define RILCONF_ENABLE_CBS "enableCellBroadcast"
|
||||||
#define RILCONF_TECHNOLOGIES "technologies"
|
#define RILCONF_TECHNOLOGIES "technologies"
|
||||||
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
|
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
|
||||||
#define RILCONF_ECCLIST_FILE "ecclistFile"
|
#define RILCONF_ECCLIST_FILE "ecclistFile"
|
||||||
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
|
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
|
||||||
#define RILCONF_EMPTY_PIN_QUERY "emptyPinQuery"
|
#define RILCONF_EMPTY_PIN_QUERY "emptyPinQuery"
|
||||||
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
|
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
|
||||||
|
#define RILCONF_VENDOR_DRIVER "vendorDriver"
|
||||||
#define RILCONF_DATA_CALL_RETRY_LIMIT "dataCallRetryLimit"
|
#define RILCONF_DATA_CALL_RETRY_LIMIT "dataCallRetryLimit"
|
||||||
#define RILCONF_DATA_CALL_RETRY_DELAY "dataCallRetryDelay"
|
#define RILCONF_DATA_CALL_RETRY_DELAY "dataCallRetryDelay"
|
||||||
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
|
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
|
||||||
#define RILCONF_REMOTE_HANGUP_REASONS "remoteHangupReasons"
|
#define RILCONF_REMOTE_HANGUP_REASONS "remoteHangupReasons"
|
||||||
|
#define RILCONF_DEFAULT_LEGACY_IMEI_QUERY "legacyImeiQuery"
|
||||||
|
|
||||||
/* Modem error ids */
|
/* Modem error ids */
|
||||||
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
|
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
|
||||||
@@ -131,9 +142,15 @@ enum ril_set_radio_cap_opt {
|
|||||||
RIL_SET_RADIO_CAP_DISABLED
|
RIL_SET_RADIO_CAP_DISABLED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ril_plugin_identity {
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
};
|
||||||
|
|
||||||
struct ril_plugin_settings {
|
struct ril_plugin_settings {
|
||||||
int dm_flags;
|
int dm_flags;
|
||||||
enum ril_set_radio_cap_opt set_radio_cap;
|
enum ril_set_radio_cap_opt set_radio_cap;
|
||||||
|
struct ril_plugin_identity identity;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct sailfish_slot_manager_impl {
|
typedef struct sailfish_slot_manager_impl {
|
||||||
@@ -143,6 +160,7 @@ typedef struct sailfish_slot_manager_impl {
|
|||||||
struct ril_plugin_settings settings;
|
struct ril_plugin_settings settings;
|
||||||
gulong caps_manager_event_id;
|
gulong caps_manager_event_id;
|
||||||
guint start_timeout_id;
|
guint start_timeout_id;
|
||||||
|
MceDisplay *display;
|
||||||
GSList *slots;
|
GSList *slots;
|
||||||
} ril_plugin;
|
} ril_plugin;
|
||||||
|
|
||||||
@@ -171,7 +189,10 @@ typedef struct sailfish_slot_impl {
|
|||||||
struct ril_sim_card *sim_card;
|
struct ril_sim_card *sim_card;
|
||||||
struct ril_sim_settings *sim_settings;
|
struct ril_sim_settings *sim_settings;
|
||||||
struct ril_oem_raw *oem_raw;
|
struct ril_oem_raw *oem_raw;
|
||||||
|
const struct ril_vendor_driver *vendor;
|
||||||
|
struct ril_vendor_hook *vendor_hook;
|
||||||
struct ril_data *data;
|
struct ril_data *data;
|
||||||
|
gboolean legacy_imei_query;
|
||||||
guint start_timeout;
|
guint start_timeout;
|
||||||
guint start_timeout_id;
|
guint start_timeout_id;
|
||||||
MceDisplay *display;
|
MceDisplay *display;
|
||||||
@@ -197,6 +218,7 @@ static void ril_debug_dump_notify(struct ofono_debug_desc *desc);
|
|||||||
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
|
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
|
||||||
static void ril_debug_mce_notify(struct ofono_debug_desc *desc);
|
static void ril_debug_mce_notify(struct ofono_debug_desc *desc);
|
||||||
static void ril_plugin_debug_notify(struct ofono_debug_desc *desc);
|
static void ril_plugin_debug_notify(struct ofono_debug_desc *desc);
|
||||||
|
static void ril_plugin_drop_orphan_slots(ril_plugin *plugin);
|
||||||
static void ril_plugin_retry_init_io(ril_slot *slot);
|
static void ril_plugin_retry_init_io(ril_slot *slot);
|
||||||
static void ril_plugin_check_modem(ril_slot *slot);
|
static void ril_plugin_check_modem(ril_slot *slot);
|
||||||
|
|
||||||
@@ -382,6 +404,11 @@ static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
|
|||||||
slot->received_sim_status = FALSE;
|
slot->received_sim_status = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slot->vendor_hook) {
|
||||||
|
ril_vendor_hook_unref(slot->vendor_hook);
|
||||||
|
slot->vendor_hook = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (slot->io) {
|
if (slot->io) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -428,6 +455,99 @@ static void ril_plugin_check_ready(ril_slot *slot)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_plugin_get_imeisv_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
ril_slot *slot = user_data;
|
||||||
|
char *imeisv = NULL;
|
||||||
|
|
||||||
|
GASSERT(slot->imei_req_id);
|
||||||
|
slot->imei_req_id = 0;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
GRilIoParser rilp;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
imeisv = grilio_parser_get_utf8(&rilp);
|
||||||
|
DBG("%s", imeisv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* slot->imei should be either NULL (when we get connected
|
||||||
|
* to rild the very first time) or match the already known
|
||||||
|
* IMEI (if rild crashed and we have reconnected)
|
||||||
|
*/
|
||||||
|
if (slot->imeisv && imeisv && strcmp(slot->imeisv, imeisv)) {
|
||||||
|
ofono_warn("IMEISV has changed \"%s\" -> \"%s\"",
|
||||||
|
slot->imeisv, imeisv);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ofono_error("Slot %u IMEISV query error: %s",
|
||||||
|
slot->config.slot, ril_error_to_string(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot->imeisv) {
|
||||||
|
/* We assume that IMEISV never changes */
|
||||||
|
g_free(imeisv);
|
||||||
|
} else {
|
||||||
|
slot->imeisv = (imeisv ? imeisv : g_strdup(""));
|
||||||
|
sailfish_manager_imeisv_obtained(slot->handle, slot->imeisv);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_plugin_check_modem(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_plugin_get_imei_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
ril_slot *slot = user_data;
|
||||||
|
char *imei = NULL;
|
||||||
|
|
||||||
|
GASSERT(slot->imei_req_id);
|
||||||
|
slot->imei_req_id = 0;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
GRilIoParser rilp;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
imei = grilio_parser_get_utf8(&rilp);
|
||||||
|
DBG("%s", imei);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* slot->imei should be either NULL (when we get connected
|
||||||
|
* to rild the very first time) or match the already known
|
||||||
|
* IMEI (if rild crashed and we have reconnected)
|
||||||
|
*/
|
||||||
|
if (slot->imei && imei && strcmp(slot->imei, imei)) {
|
||||||
|
ofono_warn("IMEI has changed \"%s\" -> \"%s\"",
|
||||||
|
slot->imei, imei);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imei) {
|
||||||
|
/* IMEI query was successful, fetch IMEISV too */
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
slot->imei_req_id =
|
||||||
|
grilio_channel_send_request_full(slot->io,
|
||||||
|
req, RIL_REQUEST_GET_IMEISV,
|
||||||
|
ril_plugin_get_imeisv_cb, NULL, slot);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
|
||||||
|
ril_error_to_string(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot->imei) {
|
||||||
|
/* We assume that IMEI never changes */
|
||||||
|
g_free(imei);
|
||||||
|
} else {
|
||||||
|
slot->imei = imei ? imei : g_strdup_printf("%d", slot->index);
|
||||||
|
sailfish_manager_imei_obtained(slot->handle, slot->imei);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_plugin_check_modem(slot);
|
||||||
|
ril_plugin_check_ready(slot);
|
||||||
|
}
|
||||||
|
|
||||||
static void ril_plugin_device_identity_cb(GRilIoChannel *io, int status,
|
static void ril_plugin_device_identity_cb(GRilIoChannel *io, int status,
|
||||||
const void *data, guint len, void *user_data)
|
const void *data, guint len, void *user_data)
|
||||||
{
|
{
|
||||||
@@ -493,6 +613,28 @@ static void ril_plugin_device_identity_cb(GRilIoChannel *io, int status,
|
|||||||
ril_plugin_check_ready(slot);
|
ril_plugin_check_ready(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_plugin_start_imei_query(ril_slot *slot, gboolean blocking,
|
||||||
|
int retries)
|
||||||
|
{
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
|
/* There was a bug in libgrilio which was making request blocking
|
||||||
|
* regardless of what we pass to grilio_request_set_blocking(),
|
||||||
|
* that's why we don't call grilio_request_set_blocking() if
|
||||||
|
* blocking is FALSE */
|
||||||
|
if (blocking) grilio_request_set_blocking(req, TRUE);
|
||||||
|
grilio_request_set_retry(req, RIL_RETRY_MS, retries);
|
||||||
|
grilio_channel_cancel_request(slot->io, slot->imei_req_id, FALSE);
|
||||||
|
slot->imei_req_id = (slot->legacy_imei_query ?
|
||||||
|
grilio_channel_send_request_full(slot->io, req,
|
||||||
|
RIL_REQUEST_GET_IMEI,
|
||||||
|
ril_plugin_get_imei_cb, NULL, slot) :
|
||||||
|
grilio_channel_send_request_full(slot->io, req,
|
||||||
|
RIL_REQUEST_DEVICE_IDENTITY,
|
||||||
|
ril_plugin_device_identity_cb, NULL, slot));
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
static enum sailfish_sim_state ril_plugin_sim_state(ril_slot *slot)
|
static enum sailfish_sim_state ril_plugin_sim_state(ril_slot *slot)
|
||||||
{
|
{
|
||||||
const struct ril_sim_card_status *status = slot->sim_card->status;
|
const struct ril_sim_card_status *status = slot->sim_card->status;
|
||||||
@@ -539,21 +681,11 @@ static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
|
|||||||
* (this time, limited number).
|
* (this time, limited number).
|
||||||
*
|
*
|
||||||
* Some RILs fail RIL_REQUEST_DEVICE_IDENTITY until
|
* Some RILs fail RIL_REQUEST_DEVICE_IDENTITY until
|
||||||
* the modem hasn't been properly initialized.
|
* the modem has been properly initialized.
|
||||||
*/
|
*/
|
||||||
GRilIoRequest *req = grilio_request_new();
|
|
||||||
|
|
||||||
DBG("Giving slot %u last chance", slot->config.slot);
|
DBG("Giving slot %u last chance", slot->config.slot);
|
||||||
grilio_request_set_retry(req, RIL_RETRY_MS,
|
ril_plugin_start_imei_query(slot, FALSE,
|
||||||
RIL_DEVICE_IDENTITY_RETRIES_LAST);
|
RIL_DEVICE_IDENTITY_RETRIES_LAST);
|
||||||
grilio_channel_cancel_request(slot->io,
|
|
||||||
slot->imei_req_id, FALSE);
|
|
||||||
slot->imei_req_id =
|
|
||||||
grilio_channel_send_request_full(slot->io,
|
|
||||||
req, RIL_REQUEST_DEVICE_IDENTITY,
|
|
||||||
ril_plugin_device_identity_cb,
|
|
||||||
NULL, slot);
|
|
||||||
grilio_request_unref(req);
|
|
||||||
}
|
}
|
||||||
slot->received_sim_status = TRUE;
|
slot->received_sim_status = TRUE;
|
||||||
}
|
}
|
||||||
@@ -595,10 +727,12 @@ static void ril_plugin_caps_switch_aborted(struct ril_radio_caps_manager *mgr,
|
|||||||
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
||||||
guint id, guint code, const void *data, guint data_len, void *user_data)
|
guint id, guint code, const void *data, guint data_len, void *user_data)
|
||||||
{
|
{
|
||||||
static const GLogModule *log_module = &ril_debug_trace_module;
|
ril_slot *slot = user_data;
|
||||||
|
struct ril_vendor_hook *hook = slot->vendor_hook;
|
||||||
|
static const GLogModule* log_module = &ril_debug_trace_module;
|
||||||
const char *prefix = io->name ? io->name : "";
|
const char *prefix = io->name ? io->name : "";
|
||||||
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
|
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
|
||||||
const char *scode;
|
const char *scode = NULL;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GRILIO_PACKET_REQ:
|
case GRILIO_PACKET_REQ:
|
||||||
@@ -606,7 +740,10 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
|||||||
code == RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION) {
|
code == RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION) {
|
||||||
scode = "V9_SET_UICC_SUBSCRIPTION";
|
scode = "V9_SET_UICC_SUBSCRIPTION";
|
||||||
} else {
|
} else {
|
||||||
scode = ril_request_to_string(code);
|
scode = ril_vendor_hook_request_to_string(hook, code);
|
||||||
|
if (!scode) {
|
||||||
|
scode = ril_request_to_string(code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c [%08x] %s",
|
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c [%08x] %s",
|
||||||
prefix, dir, id, scode);
|
prefix, dir, id, scode);
|
||||||
@@ -622,8 +759,12 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
|||||||
break;
|
break;
|
||||||
case GRILIO_PACKET_UNSOL:
|
case GRILIO_PACKET_UNSOL:
|
||||||
case GRILIO_PACKET_UNSOL_ACK_EXP:
|
case GRILIO_PACKET_UNSOL_ACK_EXP:
|
||||||
|
scode = ril_vendor_hook_event_to_string(hook, code);
|
||||||
|
if (!scode) {
|
||||||
|
scode = ril_unsol_event_to_string(code);
|
||||||
|
}
|
||||||
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c %s",
|
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c %s",
|
||||||
prefix, dir, ril_unsol_event_to_string(code));
|
prefix, dir, scode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -760,6 +901,19 @@ static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_plugin_manager_started(ril_plugin *plugin)
|
||||||
|
{
|
||||||
|
ril_plugin_drop_orphan_slots(plugin);
|
||||||
|
sailfish_slot_manager_started(plugin->handle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We no longer need this MceDisplay reference, the slots
|
||||||
|
* (if there are any) are holding references of their own.
|
||||||
|
*/
|
||||||
|
mce_display_unref(plugin->display);
|
||||||
|
plugin->display = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void ril_plugin_all_slots_started_cb(ril_slot *slot, void *param)
|
static void ril_plugin_all_slots_started_cb(ril_slot *slot, void *param)
|
||||||
{
|
{
|
||||||
if (!slot->handle) {
|
if (!slot->handle) {
|
||||||
@@ -779,7 +933,7 @@ static void ril_plugin_check_if_started(ril_plugin* plugin)
|
|||||||
g_source_remove(plugin->start_timeout_id);
|
g_source_remove(plugin->start_timeout_id);
|
||||||
/* id is zeroed by ril_plugin_manager_start_done */
|
/* id is zeroed by ril_plugin_manager_start_done */
|
||||||
GASSERT(!plugin->start_timeout_id);
|
GASSERT(!plugin->start_timeout_id);
|
||||||
sailfish_slot_manager_started(plugin->handle);
|
ril_plugin_manager_started(plugin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -789,7 +943,6 @@ static void ril_plugin_slot_connected(ril_slot *slot)
|
|||||||
ril_plugin *plugin = slot->plugin;
|
ril_plugin *plugin = slot->plugin;
|
||||||
const struct ril_plugin_settings *ps = &plugin->settings;
|
const struct ril_plugin_settings *ps = &plugin->settings;
|
||||||
const char *log_prefix = ril_plugin_log_prefix(slot);
|
const char *log_prefix = ril_plugin_log_prefix(slot);
|
||||||
GRilIoRequest *req;
|
|
||||||
|
|
||||||
ofono_debug("%s version %u", (slot->name && slot->name[0]) ?
|
ofono_debug("%s version %u", (slot->name && slot->name[0]) ?
|
||||||
slot->name : "RIL", slot->io->ril_version);
|
slot->name : "RIL", slot->io->ril_version);
|
||||||
@@ -801,19 +954,11 @@ static void ril_plugin_slot_connected(ril_slot *slot)
|
|||||||
* Modem will be registered after RIL_REQUEST_DEVICE_IDENTITY
|
* Modem will be registered after RIL_REQUEST_DEVICE_IDENTITY
|
||||||
* successfully completes. By the time ofono starts, rild may
|
* successfully completes. By the time ofono starts, rild may
|
||||||
* not be completely functional. Waiting until it responds to
|
* not be completely functional. Waiting until it responds to
|
||||||
* RIL_REQUEST_DEVICE_IDENTITY (and retrying the request on
|
* RIL_REQUEST_DEVICE_IDENTITY (or RIL_REQUEST_GET_IMEI/SV)
|
||||||
* failure) gives rild time to finish whatever it's doing during
|
* and retrying the request on failure, (hopefully) gives rild
|
||||||
* initialization.
|
* enough time to finish whatever it's doing during initialization.
|
||||||
*/
|
*/
|
||||||
GASSERT(!slot->imei_req_id);
|
ril_plugin_start_imei_query(slot, TRUE, -1);
|
||||||
req = grilio_request_new();
|
|
||||||
/* Don't allow any other requests while this one is pending */
|
|
||||||
grilio_request_set_blocking(req, TRUE);
|
|
||||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
|
||||||
slot->imei_req_id = grilio_channel_send_request_full(slot->io,
|
|
||||||
req, RIL_REQUEST_DEVICE_IDENTITY,
|
|
||||||
ril_plugin_device_identity_cb, NULL, slot);
|
|
||||||
grilio_request_unref(req);
|
|
||||||
|
|
||||||
GASSERT(!slot->radio);
|
GASSERT(!slot->radio);
|
||||||
slot->radio = ril_radio_new(slot->io);
|
slot->radio = ril_radio_new(slot->io);
|
||||||
@@ -838,10 +983,14 @@ static void ril_plugin_slot_connected(ril_slot *slot)
|
|||||||
slot->network = ril_network_new(slot->path, slot->io, log_prefix,
|
slot->network = ril_network_new(slot->path, slot->io, log_prefix,
|
||||||
slot->radio, slot->sim_card, slot->sim_settings);
|
slot->radio, slot->sim_card, slot->sim_settings);
|
||||||
|
|
||||||
|
GASSERT(!slot->vendor_hook);
|
||||||
|
slot->vendor_hook = ril_vendor_create_hook(slot->vendor, slot->io,
|
||||||
|
slot->path, &slot->config, slot->network);
|
||||||
|
|
||||||
GASSERT(!slot->data);
|
GASSERT(!slot->data);
|
||||||
slot->data = ril_data_new(plugin->data_manager, log_prefix,
|
slot->data = ril_data_new(plugin->data_manager, log_prefix,
|
||||||
slot->radio, slot->network, slot->io, &slot->data_opt,
|
slot->radio, slot->network, slot->io, &slot->data_opt,
|
||||||
&slot->config);
|
&slot->config, slot->vendor_hook);
|
||||||
|
|
||||||
GASSERT(!slot->cell_info);
|
GASSERT(!slot->cell_info);
|
||||||
if (slot->io->ril_version >= 9) {
|
if (slot->io->ril_version >= 9) {
|
||||||
@@ -1016,16 +1165,21 @@ static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
|
|||||||
char *name, guint slot_index)
|
char *name, guint slot_index)
|
||||||
{
|
{
|
||||||
ril_slot *slot = g_new0(ril_slot, 1);
|
ril_slot *slot = g_new0(ril_slot, 1);
|
||||||
|
struct ril_slot_config *config = &slot->config;
|
||||||
|
|
||||||
slot->sockpath = sockpath;
|
slot->sockpath = sockpath;
|
||||||
slot->path = path;
|
slot->path = path;
|
||||||
slot->name = name;
|
slot->name = name;
|
||||||
slot->config.slot = slot_index;
|
config->slot = slot_index;
|
||||||
slot->config.techs = RILMODEM_DEFAULT_TECHS;
|
config->techs = RILMODEM_DEFAULT_TECHS;
|
||||||
slot->config.empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
|
config->empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
|
||||||
slot->config.enable_voicecall = RILMODEM_DEFAULT_ENABLE_VOICECALL;
|
config->enable_voicecall = RILMODEM_DEFAULT_ENABLE_VOICECALL;
|
||||||
|
config->enable_cbs = RILMODEM_DEFAULT_ENABLE_CBS;
|
||||||
|
config->query_available_band_mode =
|
||||||
|
RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE;
|
||||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||||
|
slot->legacy_imei_query = RILMODEM_DEFAULT_LEGACY_IMEI_QUERY;
|
||||||
slot->start_timeout = RILMODEM_DEFAULT_START_TIMEOUT;
|
slot->start_timeout = RILMODEM_DEFAULT_START_TIMEOUT;
|
||||||
slot->data_opt.allow_data = RILMODEM_DEFAULT_DATA_OPT;
|
slot->data_opt.allow_data = RILMODEM_DEFAULT_DATA_OPT;
|
||||||
slot->data_opt.data_call_format = RILMODEM_DEFAULT_DATA_CALL_FORMAT;
|
slot->data_opt.data_call_format = RILMODEM_DEFAULT_DATA_CALL_FORMAT;
|
||||||
@@ -1050,6 +1204,29 @@ static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
|
||||||
|
{
|
||||||
|
if (slot->vendor) {
|
||||||
|
struct ril_slot_config *config = &slot->config;
|
||||||
|
struct ril_vendor_defaults defaults;
|
||||||
|
|
||||||
|
/* Let the vendor extension to adjust (some) defaults */
|
||||||
|
memset(&defaults, 0, sizeof(defaults));
|
||||||
|
defaults.legacy_imei_query = slot->legacy_imei_query;
|
||||||
|
defaults.enable_cbs = config->enable_cbs;
|
||||||
|
defaults.empty_pin_query = config->empty_pin_query;
|
||||||
|
defaults.query_available_band_mode =
|
||||||
|
config->query_available_band_mode;
|
||||||
|
|
||||||
|
ril_vendor_get_defaults(slot->vendor, &defaults);
|
||||||
|
slot->legacy_imei_query = defaults.legacy_imei_query;
|
||||||
|
config->enable_cbs = defaults.enable_cbs;
|
||||||
|
config->empty_pin_query = defaults.empty_pin_query;
|
||||||
|
config->query_available_band_mode =
|
||||||
|
defaults.query_available_band_mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static ril_slot *ril_plugin_slot_new(const char *sockpath, const char *path,
|
static ril_slot *ril_plugin_slot_new(const char *sockpath, const char *path,
|
||||||
const char *name, guint slot_index)
|
const char *name, guint slot_index)
|
||||||
{
|
{
|
||||||
@@ -1119,6 +1296,25 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
|||||||
DBG("%s: " RILCONF_SLOT " %u", group, config->slot);
|
DBG("%s: " RILCONF_SLOT " %u", group, config->slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* vendorDriver */
|
||||||
|
sval = ril_config_get_string(file, group, RILCONF_VENDOR_DRIVER);
|
||||||
|
if (sval) {
|
||||||
|
const struct ril_vendor_driver *vendor;
|
||||||
|
RIL_VENDOR_DRIVER_FOREACH(vendor) {
|
||||||
|
if (!strcasecmp(vendor->name, sval)) {
|
||||||
|
DBG("%s: " RILCONF_VENDOR_DRIVER " %s", group,
|
||||||
|
sval);
|
||||||
|
slot->vendor = vendor;
|
||||||
|
ril_plugin_slot_apply_vendor_defaults(slot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!slot->vendor) {
|
||||||
|
ofono_warn("Unknown vendor '%s'", sval);
|
||||||
|
}
|
||||||
|
g_free(sval);
|
||||||
|
}
|
||||||
|
|
||||||
/* startTimeout */
|
/* startTimeout */
|
||||||
if (ril_config_get_integer(file, group, RILCONF_START_TIMEOUT,
|
if (ril_config_get_integer(file, group, RILCONF_START_TIMEOUT,
|
||||||
&ival) && ival >= 0) {
|
&ival) && ival >= 0) {
|
||||||
@@ -1139,6 +1335,13 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
|||||||
config->enable_voicecall ? "yes" : "no");
|
config->enable_voicecall ? "yes" : "no");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* enableCellBroadcast */
|
||||||
|
if (ril_config_get_boolean(file, group, RILCONF_ENABLE_CBS,
|
||||||
|
&config->enable_cbs)) {
|
||||||
|
DBG("%s: " RILCONF_ENABLE_CBS " %s", group,
|
||||||
|
config->enable_cbs ? "yes" : "no");
|
||||||
|
}
|
||||||
|
|
||||||
/* technologies */
|
/* technologies */
|
||||||
strv = ril_config_get_strings(file, group, RILCONF_TECHNOLOGIES, ',');
|
strv = ril_config_get_strings(file, group, RILCONF_TECHNOLOGIES, ',');
|
||||||
if (strv) {
|
if (strv) {
|
||||||
@@ -1270,6 +1473,14 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
|||||||
g_free(sval);
|
g_free(sval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* legacyImeiQuery */
|
||||||
|
if (ril_config_get_boolean(file, group,
|
||||||
|
RILCONF_DEFAULT_LEGACY_IMEI_QUERY,
|
||||||
|
&slot->legacy_imei_query)) {
|
||||||
|
DBG("%s: " RILCONF_DEFAULT_LEGACY_IMEI_QUERY " %s", group,
|
||||||
|
slot->legacy_imei_query ? "on" : "off");
|
||||||
|
}
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1324,6 +1535,60 @@ static guint ril_plugin_find_unused_slot(GSList *slots)
|
|||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_plugin_parse_identity(struct ril_plugin_identity *identity,
|
||||||
|
const char *value)
|
||||||
|
{
|
||||||
|
char *sep = strchr(value, ':');
|
||||||
|
const char *user = value;
|
||||||
|
const char *group = NULL;
|
||||||
|
char *tmp_user = NULL;
|
||||||
|
const struct passwd *pw = NULL;
|
||||||
|
const struct group *gr = NULL;
|
||||||
|
|
||||||
|
if (sep) {
|
||||||
|
/* Group */
|
||||||
|
group = sep + 1;
|
||||||
|
gr = getgrnam(group);
|
||||||
|
user = tmp_user = g_strndup(value, sep - value);
|
||||||
|
|
||||||
|
if (!gr) {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Try numeric */
|
||||||
|
if (ril_parse_int(group, 0, &n)) {
|
||||||
|
gr = getgrgid(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* User */
|
||||||
|
pw = getpwnam(user);
|
||||||
|
if (!pw) {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Try numeric */
|
||||||
|
if (ril_parse_int(user, 0, &n)) {
|
||||||
|
pw = getpwuid(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pw) {
|
||||||
|
DBG("User %s -> %d", user, pw->pw_uid);
|
||||||
|
identity->uid = pw->pw_uid;
|
||||||
|
} else {
|
||||||
|
ofono_warn("Invalid user '%s'", user);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gr) {
|
||||||
|
DBG("Group %s -> %d", group, gr->gr_gid);
|
||||||
|
identity->gid = gr->gr_gid;
|
||||||
|
} else if (group) {
|
||||||
|
ofono_warn("Invalid group '%s'", group);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(tmp_user);
|
||||||
|
}
|
||||||
|
|
||||||
static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
||||||
struct ril_plugin_settings *ps)
|
struct ril_plugin_settings *ps)
|
||||||
{
|
{
|
||||||
@@ -1344,6 +1609,7 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
|||||||
} else if (!strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
} else if (!strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||||
/* Plugin configuration */
|
/* Plugin configuration */
|
||||||
int ival;
|
int ival;
|
||||||
|
char *sval;
|
||||||
|
|
||||||
/* 3GLTEHandover */
|
/* 3GLTEHandover */
|
||||||
ril_config_get_flag(file, group,
|
ril_config_get_flag(file, group,
|
||||||
@@ -1359,6 +1625,14 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
|||||||
"off", RIL_SET_RADIO_CAP_DISABLED, NULL)) {
|
"off", RIL_SET_RADIO_CAP_DISABLED, NULL)) {
|
||||||
ps->set_radio_cap = ival;
|
ps->set_radio_cap = ival;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Identity */
|
||||||
|
sval = g_key_file_get_string(file, group,
|
||||||
|
RILCONF_SETTINGS_IDENTITY, NULL);
|
||||||
|
if (sval) {
|
||||||
|
ril_plugin_parse_identity(&ps->identity, sval);
|
||||||
|
g_free(sval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1378,22 +1652,16 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
|||||||
static GSList *ril_plugin_load_config(const char *path,
|
static GSList *ril_plugin_load_config(const char *path,
|
||||||
struct ril_plugin_settings *ps)
|
struct ril_plugin_settings *ps)
|
||||||
{
|
{
|
||||||
GError *err = NULL;
|
|
||||||
GSList *l, *list = NULL;
|
GSList *l, *list = NULL;
|
||||||
GKeyFile *file = g_key_file_new();
|
GKeyFile *file = g_key_file_new();
|
||||||
gboolean empty = FALSE;
|
gboolean empty = FALSE;
|
||||||
|
|
||||||
if (g_key_file_load_from_file(file, path, 0, &err)) {
|
ril_config_merge_files(file, path);
|
||||||
DBG("Loading %s", path);
|
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
|
||||||
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
|
|
||||||
RILCONF_SETTINGS_EMPTY, &empty) && empty) {
|
RILCONF_SETTINGS_EMPTY, &empty) && empty) {
|
||||||
DBG("Empty config");
|
DBG("Empty config");
|
||||||
} else {
|
|
||||||
list = ril_plugin_parse_config_file(file, ps);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
DBG("conf load error: %s", err->message);
|
list = ril_plugin_parse_config_file(file, ps);
|
||||||
g_error_free(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!list && !empty) {
|
if (!list && !empty) {
|
||||||
@@ -1413,18 +1681,69 @@ static GSList *ril_plugin_load_config(const char *path,
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RIL expects user radio */
|
static void ril_plugin_set_perm(const char *path, mode_t mode,
|
||||||
static void ril_plugin_switch_user()
|
const struct ril_plugin_identity *id)
|
||||||
{
|
{
|
||||||
|
if (chmod(path, mode)) {
|
||||||
|
ofono_error("chmod(%s,%o) failed: %s", path, mode,
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
if (chown(path, id->uid, id->gid)) {
|
||||||
|
ofono_error("chown(%s,%d,%d) failed: %s", path, id->uid,
|
||||||
|
id->gid, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recursively updates file and directory ownership and permissions */
|
||||||
|
static void ril_plugin_set_storage_perm(const char *path,
|
||||||
|
const struct ril_plugin_identity *id)
|
||||||
|
{
|
||||||
|
DIR *d;
|
||||||
|
const mode_t dir_mode = S_IRUSR | S_IWUSR | S_IXUSR;
|
||||||
|
const mode_t file_mode = S_IRUSR | S_IWUSR;
|
||||||
|
|
||||||
|
ril_plugin_set_perm(path, dir_mode, id);
|
||||||
|
d = opendir(path);
|
||||||
|
if (d) {
|
||||||
|
const struct dirent *p;
|
||||||
|
|
||||||
|
while ((p = readdir(d)) != NULL) {
|
||||||
|
char *buf;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (!strcmp(p->d_name, ".") ||
|
||||||
|
!strcmp(p->d_name, "..")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = g_strdup_printf("%s/%s", path, p->d_name);
|
||||||
|
if (!stat(buf, &st)) {
|
||||||
|
mode_t mode;
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
ril_plugin_set_storage_perm(buf, id);
|
||||||
|
mode = dir_mode;
|
||||||
|
} else {
|
||||||
|
mode = file_mode;
|
||||||
|
}
|
||||||
|
ril_plugin_set_perm(buf, mode, id);
|
||||||
|
}
|
||||||
|
g_free(buf);
|
||||||
|
}
|
||||||
|
closedir(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_plugin_switch_identity(const struct ril_plugin_identity *id)
|
||||||
|
{
|
||||||
|
ril_plugin_set_storage_perm(ofono_storage_dir(), id);
|
||||||
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
|
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
|
||||||
ofono_error("prctl(PR_SET_KEEPCAPS) failed: %s",
|
ofono_error("prctl(PR_SET_KEEPCAPS) failed: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
} else if (setgid(RADIO_GID) < 0) {
|
} else if (setgid(id->gid) < 0) {
|
||||||
ofono_error("setgid(%d) failed: %s", RADIO_GID,
|
ofono_error("setgid(%d) failed: %s", id->gid, strerror(errno));
|
||||||
strerror(errno));
|
} else if (setuid(id->uid) < 0) {
|
||||||
} else if (setuid(RADIO_UID) < 0) {
|
ofono_error("setuid(%d) failed: %s", id->uid, strerror(errno));
|
||||||
ofono_error("setuid(%d) failed: %s", RADIO_UID,
|
|
||||||
strerror(errno));
|
|
||||||
} else {
|
} else {
|
||||||
struct __user_cap_header_struct header;
|
struct __user_cap_header_struct header;
|
||||||
struct __user_cap_data_struct cap;
|
struct __user_cap_data_struct cap;
|
||||||
@@ -1481,8 +1800,7 @@ static gboolean ril_plugin_manager_start_timeout(gpointer user_data)
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
plugin->start_timeout_id = 0;
|
plugin->start_timeout_id = 0;
|
||||||
ril_plugin_drop_orphan_slots(plugin);
|
ril_plugin_manager_started(plugin);
|
||||||
sailfish_slot_manager_started(plugin->handle);
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1501,11 +1819,20 @@ static void ril_plugin_manager_start_done(gpointer user_data)
|
|||||||
static ril_plugin *ril_plugin_manager_create(struct sailfish_slot_manager *m)
|
static ril_plugin *ril_plugin_manager_create(struct sailfish_slot_manager *m)
|
||||||
{
|
{
|
||||||
ril_plugin *plugin = g_new0(ril_plugin, 1);
|
ril_plugin *plugin = g_new0(ril_plugin, 1);
|
||||||
|
struct ril_plugin_settings *ps = &plugin->settings;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the MCE client instance early so that connection
|
||||||
|
* to the system bus gets established before we switch the
|
||||||
|
* identity.
|
||||||
|
*/
|
||||||
|
plugin->display = mce_display_new();
|
||||||
plugin->handle = m;
|
plugin->handle = m;
|
||||||
plugin->settings.dm_flags = RILMODEM_DEFAULT_DM_FLAGS;
|
ril_plugin_parse_identity(&ps->identity, RILMODEM_DEFAULT_IDENTITY);
|
||||||
plugin->settings.set_radio_cap = RIL_SET_RADIO_CAP_AUTO;
|
ps->dm_flags = RILMODEM_DEFAULT_DM_FLAGS;
|
||||||
|
ps->set_radio_cap = RIL_SET_RADIO_CAP_AUTO;
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1550,6 +1877,10 @@ static guint ril_plugin_manager_start(ril_plugin *plugin)
|
|||||||
|
|
||||||
ril_plugin_foreach_slot_param(plugin, ril_plugin_slot_check_timeout_cb,
|
ril_plugin_foreach_slot_param(plugin, ril_plugin_slot_check_timeout_cb,
|
||||||
&start_timeout);
|
&start_timeout);
|
||||||
|
|
||||||
|
/* Switch the user to the one RIL expects */
|
||||||
|
ril_plugin_switch_identity(&ps->identity);
|
||||||
|
|
||||||
plugin->start_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
|
plugin->start_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
|
||||||
start_timeout, ril_plugin_manager_start_timeout,
|
start_timeout, ril_plugin_manager_start_timeout,
|
||||||
plugin, ril_plugin_manager_start_done);
|
plugin, ril_plugin_manager_start_done);
|
||||||
@@ -1565,6 +1896,7 @@ static void ril_plugin_manager_free(ril_plugin *plugin)
|
|||||||
{
|
{
|
||||||
if (plugin) {
|
if (plugin) {
|
||||||
GASSERT(!plugin->slots);
|
GASSERT(!plugin->slots);
|
||||||
|
mce_display_unref(plugin->display);
|
||||||
ril_data_manager_unref(plugin->data_manager);
|
ril_data_manager_unref(plugin->data_manager);
|
||||||
ril_radio_caps_manager_remove_handler(plugin->caps_manager,
|
ril_radio_caps_manager_remove_handler(plugin->caps_manager,
|
||||||
plugin->caps_manager_event_id);
|
plugin->caps_manager_event_id);
|
||||||
@@ -1639,9 +1971,6 @@ static gboolean ril_plugin_start(gpointer user_data)
|
|||||||
DBG("");
|
DBG("");
|
||||||
ril_driver_init_id = 0;
|
ril_driver_init_id = 0;
|
||||||
|
|
||||||
/* Switch the user to the one RIL expects */
|
|
||||||
ril_plugin_switch_user();
|
|
||||||
|
|
||||||
/* Register the driver */
|
/* Register the driver */
|
||||||
ril_driver = sailfish_slot_driver_register(&ril_slot_driver);
|
ril_driver = sailfish_slot_driver_register(&ril_slot_driver);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "ril_types.h"
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
struct ril_radio {
|
struct ril_radio {
|
||||||
GObject object;
|
GObject object;
|
||||||
struct ril_radio_priv *priv;
|
struct ril_radio_priv *priv;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,11 +18,15 @@
|
|||||||
#include "ril_util.h"
|
#include "ril_util.h"
|
||||||
#include "ril_log.h"
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "sailfish_watch.h"
|
||||||
#include "simutil.h"
|
#include "simutil.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ofono.h"
|
#include "ofono.h"
|
||||||
|
|
||||||
#define SIM_STATE_CHANGE_TIMEOUT_SECS (5)
|
#define SIM_STATE_CHANGE_TIMEOUT_SECS (5)
|
||||||
|
#define FAC_LOCK_QUERY_TIMEOUT_SECS (10)
|
||||||
|
#define FAC_LOCK_QUERY_RETRIES (1)
|
||||||
|
#define SIM_IO_TIMEOUT_SECS (20)
|
||||||
|
|
||||||
#define EF_STATUS_INVALIDATED 0
|
#define EF_STATUS_INVALIDATED 0
|
||||||
#define EF_STATUS_VALID 1
|
#define EF_STATUS_VALID 1
|
||||||
@@ -65,6 +69,11 @@ enum ril_sim_card_event {
|
|||||||
SIM_CARD_EVENT_COUNT
|
SIM_CARD_EVENT_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ril_sim_io_event {
|
||||||
|
IO_EVENT_SIM_REFRESH,
|
||||||
|
IO_EVENT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
struct ril_sim {
|
struct ril_sim {
|
||||||
GRilIoChannel *io;
|
GRilIoChannel *io;
|
||||||
GRilIoQueue *q;
|
GRilIoQueue *q;
|
||||||
@@ -75,13 +84,17 @@ struct ril_sim {
|
|||||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||||
gboolean empty_pin_query_allowed;
|
gboolean empty_pin_query_allowed;
|
||||||
gboolean inserted;
|
gboolean inserted;
|
||||||
guint idle_id;
|
guint idle_id; /* Used by register and SIM reset callbacks */
|
||||||
gulong card_event_id[SIM_CARD_EVENT_COUNT];
|
gulong card_event_id[SIM_CARD_EVENT_COUNT];
|
||||||
|
gulong io_event_id[IO_EVENT_COUNT];
|
||||||
guint query_pin_retries_id;
|
guint query_pin_retries_id;
|
||||||
|
|
||||||
const char *log_prefix;
|
const char *log_prefix;
|
||||||
char *allocated_log_prefix;
|
char *allocated_log_prefix;
|
||||||
|
|
||||||
|
struct sailfish_watch *watch;
|
||||||
|
gulong sim_state_watch_id;
|
||||||
|
|
||||||
/* query_passwd_state context */
|
/* query_passwd_state context */
|
||||||
ofono_sim_passwd_cb_t query_passwd_state_cb;
|
ofono_sim_passwd_cb_t query_passwd_state_cb;
|
||||||
void *query_passwd_state_cb_data;
|
void *query_passwd_state_cb_data;
|
||||||
@@ -485,6 +498,7 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
|
|||||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||||
|
|
||||||
grilio_request_set_blocking(req, TRUE);
|
grilio_request_set_blocking(req, TRUE);
|
||||||
|
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||||
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
|
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
|
||||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||||
@@ -850,6 +864,18 @@ static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_sim_state_changed_cb(struct sailfish_watch *watch, void *data)
|
||||||
|
{
|
||||||
|
struct ril_sim *sd = data;
|
||||||
|
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
|
||||||
|
|
||||||
|
DBG_(sd, "%d %d", state, sd->inserted);
|
||||||
|
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
|
||||||
|
/* That will simulate SIM card removal: */
|
||||||
|
ril_sim_card_reset(sd->card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ril_sim_parse_retry_count(const void *data, guint len)
|
static int ril_sim_parse_retry_count(const void *data, guint len)
|
||||||
{
|
{
|
||||||
int retry_count = -1;
|
int retry_count = -1;
|
||||||
@@ -864,10 +890,14 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
|
|||||||
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
|
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
|
||||||
const char *pin)
|
const char *pin)
|
||||||
{
|
{
|
||||||
const char *app_id = ril_sim_app_id(sd);
|
if (sd->card->app) {
|
||||||
if (app_id) {
|
/*
|
||||||
|
* If there's no AID then so be it... Some
|
||||||
|
* adaptations (namely, MTK) don't provide it
|
||||||
|
* but don't seem to require it either.
|
||||||
|
*/
|
||||||
GRilIoRequest *req = grilio_request_array_utf8_new(2,
|
GRilIoRequest *req = grilio_request_array_utf8_new(2,
|
||||||
pin, app_id);
|
pin, sd->card->app->aid);
|
||||||
|
|
||||||
grilio_request_set_blocking(req, TRUE);
|
grilio_request_set_blocking(req, TRUE);
|
||||||
return req;
|
return req;
|
||||||
@@ -1223,7 +1253,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
|
|||||||
if (req) {
|
if (req) {
|
||||||
id = grilio_queue_send_request_full(sd->q, req, code,
|
id = grilio_queue_send_request_full(sd->q, req, code,
|
||||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||||
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
|
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
|
||||||
grilio_request_unref(req);
|
grilio_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1279,7 +1309,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
|
|||||||
id = grilio_queue_send_request_full(sd->q, req,
|
id = grilio_queue_send_request_full(sd->q, req,
|
||||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||||
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
|
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
|
||||||
grilio_request_unref(req);
|
grilio_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1356,6 +1386,13 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
|
|||||||
cb(ril_error_failure(&error), FALSE, cbd->data);
|
cb(ril_error_failure(&error), FALSE, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean ril_sim_query_facility_lock_retry(GRilIoRequest* req,
|
||||||
|
int ril_status, const void* response_data,
|
||||||
|
guint response_len, void* user_data)
|
||||||
|
{
|
||||||
|
return (ril_status == GRILIO_STATUS_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||||
enum ofono_sim_password_type type,
|
enum ofono_sim_password_type type,
|
||||||
ofono_query_facility_lock_cb_t cb, void *data)
|
ofono_query_facility_lock_cb_t cb, void *data)
|
||||||
@@ -1366,6 +1403,11 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
|||||||
GRilIoRequest *req = grilio_request_array_utf8_new(4,
|
GRilIoRequest *req = grilio_request_array_utf8_new(4,
|
||||||
type_str, "", "0" /* class */, ril_sim_app_id(sd));
|
type_str, "", "0" /* class */, ril_sim_app_id(sd));
|
||||||
|
|
||||||
|
/* Make sure that this request gets completed sooner or later */
|
||||||
|
grilio_request_set_timeout(req, FAC_LOCK_QUERY_TIMEOUT_SECS * 1000);
|
||||||
|
grilio_request_set_retry(req, RIL_RETRY_MS, FAC_LOCK_QUERY_RETRIES);
|
||||||
|
grilio_request_set_retry_func(req, ril_sim_query_facility_lock_retry);
|
||||||
|
|
||||||
DBG_(sd, "%s", type_str);
|
DBG_(sd, "%s", type_str);
|
||||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||||
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
|
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
|
||||||
@@ -1374,6 +1416,19 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
|||||||
grilio_request_unref(req);
|
grilio_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_sim *sd = user_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RIL_UNSOL_SIM_REFRESH may contain the EFID of the updated file,
|
||||||
|
* so we could be more descrete here. However I have't actually
|
||||||
|
* seen that in real life, let's just refresh everything for now.
|
||||||
|
*/
|
||||||
|
__ofono_sim_refresh(sd->sim, NULL, TRUE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean ril_sim_register(gpointer user)
|
static gboolean ril_sim_register(gpointer user)
|
||||||
{
|
{
|
||||||
struct ril_sim *sd = user;
|
struct ril_sim *sd = user;
|
||||||
@@ -1391,6 +1446,14 @@ static gboolean ril_sim_register(gpointer user)
|
|||||||
sd->card_event_id[SIM_CARD_APP_EVENT] =
|
sd->card_event_id[SIM_CARD_APP_EVENT] =
|
||||||
ril_sim_card_add_app_changed_handler(sd->card,
|
ril_sim_card_add_app_changed_handler(sd->card,
|
||||||
ril_sim_app_changed_cb, sd);
|
ril_sim_app_changed_cb, sd);
|
||||||
|
sd->sim_state_watch_id =
|
||||||
|
sailfish_watch_add_sim_state_changed_handler(sd->watch,
|
||||||
|
ril_sim_state_changed_cb, sd);
|
||||||
|
|
||||||
|
/* And RIL events */
|
||||||
|
sd->io_event_id[IO_EVENT_SIM_REFRESH] =
|
||||||
|
grilio_channel_add_unsol_event_handler(sd->io,
|
||||||
|
ril_sim_refresh_cb, RIL_UNSOL_SIM_REFRESH, sd);
|
||||||
|
|
||||||
/* Check the current state */
|
/* Check the current state */
|
||||||
ril_sim_status_changed_cb(sd->card, sd);
|
ril_sim_status_changed_cb(sd->card, sd);
|
||||||
@@ -1409,6 +1472,7 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
|||||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||||
sd->card = ril_sim_card_ref(modem->sim_card);
|
sd->card = ril_sim_card_ref(modem->sim_card);
|
||||||
sd->q = grilio_queue_new(sd->io);
|
sd->q = grilio_queue_new(sd->io);
|
||||||
|
sd->watch = sailfish_watch_new(ril_modem_get_path(modem));
|
||||||
|
|
||||||
if (modem->log_prefix && modem->log_prefix[0]) {
|
if (modem->log_prefix && modem->log_prefix[0]) {
|
||||||
sd->log_prefix = sd->allocated_log_prefix =
|
sd->log_prefix = sd->allocated_log_prefix =
|
||||||
@@ -1429,6 +1493,7 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
|||||||
|
|
||||||
DBG_(sd, "");
|
DBG_(sd, "");
|
||||||
g_list_free_full(sd->pin_cbd_list, ril_sim_pin_cbd_list_free_cb);
|
g_list_free_full(sd->pin_cbd_list, ril_sim_pin_cbd_list_free_cb);
|
||||||
|
grilio_channel_remove_all_handlers(sd->io, sd->io_event_id);
|
||||||
grilio_queue_cancel_all(sd->q, FALSE);
|
grilio_queue_cancel_all(sd->q, FALSE);
|
||||||
ofono_sim_set_data(sim, NULL);
|
ofono_sim_set_data(sim, NULL);
|
||||||
|
|
||||||
@@ -1445,6 +1510,9 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
|||||||
sd->query_passwd_state_sim_status_refresh_id);
|
sd->query_passwd_state_sim_status_refresh_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sailfish_watch_remove_handler(sd->watch, sd->sim_state_watch_id);
|
||||||
|
sailfish_watch_unref(sd->watch);
|
||||||
|
|
||||||
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
|
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
|
||||||
G_N_ELEMENTS(sd->card_event_id));
|
G_N_ELEMENTS(sd->card_event_id));
|
||||||
ril_sim_card_unref(sd->card);
|
ril_sim_card_unref(sd->card);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -24,6 +24,17 @@
|
|||||||
|
|
||||||
#include <gutil_misc.h>
|
#include <gutil_misc.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First we wait for USIM app to get activated by itself. If that
|
||||||
|
* doesn't happen within UICC_SUBSCRIPTION_START_MS we poke the SIM
|
||||||
|
* with SET_UICC_SUBSCRIPTION request, resubmitting it if it times out.
|
||||||
|
* If nothing happens within UICC_SUBSCRIPTION_TIMEOUT_MS we give up.
|
||||||
|
*
|
||||||
|
* Submitting SET_UICC_SUBSCRIPTION request when rild doesn't expect
|
||||||
|
* it sometimes breaks pretty much everything. Unfortunately, there no
|
||||||
|
* reliable way to find out when rild expects it and when it doesn't :/
|
||||||
|
*/
|
||||||
|
#define UICC_SUBSCRIPTION_START_MS (5000)
|
||||||
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
|
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
|
||||||
|
|
||||||
/* SIM I/O idle timeout is measured in the number of idle loops.
|
/* SIM I/O idle timeout is measured in the number of idle loops.
|
||||||
@@ -48,6 +59,7 @@ struct ril_sim_card_priv {
|
|||||||
int flags;
|
int flags;
|
||||||
guint status_req_id;
|
guint status_req_id;
|
||||||
guint sub_req_id;
|
guint sub_req_id;
|
||||||
|
guint sub_start_timer;
|
||||||
gulong event_id[EVENT_COUNT];
|
gulong event_id[EVENT_COUNT];
|
||||||
guint sim_io_idle_id;
|
guint sim_io_idle_id;
|
||||||
guint sim_io_idle_count;
|
guint sim_io_idle_count;
|
||||||
@@ -157,10 +169,55 @@ static void ril_sim_card_status_free(struct ril_sim_card_status *status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_sim_card_tx_start(struct ril_sim_card *self)
|
||||||
|
{
|
||||||
|
struct ril_sim_card_priv *priv = self->priv;
|
||||||
|
GRILIO_TRANSACTION_STATE tx_state =
|
||||||
|
grilio_queue_transaction_state(priv->q);
|
||||||
|
|
||||||
|
if (tx_state == GRILIO_TRANSACTION_NONE) {
|
||||||
|
tx_state = grilio_queue_transaction_start(priv->q);
|
||||||
|
DBG("status tx for slot %u %s", self->slot,
|
||||||
|
(tx_state == GRILIO_TRANSACTION_STARTED) ?
|
||||||
|
"started" : "starting");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_sim_card_tx_check(struct ril_sim_card *self)
|
||||||
|
{
|
||||||
|
struct ril_sim_card_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (grilio_queue_transaction_state(priv->q) !=
|
||||||
|
GRILIO_TRANSACTION_NONE) {
|
||||||
|
const struct ril_sim_card_status *status = self->status;
|
||||||
|
|
||||||
|
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||||
|
/* Transaction (if there is any) is finished when
|
||||||
|
* both GET_SIM_STATUS and SET_UICC_SUBSCRIPTION
|
||||||
|
* complete or get dropped */
|
||||||
|
if (!priv->status_req_id && !priv->sub_req_id &&
|
||||||
|
status->gsm_umts_index >= 0 &&
|
||||||
|
status->gsm_umts_index < status->num_apps) {
|
||||||
|
DBG("status tx for slot %u finished",
|
||||||
|
self->slot);
|
||||||
|
grilio_queue_transaction_finish(priv->q);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DBG("status tx for slot %u cancelled", self->slot);
|
||||||
|
grilio_queue_transaction_finish(priv->q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||||
{
|
{
|
||||||
struct ril_sim_card_priv *priv = self->priv;
|
struct ril_sim_card_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (priv->sub_start_timer) {
|
||||||
|
/* Don't need this timer anymore */
|
||||||
|
g_source_remove(priv->sub_start_timer);
|
||||||
|
priv->sub_start_timer = 0;
|
||||||
|
}
|
||||||
if (priv->sub_req_id) {
|
if (priv->sub_req_id) {
|
||||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||||
* so we better drop rather than cancel it (so that it gets
|
* so we better drop rather than cancel it (so that it gets
|
||||||
@@ -168,7 +225,7 @@ static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
|||||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||||
priv->sub_req_id = 0;
|
priv->sub_req_id = 0;
|
||||||
}
|
}
|
||||||
grilio_queue_transaction_finish(priv->q);
|
ril_sim_card_tx_check(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||||
@@ -184,19 +241,18 @@ static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
|||||||
ril_sim_card_subscription_done(self);
|
ril_sim_card_subscription_done(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index)
|
||||||
enum ril_uicc_subscription_action sub_action)
|
|
||||||
{
|
{
|
||||||
struct ril_sim_card_priv *priv = self->priv;
|
struct ril_sim_card_priv *priv = self->priv;
|
||||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||||
const guint sub_id = self->slot;
|
const guint sub_id = self->slot;
|
||||||
guint code;
|
guint code;
|
||||||
|
|
||||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
|
DBG("%u,%d,%u", self->slot, app_index, sub_id);
|
||||||
grilio_request_append_int32(req, self->slot);
|
grilio_request_append_int32(req, self->slot);
|
||||||
grilio_request_append_int32(req, app_index);
|
grilio_request_append_int32(req, app_index);
|
||||||
grilio_request_append_int32(req, sub_id);
|
grilio_request_append_int32(req, sub_id);
|
||||||
grilio_request_append_int32(req, sub_action);
|
grilio_request_append_int32(req, RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||||
|
|
||||||
grilio_request_set_retry(req, 0, -1);
|
grilio_request_set_retry(req, 0, -1);
|
||||||
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
|
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
|
||||||
@@ -213,7 +269,7 @@ static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
|||||||
|
|
||||||
/* Don't allow any requests other that GET_SIM_STATUS until
|
/* Don't allow any requests other that GET_SIM_STATUS until
|
||||||
* we are done with the subscription */
|
* we are done with the subscription */
|
||||||
grilio_queue_transaction_start(priv->q);
|
ril_sim_card_tx_start(self);
|
||||||
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
|
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
|
||||||
req, code, ril_sim_card_subscribe_cb, NULL, self);
|
req, code, ril_sim_card_subscribe_cb, NULL, self);
|
||||||
grilio_request_unref(req);
|
grilio_request_unref(req);
|
||||||
@@ -221,8 +277,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)
|
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
|
||||||
{
|
{
|
||||||
int selected_app = -1;
|
int i, selected_app = -1;
|
||||||
guint i;
|
|
||||||
|
|
||||||
for (i = 0; i < status->num_apps; i++) {
|
for (i = 0; i < status->num_apps; i++) {
|
||||||
const int type = status->apps[i].app_type;
|
const int type = status->apps[i].app_type;
|
||||||
@@ -251,9 +306,8 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
|||||||
ril_sim_card_subscription_done(self);
|
ril_sim_card_subscription_done(self);
|
||||||
} else {
|
} else {
|
||||||
app_index = ril_sim_card_select_app(status);
|
app_index = ril_sim_card_select_app(status);
|
||||||
if (app_index >= 0) {
|
if (app_index >= 0 && !self->priv->sub_start_timer) {
|
||||||
ril_sim_card_subscribe(self, app_index,
|
ril_sim_card_subscribe(self, app_index);
|
||||||
RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -274,6 +328,18 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean ril_sim_card_sub_start_timeout(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||||
|
struct ril_sim_card_priv *priv = self->priv;
|
||||||
|
|
||||||
|
DBG("%u", self->slot);
|
||||||
|
GASSERT(priv->sub_start_timer);
|
||||||
|
priv->sub_start_timer = 0;
|
||||||
|
ril_sim_card_update_app(self);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
static void ril_sim_card_update_status(struct ril_sim_card *self,
|
static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||||
struct ril_sim_card_status *status)
|
struct ril_sim_card_status *status)
|
||||||
{
|
{
|
||||||
@@ -283,6 +349,23 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
|||||||
struct ril_sim_card_status *old_status = self->status;
|
struct ril_sim_card_status *old_status = self->status;
|
||||||
|
|
||||||
self->status = status;
|
self->status = status;
|
||||||
|
if (diff & RIL_SIMCARD_STATE_CHANGED &&
|
||||||
|
status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||||
|
struct ril_sim_card_priv *priv = self->priv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIM card has just appeared, give it some time to
|
||||||
|
* activate the USIM app
|
||||||
|
*/
|
||||||
|
if (priv->sub_start_timer) {
|
||||||
|
g_source_remove(priv->sub_start_timer);
|
||||||
|
}
|
||||||
|
DBG("started subscription timeout for slot %u",
|
||||||
|
self->slot);
|
||||||
|
priv->sub_start_timer =
|
||||||
|
g_timeout_add(UICC_SUBSCRIPTION_START_MS,
|
||||||
|
ril_sim_card_sub_start_timeout, self);
|
||||||
|
}
|
||||||
ril_sim_card_update_app(self);
|
ril_sim_card_update_app(self);
|
||||||
g_signal_emit(self, ril_sim_card_signals
|
g_signal_emit(self, ril_sim_card_signals
|
||||||
[SIGNAL_STATUS_RECEIVED], 0);
|
[SIGNAL_STATUS_RECEIVED], 0);
|
||||||
@@ -298,6 +381,7 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
|||||||
}
|
}
|
||||||
ril_sim_card_status_free(old_status);
|
ril_sim_card_status_free(old_status);
|
||||||
} else {
|
} else {
|
||||||
|
ril_sim_card_update_app(self);
|
||||||
ril_sim_card_status_free(status);
|
ril_sim_card_status_free(status);
|
||||||
g_signal_emit(self, ril_sim_card_signals
|
g_signal_emit(self, ril_sim_card_signals
|
||||||
[SIGNAL_STATUS_RECEIVED], 0);
|
[SIGNAL_STATUS_RECEIVED], 0);
|
||||||
@@ -431,6 +515,24 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
|||||||
ril_sim_card_update_status(self, status);
|
ril_sim_card_update_status(self, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ril_sim_card_tx_check(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_sim_card_reset(struct ril_sim_card *self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
struct ril_sim_card_status *status =
|
||||||
|
g_new0(struct ril_sim_card_status, 1);
|
||||||
|
|
||||||
|
/* Simulate removal and re-submit the SIM status query */
|
||||||
|
status->card_state = RIL_CARDSTATE_ABSENT;
|
||||||
|
status->gsm_umts_index = -1;
|
||||||
|
status->cdma_index = -1;
|
||||||
|
status->ims_index = -1;
|
||||||
|
ril_sim_card_update_status(self, status);
|
||||||
|
ril_sim_card_request_status(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ril_sim_card_request_status(struct ril_sim_card *self)
|
void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||||
@@ -446,6 +548,9 @@ void ril_sim_card_request_status(struct ril_sim_card *self)
|
|||||||
} else {
|
} else {
|
||||||
GRilIoRequest* req = grilio_request_new();
|
GRilIoRequest* req = grilio_request_new();
|
||||||
|
|
||||||
|
/* Start the transaction to not allow any other
|
||||||
|
* requests to interfere with SIM status query */
|
||||||
|
ril_sim_card_tx_start(self);
|
||||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||||
priv->status_req_id =
|
priv->status_req_id =
|
||||||
grilio_queue_send_request_full(priv->q,
|
grilio_queue_send_request_full(priv->q,
|
||||||
@@ -665,6 +770,9 @@ static void ril_sim_card_finalize(GObject *object)
|
|||||||
if (priv->sim_io_idle_id) {
|
if (priv->sim_io_idle_id) {
|
||||||
g_source_remove(priv->sim_io_idle_id);
|
g_source_remove(priv->sim_io_idle_id);
|
||||||
}
|
}
|
||||||
|
if (priv->sub_start_timer) {
|
||||||
|
g_source_remove(priv->sub_start_timer);
|
||||||
|
}
|
||||||
g_hash_table_destroy(priv->sim_io_pending);
|
g_hash_table_destroy(priv->sim_io_pending);
|
||||||
grilio_channel_unref(priv->io);
|
grilio_channel_unref(priv->io);
|
||||||
grilio_queue_unref(priv->q);
|
grilio_queue_unref(priv->q);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "ril_types.h"
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
struct ril_sim_card_app {
|
struct ril_sim_card_app {
|
||||||
enum ril_app_type app_type;
|
enum ril_app_type app_type;
|
||||||
enum ril_app_state app_state;
|
enum ril_app_state app_state;
|
||||||
@@ -56,6 +58,7 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
|||||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
||||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
||||||
void ril_sim_card_unref(struct ril_sim_card *sc);
|
void ril_sim_card_unref(struct ril_sim_card *sc);
|
||||||
|
void ril_sim_card_reset(struct ril_sim_card *sc);
|
||||||
void ril_sim_card_request_status(struct ril_sim_card *sc);
|
void ril_sim_card_request_status(struct ril_sim_card *sc);
|
||||||
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
|
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
|
||||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
|
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
|
||||||
|
|||||||
@@ -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 <gutil_misc.h>
|
||||||
|
|
||||||
#include "ofono.h"
|
|
||||||
#include "storage.h"
|
|
||||||
|
|
||||||
#define RIL_PREF_MODE_DEFAULT(self) (\
|
#define RIL_PREF_MODE_DEFAULT(self) (\
|
||||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
|
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
|
||||||
OFONO_RADIO_ACCESS_MODE_LTE : \
|
OFONO_RADIO_ACCESS_MODE_LTE : \
|
||||||
@@ -41,7 +38,6 @@ enum sailfish_watch_events {
|
|||||||
struct ril_sim_settings_priv {
|
struct ril_sim_settings_priv {
|
||||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||||
struct sailfish_watch *watch;
|
struct sailfish_watch *watch;
|
||||||
GKeyFile *storage;
|
|
||||||
char *imsi;
|
char *imsi;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "ril_types.h"
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
struct ril_sim_settings_priv;
|
struct ril_sim_settings_priv;
|
||||||
|
|
||||||
struct ril_sim_settings {
|
struct ril_sim_settings {
|
||||||
@@ -34,8 +36,6 @@ struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
|||||||
enum ofono_radio_access_mode techs);
|
enum ofono_radio_access_mode techs);
|
||||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
|
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_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,
|
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *s,
|
||||||
enum ofono_radio_access_mode mode);
|
enum ofono_radio_access_mode mode);
|
||||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *s,
|
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)
|
static void ril_sms_remove(struct ofono_sms *sms)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||||
|
|
||||||
DBG("");
|
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)
|
static void ril_stk_remove(struct ofono_stk *stk)
|
||||||
{
|
{
|
||||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
ofono_stk_set_data(stk, NULL);
|
ofono_stk_set_data(stk, NULL);
|
||||||
|
|||||||
@@ -21,6 +21,13 @@
|
|||||||
#
|
#
|
||||||
#EmptyConfig=false
|
#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
|
# 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
|
# 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
|
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
|
||||||
@@ -177,6 +184,13 @@ socket=/dev/socket/rild
|
|||||||
#
|
#
|
||||||
#enableVoicecall=true
|
#enableVoicecall=true
|
||||||
|
|
||||||
|
# Support for Cell Broadcast System (CBS). By default, its enabled but if
|
||||||
|
# your rild and/or modem is not happy about it, you can turn it off.
|
||||||
|
#
|
||||||
|
# Default true
|
||||||
|
#
|
||||||
|
#enableCellBroadcast=true
|
||||||
|
|
||||||
# Timeout for the modem to show up, in milliseconds. Those that don't
|
# Timeout for the modem to show up, in milliseconds. Those that don't
|
||||||
# show up before this timeout expires, will be dropped (ignored).
|
# show up before this timeout expires, will be dropped (ignored).
|
||||||
#
|
#
|
||||||
@@ -187,3 +201,11 @@ socket=/dev/socket/rild
|
|||||||
# The default is 20000 (20 seconds)
|
# The default is 20000 (20 seconds)
|
||||||
#
|
#
|
||||||
#startTimeout=20000
|
#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
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -41,16 +41,20 @@ struct ofono_sim;
|
|||||||
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
|
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
|
||||||
|
|
||||||
struct ril_data;
|
struct ril_data;
|
||||||
|
struct ril_data_call;
|
||||||
struct ril_modem;
|
struct ril_modem;
|
||||||
struct ril_radio;
|
struct ril_radio;
|
||||||
struct ril_network;
|
struct ril_network;
|
||||||
struct ril_sim_card;
|
struct ril_sim_card;
|
||||||
|
struct ril_vendor_hook;
|
||||||
|
|
||||||
struct ril_slot_config {
|
struct ril_slot_config {
|
||||||
guint slot;
|
guint slot;
|
||||||
enum ofono_radio_access_mode techs;
|
enum ofono_radio_access_mode techs;
|
||||||
|
gboolean query_available_band_mode;
|
||||||
gboolean empty_pin_query;
|
gboolean empty_pin_query;
|
||||||
gboolean enable_voicecall;
|
gboolean enable_voicecall;
|
||||||
|
gboolean enable_cbs;
|
||||||
GUtilInts *local_hangup_reasons;
|
GUtilInts *local_hangup_reasons;
|
||||||
GUtilInts *remote_hangup_reasons;
|
GUtilInts *remote_hangup_reasons;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "netreg.h"
|
#include "netreg.h"
|
||||||
@@ -324,8 +326,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
|||||||
{
|
{
|
||||||
int access_tech = -1;
|
int access_tech = -1;
|
||||||
int tech = -1;
|
int tech = -1;
|
||||||
if (stech && stech[0]) {
|
if (ril_parse_int(stech, 0, &tech)) {
|
||||||
tech = atoi(stech);
|
|
||||||
switch (tech) {
|
switch (tech) {
|
||||||
case RADIO_TECH_GPRS:
|
case RADIO_TECH_GPRS:
|
||||||
case RADIO_TECH_GSM:
|
case RADIO_TECH_GSM:
|
||||||
@@ -382,8 +383,8 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
|||||||
|
|
||||||
if (i == OFONO_MAX_MCC_LENGTH) {
|
if (i == OFONO_MAX_MCC_LENGTH) {
|
||||||
/* Usually 2 but sometimes 3 digit network code */
|
/* Usually 2 but sometimes 3 digit network code */
|
||||||
for (i=0;
|
for (i = 0;
|
||||||
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
i < OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||||
i++) {
|
i++) {
|
||||||
op->mnc[i] = *ptr++;
|
op->mnc[i] = *ptr++;
|
||||||
}
|
}
|
||||||
@@ -410,6 +411,26 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
|||||||
return FALSE;
|
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:
|
* Local Variables:
|
||||||
* mode: C
|
* mode: C
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* oFono - Open Source Telephony - RIL-based devices
|
* 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
|
* 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
|
* 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);
|
const char *ril_radio_state_to_string(int radio_state);
|
||||||
int ril_parse_tech(const char *stech, int *ril_tech);
|
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_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) \
|
#define ril_error_init_ok(err) \
|
||||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
||||||
|
|||||||
164
ofono/drivers/ril/ril_vendor.c
Normal file
164
ofono/drivers/ril/ril_vendor.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_vendor.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
struct ril_vendor_hook *ril_vendor_create_hook
|
||||||
|
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||||
|
const char *path, const struct ril_slot_config *config,
|
||||||
|
struct ril_network *network)
|
||||||
|
{
|
||||||
|
if (vendor) {
|
||||||
|
const void *data = vendor->driver_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: we are looking for the callback in the base but
|
||||||
|
* keeping the original driver data.
|
||||||
|
*/
|
||||||
|
while (!vendor->create_hook && vendor->base) {
|
||||||
|
vendor = vendor->base;
|
||||||
|
}
|
||||||
|
if (vendor->create_hook) {
|
||||||
|
return vendor->create_hook(data, io, path, config,
|
||||||
|
network);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *self,
|
||||||
|
const struct ril_vendor_hook_proc *proc,
|
||||||
|
ril_vendor_hook_free_proc free)
|
||||||
|
{
|
||||||
|
self->proc = proc;
|
||||||
|
self->free = free;
|
||||||
|
g_atomic_int_set(&self->ref_count, 1);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *self)
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
GASSERT(self->ref_count > 0);
|
||||||
|
g_atomic_int_inc(&self->ref_count);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_hook_free(struct ril_vendor_hook *self)
|
||||||
|
{
|
||||||
|
if (self->free) {
|
||||||
|
self->free(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_vendor_hook_unref(struct ril_vendor_hook *self)
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
GASSERT(self->ref_count > 0);
|
||||||
|
if (g_atomic_int_dec_and_test(&self->ref_count)) {
|
||||||
|
ril_vendor_hook_free(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
|
||||||
|
struct ril_vendor_defaults *defaults)
|
||||||
|
{
|
||||||
|
if (vendor) {
|
||||||
|
while (!vendor->get_defaults && vendor->base) {
|
||||||
|
vendor = vendor->base;
|
||||||
|
}
|
||||||
|
if (vendor->get_defaults) {
|
||||||
|
vendor->get_defaults(defaults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *self,
|
||||||
|
guint request)
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||||
|
|
||||||
|
while (!proc->request_to_string && proc->base) {
|
||||||
|
proc = proc->base;
|
||||||
|
}
|
||||||
|
if (proc->request_to_string) {
|
||||||
|
return proc->request_to_string(self, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *self,
|
||||||
|
guint event)
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||||
|
|
||||||
|
while (!proc->event_to_string && proc->base) {
|
||||||
|
proc = proc->base;
|
||||||
|
}
|
||||||
|
if (proc->event_to_string) {
|
||||||
|
return proc->event_to_string(self, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *self,
|
||||||
|
int tech, const char *profile, const char *apn,
|
||||||
|
const char *username, const char *password,
|
||||||
|
enum ril_auth auth, const char *proto)
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||||
|
|
||||||
|
while (!proc->data_call_req && proc->base) {
|
||||||
|
proc = proc->base;
|
||||||
|
}
|
||||||
|
if (proc->data_call_req) {
|
||||||
|
return proc->data_call_req(self, tech, profile, apn,
|
||||||
|
username, password, auth, proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *self,
|
||||||
|
struct ril_data_call *call, int ver, GRilIoParser *rilp)
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||||
|
|
||||||
|
while (!proc->data_call_parse && proc->base) {
|
||||||
|
proc = proc->base;
|
||||||
|
}
|
||||||
|
if (proc->data_call_parse) {
|
||||||
|
return proc->data_call_parse(self, call, ver, rilp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
103
ofono/drivers/ril/ril_vendor.h
Normal file
103
ofono/drivers/ril/ril_vendor.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_VENDOR_H
|
||||||
|
#define RIL_VENDOR_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
struct ril_vendor_defaults {
|
||||||
|
gboolean empty_pin_query;
|
||||||
|
gboolean legacy_imei_query;
|
||||||
|
gboolean enable_cbs;
|
||||||
|
gboolean query_available_band_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_vendor_driver {
|
||||||
|
const char *name;
|
||||||
|
const void *driver_data;
|
||||||
|
const struct ril_vendor_driver *base;
|
||||||
|
void (*get_defaults)(struct ril_vendor_defaults *defaults);
|
||||||
|
struct ril_vendor_hook *(*create_hook)(const void *driver_data,
|
||||||
|
GRilIoChannel *io, const char *path,
|
||||||
|
const struct ril_slot_config *cfg,
|
||||||
|
struct ril_network *network);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_vendor_hook_proc {
|
||||||
|
const struct ril_vendor_hook_proc *base;
|
||||||
|
const char *(*request_to_string)(struct ril_vendor_hook *hook,
|
||||||
|
guint request);
|
||||||
|
const char *(*event_to_string)(struct ril_vendor_hook *hook,
|
||||||
|
guint event);
|
||||||
|
GRilIoRequest *(*data_call_req)(struct ril_vendor_hook *hook,
|
||||||
|
int tech, const char *profile, const char *apn,
|
||||||
|
const char *username, const char *password,
|
||||||
|
enum ril_auth auth, const char *proto);
|
||||||
|
gboolean (*data_call_parse)(struct ril_vendor_hook *hook,
|
||||||
|
struct ril_data_call *call, int version,
|
||||||
|
GRilIoParser *rilp);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*ril_vendor_hook_free_proc)(struct ril_vendor_hook *hook);
|
||||||
|
struct ril_vendor_hook {
|
||||||
|
const struct ril_vendor_hook_proc *proc;
|
||||||
|
ril_vendor_hook_free_proc free;
|
||||||
|
gint ref_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_vendor_hook *ril_vendor_create_hook
|
||||||
|
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||||
|
const char *path, const struct ril_slot_config *cfg,
|
||||||
|
struct ril_network *network);
|
||||||
|
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
|
||||||
|
struct ril_vendor_defaults *defaults);
|
||||||
|
|
||||||
|
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *hook,
|
||||||
|
const struct ril_vendor_hook_proc *proc,
|
||||||
|
ril_vendor_hook_free_proc free);
|
||||||
|
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *hook);
|
||||||
|
void ril_vendor_hook_unref(struct ril_vendor_hook *hook);
|
||||||
|
|
||||||
|
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *hook,
|
||||||
|
guint request);
|
||||||
|
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *hook,
|
||||||
|
guint event);
|
||||||
|
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *hook,
|
||||||
|
int tech, const char *profile, const char *apn,
|
||||||
|
const char *username, const char *password,
|
||||||
|
enum ril_auth auth, const char *proto);
|
||||||
|
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *hook,
|
||||||
|
struct ril_data_call *call, int version,
|
||||||
|
GRilIoParser *rilp);
|
||||||
|
|
||||||
|
/* Put vendor driver descriptors to the "__vendor" section */
|
||||||
|
#define RIL_VENDOR_DRIVER_DEFINE(name) \
|
||||||
|
const struct ril_vendor_driver name \
|
||||||
|
__attribute__((used, section("__vendor"))) =
|
||||||
|
#define RIL_VENDOR_DRIVER_FOREACH(var) \
|
||||||
|
for ((var) = __start___vendor; (var) < __stop___vendor; (var)++)
|
||||||
|
extern const struct ril_vendor_driver __start___vendor[];
|
||||||
|
extern const struct ril_vendor_driver __stop___vendor[];
|
||||||
|
|
||||||
|
#endif /* RIL_VENDOR_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
654
ofono/drivers/ril/ril_vendor_mtk.c
Normal file
654
ofono/drivers/ril/ril_vendor_mtk.c
Normal file
@@ -0,0 +1,654 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_vendor.h"
|
||||||
|
#include "ril_network.h"
|
||||||
|
#include "ril_data.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "sailfish_watch.h"
|
||||||
|
|
||||||
|
#include <grilio_channel.h>
|
||||||
|
#include <grilio_parser.h>
|
||||||
|
#include <grilio_request.h>
|
||||||
|
#include <grilio_queue.h>
|
||||||
|
|
||||||
|
#include <gutil_macros.h>
|
||||||
|
|
||||||
|
#include "ofono.h"
|
||||||
|
|
||||||
|
#define SET_INITIAL_ATTACH_APN_TIMEOUT (20*1000)
|
||||||
|
|
||||||
|
enum ril_mtk_watch_events {
|
||||||
|
WATCH_EVENT_IMSI_CHANGED,
|
||||||
|
WATCH_EVENT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_mtk_network_events {
|
||||||
|
NETWORK_EVENT_PREF_MODE_CHANGED,
|
||||||
|
NETWORK_EVENT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_mtk_events {
|
||||||
|
MTK_EVENT_REGISTRATION_SUSPENDED,
|
||||||
|
MTK_EVENT_SET_ATTACH_APN,
|
||||||
|
MTK_EVENT_PS_NETWORK_STATE_CHANGED,
|
||||||
|
MTK_EVENT_INCOMING_CALL_INDICATION,
|
||||||
|
MTK_EVENT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_vendor_hook_mtk {
|
||||||
|
struct ril_vendor_hook hook;
|
||||||
|
const struct ril_mtk_msg *msg;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
GRilIoChannel *io;
|
||||||
|
struct ril_network *network;
|
||||||
|
struct sailfish_watch *watch;
|
||||||
|
guint set_initial_attach_apn_id;
|
||||||
|
gboolean initial_attach_apn_ok;
|
||||||
|
gulong network_event_id[NETWORK_EVENT_COUNT];
|
||||||
|
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||||
|
gulong ril_event_id[MTK_EVENT_COUNT];
|
||||||
|
guint slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* driver_data point this this: */
|
||||||
|
struct ril_vendor_mtk_driver_data {
|
||||||
|
const char *name;
|
||||||
|
const struct ril_mtk_msg *msg;
|
||||||
|
const struct ril_vendor_hook_proc *proc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Hook with auto-detection */
|
||||||
|
struct ril_vendor_hook_mtk_auto {
|
||||||
|
struct ril_vendor_hook_mtk mtk;
|
||||||
|
const struct ril_vendor_mtk_driver_data *type;
|
||||||
|
gulong detect_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* MTK specific RIL messages (actual codes differ from model to model!) */
|
||||||
|
struct ril_mtk_msg {
|
||||||
|
gboolean attach_apn_has_roaming_protocol;
|
||||||
|
guint request_resume_registration;
|
||||||
|
|
||||||
|
/* See ril_vendor_mtk_auto_detect_event */
|
||||||
|
#define unsol_msgs unsol_ps_network_state_changed
|
||||||
|
#define MTK_UNSOL_MSGS (4)
|
||||||
|
|
||||||
|
guint unsol_ps_network_state_changed;
|
||||||
|
guint unsol_registration_suspended;
|
||||||
|
guint unsol_incoming_call_indication;
|
||||||
|
guint unsol_set_attach_apn;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ril_mtk_msg msg_mtk1 = {
|
||||||
|
.attach_apn_has_roaming_protocol = TRUE,
|
||||||
|
.request_resume_registration = 2050,
|
||||||
|
.unsol_ps_network_state_changed = 3012,
|
||||||
|
.unsol_registration_suspended = 3021,
|
||||||
|
.unsol_incoming_call_indication = 3037,
|
||||||
|
.unsol_set_attach_apn = 3065
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ril_mtk_msg msg_mtk2 = {
|
||||||
|
.attach_apn_has_roaming_protocol = FALSE,
|
||||||
|
.request_resume_registration = 2065,
|
||||||
|
.unsol_ps_network_state_changed = 3015,
|
||||||
|
.unsol_registration_suspended = 3024,
|
||||||
|
.unsol_incoming_call_indication = 3042,
|
||||||
|
.unsol_set_attach_apn = 3073
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct ril_vendor_hook_mtk *ril_vendor_hook_mtk_cast
|
||||||
|
(struct ril_vendor_hook *hook)
|
||||||
|
{
|
||||||
|
return G_CAST(hook, struct ril_vendor_hook_mtk, hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct ril_vendor_hook_mtk_auto *ril_vendor_hook_mtk_auto_cast
|
||||||
|
(struct ril_vendor_hook *hook)
|
||||||
|
{
|
||||||
|
return G_CAST(hook, struct ril_vendor_hook_mtk_auto, mtk.hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *ril_vendor_mtk_request_to_string
|
||||||
|
(struct ril_vendor_hook *hook, guint request)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||||
|
const struct ril_mtk_msg *msg = self->msg;
|
||||||
|
|
||||||
|
if (request == msg->request_resume_registration) {
|
||||||
|
return "MTK_RESUME_REGISTRATION";
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *ril_vendor_mtk_unsol_msg_name(const struct ril_mtk_msg *msg,
|
||||||
|
guint event)
|
||||||
|
{
|
||||||
|
if (event == msg->unsol_ps_network_state_changed) {
|
||||||
|
return "MTK_PS_NETWORK_STATE_CHANGED";
|
||||||
|
} else if (event == msg->unsol_registration_suspended) {
|
||||||
|
return "MTK_REGISTRATION_SUSPENDED";
|
||||||
|
} else if (event == msg->unsol_set_attach_apn) {
|
||||||
|
return "MTK_SET_ATTACH_APN";
|
||||||
|
} else if (event == msg->unsol_incoming_call_indication) {
|
||||||
|
return "MTK_INCOMING_CALL_INDICATION";
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *ril_vendor_mtk_event_to_string(struct ril_vendor_hook *hook,
|
||||||
|
guint event)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||||
|
|
||||||
|
return ril_vendor_mtk_unsol_msg_name(self->msg, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = user_data;
|
||||||
|
const struct ril_mtk_msg *msg = self->msg;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int session_id;
|
||||||
|
|
||||||
|
GASSERT(id == msg->unsol_registration_suspended);
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
if (grilio_parser_get_int32(&rilp, NULL) &&
|
||||||
|
grilio_parser_get_int32(&rilp, &session_id)) {
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
DBG("slot=%u,session_id=%d", self->slot, session_id);
|
||||||
|
grilio_request_append_int32(req, 1);
|
||||||
|
grilio_request_append_int32(req, session_id);
|
||||||
|
grilio_queue_send_request(self->q, req,
|
||||||
|
msg->request_resume_registration);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GRilIoRequest *ril_vendor_mtk_build_set_attach_apn_req
|
||||||
|
(const struct ofono_gprs_primary_context *pc,
|
||||||
|
gboolean roamingProtocol)
|
||||||
|
{
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
const char *proto = ril_data_ofono_protocol_to_ril(pc->proto);
|
||||||
|
|
||||||
|
DBG("%s %d", pc->apn, roamingProtocol);
|
||||||
|
grilio_request_append_utf8(req, pc->apn); /* apn */
|
||||||
|
grilio_request_append_utf8(req, proto); /* protocol */
|
||||||
|
if (roamingProtocol) {
|
||||||
|
grilio_request_append_utf8(req, proto); /* roamingProtocol */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc->username[0]) {
|
||||||
|
int auth;
|
||||||
|
|
||||||
|
switch (pc->auth_method) {
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||||
|
auth = RIL_AUTH_BOTH;
|
||||||
|
break;
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||||
|
auth = RIL_AUTH_NONE;
|
||||||
|
break;
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||||
|
auth = RIL_AUTH_CHAP;
|
||||||
|
break;
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||||
|
auth = RIL_AUTH_PAP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
auth = RIL_AUTH_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, auth);
|
||||||
|
grilio_request_append_utf8(req, pc->username);
|
||||||
|
grilio_request_append_utf8(req, pc->password);
|
||||||
|
} else {
|
||||||
|
grilio_request_append_int32(req, RIL_AUTH_NONE);
|
||||||
|
grilio_request_append_utf8(req, "");
|
||||||
|
grilio_request_append_utf8(req, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_request_append_utf8(req, ""); /* operatorNumeric */
|
||||||
|
grilio_request_append_int32(req, FALSE); /* canHandleIms */
|
||||||
|
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct ofono_gprs_primary_context *ril_vendor_mtk_internet_context
|
||||||
|
(struct ril_vendor_hook_mtk *self)
|
||||||
|
{
|
||||||
|
struct sailfish_watch *watch = self->watch;
|
||||||
|
|
||||||
|
if (watch->imsi) {
|
||||||
|
struct ofono_atom *atom = __ofono_modem_find_atom(watch->modem,
|
||||||
|
OFONO_ATOM_TYPE_GPRS);
|
||||||
|
|
||||||
|
if (atom) {
|
||||||
|
return __ofono_gprs_context_settings_by_type
|
||||||
|
(__ofono_atom_get_data(atom),
|
||||||
|
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_initial_attach_apn_resp(GRilIoChannel *io,
|
||||||
|
int ril_status, const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = user_data;
|
||||||
|
|
||||||
|
GASSERT(self->set_initial_attach_apn_id);
|
||||||
|
self->set_initial_attach_apn_id = 0;
|
||||||
|
if (ril_status == RIL_E_SUCCESS) {
|
||||||
|
DBG("ok");
|
||||||
|
self->initial_attach_apn_ok = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_initial_attach_apn_check
|
||||||
|
(struct ril_vendor_hook_mtk *self)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!self->set_initial_attach_apn_id && !self->initial_attach_apn_ok) {
|
||||||
|
const struct ofono_gprs_primary_context *pc =
|
||||||
|
ril_vendor_mtk_internet_context(self);
|
||||||
|
|
||||||
|
if (pc) {
|
||||||
|
GRilIoRequest *req =
|
||||||
|
ril_vendor_mtk_build_set_attach_apn_req(pc,
|
||||||
|
self->msg->attach_apn_has_roaming_protocol);
|
||||||
|
|
||||||
|
grilio_request_set_timeout(req,
|
||||||
|
SET_INITIAL_ATTACH_APN_TIMEOUT);
|
||||||
|
self->set_initial_attach_apn_id =
|
||||||
|
grilio_queue_send_request_full(self->q, req,
|
||||||
|
RIL_REQUEST_SET_INITIAL_ATTACH_APN,
|
||||||
|
ril_vendor_mtk_initial_attach_apn_resp,
|
||||||
|
NULL, self);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_initial_attach_apn_reset
|
||||||
|
(struct ril_vendor_hook_mtk *self)
|
||||||
|
{
|
||||||
|
self->initial_attach_apn_ok = FALSE;
|
||||||
|
if (self->set_initial_attach_apn_id) {
|
||||||
|
grilio_queue_cancel_request(self->q,
|
||||||
|
self->set_initial_attach_apn_id, FALSE);
|
||||||
|
self->set_initial_attach_apn_id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_watch_imsi_changed(struct sailfish_watch *watch,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = user_data;
|
||||||
|
|
||||||
|
if (watch->imsi) {
|
||||||
|
ril_vendor_mtk_initial_attach_apn_check(self);
|
||||||
|
} else {
|
||||||
|
ril_vendor_mtk_initial_attach_apn_reset(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_network_pref_mode_changed(struct ril_network *net,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = user_data;
|
||||||
|
|
||||||
|
if (net->pref_mode >= OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||||
|
ril_vendor_mtk_initial_attach_apn_check(self);
|
||||||
|
} else {
|
||||||
|
ril_vendor_mtk_initial_attach_apn_reset(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
|
||||||
|
const void *data, guint len, void *self)
|
||||||
|
{
|
||||||
|
ril_vendor_mtk_initial_attach_apn_check(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_ps_network_state_changed(GRilIoChannel *io,
|
||||||
|
guint id, const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = user_data;
|
||||||
|
|
||||||
|
ril_network_query_registration_state(self->network);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_call_state_changed(GRilIoChannel *io,
|
||||||
|
guint id, const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
/* Ignore the payload, let ril_voicecall.c do its normal stuff */
|
||||||
|
grilio_channel_inject_unsol_event(io,
|
||||||
|
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GRilIoRequest *ril_vendor_mtk_data_call_req
|
||||||
|
(struct ril_vendor_hook *hook, int tech, const char *profile,
|
||||||
|
const char *apn, const char *username, const char *password,
|
||||||
|
enum ril_auth auth, const char *proto)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, 8); /* Number of parameters */
|
||||||
|
grilio_request_append_format(req, "%d", tech);
|
||||||
|
grilio_request_append_utf8(req, profile);
|
||||||
|
grilio_request_append_utf8(req, apn);
|
||||||
|
grilio_request_append_utf8(req, username);
|
||||||
|
grilio_request_append_utf8(req, password);
|
||||||
|
grilio_request_append_format(req, "%d", auth);
|
||||||
|
grilio_request_append_utf8(req, proto);
|
||||||
|
grilio_request_append_format(req, "%d", self->slot+1);
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_vendor_hook *hook,
|
||||||
|
struct ril_data_call *call, int version,
|
||||||
|
GRilIoParser *rilp)
|
||||||
|
{
|
||||||
|
if (version < 11) {
|
||||||
|
int prot;
|
||||||
|
char *prot_str;
|
||||||
|
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
|
||||||
|
guint32 active = RIL_DATA_CALL_INACTIVE;
|
||||||
|
|
||||||
|
/* RIL_Data_Call_Response_v6 with MTK specific additions */
|
||||||
|
grilio_parser_get_uint32(rilp, &status);
|
||||||
|
grilio_parser_get_int32(rilp, &call->retry_time);
|
||||||
|
grilio_parser_get_int32(rilp, &call->cid);
|
||||||
|
grilio_parser_get_uint32(rilp, &active);
|
||||||
|
grilio_parser_get_int32(rilp, &call->mtu); /* MTK specific */
|
||||||
|
prot_str = grilio_parser_get_utf8(rilp);
|
||||||
|
prot = ril_data_protocol_to_ofono(prot_str);
|
||||||
|
g_free(prot_str);
|
||||||
|
|
||||||
|
if (prot >= 0) {
|
||||||
|
call->ifname = grilio_parser_get_utf8(rilp);
|
||||||
|
call->addresses = grilio_parser_split_utf8(rilp, " ");
|
||||||
|
call->dnses = grilio_parser_split_utf8(rilp, " ");
|
||||||
|
call->gateways = grilio_parser_split_utf8(rilp, " ");
|
||||||
|
if (call->ifname && call->addresses) {
|
||||||
|
call->prot = prot;
|
||||||
|
call->status = status;
|
||||||
|
call->active = active;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* With most Qualcomm RIL implementations, querying available band
|
||||||
|
* modes causes some magic Android properties to appear. Otherwise
|
||||||
|
* this request is pretty harmless and useless.
|
||||||
|
*
|
||||||
|
* Most MediaTek RIL implementations don't support this request and
|
||||||
|
* don't even bother to reply which slows things down because we wait
|
||||||
|
* for this request to complete at startup.
|
||||||
|
*/
|
||||||
|
defaults->query_available_band_mode = FALSE;
|
||||||
|
defaults->empty_pin_query = FALSE;
|
||||||
|
defaults->legacy_imei_query = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_hook_subscribe(struct ril_vendor_hook_mtk *self)
|
||||||
|
{
|
||||||
|
const struct ril_mtk_msg *msg = self->msg;
|
||||||
|
|
||||||
|
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
|
||||||
|
grilio_channel_add_unsol_event_handler(self->io,
|
||||||
|
ril_vendor_mtk_registration_suspended,
|
||||||
|
msg->unsol_registration_suspended, self);
|
||||||
|
if (msg->unsol_set_attach_apn) {
|
||||||
|
self->ril_event_id[MTK_EVENT_SET_ATTACH_APN] =
|
||||||
|
grilio_channel_add_unsol_event_handler(self->io,
|
||||||
|
ril_vendor_mtk_set_attach_apn,
|
||||||
|
msg->unsol_set_attach_apn, self);
|
||||||
|
}
|
||||||
|
if (msg->unsol_ps_network_state_changed) {
|
||||||
|
self->ril_event_id[MTK_EVENT_PS_NETWORK_STATE_CHANGED] =
|
||||||
|
grilio_channel_add_unsol_event_handler(self->io,
|
||||||
|
ril_vendor_mtk_ps_network_state_changed,
|
||||||
|
msg->unsol_ps_network_state_changed, self);
|
||||||
|
}
|
||||||
|
if (msg->unsol_incoming_call_indication) {
|
||||||
|
self->ril_event_id[MTK_EVENT_INCOMING_CALL_INDICATION] =
|
||||||
|
grilio_channel_add_unsol_event_handler(self->io,
|
||||||
|
ril_vendor_mtk_call_state_changed,
|
||||||
|
msg->unsol_incoming_call_indication, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_hook_init(struct ril_vendor_hook_mtk *self,
|
||||||
|
const struct ril_vendor_mtk_driver_data *mtk_driver_data,
|
||||||
|
ril_vendor_hook_free_proc free, GRilIoChannel *io, const char *path,
|
||||||
|
const struct ril_slot_config *config, struct ril_network *network)
|
||||||
|
{
|
||||||
|
self->msg = mtk_driver_data->msg;
|
||||||
|
self->q = grilio_queue_new(io);
|
||||||
|
self->io = grilio_channel_ref(io);
|
||||||
|
self->watch = sailfish_watch_new(path);
|
||||||
|
self->slot = config->slot;
|
||||||
|
self->network = ril_network_ref(network);
|
||||||
|
self->watch_event_id[WATCH_EVENT_IMSI_CHANGED] =
|
||||||
|
sailfish_watch_add_imsi_changed_handler(self->watch,
|
||||||
|
ril_vendor_mtk_watch_imsi_changed, self);
|
||||||
|
self->network_event_id[NETWORK_EVENT_PREF_MODE_CHANGED] =
|
||||||
|
ril_network_add_pref_mode_changed_handler(self->network,
|
||||||
|
ril_vendor_mtk_network_pref_mode_changed, self);
|
||||||
|
ril_vendor_mtk_hook_subscribe(self);
|
||||||
|
ril_vendor_hook_init(&self->hook, mtk_driver_data->proc, free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_destroy(struct ril_vendor_hook_mtk *self)
|
||||||
|
{
|
||||||
|
grilio_queue_cancel_all(self->q, FALSE);
|
||||||
|
grilio_channel_remove_all_handlers(self->io, self->ril_event_id);
|
||||||
|
grilio_queue_unref(self->q);
|
||||||
|
grilio_channel_unref(self->io);
|
||||||
|
sailfish_watch_remove_all_handlers(self->watch, self->watch_event_id);
|
||||||
|
sailfish_watch_unref(self->watch);
|
||||||
|
ril_network_remove_all_handlers(self->network, self->network_event_id);
|
||||||
|
ril_network_unref(self->network);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_free(struct ril_vendor_hook *hook)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
|
||||||
|
|
||||||
|
DBG("slot %u", self->slot);
|
||||||
|
ril_vendor_mtk_destroy(self);
|
||||||
|
g_free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
|
||||||
|
(const void *driver_data, GRilIoChannel *io, const char *path,
|
||||||
|
const struct ril_slot_config *config,
|
||||||
|
struct ril_network *network)
|
||||||
|
{
|
||||||
|
const struct ril_vendor_mtk_driver_data *mtk_driver_data = driver_data;
|
||||||
|
struct ril_vendor_hook_mtk *self =
|
||||||
|
g_new0(struct ril_vendor_hook_mtk, 1);
|
||||||
|
|
||||||
|
ril_vendor_mtk_hook_init(self, mtk_driver_data, ril_vendor_mtk_free,
|
||||||
|
io, path, config, network);
|
||||||
|
DBG("%s slot %u", mtk_driver_data->name, self->slot);
|
||||||
|
return &self->hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct ril_vendor_hook_proc ril_vendor_mtk_hook_base_proc = {
|
||||||
|
.request_to_string = ril_vendor_mtk_request_to_string,
|
||||||
|
.event_to_string = ril_vendor_mtk_event_to_string,
|
||||||
|
.data_call_req = ril_vendor_mtk_data_call_req
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ril_vendor_driver ril_vendor_mtk_base = {
|
||||||
|
.get_defaults = ril_vendor_mtk_get_defaults,
|
||||||
|
.create_hook = ril_vendor_mtk_create_hook_from_data
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk1_data = {
|
||||||
|
.name = "mtk1",
|
||||||
|
.msg = &msg_mtk1,
|
||||||
|
.proc = &ril_vendor_mtk_hook_base_proc
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ril_vendor_hook_proc ril_vendor_mtk2_proc = {
|
||||||
|
.base = &ril_vendor_mtk_hook_base_proc,
|
||||||
|
.data_call_parse = ril_vendor_mtk_data_call_parse_v6
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk2_data = {
|
||||||
|
.name = "mtk2",
|
||||||
|
.msg = &msg_mtk2,
|
||||||
|
.proc = &ril_vendor_mtk2_proc
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_MTK_TYPE (&ril_vendor_mtk1_data)
|
||||||
|
|
||||||
|
static const struct ril_vendor_mtk_driver_data *mtk_types [] = {
|
||||||
|
&ril_vendor_mtk1_data,
|
||||||
|
&ril_vendor_mtk2_data
|
||||||
|
};
|
||||||
|
|
||||||
|
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk1) {
|
||||||
|
.name = "mtk1",
|
||||||
|
.driver_data = &ril_vendor_mtk1_data,
|
||||||
|
.base = &ril_vendor_mtk_base
|
||||||
|
};
|
||||||
|
|
||||||
|
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk2) {
|
||||||
|
.name = "mtk2",
|
||||||
|
.driver_data = &ril_vendor_mtk2_data,
|
||||||
|
.base = &ril_vendor_mtk_base
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Auto-selection */
|
||||||
|
|
||||||
|
static gboolean ril_vendor_mtk_auto_set_type
|
||||||
|
(struct ril_vendor_hook_mtk_auto *self,
|
||||||
|
const struct ril_vendor_mtk_driver_data *type)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||||
|
gboolean changed = FALSE;
|
||||||
|
|
||||||
|
if (self->type != type) {
|
||||||
|
DBG("switching type %s -> %s", self->type->name, type->name);
|
||||||
|
self->type = type;
|
||||||
|
mtk->msg = type->msg;
|
||||||
|
mtk->hook.proc = type->proc;
|
||||||
|
grilio_channel_remove_all_handlers(mtk->io, mtk->ril_event_id);
|
||||||
|
ril_vendor_mtk_hook_subscribe(mtk);
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_channel_remove_handler(mtk->io, self->detect_id);
|
||||||
|
self->detect_id = 0;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
|
||||||
|
const void *data, guint len, void *self)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS(mtk_types); i++) {
|
||||||
|
const struct ril_vendor_mtk_driver_data *type = mtk_types[i];
|
||||||
|
const struct ril_mtk_msg *msg = type->msg;
|
||||||
|
const guint *ids = &msg->unsol_msgs;
|
||||||
|
guint j;
|
||||||
|
|
||||||
|
for (j = 0; j < MTK_UNSOL_MSGS; j++) {
|
||||||
|
if (ids[j] == id) {
|
||||||
|
DBG("event %u is %s %s", id, type->name,
|
||||||
|
ril_vendor_mtk_unsol_msg_name(msg,id));
|
||||||
|
if (ril_vendor_mtk_auto_set_type(self, type)) {
|
||||||
|
/* And repeat the event to invoke
|
||||||
|
* the handler */
|
||||||
|
grilio_channel_inject_unsol_event(io,
|
||||||
|
id, data, len);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_vendor_mtk_auto_free(struct ril_vendor_hook *hook)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk_auto *self =
|
||||||
|
ril_vendor_hook_mtk_auto_cast(hook);
|
||||||
|
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||||
|
|
||||||
|
DBG("slot %u", mtk->slot);
|
||||||
|
grilio_channel_remove_handler(mtk->io, self->detect_id);
|
||||||
|
ril_vendor_mtk_destroy(mtk);
|
||||||
|
g_free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_auto
|
||||||
|
(const void *driver_data, GRilIoChannel *io, const char *path,
|
||||||
|
const struct ril_slot_config *cfg, struct ril_network *network)
|
||||||
|
{
|
||||||
|
struct ril_vendor_hook_mtk_auto *self =
|
||||||
|
g_new0(struct ril_vendor_hook_mtk_auto, 1);
|
||||||
|
struct ril_vendor_hook_mtk *mtk = &self->mtk;
|
||||||
|
|
||||||
|
/* Pick the default */
|
||||||
|
self->type = DEFAULT_MTK_TYPE;
|
||||||
|
ril_vendor_mtk_hook_init(mtk, self->type, ril_vendor_mtk_auto_free,
|
||||||
|
io, path, cfg, network);
|
||||||
|
DBG("%s slot %u", self->type->name, mtk->slot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subscribe for (all) unsolicited events. Keep on listening until
|
||||||
|
* we receive an MTK specific event that tells us which particular
|
||||||
|
* kind of MTK adaptation we are using.
|
||||||
|
*/
|
||||||
|
self->detect_id = grilio_channel_add_unsol_event_handler(mtk->io,
|
||||||
|
ril_vendor_mtk_auto_detect_event, 0, self);
|
||||||
|
return &mtk->hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk) {
|
||||||
|
.name = "mtk",
|
||||||
|
.get_defaults = ril_vendor_mtk_get_defaults,
|
||||||
|
.create_hook = ril_vendor_mtk_create_hook_auto
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -335,14 +335,18 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
|||||||
GASSERT(vd->clcc_poll_id);
|
GASSERT(vd->clcc_poll_id);
|
||||||
vd->clcc_poll_id = 0;
|
vd->clcc_poll_id = 0;
|
||||||
|
|
||||||
if (status != RIL_E_SUCCESS) {
|
/*
|
||||||
ofono_error("We are polling CLCC and received an error");
|
* Only RIL_E_SUCCESS and RIL_E_RADIO_NOT_AVAILABLE are expected here,
|
||||||
ofono_error("All bets are off for call management");
|
* all other errors are filtered out by ril_voicecall_clcc_retry()
|
||||||
return;
|
*/
|
||||||
|
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;
|
n = calls;
|
||||||
o = vd->calls;
|
o = vd->calls;
|
||||||
|
|
||||||
@@ -436,12 +440,25 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
|||||||
vd->calls = calls;
|
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)
|
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||||
{
|
{
|
||||||
GASSERT(vd);
|
GASSERT(vd);
|
||||||
if (!vd->clcc_poll_id) {
|
if (!vd->clcc_poll_id) {
|
||||||
GRilIoRequest* req = grilio_request_new();
|
GRilIoRequest* req = grilio_request_new();
|
||||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
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,
|
vd->clcc_poll_id = grilio_queue_send_request_full(vd->q,
|
||||||
req, RIL_REQUEST_GET_CURRENT_CALLS,
|
req, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||||
ril_voicecall_clcc_poll_cb, NULL, vd);
|
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);
|
||||||
|
}
|
||||||
@@ -61,6 +61,9 @@
|
|||||||
/* size of RIL_CellInfoTdscdma */
|
/* size of RIL_CellInfoTdscdma */
|
||||||
#define NETMON_RIL_CELLINFO_SIZE_TDSCDMA 24
|
#define NETMON_RIL_CELLINFO_SIZE_TDSCDMA 24
|
||||||
|
|
||||||
|
#define MSECS_RATE_INVALID (0x7fffffff)
|
||||||
|
#define SECS_TO_MSECS(x) ((x) * 1000)
|
||||||
|
|
||||||
struct netmon_data {
|
struct netmon_data {
|
||||||
GRil *ril;
|
GRil *ril;
|
||||||
};
|
};
|
||||||
@@ -96,11 +99,9 @@ static int ril_cell_type_to_size(int cell_type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
static int process_cellinfo_list(struct ril_msg *message,
|
||||||
|
struct ofono_netmon *netmon)
|
||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
|
||||||
ofono_netmon_cb_t cb = cbd->cb;
|
|
||||||
struct ofono_netmon *netmon = cbd->data;
|
|
||||||
struct parcel rilp;
|
struct parcel rilp;
|
||||||
int skip_len;
|
int skip_len;
|
||||||
int cell_info_cnt;
|
int cell_info_cnt;
|
||||||
@@ -114,7 +115,7 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
|||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if (message->error != RIL_E_SUCCESS)
|
if (message->error != RIL_E_SUCCESS)
|
||||||
goto error;
|
return OFONO_ERROR_TYPE_FAILURE;
|
||||||
|
|
||||||
g_ril_init_parcel(message, &rilp);
|
g_ril_init_parcel(message, &rilp);
|
||||||
|
|
||||||
@@ -146,7 +147,7 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!registered)
|
if (!registered)
|
||||||
goto error;
|
return OFONO_ERROR_TYPE_FAILURE;
|
||||||
|
|
||||||
if (cell_type == NETMON_RIL_CELLINFO_TYPE_GSM) {
|
if (cell_type == NETMON_RIL_CELLINFO_TYPE_GSM) {
|
||||||
mcc = parcel_r_int32(&rilp);
|
mcc = parcel_r_int32(&rilp);
|
||||||
@@ -216,17 +217,53 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
|||||||
OFONO_NETMON_INFO_BER, ber,
|
OFONO_NETMON_INFO_BER, ber,
|
||||||
OFONO_NETMON_INFO_INVALID);
|
OFONO_NETMON_INFO_INVALID);
|
||||||
|
|
||||||
} else {
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
return OFONO_ERROR_TYPE_NO_ERROR;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_netmon_cb_t cb = cbd->cb;
|
||||||
|
struct ofono_netmon *netmon = cbd->data;
|
||||||
|
|
||||||
|
if (process_cellinfo_list(message, netmon) ==
|
||||||
|
OFONO_ERROR_TYPE_NO_ERROR) {
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ril_cellinfo_notify(struct ril_msg *message, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_netmon *netmon = user_data;
|
||||||
|
|
||||||
|
process_cellinfo_list(message, netmon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_cell_info_notify(struct ofono_netmon *netmon)
|
||||||
|
{
|
||||||
|
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||||
|
struct parcel rilp;
|
||||||
|
|
||||||
|
parcel_init(&rilp);
|
||||||
|
|
||||||
|
parcel_w_int32(&rilp, 1); /* Number of elements */
|
||||||
|
|
||||||
|
parcel_w_int32(&rilp, MSECS_RATE_INVALID);
|
||||||
|
|
||||||
|
if (g_ril_send(nmd->ril, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||||
|
&rilp, NULL, NULL, NULL) == 0)
|
||||||
|
ofono_error("%s: setup failed\n", __func__);
|
||||||
|
|
||||||
|
if (g_ril_register(nmd->ril, RIL_UNSOL_CELL_INFO_LIST,
|
||||||
|
ril_cellinfo_notify, netmon) == 0)
|
||||||
|
ofono_error("%s: setup failed\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
static int ril_netmon_probe(struct ofono_netmon *netmon,
|
static int ril_netmon_probe(struct ofono_netmon *netmon,
|
||||||
unsigned int vendor, void *user)
|
unsigned int vendor, void *user)
|
||||||
{
|
{
|
||||||
@@ -237,6 +274,8 @@ static int ril_netmon_probe(struct ofono_netmon *netmon,
|
|||||||
|
|
||||||
ofono_netmon_set_data(netmon, ud);
|
ofono_netmon_set_data(netmon, ud);
|
||||||
|
|
||||||
|
setup_cell_info_notify(netmon);
|
||||||
|
|
||||||
g_idle_add(ril_delayed_register, netmon);
|
g_idle_add(ril_delayed_register, netmon);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -257,18 +296,55 @@ static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
|||||||
struct cb_data *cbd = cb_data_new(cb, data, nmd);
|
struct cb_data *cbd = cb_data_new(cb, data, nmd);
|
||||||
|
|
||||||
if (g_ril_send(nmd->ril, RIL_REQUEST_GET_CELL_INFO_LIST, NULL,
|
if (g_ril_send(nmd->ril, RIL_REQUEST_GET_CELL_INFO_LIST, NULL,
|
||||||
ril_netmon_update_cb, cbd, NULL) > 0)
|
ril_netmon_update_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
CALLBACK_WITH_FAILURE(cb, data);
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void periodic_update_cb(struct ril_msg *message, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_netmon_cb_t cb = cbd->cb;
|
||||||
|
|
||||||
|
if (message->error != RIL_E_SUCCESS)
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_periodic_update(struct ofono_netmon *netmon,
|
||||||
|
unsigned int enable, unsigned int period,
|
||||||
|
ofono_netmon_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data, nmd);
|
||||||
|
struct parcel rilp;
|
||||||
|
|
||||||
|
parcel_init(&rilp);
|
||||||
|
|
||||||
|
parcel_w_int32(&rilp, 1); /* Number of elements */
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
parcel_w_int32(&rilp, SECS_TO_MSECS(period));
|
||||||
|
else
|
||||||
|
parcel_w_int32(&rilp, MSECS_RATE_INVALID);
|
||||||
|
|
||||||
|
if (g_ril_send(nmd->ril, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||||
|
&rilp, periodic_update_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
static struct ofono_netmon_driver driver = {
|
static struct ofono_netmon_driver driver = {
|
||||||
.name = RILMODEM,
|
.name = RILMODEM,
|
||||||
.probe = ril_netmon_probe,
|
.probe = ril_netmon_probe,
|
||||||
.remove = ril_netmon_remove,
|
.remove = ril_netmon_remove,
|
||||||
.request_update = ril_netmon_request_update,
|
.request_update = ril_netmon_request_update,
|
||||||
|
.enable_periodic_update = ril_netmon_periodic_update,
|
||||||
};
|
};
|
||||||
|
|
||||||
void ril_netmon_init(void)
|
void ril_netmon_init(void)
|
||||||
|
|||||||
@@ -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 radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||||
struct cb_data *cbd = cb_data_new(cb, data, rs);
|
struct cb_data *cbd = cb_data_new(cb, data, rs);
|
||||||
struct parcel rilp;
|
struct parcel rilp;
|
||||||
int pref = PREF_NET_TYPE_GSM_WCDMA;
|
int pref = PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ static int rilmodem_init(void)
|
|||||||
ril_netmon_init();
|
ril_netmon_init();
|
||||||
ril_stk_init();
|
ril_stk_init();
|
||||||
ril_cbs_init();
|
ril_cbs_init();
|
||||||
|
ril_lte_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -78,6 +79,7 @@ static void rilmodem_exit(void)
|
|||||||
ril_netmon_exit();
|
ril_netmon_exit();
|
||||||
ril_stk_exit();
|
ril_stk_exit();
|
||||||
ril_cbs_exit();
|
ril_cbs_exit();
|
||||||
|
ril_lte_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,
|
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_init(void);
|
||||||
extern void ril_cbs_exit(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);
|
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,
|
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor,
|
||||||
void *user)
|
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,
|
g_ril_register(ril, RIL_UNSOL_STK_EVENT_NOTIFY,
|
||||||
ril_stk_event_notify, stk);
|
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;
|
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[384];
|
||||||
|
|
||||||
|
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)
|
static int telitmodem_init(void)
|
||||||
{
|
{
|
||||||
telit_location_reporting_init();
|
telit_location_reporting_init();
|
||||||
|
telitncm_gprs_context_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -42,6 +43,7 @@ static int telitmodem_init(void)
|
|||||||
static void telitmodem_exit(void)
|
static void telitmodem_exit(void)
|
||||||
{
|
{
|
||||||
telit_location_reporting_exit();
|
telit_location_reporting_exit();
|
||||||
|
telitncm_gprs_context_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
OFONO_PLUGIN_DEFINE(telitmodem, "Telit modem driver", VERSION,
|
OFONO_PLUGIN_DEFINE(telitmodem, "Telit modem driver", VERSION,
|
||||||
|
|||||||
@@ -23,3 +23,5 @@
|
|||||||
|
|
||||||
extern void telit_location_reporting_init();
|
extern void telit_location_reporting_init();
|
||||||
extern void telit_location_reporting_exit();
|
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 *none_prefix[] = { NULL };
|
||||||
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||||
|
static const char *uipaddr_prefix[] = { "+UIPADDR:", NULL };
|
||||||
|
|
||||||
struct gprs_context_data {
|
struct gprs_context_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
@@ -51,6 +52,44 @@ struct gprs_context_data {
|
|||||||
void *cb_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
|
* 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.
|
* 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 *laddrnetmask = NULL;
|
||||||
const char *gw = NULL;
|
const char *gw = NULL;
|
||||||
const char *dns[3] = { NULL, NULL, NULL };
|
const char *dns[3] = { NULL, NULL, NULL };
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
DBG("ok %d", ok);
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
@@ -159,6 +199,17 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
if (dns[0])
|
if (dns[0])
|
||||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
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);
|
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);
|
g_at_chat_unref(gcd->chat);
|
||||||
|
|
||||||
memset(gcd, 0, sizeof(*gcd));
|
memset(gcd, 0, sizeof(*gcd));
|
||||||
|
g_free(gcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ofono_gprs_context_driver driver = {
|
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
|
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||||
#include <ofono/plugin.h>
|
#include <ofono/plugin.h>
|
||||||
#include <ofono/types.h>
|
#include <ofono/types.h>
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
|
||||||
#include "ubloxmodem.h"
|
#include "ubloxmodem.h"
|
||||||
|
|
||||||
static int ubloxmodem_init(void)
|
static int ubloxmodem_init(void)
|
||||||
{
|
{
|
||||||
ublox_gprs_context_init();
|
ublox_gprs_context_init();
|
||||||
|
ublox_netmon_init();
|
||||||
|
ublox_lte_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -42,6 +45,8 @@ static int ubloxmodem_init(void)
|
|||||||
static void ubloxmodem_exit(void)
|
static void ubloxmodem_exit(void)
|
||||||
{
|
{
|
||||||
ublox_gprs_context_exit();
|
ublox_gprs_context_exit();
|
||||||
|
ublox_netmon_exit();
|
||||||
|
ublox_lte_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
OFONO_PLUGIN_DEFINE(ubloxmodem, "U-Blox Toby L2 high speed modem driver",
|
OFONO_PLUGIN_DEFINE(ubloxmodem, "U-Blox Toby L2 high speed modem driver",
|
||||||
|
|||||||
@@ -21,5 +21,13 @@
|
|||||||
|
|
||||||
#include <drivers/atmodem/atutil.h>
|
#include <drivers/atmodem/atutil.h>
|
||||||
|
|
||||||
|
#define UBLOXMODEM "ubloxmodem"
|
||||||
|
|
||||||
extern void ublox_gprs_context_init(void);
|
extern void ublox_gprs_context_init(void);
|
||||||
extern void ublox_gprs_context_exit(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);
|
||||||
|
|||||||
233
ofono/drivers/xmm7modem/radio-settings.c
Normal file
233
ofono/drivers/xmm7modem/radio-settings.c
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/log.h>
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
#include <ofono/radio-settings.h>
|
||||||
|
|
||||||
|
#include "gatchat.h"
|
||||||
|
#include "gatresult.h"
|
||||||
|
|
||||||
|
#include "xmm7modem.h"
|
||||||
|
|
||||||
|
static const char *none_prefix[] = { NULL };
|
||||||
|
static const char *xact_prefix[] = { "+XACT:", NULL };
|
||||||
|
|
||||||
|
struct radio_settings_data {
|
||||||
|
GAtChat *chat;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void xact_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||||
|
enum ofono_radio_access_mode mode;
|
||||||
|
struct ofono_error error;
|
||||||
|
GAtResultIter iter;
|
||||||
|
int value, preferred;
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
cb(&error, -1, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (g_at_result_iter_next(&iter, "+XACT:") == FALSE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (g_at_result_iter_next_number(&iter, &value) == FALSE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (g_at_result_iter_next_number(&iter, &preferred) == FALSE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(&error, mode, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xmm_query_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
|
if (g_at_chat_send(rsd->chat, "AT+XACT?", xact_prefix,
|
||||||
|
xact_query_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xact_modify_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
cb(&error, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xmm_set_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
enum ofono_radio_access_mode mode,
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
char buf[20];
|
||||||
|
int value = 6, preferred = 2;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||||
|
value = 6;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||||
|
value = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == 6)
|
||||||
|
snprintf(buf, sizeof(buf), "AT+XACT=%u,%u", value, preferred);
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "AT+XACT=%u", value);
|
||||||
|
|
||||||
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
|
xact_modify_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xact_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_radio_settings *rs = user_data;
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
ofono_radio_settings_remove(rs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_radio_settings_register(rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xmm_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||||
|
unsigned int vendor, void *user)
|
||||||
|
{
|
||||||
|
GAtChat *chat = user;
|
||||||
|
struct radio_settings_data *rsd;
|
||||||
|
|
||||||
|
rsd = g_try_new0(struct radio_settings_data, 1);
|
||||||
|
if (rsd == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rsd->chat = g_at_chat_clone(chat);
|
||||||
|
|
||||||
|
ofono_radio_settings_set_data(rs, rsd);
|
||||||
|
|
||||||
|
g_at_chat_send(rsd->chat, "AT+XACT=?", xact_prefix,
|
||||||
|
xact_support_cb, rs, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xmm_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||||
|
{
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
ofono_radio_settings_set_data(rs, NULL);
|
||||||
|
|
||||||
|
g_at_chat_unref(rsd->chat);
|
||||||
|
g_free(rsd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ofono_radio_settings_driver driver = {
|
||||||
|
.name = "xmm7modem",
|
||||||
|
.probe = xmm_radio_settings_probe,
|
||||||
|
.remove = xmm_radio_settings_remove,
|
||||||
|
.query_rat_mode = xmm_query_rat_mode,
|
||||||
|
.set_rat_mode = xmm_set_rat_mode
|
||||||
|
};
|
||||||
|
|
||||||
|
void xmm_radio_settings_init(void)
|
||||||
|
{
|
||||||
|
ofono_radio_settings_driver_register(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xmm_radio_settings_exit(void)
|
||||||
|
{
|
||||||
|
ofono_radio_settings_driver_unregister(&driver);
|
||||||
|
}
|
||||||
50
ofono/drivers/xmm7modem/xmm7modem.c
Normal file
50
ofono/drivers/xmm7modem/xmm7modem.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gatchat.h>
|
||||||
|
|
||||||
|
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||||
|
#include <ofono/plugin.h>
|
||||||
|
#include <ofono/types.h>
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
|
||||||
|
#include "xmm7modem.h"
|
||||||
|
|
||||||
|
static int xmm7modem_init(void)
|
||||||
|
{
|
||||||
|
xmm_radio_settings_init();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xmm7modem_exit(void)
|
||||||
|
{
|
||||||
|
xmm_radio_settings_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
OFONO_PLUGIN_DEFINE(xmm7modem, "Intel xmm7xxx series modem driver",
|
||||||
|
VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||||
|
xmm7modem_init, xmm7modem_exit)
|
||||||
27
ofono/drivers/xmm7modem/xmm7modem.h
Normal file
27
ofono/drivers/xmm7modem/xmm7modem.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <drivers/atmodem/atutil.h>
|
||||||
|
|
||||||
|
#define XMM7MODEM "xmm7modem"
|
||||||
|
|
||||||
|
extern void xmm_radio_settings_init(void);
|
||||||
|
extern void xmm_radio_settings_exit(void);
|
||||||
@@ -116,66 +116,109 @@ static inline void debug(GAtMux *mux, const char *format, ...)
|
|||||||
|
|
||||||
static void dispatch_sources(GAtMuxChannel *channel, GIOCondition condition)
|
static void dispatch_sources(GAtMuxChannel *channel, GIOCondition condition)
|
||||||
{
|
{
|
||||||
GAtMuxWatch *source;
|
|
||||||
GSList *c;
|
GSList *c;
|
||||||
GSList *p;
|
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;
|
p = NULL;
|
||||||
c = channel->sources;
|
c = channel->sources;
|
||||||
|
|
||||||
while (c) {
|
while (c) {
|
||||||
gboolean destroy = FALSE;
|
GSList *n = c->next;
|
||||||
|
GSource *s = c->data;
|
||||||
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);
|
|
||||||
|
|
||||||
|
if (g_source_is_destroyed(s)) {
|
||||||
if (p)
|
if (p)
|
||||||
p->next = c->next;
|
p->next = n;
|
||||||
else
|
else
|
||||||
channel->sources = c->next;
|
channel->sources = n;
|
||||||
|
|
||||||
t = c;
|
g_slist_free_1(c);
|
||||||
c = c->next;
|
|
||||||
g_slist_free_1(t);
|
|
||||||
} else {
|
} else {
|
||||||
p = c;
|
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,
|
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)
|
static void watch_finalize(GSource *source)
|
||||||
{
|
{
|
||||||
GAtMuxWatch *watch = (GAtMuxWatch *) source;
|
GAtMuxWatch *watch = (GAtMuxWatch *) source;
|
||||||
|
GAtMuxChannel *dlc = (GAtMuxChannel *) watch->channel;
|
||||||
|
|
||||||
|
dlc->sources = g_slist_remove(dlc->sources, watch);
|
||||||
g_io_channel_unref(watch->channel);
|
g_io_channel_unref(watch->channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,6 +684,9 @@ gboolean g_at_mux_shutdown(GAtMux *mux)
|
|||||||
if (mux->read_watch > 0)
|
if (mux->read_watch > 0)
|
||||||
g_source_remove(mux->read_watch);
|
g_source_remove(mux->read_watch);
|
||||||
|
|
||||||
|
if (mux->write_watch > 0)
|
||||||
|
g_source_remove(mux->write_watch);
|
||||||
|
|
||||||
for (i = 0; i < MAX_CHANNELS; i++) {
|
for (i = 0; i < MAX_CHANNELS; i++) {
|
||||||
if (mux->dlcs[i] == NULL)
|
if (mux->dlcs[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
#include "crc-ccitt.h"
|
#include "crc-ccitt.h"
|
||||||
#include "ppp.h"
|
#include "ppp.h"
|
||||||
|
|
||||||
#define DEFAULT_MRU 1500
|
|
||||||
#define DEFAULT_MTU 1500
|
#define DEFAULT_MTU 1500
|
||||||
|
|
||||||
#define PPP_ADDR_FIELD 0xff
|
#define PPP_ADDR_FIELD 0xff
|
||||||
@@ -66,7 +65,6 @@ struct _GAtPPP {
|
|||||||
struct ppp_chap *chap;
|
struct ppp_chap *chap;
|
||||||
struct ppp_pap *pap;
|
struct ppp_pap *pap;
|
||||||
GAtHDLC *hdlc;
|
GAtHDLC *hdlc;
|
||||||
gint mru;
|
|
||||||
gint mtu;
|
gint mtu;
|
||||||
char username[256];
|
char username[256];
|
||||||
char password[256];
|
char password[256];
|
||||||
@@ -830,7 +828,6 @@ static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
|
|||||||
ppp->fd = -1;
|
ppp->fd = -1;
|
||||||
|
|
||||||
/* set options to defaults */
|
/* set options to defaults */
|
||||||
ppp->mru = DEFAULT_MRU;
|
|
||||||
ppp->mtu = DEFAULT_MTU;
|
ppp->mtu = DEFAULT_MTU;
|
||||||
|
|
||||||
/* initialize the lcp state */
|
/* initialize the lcp state */
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user