forked from sailfishos/ofono
Compare commits
483 Commits
mer/1.21+g
...
mer/1.23+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08bae57a2b | ||
|
|
1915aeda76 | ||
|
|
51bfb17cbc | ||
|
|
a83b553032 | ||
|
|
ec00abd62d | ||
|
|
80924d5787 | ||
|
|
2bdd05aa31 | ||
|
|
544f02e5a2 | ||
|
|
6d4638f9bf | ||
|
|
6584919e9d | ||
|
|
34fb44f4eb | ||
|
|
c98d2f41c5 | ||
|
|
b279be4528 | ||
|
|
a7912fea39 | ||
|
|
f291cea905 | ||
|
|
68f7d30b77 | ||
|
|
890a2697fe | ||
|
|
9568c8449b | ||
|
|
cf91be9742 | ||
|
|
087771dc0f | ||
|
|
645dfe47e5 | ||
|
|
68e8b02d3b | ||
|
|
aa4309e8cb | ||
|
|
cb6b24d950 | ||
|
|
6d1ab13c74 | ||
|
|
45424a3f96 | ||
|
|
4f7398e39d | ||
|
|
cd118ce70b | ||
|
|
99d4ce538e | ||
|
|
9b2c4bcf76 | ||
|
|
0122db04a3 | ||
|
|
021db194cb | ||
|
|
e0a0896205 | ||
|
|
49d0bbbb28 | ||
|
|
9193d06b77 | ||
|
|
b0cd3e4544 | ||
|
|
29cce6969b | ||
|
|
b87f666e4b | ||
|
|
1c1e4fa28b | ||
|
|
f597119845 | ||
|
|
633888932d | ||
|
|
a37f325d4a | ||
|
|
0afceac554 | ||
|
|
109751bcc0 | ||
|
|
30dfbf8fd7 | ||
|
|
c7aab2e790 | ||
|
|
412a2a0e7f | ||
|
|
f1aeedd113 | ||
|
|
639fce8eca | ||
|
|
9cfd0a195e | ||
|
|
cf2d8488cc | ||
|
|
ab0ac10abd | ||
|
|
b2df7de223 | ||
|
|
b56930a87f | ||
|
|
f65e8dd5af | ||
|
|
f2439243b2 | ||
|
|
93ff644856 | ||
|
|
08f8555d51 | ||
|
|
04b2a9b0f9 | ||
|
|
4d513b68d2 | ||
|
|
36f971dc78 | ||
|
|
8ba2d96cff | ||
|
|
a76f50be67 | ||
|
|
43227086c0 | ||
|
|
e40811fbc6 | ||
|
|
8c543b054a | ||
|
|
53233b4dc8 | ||
|
|
4458fbf844 | ||
|
|
542a086d93 | ||
|
|
1176662a81 | ||
|
|
ae29a08a76 | ||
|
|
af1a569430 | ||
|
|
a75558031b | ||
|
|
139fff2e5d | ||
|
|
12614d377a | ||
|
|
463f4f183e | ||
|
|
0ba7505f1e | ||
|
|
c1156320ac | ||
|
|
afe4fc66f0 | ||
|
|
c04b14c49a | ||
|
|
4d6aefcea5 | ||
|
|
c3c4b21c32 | ||
|
|
5ffc3fc426 | ||
|
|
690d62820a | ||
|
|
f1fbd04d66 | ||
|
|
8eaf694b9a | ||
|
|
5087fd9dd7 | ||
|
|
92aebc3ce8 | ||
|
|
c0a5b0fdf3 | ||
|
|
587879b6c2 | ||
|
|
f9ca5c30a6 | ||
|
|
3f9dff449f | ||
|
|
d554061955 | ||
|
|
3ae306ed57 | ||
|
|
6448c0c270 | ||
|
|
e521938d95 | ||
|
|
80158ea5bc | ||
|
|
bfba3e2312 | ||
|
|
e4fc7b9b0c | ||
|
|
f1ec346941 | ||
|
|
9f9bb11a66 | ||
|
|
cf3143bb69 | ||
|
|
56f46a80c0 | ||
|
|
6fb02515f0 | ||
|
|
4efb502fad | ||
|
|
842331f701 | ||
|
|
f743c89bc8 | ||
|
|
20d9835aed | ||
|
|
f4c24f5f83 | ||
|
|
6c07b110c7 | ||
|
|
6205fad90f | ||
|
|
9b7358e5e5 | ||
|
|
502cd55c4e | ||
|
|
103b20bcfd | ||
|
|
8b083e0121 | ||
|
|
8b1fc771ea | ||
|
|
7bb19531cd | ||
|
|
252df1349a | ||
|
|
5a2d64371c | ||
|
|
6995849600 | ||
|
|
69149b3039 | ||
|
|
77eb51bc39 | ||
|
|
d05b1137d5 | ||
|
|
9eae00b28b | ||
|
|
48a6492a68 | ||
|
|
443898d8ef | ||
|
|
23718794cc | ||
|
|
450c5f9b69 | ||
|
|
4f6b8b7243 | ||
|
|
3eec92ec7a | ||
|
|
4216026a7c | ||
|
|
9eb2820397 | ||
|
|
f33550f37f | ||
|
|
020dc3020e | ||
|
|
ad0b9e6303 | ||
|
|
d773d28dad | ||
|
|
4d9fea27ea | ||
|
|
c4a8186f7a | ||
|
|
2c5f1a6626 | ||
|
|
dcb057802f | ||
|
|
fd889b3fac | ||
|
|
fe3f46f29b | ||
|
|
b8eae5f967 | ||
|
|
d818544d92 | ||
|
|
dc1377eb0a | ||
|
|
06599ff36d | ||
|
|
4d2ef8b2da | ||
|
|
cc7f5796bb | ||
|
|
65d2b1306a | ||
|
|
b484003494 | ||
|
|
8a6ec5e645 | ||
|
|
fdc4b27b05 | ||
|
|
9b338c4055 | ||
|
|
fbaf86d862 | ||
|
|
d5c6316a13 | ||
|
|
bf092b518c | ||
|
|
9de95af924 | ||
|
|
5988c88968 | ||
|
|
354793cbe3 | ||
|
|
259c6e2617 | ||
|
|
aa88654d09 | ||
|
|
50499bc69d | ||
|
|
8c64f94743 | ||
|
|
0eabc3ea79 | ||
|
|
8116bd13d1 | ||
|
|
30bbccfd91 | ||
|
|
028a6ab1c7 | ||
|
|
32607771b5 | ||
|
|
d37dfc1ad1 | ||
|
|
e0bfba6fbe | ||
|
|
414791a6f0 | ||
|
|
3fa059a027 | ||
|
|
540b558147 | ||
|
|
6bfb0d07ab | ||
|
|
19a8a137c1 | ||
|
|
11913b2a44 | ||
|
|
2a1e29ab9e | ||
|
|
a64cc4d5b9 | ||
|
|
f464a7c6c1 | ||
|
|
daceb07bb1 | ||
|
|
f9ef31cd5c | ||
|
|
c3c3bab6a2 | ||
|
|
08f0bb08f1 | ||
|
|
ce2b18ede2 | ||
|
|
5f9e43c2da | ||
|
|
2ee038a457 | ||
|
|
3a4f63171f | ||
|
|
64878cced6 | ||
|
|
3f115b2d0d | ||
|
|
c66eec1b1e | ||
|
|
85d1eda7c9 | ||
|
|
08d8d5de73 | ||
|
|
172c97df83 | ||
|
|
1e3e413714 | ||
|
|
15ef3c9c0e | ||
|
|
e9eb113a22 | ||
|
|
abdfb38006 | ||
|
|
79e22d4570 | ||
|
|
aab791f2ad | ||
|
|
90c0ffddea | ||
|
|
a3149c53d9 | ||
|
|
b02a37a9c5 | ||
|
|
eecf9fde2c | ||
|
|
f2bb5d08ba | ||
|
|
d44a1af644 | ||
|
|
50fbd5351b | ||
|
|
9c8700b5c6 | ||
|
|
9221153db9 | ||
|
|
8997e02997 | ||
|
|
7121855966 | ||
|
|
0d013c3f9b | ||
|
|
e2299cbddc | ||
|
|
34cd275117 | ||
|
|
2396ead477 | ||
|
|
32dc1d1806 | ||
|
|
aed679d6da | ||
|
|
baea6fb7e9 | ||
|
|
ba64ce870f | ||
|
|
1e25fbbcbf | ||
|
|
d13339af6c | ||
|
|
890f3235cb | ||
|
|
2603419fa4 | ||
|
|
1abdcc9226 | ||
|
|
928a905cce | ||
|
|
f241580817 | ||
|
|
26826c15c9 | ||
|
|
5b3a045e6c | ||
|
|
c8a08bd815 | ||
|
|
53d1f1ce03 | ||
|
|
1aec6df272 | ||
|
|
b43df906ca | ||
|
|
1d42a2a6a9 | ||
|
|
bab1cb2479 | ||
|
|
a8be51ceef | ||
|
|
a658ec7e77 | ||
|
|
960db7cf2b | ||
|
|
842fe25bcd | ||
|
|
7aa2cbb8cb | ||
|
|
612b295eae | ||
|
|
168919770d | ||
|
|
b603be82ee | ||
|
|
bbeaadd191 | ||
|
|
99d7c4e884 | ||
|
|
9753700d58 | ||
|
|
7772c8971b | ||
|
|
13b39ba633 | ||
|
|
77ac688c5e | ||
|
|
f4bbba9547 | ||
|
|
17f5b9faa5 | ||
|
|
4b266cfbfd | ||
|
|
e56998d640 | ||
|
|
b87fb13b7b | ||
|
|
32753de8a7 | ||
|
|
331c6e98d2 | ||
|
|
69f1b7b36f | ||
|
|
ca6447102f | ||
|
|
9b3dc8143d | ||
|
|
919df873f3 | ||
|
|
7aed70b642 | ||
|
|
0776d5b19b | ||
|
|
ca4c2c4a07 | ||
|
|
eab88cd6cb | ||
|
|
0be2675072 | ||
|
|
d226729730 | ||
|
|
417bbaa963 | ||
|
|
9974013cce | ||
|
|
53e07c0932 | ||
|
|
edce8b06c6 | ||
|
|
8d72007e95 | ||
|
|
ffa0e801a3 | ||
|
|
f6c7117097 | ||
|
|
3d9013eea8 | ||
|
|
b76517559b | ||
|
|
6bdb51dc29 | ||
|
|
4f066a2133 | ||
|
|
61d87e5cf9 | ||
|
|
3d33bea585 | ||
|
|
a741db6087 | ||
|
|
f9a175b1a8 | ||
|
|
04133f8316 | ||
|
|
2e6ae0f001 | ||
|
|
432c05928b | ||
|
|
38054818ed | ||
|
|
f3e4550d67 | ||
|
|
a91c8de5c2 | ||
|
|
9c29518418 | ||
|
|
951e9439d4 | ||
|
|
7cd984aa1a | ||
|
|
06227e5e50 | ||
|
|
bba23c3095 | ||
|
|
a892edaea5 | ||
|
|
2ede8f2464 | ||
|
|
1759502c96 | ||
|
|
134efba989 | ||
|
|
9331cc1ecb | ||
|
|
7c8da34a38 | ||
|
|
a05523974e | ||
|
|
71ef390b4a | ||
|
|
717f6452aa | ||
|
|
0803c21840 | ||
|
|
095060b001 | ||
|
|
c2971da092 | ||
|
|
f07424f0aa | ||
|
|
266a52a40a | ||
|
|
eeea5476d1 | ||
|
|
e38a63d179 | ||
|
|
0ff8608ac3 | ||
|
|
5a330b9852 | ||
|
|
78a9323619 | ||
|
|
8267e206eb | ||
|
|
fac7684958 | ||
|
|
6ba3170ce2 | ||
|
|
b29730b268 | ||
|
|
e095636c97 | ||
|
|
6fef5444fb | ||
|
|
0e62e613e8 | ||
|
|
c08be69130 | ||
|
|
419caedc2c | ||
|
|
ee6a307804 | ||
|
|
412d8c3d4d | ||
|
|
0efebd16d9 | ||
|
|
7a6928c02f | ||
|
|
ec134e68d2 | ||
|
|
a8be769c87 | ||
|
|
a2d87f64c4 | ||
|
|
3ecd55a205 | ||
|
|
d8ea82b2f1 | ||
|
|
c95fe16a9b | ||
|
|
55e923250a | ||
|
|
f5653ae240 | ||
|
|
ecf23c1333 | ||
|
|
e71036f7d7 | ||
|
|
b8e8b930f8 | ||
|
|
65a3f7ee46 | ||
|
|
26c5c4bfa3 | ||
|
|
2d35e5e28d | ||
|
|
ae78d9a946 | ||
|
|
243dd7d17c | ||
|
|
acaafafbb9 | ||
|
|
4f378c806b | ||
|
|
bd33ff471c | ||
|
|
d423608e46 | ||
|
|
3b708effd9 | ||
|
|
f01722cca5 | ||
|
|
f62d53fbd0 | ||
|
|
942aee3f25 | ||
|
|
ecc83568fd | ||
|
|
c911c05fcb | ||
|
|
680979f782 | ||
|
|
250a6abb71 | ||
|
|
6c5d2ab803 | ||
|
|
bf8cb3995c | ||
|
|
8973e52e45 | ||
|
|
0e8dc3605e | ||
|
|
537a39f94a | ||
|
|
c3d93e83d7 | ||
|
|
7cdf3db124 | ||
|
|
398942c78e | ||
|
|
26e39508ad | ||
|
|
a16fcd0d37 | ||
|
|
432e700272 | ||
|
|
aa694b592f | ||
|
|
c5c8b72761 | ||
|
|
2ab7aa0f97 | ||
|
|
549fe2355f | ||
|
|
7493187e47 | ||
|
|
9a3d8d671c | ||
|
|
39eac13743 | ||
|
|
6329bb8639 | ||
|
|
75b07c5c80 | ||
|
|
4f6f964ca4 | ||
|
|
7af95f6db5 | ||
|
|
99f4667eb7 | ||
|
|
c1c3ecab31 | ||
|
|
83dc99658c | ||
|
|
9a7b538087 | ||
|
|
9f7a1ffe3f | ||
|
|
1f81ec7d9d | ||
|
|
6e833401cc | ||
|
|
d9c68c4fb9 | ||
|
|
9e6f7721a0 | ||
|
|
9c529dcdcc | ||
|
|
41814c6e6a | ||
|
|
cf99a5769f | ||
|
|
076e2f0ef1 | ||
|
|
fd76cb72ad | ||
|
|
554e4ab8e5 | ||
|
|
08f3da7577 | ||
|
|
2cbd3b6050 | ||
|
|
78d3d1892d | ||
|
|
1448bd2320 | ||
|
|
ea8dfb48ab | ||
|
|
80921e8b7e | ||
|
|
e4cc912719 | ||
|
|
c5f736d3c3 | ||
|
|
ddf4cec9b8 | ||
|
|
685d0b34d7 | ||
|
|
896f2f7a71 | ||
|
|
e96aacb9e7 | ||
|
|
91560afeec | ||
|
|
09fb8635c9 | ||
|
|
1cb80d7d2f | ||
|
|
7db5552e79 | ||
|
|
d87e40d0ff | ||
|
|
35131ff56b | ||
|
|
c5cc678b2b | ||
|
|
31be9a099b | ||
|
|
ccaf993977 | ||
|
|
74d633c58e | ||
|
|
f870880cf9 | ||
|
|
50c06afc73 | ||
|
|
e4e0ccd51d | ||
|
|
ee052af454 | ||
|
|
296b272274 | ||
|
|
9b9e5159f5 | ||
|
|
fa8002200c | ||
|
|
4cc71c78ec | ||
|
|
27b31e65bb | ||
|
|
e26d365a94 | ||
|
|
63f06cd11c | ||
|
|
96ca3aa907 | ||
|
|
11a84853fe | ||
|
|
a393cf0b11 | ||
|
|
6f263ee8d5 | ||
|
|
92a4760f46 | ||
|
|
c43d41829f | ||
|
|
25638a30c0 | ||
|
|
ed669bf66c | ||
|
|
e01dbd2b21 | ||
|
|
a8f0f26df8 | ||
|
|
56c84395ba | ||
|
|
3bf2b1df5c | ||
|
|
75041ccc37 | ||
|
|
e91ef8a701 | ||
|
|
620a20abdc | ||
|
|
d85fa8a64d | ||
|
|
d33b20889b | ||
|
|
cb8801752c | ||
|
|
a0722f8538 | ||
|
|
e016281b86 | ||
|
|
781a528625 | ||
|
|
5b1ab91b77 | ||
|
|
9604d9ef0a | ||
|
|
598acaa1a8 | ||
|
|
60193032f5 | ||
|
|
9faf27ec28 | ||
|
|
32c26c5a35 | ||
|
|
79fb591342 | ||
|
|
f6e46f78e3 | ||
|
|
7c587772d1 | ||
|
|
0d0728593b | ||
|
|
fd3916b2c7 | ||
|
|
c35557c2ed | ||
|
|
bb07543dd6 | ||
|
|
d346f1289c | ||
|
|
e170b6df4c | ||
|
|
761cd320bb | ||
|
|
60bc47aea2 | ||
|
|
183e4dab4b | ||
|
|
d6cdfc92ad | ||
|
|
b68752640c | ||
|
|
a53fc6ea7e | ||
|
|
63fe971077 | ||
|
|
011f3b74d1 | ||
|
|
4d2e314ad6 | ||
|
|
d846618057 | ||
|
|
38115199f7 | ||
|
|
f88c7ce919 | ||
|
|
9d6b3ec124 | ||
|
|
6dcf5cebc1 | ||
|
|
0e87392c90 | ||
|
|
dab76692db | ||
|
|
21bc90f638 | ||
|
|
d8707d52be | ||
|
|
fa0abf892d | ||
|
|
8a28d4eea8 | ||
|
|
4f0be99683 | ||
|
|
95933beb2d | ||
|
|
018a712e29 | ||
|
|
e6777f1ecc | ||
|
|
a58e1a5e9b | ||
|
|
61be41240f | ||
|
|
dbb40560c6 |
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>
|
||||
15
ofono/.gitignore
vendored
15
ofono/.gitignore
vendored
@@ -32,6 +32,8 @@ src/ofono.service
|
||||
dundee/dundee
|
||||
dundee/dundee.service
|
||||
|
||||
test-driver
|
||||
test-suite.log
|
||||
unit/test-common
|
||||
unit/test-util
|
||||
unit/test-idmap
|
||||
@@ -42,20 +44,31 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-dbus-access
|
||||
unit/test-dbus-queue
|
||||
unit/test-gprs-filter
|
||||
unit/test-ril_config
|
||||
unit/test-ril_ecclist
|
||||
unit/test-ril_util
|
||||
unit/test-ril_vendor
|
||||
unit/test-ril-transport
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
unit/test-rilmodem-sms
|
||||
unit/test-sailfish_access
|
||||
unit/test-sailfish_cell_info
|
||||
unit/test-sailfish_cell_info_dbus
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sailfish_sim_info_dbus
|
||||
unit/test-sailfish_watch
|
||||
unit/test-config
|
||||
unit/test-watch
|
||||
unit/test-sms-filter
|
||||
unit/test-voicecall-filter
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
unit/test-mbim
|
||||
|
||||
unit/test-grilreply
|
||||
unit/test-grilrequest
|
||||
|
||||
@@ -115,6 +115,7 @@ Antara Borwankar <antara.borwankar@gmail.com>
|
||||
Martin Chaplet <m.chaplet@kerlink.fr>
|
||||
Suman Mallela <suman.m@intel.com>
|
||||
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
|
||||
Ankit Navik <ankit.p.navik@intel.com>
|
||||
Antoine Aubert <a.aubert@overkiz.com>
|
||||
Djalal Harouni <djalal@endocode.com>
|
||||
Christophe Ronco <c.ronco@kerlink.fr>
|
||||
@@ -126,3 +127,6 @@ Jonas Bonn <jonas@southpole.se>
|
||||
Matthijs Kooijman <matthijs@stdin.nl>
|
||||
Clayton Craft <clayton@craftyguy.net>
|
||||
Joey Hewitt <joey@joeyhewitt.com>
|
||||
Richard Röjfors <richard.rojfors@gmail.com>
|
||||
Philippe De Swert <philippe.deswert@nomovok.com>
|
||||
Gabriel Lucas <gabriel.lucas@smile.fr>
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
ver 1.23:
|
||||
Fix issue with handling SIM AID sessions.
|
||||
Add support for QMI LTE bearer handling.
|
||||
Add support for memory location dialing.
|
||||
|
||||
ver 1.22:
|
||||
Fix issue with GPIO handling and Nokia modems.
|
||||
Fix issue with SIM state callback and AT modems.
|
||||
Fix issue with data mode and DCD for U-Blox modems.
|
||||
Fix issue with SMS receive on QMI based Quectel EC21.
|
||||
Fix issue with HFP support and last call dialed request.
|
||||
Fix issue with PIM retires handling and Gemalto modems.
|
||||
Fix issue with atom registration and SIM state handling.
|
||||
Add support for handling SIM card AID session management.
|
||||
Add support for handling GSM/UMTS and IMS authentication.
|
||||
Add support for IP Multimedia Subsystem (IMS) atom.
|
||||
Add support for MBIM based modems.
|
||||
|
||||
ver 1.21:
|
||||
Fix issue with USSD notification received handling.
|
||||
Fix issue with crashing SIM filesystem notifications.
|
||||
|
||||
@@ -23,18 +23,15 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/cdma-provision.h include/handsfree.h \
|
||||
include/sim-mnclength.h \
|
||||
include/handsfree-audio.h include/siri.h \
|
||||
include/sms-filter.h \
|
||||
include/netmon.h include/lte.h \
|
||||
include/storage.h \
|
||||
gdbus/gdbus.h
|
||||
include/sms-filter.h include/gprs-filter.h \
|
||||
include/voicecall-filter.h include/dbus-access.h \
|
||||
include/ril-constants.h include/ril-transport.h \
|
||||
include/watch.h gdbus/gdbus.h \
|
||||
include/netmon.h include/lte.h include/ims.h \
|
||||
include/storage.h
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
|
||||
include/sailfish_manager.h include/sailfish_watch.h
|
||||
endif
|
||||
|
||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
||||
$(nodist_pkginclude_HEADERS), \
|
||||
include/ofono/$(notdir $(file)))
|
||||
@@ -66,7 +63,7 @@ endif
|
||||
builtin_modules =
|
||||
builtin_sources =
|
||||
builtin_libadd =
|
||||
builtin_cflags =
|
||||
builtin_cflags = -DSAILFISH_OS
|
||||
|
||||
noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
|
||||
|
||||
@@ -129,8 +126,13 @@ builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_manager_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_watch.c
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c
|
||||
endif
|
||||
|
||||
|
||||
if SAILFISH_ACCESS
|
||||
builtin_modules += sailfish_access
|
||||
builtin_sources += plugins/sailfish_access.c
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
@@ -143,9 +145,16 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_connman.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
drivers/ril/ril_devmon.c \
|
||||
drivers/ril/ril_devmon_auto.c \
|
||||
drivers/ril/ril_devmon_combine.c \
|
||||
drivers/ril/ril_devmon_ds.c \
|
||||
drivers/ril/ril_devmon_ss.c \
|
||||
drivers/ril/ril_devmon_ur.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
@@ -281,7 +290,8 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
|
||||
drivers/qmimodem/wds.h \
|
||||
drivers/qmimodem/pds.h \
|
||||
drivers/qmimodem/common.h \
|
||||
drivers/qmimodem/wda.h
|
||||
drivers/qmimodem/wda.h \
|
||||
drivers/qmimodem/voice.h
|
||||
|
||||
builtin_modules += qmimodem
|
||||
builtin_sources += $(qmi_sources) \
|
||||
@@ -297,6 +307,7 @@ builtin_sources += $(qmi_sources) \
|
||||
drivers/qmimodem/ussd.c \
|
||||
drivers/qmimodem/gprs.c \
|
||||
drivers/qmimodem/gprs-context.c \
|
||||
drivers/qmimodem/lte.c \
|
||||
drivers/qmimodem/radio-settings.c \
|
||||
drivers/qmimodem/location-reporting.c \
|
||||
drivers/qmimodem/netmon.c
|
||||
@@ -329,7 +340,6 @@ builtin_sources += drivers/atmodem/atmodem.h \
|
||||
drivers/atmodem/atutil.c \
|
||||
drivers/atmodem/gprs.c \
|
||||
drivers/atmodem/gprs-context.c \
|
||||
drivers/atmodem/sim-auth.c \
|
||||
drivers/atmodem/gnss.c \
|
||||
drivers/atmodem/lte.c
|
||||
|
||||
@@ -466,7 +476,8 @@ builtin_modules += xmm7modem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/xmm7modem/xmm7modem.h \
|
||||
drivers/xmm7modem/xmm7modem.c \
|
||||
drivers/xmm7modem/radio-settings.c
|
||||
drivers/xmm7modem/radio-settings.c \
|
||||
drivers/xmm7modem/ims.c
|
||||
|
||||
if PHONESIM
|
||||
builtin_modules += phonesim
|
||||
@@ -562,9 +573,6 @@ builtin_sources += plugins/samsung.c
|
||||
builtin_modules += sim900
|
||||
builtin_sources += plugins/sim900.c
|
||||
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c
|
||||
|
||||
@@ -707,6 +715,36 @@ builtin_sources += plugins/smshistory.c
|
||||
builtin_modules += allowed_apns
|
||||
builtin_sources += plugins/allowed-apns.c
|
||||
|
||||
if ELL
|
||||
builtin_cflags += @ELL_CFLAGS@
|
||||
builtin_libadd += @ELL_LIBS@
|
||||
|
||||
if MBIMMODEM
|
||||
mbim_sources = drivers/mbimmodem/mbim.h \
|
||||
drivers/mbimmodem/mbim.c \
|
||||
drivers/mbimmodem/mbim-desc.h \
|
||||
drivers/mbimmodem/mbim-desc.c \
|
||||
drivers/mbimmodem/mbim-message.h \
|
||||
drivers/mbimmodem/mbim-message.c
|
||||
|
||||
builtin_modules += mbimmodem
|
||||
builtin_sources += $(mbim_sources) \
|
||||
drivers/mbimmodem/util.h \
|
||||
drivers/mbimmodem/util.c \
|
||||
drivers/mbimmodem/mbimmodem.h \
|
||||
drivers/mbimmodem/mbimmodem.c \
|
||||
drivers/mbimmodem/devinfo.c \
|
||||
drivers/mbimmodem/sim.c \
|
||||
drivers/mbimmodem/network-registration.c \
|
||||
drivers/mbimmodem/sms.c \
|
||||
drivers/mbimmodem/gprs.c \
|
||||
drivers/mbimmodem/gprs-context.c
|
||||
|
||||
builtin_modules += mbim
|
||||
builtin_sources += plugins/mbim.c
|
||||
endif
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = src/ofonod
|
||||
|
||||
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
@@ -736,9 +774,11 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/cdma-provision.c src/handsfree.c \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/sms-filter.c src/dbus-queue.c \
|
||||
src/hfp.h src/siri.c \
|
||||
src/netmon.c src/lte.c \
|
||||
src/sms-filter.c src/gprs-filter.c \
|
||||
src/dbus-queue.c src/dbus-access.c src/config.c \
|
||||
src/voicecall-filter.c src/ril-transport.c \
|
||||
src/hfp.h src/siri.c src/watchlist.c \
|
||||
src/netmon.c src/lte.c src/ims.c \
|
||||
src/netmonagent.c src/netmonagent.h
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@@ -749,7 +789,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
|
||||
|
||||
BUILT_SOURCES = $(local_headers) src/builtin.h
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
|
||||
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
|
||||
|
||||
plugindir = $(pkglibdir)/plugins
|
||||
|
||||
@@ -765,7 +806,8 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
|
||||
|
||||
AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \
|
||||
-I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril \
|
||||
-I$(srcdir)/plugins/sailfish_manager
|
||||
|
||||
doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \
|
||||
@@ -789,7 +831,8 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt \
|
||||
doc/lte-api.txt \
|
||||
doc/cinterion-hardware-monitor-api.txt
|
||||
doc/cinterion-hardware-monitor-api.txt \
|
||||
doc/ims-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -898,7 +941,10 @@ test_scripts = test/backtrace \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling \
|
||||
test/set-lte-property \
|
||||
test/test-serving-cell-info
|
||||
test/test-serving-cell-info \
|
||||
test/ims-register \
|
||||
test/ims-unregister \
|
||||
test/list-applications
|
||||
|
||||
|
||||
if TEST
|
||||
@@ -919,15 +965,13 @@ unit_objects =
|
||||
|
||||
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
||||
unit/test-simutil unit/test-stkutil \
|
||||
unit/test-sms unit/test-cdmasms \
|
||||
unit/test-provision unit/test-sms-filter
|
||||
unit/test-sms unit/test-cdmasms
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-Iplugins/sailfish_manager
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info
|
||||
@@ -940,60 +984,95 @@ unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-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
|
||||
@DBUS_GLIB_CFLAGS@
|
||||
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info_dbus
|
||||
|
||||
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
unit/fake_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/watch.c src/log.c
|
||||
src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info
|
||||
|
||||
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
|
||||
unit/test-dbus.c unit/fake_sailfish_watch.c \
|
||||
unit/test-dbus.c unit/fake_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
|
||||
src/dbus.c src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
|
||||
-Iplugins/sailfish_manager
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info_dbus
|
||||
|
||||
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
unit/fake_watch.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/log.c
|
||||
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_manager
|
||||
|
||||
unit_test_sailfish_watch_SOURCES = unit/test-sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_watch.c \
|
||||
src/log.c src/watch.c
|
||||
unit_test_sailfish_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
unit_test_sailfish_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_watch_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_watch
|
||||
unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \
|
||||
src/log.c src/watchlist.c
|
||||
unit_test_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_watch_OBJECTS)
|
||||
unit_tests += unit/test-watch
|
||||
|
||||
endif
|
||||
|
||||
unit_test_config_SOURCES = unit/test-config.c drivers/ril/ril_util.c \
|
||||
src/config.c src/log.c
|
||||
unit_test_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_config_OBJECTS)
|
||||
unit_tests += unit/test-config
|
||||
|
||||
if SAILFISH_ACCESS
|
||||
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
|
||||
plugins/sailfish_access.c src/dbus-access.c src/log.c
|
||||
unit_test_sailfish_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_sailfish_access_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_access_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_access
|
||||
endif
|
||||
|
||||
unit_test_dbus_access_SOURCES = unit/test-dbus-access.c src/dbus-access.c \
|
||||
src/log.c
|
||||
unit_test_dbus_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_dbus_access_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_access_OBJECTS)
|
||||
unit_tests += unit/test-dbus-access
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_config.c src/log.c
|
||||
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_config_OBJECTS)
|
||||
unit_tests += unit/test-ril_config
|
||||
|
||||
unit_test_ril_ecclist_SOURCES = unit/test-ril_ecclist.c \
|
||||
drivers/ril/ril_ecclist.c src/log.c
|
||||
unit_test_ril_ecclist_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_ecclist_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_ecclist_OBJECTS)
|
||||
unit_tests += unit/test-ril_ecclist
|
||||
|
||||
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)
|
||||
@@ -1001,6 +1080,14 @@ unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_util_OBJECTS)
|
||||
unit_tests += unit/test-ril_util
|
||||
|
||||
unit_test_ril_vendor_SOURCES = unit/test-ril_vendor.c unit/fake_watch.c \
|
||||
drivers/ril/ril_vendor.c drivers/ril/ril_vendor_mtk.c \
|
||||
drivers/ril/ril_util.c src/log.c
|
||||
unit_test_ril_vendor_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_vendor_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_vendor_OBJECTS)
|
||||
unit_tests += unit/test-ril_vendor
|
||||
|
||||
else
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
@@ -1011,6 +1098,13 @@ unit_tests += unit/test-rilmodem-cs \
|
||||
endif
|
||||
endif
|
||||
|
||||
if ELL
|
||||
if MBIMMODEM
|
||||
unit_tests += unit/test-mbim
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
noinst_PROGRAMS = $(unit_tests) \
|
||||
unit/test-sms-root unit/test-mux unit/test-caif
|
||||
|
||||
@@ -1070,6 +1164,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||
src/dbus-queue.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_queue_OBJECTS)
|
||||
unit_tests += unit/test-dbus-queue
|
||||
|
||||
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
plugins/provision.h plugins/mbpi.c \
|
||||
plugins/sailfish_provision.c \
|
||||
@@ -1077,12 +1179,36 @@ unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_provision_OBJECTS)
|
||||
unit_tests += unit/test-provision
|
||||
|
||||
unit_test_ril_transport_SOURCES = unit/test-ril-transport.c \
|
||||
src/ril-transport.c src/log.c
|
||||
unit_test_ril_transport_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_transport_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_transport_OBJECTS)
|
||||
unit_tests += unit/test-ril-transport
|
||||
|
||||
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
|
||||
src/sms-filter.c src/log.c
|
||||
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sms_filter_OBJECTS)
|
||||
unit_tests += unit/test-sms-filter
|
||||
|
||||
unit_test_gprs_filter_SOURCES = unit/test-gprs-filter.c \
|
||||
src/gprs-filter.c src/log.c
|
||||
unit_test_gprs_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_gprs_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_gprs_filter_OBJECTS)
|
||||
unit_tests += unit/test-gprs-filter
|
||||
|
||||
unit_test_voicecall_filter_SOURCES = unit/test-voicecall-filter.c \
|
||||
src/voicecall-filter.c src/log.c \
|
||||
src/common.c src/util.c
|
||||
unit_test_voicecall_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_voicecall_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_voicecall_filter_OBJECTS)
|
||||
unit_tests += unit/test-voicecall-filter
|
||||
|
||||
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
|
||||
gatchat/ringbuffer.h gatchat/ringbuffer.c \
|
||||
@@ -1121,6 +1247,12 @@ unit_test_rilmodem_gprs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_gprs_OBJECTS)
|
||||
|
||||
unit_test_mbim_SOURCES = unit/test-mbim.c \
|
||||
drivers/mbimmodem/mbim-message.c \
|
||||
drivers/mbimmodem/mbim.c
|
||||
unit_test_mbim_LDADD = @ELL_LIBS@
|
||||
unit_objects += $(unit_test_mbim_OBJECTS)
|
||||
|
||||
TESTS = $(unit_tests)
|
||||
|
||||
if TOOLS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.21)
|
||||
AC_INIT(ofono, 1.23)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -33,7 +33,7 @@ AC_PROG_LIBTOOL
|
||||
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
|
||||
[disable code optimization through compiler]), [
|
||||
if (test "${enableval}" = "no"); then
|
||||
CFLAGS="$CFLAGS -O0"
|
||||
CFLAGS="$CFLAGS -O0 -U_FORTIFY_SOURCE"
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -183,17 +183,19 @@ AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||
[enable_sailfish_rilmodem="no"])
|
||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.35, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.35 is required))
|
||||
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||
|
||||
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.20, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.20 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.35, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.35 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.6, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.6 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||
enable_sailfish_manager=yes
|
||||
need_glibutil=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(sailfish-manager,
|
||||
@@ -202,12 +204,10 @@ AC_ARG_ENABLE(sailfish-manager,
|
||||
[enable_sailfish_manager=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
|
||||
|
||||
if (test "${enable_sailfish_manager}" = "yes"); then
|
||||
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
|
||||
AC_MSG_ERROR(dbus-glib is required by unit tests))
|
||||
AC_SUBST(DBUS_GLIB_CFLAGS)
|
||||
AC_SUBST(DBUS_GLIB_LIBS)
|
||||
fi
|
||||
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)
|
||||
|
||||
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]), [
|
||||
@@ -292,6 +292,25 @@ AC_ARG_ENABLE(upower, AC_HELP_STRING([--disable-upower],
|
||||
[enable_upower=${enableval}])
|
||||
AM_CONDITIONAL(UPOWER, test "${enable_power}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(mbimmodem, AC_HELP_STRING([--enable-mbimmodem],
|
||||
[enable MBIM based modem support]),
|
||||
[enable_mbimmodem=${enableval}])
|
||||
|
||||
AC_ARG_ENABLE(ell, AC_HELP_STRING([--enable-ell],
|
||||
[enable support for ell]),
|
||||
[enable_ell=${enableval}])
|
||||
|
||||
if (test "${enable_ell}" = "yes"); then
|
||||
AC_DEFINE(HAVE_ELL, 1, [Defined if Ell is enabled])
|
||||
PKG_CHECK_MODULES(ELL, ell >= 0.2, dummy=yes,
|
||||
AC_MSG_ERROR(ell library >= 0.2 is required))
|
||||
AC_SUBST(ELL_CFLAGS)
|
||||
AC_SUBST(ELL_LIBS)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(MBIMMODEM, test "${enable_ell}" != "no" && test "${enable_mbimmodem}" = "yes")
|
||||
AM_CONDITIONAL(ELL, test "${enable_ell}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
|
||||
[do not install configuration and data files]),
|
||||
[enable_datafiles=${enableval}])
|
||||
@@ -303,13 +322,23 @@ AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforw
|
||||
[enable_sailfish_pushforwarder="no"])
|
||||
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
|
||||
if (test "${enable_sailfish_pushforwarder}" != "no"); then
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.15, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.15 is required))
|
||||
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
|
||||
AC_MSG_ERROR(WSP decoder is required))
|
||||
CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
|
||||
LIBS="$LIBS $WSPCODEC_LIBS"
|
||||
need_glibutil=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(sailfish-access, AC_HELP_STRING([--enable-sailfish-access],
|
||||
[enable Sailfish OS access plugin]),
|
||||
[enable_sailfish_access=${enableval}],
|
||||
[enable_sailfish_access="no"])
|
||||
|
||||
AM_CONDITIONAL(SAILFISH_ACCESS, test "${enable_sailfish_access}" != "no")
|
||||
if (test "${enable_sailfish_access}" == "yes"); then
|
||||
PKG_CHECK_MODULES(DBUSACCESS, libdbusaccess, dummy=yes,
|
||||
AC_MSG_ERROR(libdbusaccess is required))
|
||||
CFLAGS="$CFLAGS $DBUSACCESS_CFLAGS"
|
||||
LIBS="$LIBS $DBUSACCESS_LIBS"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(sailfish-debuglog, AC_HELP_STRING([--enable-sailfish-debuglog],
|
||||
@@ -324,11 +353,6 @@ if (test "${enable_sailfish_debuglog}" = "yes"); then
|
||||
LIBS="$LIBS $DBUSLOG_LIBS"
|
||||
fi
|
||||
|
||||
if (test "${need_glibutil}" = "yes"); then
|
||||
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||
fi
|
||||
|
||||
if (test "${prefix}" = "NONE"); then
|
||||
dnl no prefix and no localstatedir, so default to /var
|
||||
if (test "$localstatedir" = '${prefix}/var'); then
|
||||
|
||||
59
ofono/doc/ims-api.txt
Normal file
59
ofono/doc/ims-api.txt
Normal file
@@ -0,0 +1,59 @@
|
||||
IpMultimediaSystem Hierarchy
|
||||
============================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.IpMultimediaSystem
|
||||
Object path [variable prefix]/{modem0,modem1,...}
|
||||
|
||||
Methods dict GetProperties()
|
||||
|
||||
Returns all IpMultimediaSystem 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
|
||||
|
||||
void Register()
|
||||
|
||||
Attempts to register to IMS. A successful method return
|
||||
indicates that the registration process could be
|
||||
initiated successfully. The actual registration state
|
||||
will be reflected by the 'Registered' property.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.NotImplemented
|
||||
|
||||
void Unregister()
|
||||
|
||||
Attempts to unregister from IMS. A successful method
|
||||
return indicates that the unregistration process could
|
||||
be initiated successfully. The actual unregistration
|
||||
state will be reflected by the 'Registered' property.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.NotImplemented
|
||||
|
||||
Signals PropertyChanged(string property, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
property.
|
||||
|
||||
Properties boolean Registered [readonly]
|
||||
|
||||
Contains the current IMS registration state.
|
||||
|
||||
boolean VoiceCapable [readonly, optional]
|
||||
|
||||
Boolean representing whether voice call transfer over
|
||||
RTP (IMS) is available.
|
||||
|
||||
boolean SmsCapable [readonly, optional]
|
||||
|
||||
Boolean representing whether SMS-over-IMS is available.
|
||||
@@ -95,6 +95,13 @@ Properties boolean Powered [readwrite]
|
||||
String representing the software version number of the
|
||||
modem device.
|
||||
|
||||
string SystemPath [readonly, optional]
|
||||
|
||||
String representing the system path for the modem
|
||||
device.
|
||||
For modems detected by udev events, this corresponds to
|
||||
the modem sysfs path.
|
||||
|
||||
array{string} Features [readonly]
|
||||
|
||||
List of currently enabled features. It uses simple
|
||||
@@ -127,6 +134,8 @@ Properties boolean Powered [readwrite]
|
||||
org.ofono.CallVolume
|
||||
org.ofono.CellBroadcast
|
||||
org.ofono.Handsfree
|
||||
org.ofono.IpMultimediaSystem
|
||||
org.ofono.LongTermEvolution
|
||||
org.ofono.LocationReporting
|
||||
org.ofono.MessageManager
|
||||
org.ofono.MessageWaiting
|
||||
|
||||
@@ -200,3 +200,8 @@ Properties boolean Present [readonly]
|
||||
might have changed the retry counters, i.e. calls to
|
||||
ChangePin(), EnterPin(), ResetPin() LockPin(),
|
||||
UnlockPin().
|
||||
|
||||
string ImsPrivateIdentity [readonly, optional]
|
||||
|
||||
Contains the SIM's ImsPrivateIdentity, read from the
|
||||
ISIM.
|
||||
|
||||
104
ofono/doc/sim-auth-api.txt
Normal file
104
ofono/doc/sim-auth-api.txt
Normal file
@@ -0,0 +1,104 @@
|
||||
SimAuthentication heiarchy [experimental]
|
||||
===========================================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.SimAuthentication
|
||||
Object path [variable prefix]/{modem0,modem1,...}
|
||||
|
||||
Methods array{object,dict} GetApplications()
|
||||
|
||||
Get an array of all SIM applications found during
|
||||
discovery. In the format "a{oa{sv}}" where 'o' is
|
||||
the object path for the application e.g.
|
||||
|
||||
o = "/modem1/A0000000871004FFFFFFFF8906190000"
|
||||
|
||||
Each dictionary will contain 'Type' e.g. 'Ims' and
|
||||
'Name' e.g. 'ISim'
|
||||
|
||||
For each application there will be a corresponding
|
||||
object that matches the path (o). The type will
|
||||
signify which interfaces are under that object (below).
|
||||
|
||||
type = Umts --> org.ofono.USimApplication
|
||||
type = Ims --> org.ofono.ISimApplication
|
||||
|
||||
SimAuth USIM application heiarchy [experimental]
|
||||
===========================================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.USimApplication
|
||||
Object path [variable prefix]/{modem0,modem1,...}/{AID name}
|
||||
|
||||
Methods dict GetProperties()
|
||||
|
||||
Returns properties for the USimApplication. See
|
||||
properties section for available properties.
|
||||
|
||||
array{dict{string, array{byte}}}
|
||||
GsmAuthenticate(array{array{byte}} rands)
|
||||
|
||||
Run the USIM application GSM AUTHENTICATE algorithm
|
||||
with N random challenges 'rands'. This should be an
|
||||
array of an array of bytes ("aay"). The number of
|
||||
random challenges is limited to a maximum of 3.
|
||||
|
||||
Returns the derived Kc/SRES values as an array of
|
||||
dictionaries. The index of each dictionary matches
|
||||
the index of the rand value in the method call. The
|
||||
keys for each dictionary are "Kc" and "SRES" and both
|
||||
are arrays of bytes.
|
||||
|
||||
Possible Errors:
|
||||
[service].Error.NotSupported
|
||||
[service].Error.Busy
|
||||
|
||||
dict{string, array{byte}}
|
||||
UmtsAuthenticate(array{byte} rand, array{byte} autn)
|
||||
|
||||
Run the UMTS AUTHENTICATE algorithm in the 3G
|
||||
context with 'rand' and 'autn'. A dictionary will be
|
||||
returned containing 'RES', 'CK', 'IK' and possibly
|
||||
'Kc' if service 27 is available. If there was a
|
||||
sync error 'AUTS' will be returned.
|
||||
|
||||
Possible Errors: [service].Error.NotSupported
|
||||
|
||||
Properties string Type [readonly]
|
||||
|
||||
Type of application: 'Umts'
|
||||
|
||||
string Name [readonly]
|
||||
|
||||
Human readable name: 'USim'
|
||||
|
||||
SimAuth ISIM application heiarchy [experimental]
|
||||
===========================================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.ISimApplication
|
||||
Object [variable prefix]/{modem0,modem1,...}/{AID name}
|
||||
|
||||
Methods dict GetProperties()
|
||||
|
||||
Returns properties for the ISimApplication. See
|
||||
the properties section for available properties.
|
||||
|
||||
dict{string, array{byte}
|
||||
ImsAuthenticate(array{byte} rand, array{byte} autn)
|
||||
|
||||
Run the UMTS AUTHENTICATE algorithm in the IMS
|
||||
context with 'rand' and 'autn'. A dictionary will be
|
||||
returned containing 'RES', 'CK', 'IK' and possibly
|
||||
'Kc' if service 27 is available. If there was a
|
||||
sync error 'AUTS' will be returned.
|
||||
|
||||
Possible Errors: [service].Error.NotSupported
|
||||
|
||||
Properties string Type [readonly]
|
||||
|
||||
Type of application: 'Ims'
|
||||
|
||||
string Name [readonly]
|
||||
|
||||
Human readable name: 'ISim'
|
||||
@@ -59,6 +59,27 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
object DialLast()
|
||||
|
||||
Initiates a new outgoing call to the last dialled number.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.InvalidFormat
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
object DialMemory(string memory position, string hide_callerid)
|
||||
|
||||
Initiates a new outgoing call to the number in the given memory
|
||||
position/favourite. For callerid see the Dial method.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.InvalidFormat
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
void Transfer()
|
||||
|
||||
Joins the currently Active (or Outgoing, depending
|
||||
|
||||
@@ -50,7 +50,6 @@ static int atmodem_init(void)
|
||||
at_call_volume_init();
|
||||
at_gprs_init();
|
||||
at_gprs_context_init();
|
||||
at_sim_auth_init();
|
||||
at_gnss_init();
|
||||
at_lte_init();
|
||||
|
||||
@@ -59,7 +58,6 @@ static int atmodem_init(void)
|
||||
|
||||
static void atmodem_exit(void)
|
||||
{
|
||||
at_sim_auth_exit();
|
||||
at_stk_exit();
|
||||
at_sim_exit();
|
||||
at_sms_exit();
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/sim-auth.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
#include "simutil.h"
|
||||
#include "vendor.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
struct sim_auth_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
};
|
||||
|
||||
static const char *cuad_prefix[] = { "+CUAD:", NULL };
|
||||
|
||||
static void at_discover_apps_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
GAtResultIter iter;
|
||||
ofono_sim_list_apps_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
const unsigned char *dataobj;
|
||||
gint linelen;
|
||||
unsigned char *buffer;
|
||||
int len;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, NULL, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
len = 0;
|
||||
while (g_at_result_iter_next(&iter, "+CUAD:")) {
|
||||
if (!g_at_result_iter_next_hexstring(&iter, NULL, &linelen))
|
||||
goto error;
|
||||
|
||||
len += linelen;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
buffer = g_malloc(len);
|
||||
len = 0;
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CUAD:")) {
|
||||
g_at_result_iter_next_hexstring(&iter, &dataobj, &linelen);
|
||||
memcpy(buffer + len, dataobj, linelen);
|
||||
len += linelen;
|
||||
}
|
||||
|
||||
cb(&error, buffer, len, cbd->data);
|
||||
|
||||
g_free(buffer);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
||||
}
|
||||
|
||||
static void at_discover_apps(struct ofono_sim_auth *sa,
|
||||
ofono_sim_list_apps_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct sim_auth_data *sad = ofono_sim_auth_get_data(sa);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(sad->chat, "AT+CUAD", cuad_prefix,
|
||||
at_discover_apps_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
||||
}
|
||||
|
||||
static gboolean at_sim_auth_register(gpointer user)
|
||||
{
|
||||
struct ofono_sim_auth *sa = user;
|
||||
|
||||
ofono_sim_auth_register(sa);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_sim_auth_probe(struct ofono_sim_auth *sa, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct sim_auth_data *sad;
|
||||
|
||||
sad = g_new0(struct sim_auth_data, 1);
|
||||
sad->chat = g_at_chat_clone(chat);
|
||||
sad->vendor = vendor;
|
||||
|
||||
ofono_sim_auth_set_data(sa, sad);
|
||||
g_idle_add(at_sim_auth_register, sa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at_sim_auth_remove(struct ofono_sim_auth *sa)
|
||||
{
|
||||
struct sim_auth_data *sad = ofono_sim_auth_get_data(sa);
|
||||
|
||||
g_idle_remove_by_data(sa);
|
||||
ofono_sim_auth_set_data(sa, NULL);
|
||||
|
||||
g_at_chat_unref(sad->chat);
|
||||
g_free(sad);
|
||||
}
|
||||
|
||||
static struct ofono_sim_auth_driver driver = {
|
||||
.name = "atmodem",
|
||||
.probe = at_sim_auth_probe,
|
||||
.remove = at_sim_auth_remove,
|
||||
.list_apps = at_discover_apps,
|
||||
};
|
||||
|
||||
void at_sim_auth_init(void)
|
||||
{
|
||||
ofono_sim_auth_driver_register(&driver);
|
||||
}
|
||||
|
||||
void at_sim_auth_exit(void)
|
||||
{
|
||||
ofono_sim_auth_driver_unregister(&driver);
|
||||
}
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "gatresult.h"
|
||||
#include "simutil.h"
|
||||
#include "vendor.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
@@ -50,7 +51,6 @@
|
||||
struct sim_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
guint ready_id;
|
||||
guint passwd_type_mask;
|
||||
struct at_util_sim_state_query *sim_state_query;
|
||||
};
|
||||
@@ -65,14 +65,36 @@ static const char *pinnum_prefix[] = { "%PINNUM:", NULL };
|
||||
static const char *oercn_prefix[] = { "_OERCN:", NULL };
|
||||
static const char *cpinr_prefixes[] = { "+CPINR:", "+CPINRE:", NULL };
|
||||
static const char *epin_prefix[] = { "*EPIN:", NULL };
|
||||
static const char *spic_prefix[] = { "+SPIC:", NULL };
|
||||
static const char *simcom_spic_prefix[] = { "+SPIC:", NULL };
|
||||
static const char *cinterion_spic_prefix[] = { "^SPIC:", NULL };
|
||||
static const char *pct_prefix[] = { "#PCT:", NULL };
|
||||
static const char *pnnm_prefix[] = { "+PNNM:", NULL };
|
||||
static const char *qpinc_prefix[] = { "+QPINC:", NULL };
|
||||
static const char *upincnt_prefix[] = { "+UPINCNT:", NULL };
|
||||
static const char *cuad_prefix[] = { "+CUAD:", NULL };
|
||||
static const char *ccho_prefix[] = { "+CCHO:", NULL };
|
||||
static const char *crla_prefix[] = { "+CRLA:", NULL };
|
||||
static const char *cgla_prefix[] = { "+CGLA:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
static void append_file_path(char *buf, const unsigned char *path,
|
||||
unsigned int path_len)
|
||||
{
|
||||
if (path_len > 0) {
|
||||
*buf++ = ',';
|
||||
*buf++ = ',';
|
||||
*buf++ = '\"';
|
||||
|
||||
for (; path_len; path_len--)
|
||||
buf += sprintf(buf, "%02hhX", *path++);
|
||||
|
||||
*buf++ = '\"';
|
||||
*buf = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void get_response_common_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data, const char *prefix)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
GAtResultIter iter;
|
||||
@@ -94,7 +116,7 @@ static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CRSM:"))
|
||||
if (!g_at_result_iter_next(&iter, prefix))
|
||||
goto error;
|
||||
|
||||
g_at_result_iter_next_number(&iter, &sw1);
|
||||
@@ -135,6 +157,11 @@ error:
|
||||
EF_STATUS_INVALIDATED, cbd->data);
|
||||
}
|
||||
|
||||
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
get_response_common_cb(ok, result, user_data, "+CRSM:");
|
||||
}
|
||||
|
||||
static void at_sim_read_info(struct ofono_sim *sim, int fileid,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
@@ -176,15 +203,7 @@ static void at_sim_read_info(struct ofono_sim *sim, int fileid,
|
||||
break;
|
||||
}
|
||||
|
||||
if (path_len > 0) {
|
||||
len += sprintf(buf + len, ",,\"");
|
||||
|
||||
for (; path_len; path_len--)
|
||||
len += sprintf(buf + len, "%02hhX", *path++);
|
||||
|
||||
buf[len++] = '\"';
|
||||
buf[len] = '\0';
|
||||
}
|
||||
append_file_path(buf + len, path, path_len);
|
||||
|
||||
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
|
||||
at_crsm_info_cb, cbd, g_free) > 0)
|
||||
@@ -258,17 +277,7 @@ static void at_sim_read_binary(struct ofono_sim *sim, int fileid,
|
||||
len = snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid,
|
||||
start >> 8, start & 0xff, length);
|
||||
|
||||
if (path_len > 0) {
|
||||
buf[len++] = ',';
|
||||
buf[len++] = ',';
|
||||
buf[len++] = '\"';
|
||||
|
||||
for (; path_len; path_len--)
|
||||
len += sprintf(buf + len, "%02hhX", *path++);
|
||||
|
||||
buf[len++] = '\"';
|
||||
buf[len] = '\0';
|
||||
}
|
||||
append_file_path(buf + len, path, path_len);
|
||||
|
||||
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
|
||||
at_crsm_read_cb, cbd, g_free) > 0)
|
||||
@@ -288,10 +297,13 @@ static void at_sim_read_record(struct ofono_sim *sim, int fileid,
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[128];
|
||||
unsigned int len;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
|
||||
len = snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
|
||||
record, length);
|
||||
|
||||
append_file_path(buf + len, path, path_len);
|
||||
|
||||
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
|
||||
at_crsm_read_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
@@ -837,7 +849,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
cb(&error, retries, cbd->data);
|
||||
}
|
||||
|
||||
static void at_spic_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
static void simcom_spic_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
@@ -1054,6 +1066,46 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void cinterion_spic_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
const char *final = g_at_result_final_response(result);
|
||||
GAtResultIter iter;
|
||||
struct ofono_error error;
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
size_t i;
|
||||
int pin_type = ofono_sim_get_password_type(sim);
|
||||
|
||||
decode_at_error(&error, final);
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
retries[i] = -1;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^SPIC:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &retries[pin_type]))
|
||||
goto error;
|
||||
|
||||
DBG("Retry : %d, type : %d", retries[pin_type], pin_type);
|
||||
cb(&error, retries, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb,
|
||||
void *data)
|
||||
@@ -1101,8 +1153,8 @@ static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_SIMCOM:
|
||||
if (g_at_chat_send(sd->chat, "AT+SPIC", spic_prefix,
|
||||
at_spic_cb, cbd, g_free) > 0)
|
||||
if (g_at_chat_send(sd->chat, "AT+SPIC", simcom_spic_prefix,
|
||||
simcom_spic_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_TELIT:
|
||||
@@ -1126,6 +1178,11 @@ static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
upincnt_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
if (g_at_chat_send(sd->chat, "AT^SPIC", cinterion_spic_prefix,
|
||||
cinterion_spic_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
|
||||
at_cpinr_cb, cbd, g_free) > 0)
|
||||
@@ -1216,100 +1273,24 @@ static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void at_xsim_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct sim_data *sd = cbd->user;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
|
||||
GAtResultIter iter;
|
||||
int state;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+XSIM:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &state))
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
case 3: /* PIN verified – Ready */
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
cb(&error, cbd->data);
|
||||
|
||||
g_at_chat_unregister(sd->chat, sd->ready_id);
|
||||
sd->ready_id = 0;
|
||||
}
|
||||
|
||||
static void at_epev_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct sim_data *sd = cbd->user;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
|
||||
|
||||
cb(&error, cbd->data);
|
||||
|
||||
g_at_chat_unregister(sd->chat, sd->ready_id);
|
||||
sd->ready_id = 0;
|
||||
}
|
||||
|
||||
static void at_qss_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct sim_data *sd = cbd->user;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
|
||||
GAtResultIter iter;
|
||||
int state;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "#QSS:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &state))
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
case 3: /* SIM inserted and READY. */
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
cb(&error, cbd->data);
|
||||
|
||||
g_at_chat_unregister(sd->chat, sd->ready_id);
|
||||
sd->ready_id = 0;
|
||||
}
|
||||
|
||||
static void sim_state_cb(gboolean present, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct sim_data *sd = cbd->user;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
void *data = cbd->data;
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
|
||||
at_util_sim_state_query_free(sd->sim_state_query);
|
||||
sd->sim_state_query = NULL;
|
||||
|
||||
if (present == 1)
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
ofono_sim_initialized_notify(sim);
|
||||
}
|
||||
|
||||
static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct sim_data *sd = cbd->user;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
@@ -1319,36 +1300,6 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
goto done;
|
||||
|
||||
switch (sd->vendor) {
|
||||
case OFONO_VENDOR_IFX:
|
||||
/*
|
||||
* On the IFX modem, AT+CPIN? can return READY too
|
||||
* early and so use +XSIM notification to detect
|
||||
* the ready state of the SIM.
|
||||
*/
|
||||
sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
|
||||
at_xsim_notify,
|
||||
FALSE, cbd, g_free);
|
||||
return;
|
||||
case OFONO_VENDOR_MBM:
|
||||
/*
|
||||
* On the MBM modem, AT+CPIN? keeps returning SIM PIN
|
||||
* for a moment after successful AT+CPIN="..", but then
|
||||
* sends *EPEV when that changes.
|
||||
*/
|
||||
sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
|
||||
at_epev_notify,
|
||||
FALSE, cbd, g_free);
|
||||
return;
|
||||
case OFONO_VENDOR_TELIT:
|
||||
/*
|
||||
* On the Telit modem, AT+CPIN? can return READY too
|
||||
* early and so use #QSS notification to detect
|
||||
* the ready state of the SIM.
|
||||
*/
|
||||
sd->ready_id = g_at_chat_register(sd->chat, "#QSS",
|
||||
at_qss_notify,
|
||||
FALSE, cbd, g_free);
|
||||
return;
|
||||
case OFONO_VENDOR_ZTE:
|
||||
case OFONO_VENDOR_ALCATEL:
|
||||
case OFONO_VENDOR_HUAWEI:
|
||||
@@ -1366,15 +1317,12 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
* state.
|
||||
*/
|
||||
sd->sim_state_query = at_util_sim_state_query_new(sd->chat,
|
||||
2, 20, sim_state_cb, cbd,
|
||||
g_free);
|
||||
return;
|
||||
2, 20, sim_state_cb, sim,
|
||||
NULL);
|
||||
}
|
||||
|
||||
done:
|
||||
cb(&error, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void at_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
@@ -1385,12 +1333,12 @@ static void at_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
char buf[64];
|
||||
int ret;
|
||||
|
||||
cbd->user = sd;
|
||||
cbd->user = sim;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
|
||||
|
||||
ret = g_at_chat_send(sd->chat, buf, none_prefix,
|
||||
at_pin_send_cb, cbd, NULL);
|
||||
at_pin_send_cb, cbd, g_free);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
@@ -1603,6 +1551,327 @@ done:
|
||||
ofono_sim_register(sim);
|
||||
}
|
||||
|
||||
static void at_discover_apps_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
GAtResultIter iter;
|
||||
ofono_sim_list_apps_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
const unsigned char *buffer;
|
||||
int len;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, NULL, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CUAD:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_hexstring(&iter, &buffer, &len))
|
||||
goto error;
|
||||
|
||||
cb(&error, buffer, len, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
||||
}
|
||||
|
||||
static void at_discover_apps(struct ofono_sim *sim,
|
||||
ofono_sim_list_apps_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(sd->chat, "AT+CUAD", cuad_prefix,
|
||||
at_discover_apps_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
||||
}
|
||||
|
||||
static void at_open_channel_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
GAtResultIter iter;
|
||||
ofono_sim_open_channel_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
int session_id = -1;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CCHO:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &session_id))
|
||||
goto error;
|
||||
|
||||
cb(&error, session_id, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
cb(&error, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void at_open_channel(struct ofono_sim *sim, const unsigned char *aid,
|
||||
ofono_sim_open_channel_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char cmd[43];
|
||||
int ret = 0;
|
||||
|
||||
strcpy(cmd, "AT+CCHO=\"");
|
||||
ret += 9;
|
||||
|
||||
encode_hex_own_buf(aid, 16, 0, cmd + ret);
|
||||
ret += 32;
|
||||
|
||||
strcpy(cmd + ret, "\"");
|
||||
|
||||
if (g_at_chat_send(sd->chat, cmd, ccho_prefix, at_open_channel_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void at_close_channel_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_close_channel_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (cb)
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void at_close_channel(struct ofono_sim *sim, int session_id,
|
||||
ofono_sim_close_channel_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char cmd[15];
|
||||
|
||||
sprintf(cmd, "AT+CCHC=%d", session_id);
|
||||
|
||||
g_at_chat_send(sd->chat, cmd, NULL, at_close_channel_cb, cbd, g_free);
|
||||
}
|
||||
|
||||
static void at_crla_read_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
GAtResultIter iter;
|
||||
ofono_sim_read_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
const guint8 *response;
|
||||
gint sw1, sw2, len;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, NULL, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CRLA:")) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_next_number(&iter, &sw1);
|
||||
g_at_result_iter_next_number(&iter, &sw2);
|
||||
|
||||
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
||||
(sw1 == 0x90 && sw2 != 0x00)) {
|
||||
memset(&error, 0, sizeof(error));
|
||||
|
||||
error.type = OFONO_ERROR_TYPE_SIM;
|
||||
error.error = (sw1 << 8) | sw2;
|
||||
|
||||
cb(&error, NULL, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("crla_read_cb: %02x, %02x, %d", sw1, sw2, len);
|
||||
|
||||
cb(&error, response, len, cbd->data);
|
||||
}
|
||||
|
||||
static void at_session_read_binary(struct ofono_sim *sim, int session,
|
||||
int fileid, int start, int length,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
unsigned int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,176,%i,%i,%i,%i,,",
|
||||
session, fileid, start >> 8, start & 0xff, length);
|
||||
|
||||
append_file_path(buf + len, path, path_len);
|
||||
|
||||
if (g_at_chat_send(sd->chat, buf, crla_prefix,
|
||||
at_crla_read_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
||||
}
|
||||
|
||||
static void at_session_read_record(struct ofono_sim *sim, int session_id,
|
||||
int fileid, int record, int length,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[128];
|
||||
unsigned int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,178,%i,%i,4,%i",
|
||||
session_id, fileid, record, length);
|
||||
|
||||
append_file_path(buf + len, path, path_len);
|
||||
|
||||
if (g_at_chat_send(sd->chat, buf, crla_prefix,
|
||||
at_crla_read_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
||||
}
|
||||
|
||||
static void at_crla_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
get_response_common_cb(ok, result, user_data, "+CRLA:");
|
||||
}
|
||||
|
||||
static void at_session_read_info(struct ofono_sim *sim, int session_id,
|
||||
int fileid, const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_file_info_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[128];
|
||||
unsigned int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,192,%i", session_id,
|
||||
fileid);
|
||||
|
||||
append_file_path(buf + len, path, path_len);
|
||||
|
||||
if (g_at_chat_send(sd->chat, buf, crla_prefix,
|
||||
at_crla_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
|
||||
EF_STATUS_INVALIDATED, data);
|
||||
}
|
||||
|
||||
static void logical_access_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_logical_access_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
const char *str_data;
|
||||
unsigned char *raw;
|
||||
gint len = 0;
|
||||
GAtResultIter iter;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CGLA:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &len))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &str_data))
|
||||
goto error;
|
||||
|
||||
raw = alloca(len / 2);
|
||||
|
||||
decode_hex_own_buf(str_data, len, NULL, 0, raw);
|
||||
|
||||
cb(&error, raw, len / 2, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
cb(&error, NULL, 0, cbd->data);
|
||||
}
|
||||
|
||||
static void at_logical_access(struct ofono_sim *sim, int session_id,
|
||||
const unsigned char *pdu, unsigned int len,
|
||||
ofono_sim_logical_access_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int ret = 0;
|
||||
char cmd[(len * 2) + 19];
|
||||
|
||||
ret = sprintf(cmd, "AT+CGLA=%d,%d,\"", session_id, len * 2);
|
||||
|
||||
encode_hex_own_buf(pdu, len, 0, cmd + ret);
|
||||
ret += len * 2;
|
||||
|
||||
strcpy(cmd + ret, "\"");
|
||||
|
||||
if (g_at_chat_send(sd->chat, cmd, cgla_prefix, logical_access_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
||||
}
|
||||
|
||||
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
@@ -1614,9 +1883,6 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
sd->chat = g_at_chat_clone(chat);
|
||||
sd->vendor = vendor;
|
||||
|
||||
if (sd->vendor == OFONO_VENDOR_MBM)
|
||||
g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
|
||||
|
||||
ofono_sim_set_data(sim, sd);
|
||||
|
||||
/* <fac>s supported by default */
|
||||
@@ -1662,6 +1928,13 @@ static struct ofono_sim_driver driver = {
|
||||
.lock = at_pin_enable,
|
||||
.change_passwd = at_change_passwd,
|
||||
.query_facility_lock = at_query_clck,
|
||||
.list_apps = at_discover_apps,
|
||||
.open_channel = at_open_channel,
|
||||
.close_channel = at_close_channel,
|
||||
.session_read_binary = at_session_read_binary,
|
||||
.session_read_record = at_session_read_record,
|
||||
.session_read_info = at_session_read_info,
|
||||
.logical_access = at_logical_access
|
||||
};
|
||||
|
||||
static struct ofono_sim_driver driver_noef = {
|
||||
|
||||
@@ -125,6 +125,7 @@ static struct ofono_call *create_call(struct ofono_voicecall *vc, int type,
|
||||
if (clip != 2) {
|
||||
strncpy(call->phone_number.number, num,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
call->phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
call->phone_number.type = num_type;
|
||||
}
|
||||
|
||||
@@ -404,6 +405,45 @@ static void hfp_dial(struct ofono_voicecall *vc,
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void hfp_dial_last(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
cbd->user = vc;
|
||||
|
||||
if (g_at_chat_send(vd->chat, "AT+BLDN", none_prefix,
|
||||
atd_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
|
||||
}
|
||||
|
||||
static void hfp_dial_memory(struct ofono_voicecall *vc,
|
||||
unsigned int memory_location,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[256];
|
||||
|
||||
cbd->user = vc;
|
||||
DBG("Calling memory location %d\n", memory_location);
|
||||
snprintf(buf, sizeof(buf), "ATD>%d;", memory_location);
|
||||
|
||||
if (g_at_chat_send(vd->chat, buf, none_prefix,
|
||||
atd_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
DBG("at_chat_failed");
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void hfp_template(const char *cmd, struct ofono_voicecall *vc,
|
||||
GAtResultFunc result_cb, unsigned int affected_types,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
@@ -1268,6 +1308,8 @@ static struct ofono_voicecall_driver driver = {
|
||||
.probe = hfp_voicecall_probe,
|
||||
.remove = hfp_voicecall_remove,
|
||||
.dial = hfp_dial,
|
||||
.dial_last = hfp_dial_last,
|
||||
.dial_memory = hfp_dial_memory,
|
||||
.answer = hfp_answer,
|
||||
.hangup_active = hfp_hangup,
|
||||
.hold_all_active = hfp_hold_all_active,
|
||||
|
||||
107
ofono/drivers/mbimmodem/devinfo.c
Normal file
107
ofono/drivers/mbimmodem/devinfo.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
*
|
||||
* 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 <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/devinfo.h>
|
||||
|
||||
#include "drivers/mbimmodem/mbimmodem.h"
|
||||
|
||||
struct devinfo_data {
|
||||
struct l_idle *delayed_register;
|
||||
};
|
||||
|
||||
static void mbim_query_revision(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_modem *modem = ofono_devinfo_get_modem(info);
|
||||
const char *revision = ofono_modem_get_string(modem, "FirmwareInfo");
|
||||
|
||||
if (revision)
|
||||
CALLBACK_WITH_SUCCESS(cb, revision, data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
|
||||
static void mbim_query_serial(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_modem *modem = ofono_devinfo_get_modem(info);
|
||||
const char *serial = ofono_modem_get_string(modem, "DeviceId");
|
||||
|
||||
if (serial)
|
||||
CALLBACK_WITH_SUCCESS(cb, serial, data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
|
||||
static void delayed_register(struct l_idle *idle, void *user_data)
|
||||
{
|
||||
struct ofono_devinfo *info = user_data;
|
||||
struct devinfo_data *dd = ofono_devinfo_get_data(info);
|
||||
|
||||
l_idle_remove(idle);
|
||||
dd->delayed_register = NULL;
|
||||
|
||||
ofono_devinfo_register(info);
|
||||
}
|
||||
|
||||
static int mbim_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct devinfo_data *dd = l_new(struct devinfo_data, 1);
|
||||
|
||||
dd->delayed_register = l_idle_create(delayed_register, info, NULL);
|
||||
ofono_devinfo_set_data(info, dd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_devinfo_remove(struct ofono_devinfo *info)
|
||||
{
|
||||
struct devinfo_data *dd = ofono_devinfo_get_data(info);
|
||||
|
||||
ofono_devinfo_set_data(info, NULL);
|
||||
l_idle_remove(dd->delayed_register);
|
||||
l_free(dd);
|
||||
}
|
||||
|
||||
static struct ofono_devinfo_driver driver = {
|
||||
.name = "mbim",
|
||||
.probe = mbim_devinfo_probe,
|
||||
.remove = mbim_devinfo_remove,
|
||||
.query_revision = mbim_query_revision,
|
||||
.query_serial = mbim_query_serial,
|
||||
};
|
||||
|
||||
void mbim_devinfo_init(void)
|
||||
{
|
||||
ofono_devinfo_driver_register(&driver);
|
||||
}
|
||||
|
||||
void mbim_devinfo_exit(void)
|
||||
{
|
||||
ofono_devinfo_driver_unregister(&driver);
|
||||
}
|
||||
464
ofono/drivers/mbimmodem/gprs-context.c
Normal file
464
ofono/drivers/mbimmodem/gprs-context.c
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include "drivers/mbimmodem/mbim.h"
|
||||
#include "drivers/mbimmodem/mbim-message.h"
|
||||
#include "drivers/mbimmodem/mbimmodem.h"
|
||||
|
||||
enum state {
|
||||
STATE_IDLE,
|
||||
STATE_ENABLING,
|
||||
STATE_DISABLING,
|
||||
STATE_ACTIVE,
|
||||
};
|
||||
|
||||
struct gprs_context_data {
|
||||
struct mbim_device *device;
|
||||
unsigned int active_context;
|
||||
enum ofono_gprs_proto proto;
|
||||
enum state state;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static uint32_t proto_to_context_ip_type(enum ofono_gprs_proto proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case OFONO_GPRS_PROTO_IP:
|
||||
return 1; /* MBIMContextIPTypeIPv4 */
|
||||
case OFONO_GPRS_PROTO_IPV6:
|
||||
return 2; /* MBIMContextIPTypeIPv6 */
|
||||
case OFONO_GPRS_PROTO_IPV4V6:
|
||||
return 3; /* MBIMContextIPTypeIPv4v6 */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t auth_method_to_auth_protocol(enum ofono_gprs_auth_method method)
|
||||
{
|
||||
switch (method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
return 2; /* MBIMAuthProtocolChap */
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
return 1; /* MBIMAuthProtocolPap */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_deactivate_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
if (!gcd->cb)
|
||||
return;
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
else
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void mbim_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);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("cid %u", cid);
|
||||
|
||||
gcd->state = STATE_DISABLING;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_CONNECT,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(message, "uusssuuu16y",
|
||||
cid, 0, NULL, NULL, NULL, 0, 0, 0,
|
||||
mbim_context_type_internet);
|
||||
|
||||
if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
|
||||
mbim_deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
mbim_message_unref(message);
|
||||
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void mbim_ip_configuration_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
|
||||
const char *interface;
|
||||
uint32_t session_id;
|
||||
uint32_t ipv4_config_available;
|
||||
uint32_t ipv6_config_available;
|
||||
uint32_t n_ipv4_addr;
|
||||
uint32_t ipv4_addr_offset;
|
||||
uint32_t n_ipv6_addr;
|
||||
uint32_t ipv6_addr_offset;
|
||||
uint32_t ipv4_gw_offset;
|
||||
uint32_t ipv6_gw_offset;
|
||||
uint32_t n_ipv4_dns;
|
||||
uint32_t ipv4_dns_offset;
|
||||
uint32_t n_ipv6_dns;
|
||||
uint32_t ipv6_dns_offset;
|
||||
uint32_t ipv4_mtu;
|
||||
uint32_t ipv6_mtu;
|
||||
|
||||
struct in6_addr ipv6;
|
||||
struct in_addr ipv4;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
DBG("%u", mbim_message_get_error(message));
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuuuuuuuuuuuuuu",
|
||||
&session_id,
|
||||
&ipv4_config_available, &ipv6_config_available,
|
||||
&n_ipv4_addr, &ipv4_addr_offset,
|
||||
&n_ipv6_addr, &ipv6_addr_offset,
|
||||
&ipv4_gw_offset, &ipv6_gw_offset,
|
||||
&n_ipv4_dns, &ipv4_dns_offset,
|
||||
&n_ipv6_dns, &ipv6_dns_offset,
|
||||
&ipv4_mtu, &ipv6_mtu))
|
||||
goto error;
|
||||
|
||||
if (gcd->proto == OFONO_GPRS_PROTO_IPV6)
|
||||
goto ipv6;
|
||||
|
||||
if (ipv4_config_available & 0x1) { /* Address Info present */
|
||||
uint32_t prefix;
|
||||
|
||||
if (!mbim_message_get_ipv4_element(message, ipv4_addr_offset,
|
||||
&prefix, &ipv4))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET, &ipv4, buf, sizeof(buf));
|
||||
ofono_gprs_context_set_ipv4_address(gc, buf, TRUE);
|
||||
ofono_gprs_context_set_ipv4_prefix_length(gc, prefix);
|
||||
} else
|
||||
ofono_gprs_context_set_ipv4_address(gc, NULL, FALSE);
|
||||
|
||||
if (ipv4_config_available & 0x2) { /* IPv4 Gateway info */
|
||||
if (!mbim_message_get_ipv4_address(message,
|
||||
ipv4_gw_offset, &ipv4))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET, &ipv4, buf, sizeof(buf));
|
||||
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, buf);
|
||||
}
|
||||
|
||||
if (ipv4_config_available & 0x3) { /* IPv4 DNS Info */
|
||||
const char *dns[3];
|
||||
char dns1[INET_ADDRSTRLEN];
|
||||
char dns2[INET_ADDRSTRLEN];
|
||||
|
||||
memset(dns, 0, sizeof(dns));
|
||||
|
||||
if (n_ipv4_dns > 1) { /* Grab second DNS */
|
||||
if (!mbim_message_get_ipv4_address(message,
|
||||
ipv4_dns_offset + 4,
|
||||
&ipv4))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET, &ipv4, dns2, sizeof(dns2));
|
||||
dns[1] = dns2;
|
||||
}
|
||||
|
||||
if (n_ipv4_dns > 0) { /* Grab first DNS */
|
||||
if (!mbim_message_get_ipv4_address(message,
|
||||
ipv4_dns_offset,
|
||||
&ipv4))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET, &ipv4, dns1, sizeof(dns1));
|
||||
dns[0] = dns1;
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
}
|
||||
}
|
||||
|
||||
if (gcd->proto == OFONO_GPRS_PROTO_IP)
|
||||
goto done;
|
||||
ipv6:
|
||||
if (ipv6_config_available & 0x1) { /* Address Info present */
|
||||
uint32_t prefix;
|
||||
|
||||
if (!mbim_message_get_ipv6_element(message, ipv6_addr_offset,
|
||||
&prefix, &ipv6))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET6, &ipv6, buf, sizeof(buf));
|
||||
ofono_gprs_context_set_ipv6_address(gc, buf);
|
||||
ofono_gprs_context_set_ipv6_prefix_length(gc, prefix);
|
||||
}
|
||||
|
||||
if (ipv6_config_available & 0x2) { /* IPv6 Gateway info */
|
||||
if (!mbim_message_get_ipv6_address(message,
|
||||
ipv6_gw_offset, &ipv6))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET6, &ipv6, buf, sizeof(buf));
|
||||
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, buf);
|
||||
}
|
||||
|
||||
if (ipv6_config_available & 0x3) { /* IPv6 DNS Info */
|
||||
const char *dns[3];
|
||||
char dns1[INET6_ADDRSTRLEN];
|
||||
char dns2[INET6_ADDRSTRLEN];
|
||||
|
||||
memset(dns, 0, sizeof(dns));
|
||||
|
||||
if (n_ipv6_dns > 1) { /* Grab second DNS */
|
||||
if (!mbim_message_get_ipv6_address(message,
|
||||
ipv6_dns_offset + 16,
|
||||
&ipv6))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET6, &ipv6, dns2, sizeof(dns2));
|
||||
dns[1] = dns2;
|
||||
}
|
||||
|
||||
if (n_ipv6_dns > 0) { /* Grab first DNS */
|
||||
if (!mbim_message_get_ipv6_address(message,
|
||||
ipv6_dns_offset,
|
||||
&ipv6))
|
||||
goto error;
|
||||
|
||||
inet_ntop(AF_INET6, &ipv6, dns1, sizeof(dns1));
|
||||
dns[0] = dns1;
|
||||
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc, dns);
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
||||
gcd->state = STATE_ACTIVE;
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
gcd->cb = NULL;
|
||||
gcd->cb_data = NULL;
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
gcd->state = STATE_IDLE;
|
||||
gcd->cb = NULL;
|
||||
gcd->cb_data = NULL;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_CONNECT,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(message, "uusssuuu16y",
|
||||
gcd->active_context, 0,
|
||||
NULL, NULL, NULL, 0, 0, 0,
|
||||
mbim_context_type_internet);
|
||||
|
||||
if (!mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
|
||||
NULL, NULL, NULL))
|
||||
mbim_message_unref(message);
|
||||
}
|
||||
|
||||
static void mbim_activate_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_IP_CONFIGURATION,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "uuuuuuuuuuuuuuu",
|
||||
gcd->active_context,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
|
||||
mbim_ip_configuration_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
gcd->state = STATE_IDLE;
|
||||
gcd->cb = NULL;
|
||||
gcd->cb_data = NULL;
|
||||
}
|
||||
|
||||
static void mbim_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);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("cid %u", ctx->cid);
|
||||
|
||||
gcd->state = STATE_ENABLING;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
gcd->active_context = ctx->cid;
|
||||
gcd->proto = ctx->proto;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_CONNECT,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(message, "uusssuuu16y",
|
||||
ctx->cid,
|
||||
1, /* MBIMActivationCommandActivate */
|
||||
ctx->apn,
|
||||
ctx->username[0] ? ctx->username : NULL,
|
||||
ctx->password[0] ? ctx->password : NULL,
|
||||
0, /*MBIMCompressionNone */
|
||||
auth_method_to_auth_protocol(ctx->auth_method),
|
||||
proto_to_context_ip_type(ctx->proto),
|
||||
mbim_context_type_internet);
|
||||
|
||||
if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
|
||||
mbim_activate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void mbim_gprs_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
DBG("");
|
||||
mbim_gprs_deactivate_primary(gc, cid, NULL, NULL);
|
||||
}
|
||||
|
||||
static void mbim_connect_notify(struct mbim_message *message, void *user)
|
||||
{
|
||||
uint32_t session_id;
|
||||
uint32_t activation_state;
|
||||
uint32_t voice_call_state;
|
||||
uint32_t ip_type;
|
||||
uint8_t context_type[16];
|
||||
uint32_t nw_error;
|
||||
char uuidstr[37];
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuuu16yu",
|
||||
&session_id, &activation_state,
|
||||
&voice_call_state, &ip_type,
|
||||
context_type, &nw_error))
|
||||
return;
|
||||
|
||||
DBG("session_id: %u, activation_state: %u, ip_type: %u",
|
||||
session_id, activation_state, ip_type);
|
||||
l_uuid_to_string(context_type, uuidstr, sizeof(uuidstr));
|
||||
DBG("context_type: %s, nw_error: %u", uuidstr, nw_error);
|
||||
}
|
||||
|
||||
static int mbim_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct mbim_device *device = data;
|
||||
struct gprs_context_data *gcd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_device_register(device, GPRS_CONTEXT_GROUP,
|
||||
mbim_uuid_basic_connect,
|
||||
MBIM_CID_CONNECT,
|
||||
mbim_connect_notify, gc, NULL))
|
||||
return -EIO;
|
||||
|
||||
gcd = l_new(struct gprs_context_data, 1);
|
||||
gcd->device = mbim_device_ref(device);
|
||||
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_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);
|
||||
|
||||
mbim_device_cancel_group(gcd->device, GPRS_CONTEXT_GROUP);
|
||||
mbim_device_unregister_group(gcd->device, GPRS_CONTEXT_GROUP);
|
||||
mbim_device_unref(gcd->device);
|
||||
gcd->device = NULL;
|
||||
l_free(gcd);
|
||||
}
|
||||
|
||||
static struct ofono_gprs_context_driver driver = {
|
||||
.name = "mbim",
|
||||
.probe = mbim_gprs_context_probe,
|
||||
.remove = mbim_gprs_context_remove,
|
||||
.activate_primary = mbim_gprs_activate_primary,
|
||||
.deactivate_primary = mbim_gprs_deactivate_primary,
|
||||
.detach_shutdown = mbim_gprs_detach_shutdown
|
||||
};
|
||||
|
||||
void mbim_gprs_context_init(void)
|
||||
{
|
||||
ofono_gprs_context_driver_register(&driver);
|
||||
}
|
||||
|
||||
void mbim_gprs_context_exit(void)
|
||||
{
|
||||
ofono_gprs_context_driver_unregister(&driver);
|
||||
}
|
||||
299
ofono/drivers/mbimmodem/gprs.c
Normal file
299
ofono/drivers/mbimmodem/gprs.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include "common.h"
|
||||
|
||||
#include "drivers/mbimmodem/mbim.h"
|
||||
#include "drivers/mbimmodem/mbim-message.h"
|
||||
#include "drivers/mbimmodem/mbimmodem.h"
|
||||
|
||||
struct gprs_data {
|
||||
struct mbim_device *device;
|
||||
struct l_idle *delayed_register;
|
||||
};
|
||||
|
||||
static void mbim_packet_service_set_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_gprs_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
else
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("");
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_PACKET_SERVICE,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
/*
|
||||
* MBIMPacketServiceActionAttach (0) or
|
||||
* MBIMPacketServiceActionDetach (1)
|
||||
*/
|
||||
mbim_message_set_arguments(message, "u", attached ? 0 : 1);
|
||||
|
||||
if (mbim_device_send(gd->device, GPRS_GROUP, message,
|
||||
mbim_packet_service_set_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void mbim_packet_service_query_cb(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_gprs_status_cb_t cb = cbd->cb;
|
||||
uint32_t dummy;
|
||||
uint32_t state;
|
||||
|
||||
DBG("%u", mbim_message_get_error(message));
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uu", &dummy, &state))
|
||||
goto error;
|
||||
|
||||
if (state == 2)
|
||||
CALLBACK_WITH_SUCCESS(cb,
|
||||
NETWORK_REGISTRATION_STATUS_REGISTERED,
|
||||
cbd->data);
|
||||
else
|
||||
CALLBACK_WITH_SUCCESS(cb, NETWORK_REGISTRATION_STATUS_UNKNOWN,
|
||||
cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
ofono_gprs_status_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("");
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_PACKET_SERVICE,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (mbim_device_send(gd->device, GPRS_GROUP, message,
|
||||
mbim_packet_service_query_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void mbim_packet_service_changed(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct ofono_gprs *gprs = user;
|
||||
uint32_t nw_error;
|
||||
uint32_t packet_service_state;
|
||||
uint32_t highest_avail_data_class;
|
||||
uint64_t uplink_speed;
|
||||
uint64_t downlink_speed;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuutt",
|
||||
&nw_error,
|
||||
&packet_service_state,
|
||||
&highest_avail_data_class,
|
||||
&uplink_speed,
|
||||
&downlink_speed))
|
||||
return;
|
||||
|
||||
DBG("uplink: %"PRIu64", downlink: %"PRIu64,
|
||||
uplink_speed, downlink_speed);
|
||||
DBG("nw_error: %u", nw_error);
|
||||
|
||||
if (packet_service_state == 2) {
|
||||
uint32_t bearer =
|
||||
mbim_data_class_to_tech(highest_avail_data_class);
|
||||
|
||||
ofono_gprs_status_notify(gprs,
|
||||
NETWORK_REGISTRATION_STATUS_REGISTERED);
|
||||
ofono_gprs_bearer_notify(gprs, bearer);
|
||||
} else
|
||||
ofono_gprs_status_notify(gprs,
|
||||
NETWORK_REGISTRATION_STATUS_UNKNOWN);
|
||||
}
|
||||
|
||||
static void provisioned_contexts_query_cb(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct mbim_message_iter contexts;
|
||||
uint32_t n_contexts;
|
||||
uint32_t id;
|
||||
uint8_t type[16];
|
||||
char *apn;
|
||||
char *username;
|
||||
char *password;
|
||||
uint32_t compression;
|
||||
uint32_t auth_protocol;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
return;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "a(u16ysssuu)",
|
||||
&n_contexts, &contexts))
|
||||
return;
|
||||
|
||||
DBG("n_contexts: %u", n_contexts);
|
||||
|
||||
while (mbim_message_iter_next_entry(&contexts, &id, type, &apn,
|
||||
&username, &password,
|
||||
&compression, &auth_protocol)) {
|
||||
char uuidstr[37];
|
||||
|
||||
l_uuid_to_string(type, uuidstr, sizeof(uuidstr));
|
||||
DBG("id: %u, type: %s", id, uuidstr);
|
||||
DBG("apn: %s, username: %s, password: %s",
|
||||
apn, username, password);
|
||||
DBG("compression: %u, auth_protocol: %u",
|
||||
compression, auth_protocol);
|
||||
|
||||
l_free(apn);
|
||||
l_free(username);
|
||||
l_free(password);
|
||||
}
|
||||
}
|
||||
|
||||
static void delayed_register(struct l_idle *idle, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("");
|
||||
|
||||
l_idle_remove(idle);
|
||||
gd->delayed_register = NULL;
|
||||
|
||||
/* Query provisioned contexts for debugging purposes only */
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_PROVISIONED_CONTEXTS,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
mbim_device_send(gd->device, 0, message,
|
||||
provisioned_contexts_query_cb, gprs, NULL);
|
||||
|
||||
if (!mbim_device_register(gd->device, GPRS_GROUP,
|
||||
mbim_uuid_basic_connect,
|
||||
MBIM_CID_PACKET_SERVICE,
|
||||
mbim_packet_service_changed,
|
||||
gprs, NULL))
|
||||
goto error;
|
||||
|
||||
ofono_gprs_register(gprs);
|
||||
return;
|
||||
|
||||
error:
|
||||
ofono_gprs_remove(gprs);
|
||||
}
|
||||
|
||||
static int mbim_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct mbim_device *device = data;
|
||||
struct gprs_data *gd;
|
||||
|
||||
DBG("");
|
||||
|
||||
gd = l_new(struct gprs_data, 1);
|
||||
gd->device = mbim_device_ref(device);
|
||||
gd->delayed_register = l_idle_create(delayed_register, gprs, NULL);
|
||||
|
||||
ofono_gprs_set_data(gprs, gd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_gprs_remove(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
l_idle_remove(gd->delayed_register);
|
||||
mbim_device_cancel_group(gd->device, GPRS_GROUP);
|
||||
mbim_device_unregister_group(gd->device, GPRS_GROUP);
|
||||
mbim_device_unref(gd->device);
|
||||
gd->device = NULL;
|
||||
l_free(gd);
|
||||
}
|
||||
|
||||
static struct ofono_gprs_driver driver = {
|
||||
.name = "mbim",
|
||||
.probe = mbim_gprs_probe,
|
||||
.remove = mbim_gprs_remove,
|
||||
.set_attached = mbim_gprs_set_attached,
|
||||
.attached_status = mbim_gprs_registration_status,
|
||||
};
|
||||
|
||||
void mbim_gprs_init(void)
|
||||
{
|
||||
ofono_gprs_driver_register(&driver);
|
||||
}
|
||||
|
||||
void mbim_gprs_exit(void)
|
||||
{
|
||||
ofono_gprs_driver_unregister(&driver);
|
||||
}
|
||||
80
ofono/drivers/mbimmodem/mbim-desc.c
Normal file
80
ofono/drivers/mbimmodem/mbim-desc.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "mbim-desc.h"
|
||||
|
||||
/*
|
||||
* Attempts to find MBIM specific descriptors.
|
||||
*
|
||||
* Returns true if the MBIM Function descriptor was found, false otherwise.
|
||||
*/
|
||||
bool mbim_find_descriptors(const uint8_t *data, size_t data_len,
|
||||
const struct mbim_desc **out_desc,
|
||||
const struct mbim_extended_desc **out_ext_desc)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
while (data_len > 3) {
|
||||
uint8_t len = data[0];
|
||||
|
||||
if (data[1] != 0x24)
|
||||
goto next;
|
||||
|
||||
/* MBIM v1.0, Table 4-3 */
|
||||
switch (data[2]) {
|
||||
case 0x1b:
|
||||
if (!out_desc)
|
||||
break;
|
||||
|
||||
if (len != sizeof(struct mbim_desc) || data_len < len)
|
||||
break;
|
||||
|
||||
*out_desc = (const struct mbim_desc *) data;
|
||||
r = true;
|
||||
break;
|
||||
case 0x1c:
|
||||
if (!out_ext_desc)
|
||||
break;
|
||||
|
||||
if (len != sizeof(struct mbim_extended_desc) ||
|
||||
data_len < len)
|
||||
break;
|
||||
|
||||
*out_ext_desc =
|
||||
(const struct mbim_extended_desc *) data;
|
||||
break;
|
||||
}
|
||||
|
||||
next:
|
||||
data_len -= len;
|
||||
data += len;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
49
ofono/drivers/mbimmodem/mbim-desc.h
Normal file
49
ofono/drivers/mbimmodem/mbim-desc.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
*
|
||||
* 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 <linux/types.h>
|
||||
|
||||
/* MBIM v1.0, Section 6.4: MBIM Functional Descriptor */
|
||||
struct mbim_desc {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
__le16 bcdMBIMVersion;
|
||||
__le16 wMaxControlMessage;
|
||||
uint8_t bNumberFilters;
|
||||
uint8_t bMaxFilterSize;
|
||||
__le16 wMaxSegmentSize;
|
||||
uint8_t bmNetworkCapabilities;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* MBIM v1.0, Section 6.5: MBIM Extended Functional Descriptor */
|
||||
struct mbim_extended_desc {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
__le16 bcdMBIMExtendedVersion;
|
||||
uint8_t bMaxOutstandingCommandMessages;
|
||||
__le16 wMTU;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
bool mbim_find_descriptors(const uint8_t *data, size_t data_len,
|
||||
const struct mbim_desc **out_desc,
|
||||
const struct mbim_extended_desc **out_ext_desc);
|
||||
1738
ofono/drivers/mbimmodem/mbim-message.c
Normal file
1738
ofono/drivers/mbimmodem/mbim-message.c
Normal file
File diff suppressed because it is too large
Load Diff
96
ofono/drivers/mbimmodem/mbim-message.h
Normal file
96
ofono/drivers/mbimmodem/mbim-message.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
struct mbim_message;
|
||||
struct mbim_message_iter;
|
||||
|
||||
enum mbim_command_type {
|
||||
MBIM_COMMAND_TYPE_QUERY = 0,
|
||||
MBIM_COMMAND_TYPE_SET = 1,
|
||||
};
|
||||
|
||||
struct mbim_message_iter {
|
||||
const char *sig_start;
|
||||
uint8_t sig_len;
|
||||
uint8_t sig_pos;
|
||||
const struct iovec *iov;
|
||||
uint32_t n_iov;
|
||||
uint32_t cur_iov;
|
||||
size_t cur_iov_offset;
|
||||
size_t len;
|
||||
size_t pos;
|
||||
size_t base_offset;
|
||||
uint32_t n_elem;
|
||||
char container_type;
|
||||
};
|
||||
|
||||
struct mbim_message *mbim_message_new(const uint8_t *uuid, uint32_t cid,
|
||||
enum mbim_command_type type);
|
||||
struct mbim_message *mbim_message_ref(struct mbim_message *msg);
|
||||
void mbim_message_unref(struct mbim_message *msg);
|
||||
|
||||
uint32_t mbim_message_get_error(struct mbim_message *message);
|
||||
uint32_t mbim_message_get_cid(struct mbim_message *message);
|
||||
const uint8_t *mbim_message_get_uuid(struct mbim_message *message);
|
||||
bool mbim_message_get_arguments(struct mbim_message *message,
|
||||
const char *signature, ...);
|
||||
|
||||
bool mbim_message_get_ipv4_address(struct mbim_message *message,
|
||||
uint32_t offset,
|
||||
struct in_addr *addr);
|
||||
bool mbim_message_get_ipv4_element(struct mbim_message *message,
|
||||
uint32_t offset,
|
||||
uint32_t *prefix_len,
|
||||
struct in_addr *addr);
|
||||
bool mbim_message_get_ipv6_address(struct mbim_message *essage,
|
||||
uint32_t offset,
|
||||
struct in6_addr *addr);
|
||||
bool mbim_message_get_ipv6_element(struct mbim_message *message,
|
||||
uint32_t offset,
|
||||
uint32_t *prefix_len,
|
||||
struct in6_addr *addr);
|
||||
|
||||
bool mbim_message_iter_next_entry(struct mbim_message_iter *iter, ...);
|
||||
|
||||
struct mbim_message_builder *mbim_message_builder_new(struct mbim_message *msg);
|
||||
void mbim_message_builder_free(struct mbim_message_builder *builder);
|
||||
bool mbim_message_builder_append_basic(struct mbim_message_builder *builder,
|
||||
char type, const void *value);
|
||||
bool mbim_message_builder_append_bytes(struct mbim_message_builder *builder,
|
||||
size_t len, const uint8_t *bytes);
|
||||
bool mbim_message_builder_enter_struct(struct mbim_message_builder *builder,
|
||||
const char *signature);
|
||||
bool mbim_message_builder_leave_struct(struct mbim_message_builder *builder);
|
||||
bool mbim_message_builder_enter_array(struct mbim_message_builder *builder,
|
||||
const char *signature);
|
||||
bool mbim_message_builder_leave_array(struct mbim_message_builder *builder);
|
||||
bool mbim_message_builder_enter_databuf(struct mbim_message_builder *builder,
|
||||
const char *signature);
|
||||
bool mbim_message_builder_leave_databuf(struct mbim_message_builder *builder);
|
||||
struct mbim_message *mbim_message_builder_finalize(
|
||||
struct mbim_message_builder *builder);
|
||||
|
||||
bool mbim_message_set_arguments(struct mbim_message *message,
|
||||
const char *signature, ...);
|
||||
59
ofono/drivers/mbimmodem/mbim-private.h
Normal file
59
ofono/drivers/mbimmodem/mbim-private.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#define align_len(len, boundary) (((len)+(boundary)-1) & ~((boundary)-1))
|
||||
|
||||
enum mbim_control_message {
|
||||
MBIM_OPEN_MSG = 0x1,
|
||||
MBIM_CLOSE_MSG = 0x2,
|
||||
MBIM_COMMAND_MSG = 0x3,
|
||||
MBIM_HOST_ERROR_MSG = 0x4,
|
||||
MBIM_OPEN_DONE = 0x80000001,
|
||||
MBIM_CLOSE_DONE = 0x80000002,
|
||||
MBIM_COMMAND_DONE = 0x80000003,
|
||||
MBIM_FUNCTION_ERROR_MSG = 0x80000004,
|
||||
MBIM_INDICATE_STATUS_MSG = 0x80000007,
|
||||
};
|
||||
|
||||
/* MBIM v1.0, Section 9.1 */
|
||||
struct mbim_message_header {
|
||||
__le32 type;
|
||||
__le32 len;
|
||||
__le32 tid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* MBIM v1.0, Section 9.1 */
|
||||
struct mbim_fragment_header {
|
||||
__le32 num_frags;
|
||||
__le32 cur_frag;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mbim_message *_mbim_message_build(const void *header,
|
||||
struct iovec *frags,
|
||||
uint32_t n_frags);
|
||||
struct mbim_message *_mbim_message_new_command_done(const uint8_t *uuid,
|
||||
uint32_t cid, uint32_t status);
|
||||
uint32_t _mbim_information_buffer_offset(uint32_t type);
|
||||
void _mbim_message_set_tid(struct mbim_message *message, uint32_t tid);
|
||||
void *_mbim_message_to_bytearray(struct mbim_message *message, size_t *out_len);
|
||||
void *_mbim_message_get_header(struct mbim_message *message, size_t *out_len);
|
||||
struct iovec *_mbim_message_get_body(struct mbim_message *message,
|
||||
size_t *out_n_iov, size_t *out_len);
|
||||
1218
ofono/drivers/mbimmodem/mbim.c
Normal file
1218
ofono/drivers/mbimmodem/mbim.c
Normal file
File diff suppressed because it is too large
Load Diff
149
ofono/drivers/mbimmodem/mbim.h
Normal file
149
ofono/drivers/mbimmodem/mbim.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
struct mbim_device;
|
||||
struct mbim_message;
|
||||
|
||||
#define MBIM_CID_DEVICE_CAPS 1
|
||||
#define MBIM_CID_SUBSCRIBER_READY_STATUS 2
|
||||
#define MBIM_CID_RADIO_STATE 3
|
||||
#define MBIM_CID_PIN 4
|
||||
#define MBIM_CID_PIN_LIST 5
|
||||
#define MBIM_CID_HOME_PROVIDER 6
|
||||
#define MBIM_CID_PREFERRED_PROVIDERS 7
|
||||
#define MBIM_CID_VISIBLE_PROVIDERS 8
|
||||
#define MBIM_CID_REGISTER_STATE 9
|
||||
#define MBIM_CID_PACKET_SERVICE 10
|
||||
#define MBIM_CID_SIGNAL_STATE 11
|
||||
#define MBIM_CID_CONNECT 12
|
||||
#define MBIM_CID_PROVISIONED_CONTEXTS 13
|
||||
#define MBIM_CID_SERVICE_ACTIVATION 14
|
||||
#define MBIM_CID_IP_CONFIGURATION 15
|
||||
#define MBIM_CID_DEVICE_SERVICES 16
|
||||
#define MBIM_CID_DEVICE_SERVICE_SUBSCRIBE_LIST 19
|
||||
#define MBIM_CID_PACKET_STATISTICS 20
|
||||
#define MBIM_CID_NETWORK_IDLE_HINT 21
|
||||
#define MBIM_CID_EMERGENCY_MODE 22
|
||||
#define MBIM_CID_IP_PACKET_FILTERS 23
|
||||
#define MBIM_CID_MULTICARRIER_PROVIDERS 24
|
||||
|
||||
#define MBIM_CID_SMS_CONFIGURATION 1
|
||||
#define MBIM_CID_SMS_READ 2
|
||||
#define MBIM_CID_SMS_SEND 3
|
||||
#define MBIM_CID_SMS_DELETE 4
|
||||
#define MBIM_CID_SMS_MESSAGE_STORE_STATUS 5
|
||||
|
||||
#define MBIM_CID_USSD 1
|
||||
|
||||
#define MBIM_CID_PHONEBOOK_CONFIGURATION 1
|
||||
#define MBIM_CID_PHONEBOOK_READ 2
|
||||
#define MBIM_CID_PHONEBOOK_DELETE 3
|
||||
#define MBIM_CID_PHONEBOOK_WRITE 4
|
||||
|
||||
#define MBIM_CID_STK_PAC 1
|
||||
#define MBIM_CID_STK_TERMINAL_RESPONSE 2
|
||||
#define MBIM_CID_STK_ENVELOPE 3
|
||||
|
||||
#define MBIM_CID_AKA_AUTH 1
|
||||
#define MBIM_CID_AKAP_AUTH 2
|
||||
#define MBIM_CID_SIM_AUTH 3
|
||||
|
||||
#define MBIM_CID_DSS_CONNECT 1
|
||||
|
||||
/* Table 10-11 */
|
||||
enum mbim_data_class {
|
||||
MBIM_DATA_CLASS_NONE = 0x00,
|
||||
MBIM_DATA_CLASS_GPRS = 0x01,
|
||||
MBIM_DATA_CLASS_EDGE = 0x02,
|
||||
MBIM_DATA_CLASS_UMTS = 0x04,
|
||||
MBIM_DATA_CLASS_HSDPA = 0x08,
|
||||
MBIM_DATA_CLASS_HSUPA = 0x10,
|
||||
MBIM_DATA_CLASS_LTE = 0x20,
|
||||
MBIM_DATA_CLASS_1XRTT = 0x10000,
|
||||
MBIM_DATA_CLASS_EVDO = 0x20000,
|
||||
MBIM_DATA_CLASS_EVDO_REVA = 0x40000,
|
||||
MBIM_DATA_CLASS_1XEVDV = 0x80000,
|
||||
MBIM_DATA_CLASS_3XRTT = 0x100000,
|
||||
MBIM_DATA_CLASS_1XEVDO_REVB = 0x200000,
|
||||
MBIM_DATA_CLASS_UMB = 0x400000,
|
||||
MBIM_DATA_CLASS_CUSTOM = 0x80000000,
|
||||
};
|
||||
|
||||
typedef void (*mbim_device_debug_func_t) (const char *str, void *user_data);
|
||||
typedef void (*mbim_device_disconnect_func_t) (void *user_data);
|
||||
typedef void (*mbim_device_destroy_func_t) (void *user_data);
|
||||
typedef void (*mbim_device_ready_func_t) (void *user_data);
|
||||
typedef void (*mbim_device_reply_func_t) (struct mbim_message *message,
|
||||
void *user_data);
|
||||
|
||||
extern const uint8_t mbim_uuid_basic_connect[];
|
||||
extern const uint8_t mbim_uuid_sms[];
|
||||
extern const uint8_t mbim_uuid_ussd[];
|
||||
extern const uint8_t mbim_uuid_phonebook[];
|
||||
extern const uint8_t mbim_uuid_stk[];
|
||||
extern const uint8_t mbim_uuid_auth[];
|
||||
extern const uint8_t mbim_uuid_dss[];
|
||||
|
||||
extern const uint8_t mbim_context_type_none[];
|
||||
extern const uint8_t mbim_context_type_internet[];
|
||||
extern const uint8_t mbim_context_type_vpn[];
|
||||
extern const uint8_t mbim_context_type_voice[];
|
||||
extern const uint8_t mbim_context_type_video_share[];
|
||||
extern const uint8_t mbim_context_type_purchase[];
|
||||
extern const uint8_t mbim_context_type_ims[];
|
||||
extern const uint8_t mbim_context_type_mms[];
|
||||
extern const uint8_t mbim_context_type_local[];
|
||||
|
||||
struct mbim_device *mbim_device_new(int fd, uint32_t max_segment_size);
|
||||
bool mbim_device_set_close_on_unref(struct mbim_device *device, bool do_close);
|
||||
struct mbim_device *mbim_device_ref(struct mbim_device *device);
|
||||
void mbim_device_unref(struct mbim_device *device);
|
||||
bool mbim_device_shutdown(struct mbim_device *device);
|
||||
|
||||
bool mbim_device_set_max_outstanding(struct mbim_device *device, uint32_t max);
|
||||
|
||||
bool mbim_device_set_debug(struct mbim_device *device,
|
||||
mbim_device_debug_func_t func, void *user_data,
|
||||
mbim_device_destroy_func_t destroy);
|
||||
bool mbim_device_set_disconnect_handler(struct mbim_device *device,
|
||||
mbim_device_disconnect_func_t function,
|
||||
void *user_data,
|
||||
mbim_device_destroy_func_t destroy);
|
||||
bool mbim_device_set_ready_handler(struct mbim_device *device,
|
||||
mbim_device_ready_func_t function,
|
||||
void *user_data,
|
||||
mbim_device_destroy_func_t destroy);
|
||||
|
||||
uint32_t mbim_device_send(struct mbim_device *device, uint32_t gid,
|
||||
struct mbim_message *message,
|
||||
mbim_device_reply_func_t function,
|
||||
void *user_data,
|
||||
mbim_device_destroy_func_t destroy);
|
||||
bool mbim_device_cancel(struct mbim_device *device, uint32_t tid);
|
||||
bool mbim_device_cancel_group(struct mbim_device *device, uint32_t gid);
|
||||
|
||||
uint32_t mbim_device_register(struct mbim_device *device, uint32_t gid,
|
||||
const uint8_t *uuid, uint32_t cid,
|
||||
mbim_device_reply_func_t notify,
|
||||
void *user_data,
|
||||
mbim_device_destroy_func_t destroy);
|
||||
bool mbim_device_unregister(struct mbim_device *device, uint32_t id);
|
||||
bool mbim_device_unregister_group(struct mbim_device *device, uint32_t gid);
|
||||
53
ofono/drivers/mbimmodem/mbimmodem.c
Normal file
53
ofono/drivers/mbimmodem/mbimmodem.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
*
|
||||
* 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 OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
|
||||
#include "mbimmodem.h"
|
||||
|
||||
static int mbimmodem_init(void)
|
||||
{
|
||||
mbim_devinfo_init();
|
||||
mbim_sim_init();
|
||||
mbim_netreg_init();
|
||||
mbim_sms_exit();
|
||||
mbim_gprs_init();
|
||||
mbim_gprs_context_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbimmodem_exit(void)
|
||||
{
|
||||
mbim_gprs_context_exit();
|
||||
mbim_gprs_exit();
|
||||
mbim_sms_exit();
|
||||
mbim_netreg_exit();
|
||||
mbim_sim_exit();
|
||||
mbim_devinfo_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(mbimmodem, "MBIM modem driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, mbimmodem_init, mbimmodem_exit)
|
||||
48
ofono/drivers/mbimmodem/mbimmodem.h
Normal file
48
ofono/drivers/mbimmodem/mbimmodem.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
*
|
||||
* 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 "util.h"
|
||||
|
||||
enum MBIM_GROUP {
|
||||
SIM_GROUP = 1,
|
||||
NETREG_GROUP = 2,
|
||||
SMS_GROUP = 3,
|
||||
GPRS_GROUP = 4,
|
||||
GPRS_CONTEXT_GROUP = 101,
|
||||
};
|
||||
|
||||
extern void mbim_devinfo_init(void);
|
||||
extern void mbim_devinfo_exit(void);
|
||||
|
||||
extern void mbim_sim_init(void);
|
||||
extern void mbim_sim_exit(void);
|
||||
|
||||
extern void mbim_netreg_init(void);
|
||||
extern void mbim_netreg_exit(void);
|
||||
|
||||
extern void mbim_sms_init(void);
|
||||
extern void mbim_sms_exit(void);
|
||||
|
||||
extern void mbim_gprs_init(void);
|
||||
extern void mbim_gprs_exit(void);
|
||||
|
||||
extern void mbim_gprs_context_init(void);
|
||||
extern void mbim_gprs_context_exit(void);
|
||||
416
ofono/drivers/mbimmodem/network-registration.c
Normal file
416
ofono/drivers/mbimmodem/network-registration.c
Normal file
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
#include "src/common.h"
|
||||
|
||||
#include "drivers/mbimmodem/mbim.h"
|
||||
#include "drivers/mbimmodem/mbim-message.h"
|
||||
#include "drivers/mbimmodem/mbimmodem.h"
|
||||
|
||||
struct netreg_data {
|
||||
struct mbim_device *device;
|
||||
struct l_idle *delayed_register;
|
||||
};
|
||||
|
||||
static inline int register_state_to_status(uint32_t register_state)
|
||||
{
|
||||
switch (register_state) {
|
||||
case 0: /* MBIMRegisterStateUnknown */
|
||||
return NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
case 1: /* MBIMRegisterStateDeregistered */
|
||||
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
case 2: /* MBIMRegisterStateSearching */
|
||||
return NETWORK_REGISTRATION_STATUS_SEARCHING;
|
||||
case 3: /* MBIMRegisterStateHome */
|
||||
return NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
case 4: /* MBIMRegisterStateRoaming */
|
||||
case 5: /* MBIMRegisterStatePartner */
|
||||
return NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||
case 6: /* MBIMRegisterStateDenied */
|
||||
return NETWORK_REGISTRATION_STATUS_DENIED;
|
||||
}
|
||||
|
||||
return NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
static void mbim_register_state_changed(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct ofono_netreg *netreg = user;
|
||||
uint32_t nw_error;
|
||||
uint32_t register_state;
|
||||
uint32_t register_mode;
|
||||
uint32_t available_data_classes;
|
||||
int status;
|
||||
int tech;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuuu",
|
||||
&nw_error, ®ister_state,
|
||||
®ister_mode,
|
||||
&available_data_classes))
|
||||
return;
|
||||
|
||||
DBG("NwError: %u, RegisterMode: %u", nw_error, register_mode);
|
||||
|
||||
status = register_state_to_status(register_state);
|
||||
tech = mbim_data_class_to_tech(available_data_classes);
|
||||
|
||||
ofono_netreg_status_notify(netreg, status, -1, -1, tech);
|
||||
}
|
||||
|
||||
static void mbim_registration_status_cb(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_netreg_status_cb_t cb = cbd->cb;
|
||||
uint32_t dummy;
|
||||
uint32_t register_state;
|
||||
uint32_t available_data_classes;
|
||||
int status;
|
||||
int tech;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuuu",
|
||||
&dummy, ®ister_state,
|
||||
&dummy,
|
||||
&available_data_classes))
|
||||
goto error;
|
||||
|
||||
status = register_state_to_status(register_state);
|
||||
tech = mbim_data_class_to_tech(available_data_classes);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, status, -1, -1, tech, cbd->data);
|
||||
return;
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_registration_status(struct ofono_netreg *netreg,
|
||||
ofono_netreg_status_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_REGISTER_STATE,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (mbim_device_send(nd->device, NETREG_GROUP, message,
|
||||
mbim_registration_status_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
|
||||
}
|
||||
|
||||
static void mbim_current_operator_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_netreg_operator_cb_t cb = cbd->cb;
|
||||
struct ofono_network_operator op;
|
||||
uint32_t dummy;
|
||||
uint32_t register_state;
|
||||
uint32_t available_data_classes;
|
||||
L_AUTO_FREE_VAR(char *, provider_id) = NULL;
|
||||
L_AUTO_FREE_VAR(char *, provider_name) = NULL;
|
||||
L_AUTO_FREE_VAR(char *, roaming_text) = NULL;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuuuusss",
|
||||
&dummy, ®ister_state, &dummy,
|
||||
&available_data_classes, &dummy,
|
||||
&provider_id, &provider_name,
|
||||
&roaming_text))
|
||||
goto error;
|
||||
|
||||
if (register_state < 3 || register_state > 5)
|
||||
goto error;
|
||||
|
||||
DBG("provider: %s(%s)", provider_name, provider_id);
|
||||
|
||||
/* If MBIMRegisterStateRoaming or MBIMRegisterStatePartner */
|
||||
if (register_state == 4 || register_state == 5)
|
||||
DBG("roaming text: %s", roaming_text);
|
||||
|
||||
strncpy(op.name, provider_name, OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
op.name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
|
||||
|
||||
strncpy(op.mcc, provider_id, OFONO_MAX_MCC_LENGTH);
|
||||
op.mcc[OFONO_MAX_MCC_LENGTH] = '\0';
|
||||
|
||||
strncpy(op.mnc, provider_id + OFONO_MAX_MCC_LENGTH,
|
||||
OFONO_MAX_MNC_LENGTH);
|
||||
op.mnc[OFONO_MAX_MNC_LENGTH] = '\0';
|
||||
|
||||
/* Set to current */
|
||||
op.status = 2;
|
||||
op.tech = mbim_data_class_to_tech(available_data_classes);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, &op, cbd->data);
|
||||
return;
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_current_operator(struct ofono_netreg *netreg,
|
||||
ofono_netreg_operator_cb_t cb, void *data)
|
||||
{
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_REGISTER_STATE,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (mbim_device_send(nd->device, NETREG_GROUP, message,
|
||||
mbim_current_operator_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
|
||||
static void mbim_register_state_set_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_netreg_register_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
else
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_register_auto(struct ofono_netreg *netreg,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
static const uint32_t data_class = MBIM_DATA_CLASS_GPRS |
|
||||
MBIM_DATA_CLASS_EDGE |
|
||||
MBIM_DATA_CLASS_UMTS |
|
||||
MBIM_DATA_CLASS_HSDPA |
|
||||
MBIM_DATA_CLASS_HSUPA |
|
||||
MBIM_DATA_CLASS_LTE;
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_REGISTER_STATE,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(message, "suu", NULL, 0, data_class);
|
||||
|
||||
if (mbim_device_send(nd->device, NETREG_GROUP, message,
|
||||
mbim_register_state_set_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static inline int convert_signal_strength(uint32_t strength)
|
||||
{
|
||||
if (strength == 99)
|
||||
return -1;
|
||||
|
||||
return strength * 100 / 31;
|
||||
}
|
||||
|
||||
static void mbim_signal_state_query_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_netreg_strength_cb_t cb = cbd->cb;
|
||||
uint32_t strength;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "u", &strength))
|
||||
goto error;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, convert_signal_strength(strength), cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_signal_strength(struct ofono_netreg *netreg,
|
||||
ofono_netreg_strength_cb_t cb, void *data)
|
||||
{
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_SIGNAL_STATE,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (mbim_device_send(nd->device, NETREG_GROUP, message,
|
||||
mbim_signal_state_query_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void mbim_signal_state_changed(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct ofono_netreg *netreg = user;
|
||||
uint32_t strength;
|
||||
uint32_t error_rate;
|
||||
uint32_t signal_strength_interval;
|
||||
uint32_t rssi_threshold;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuuu",
|
||||
&strength, &error_rate,
|
||||
&signal_strength_interval,
|
||||
&rssi_threshold))
|
||||
return;
|
||||
|
||||
DBG("strength: %u, error_rate: %u", strength, error_rate);
|
||||
DBG("strength interval: %u, rssi_threshold: %u",
|
||||
signal_strength_interval, rssi_threshold);
|
||||
|
||||
ofono_netreg_strength_notify(netreg, convert_signal_strength(strength));
|
||||
}
|
||||
|
||||
static void delayed_register(struct l_idle *idle, void *user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
|
||||
DBG("");
|
||||
|
||||
l_idle_remove(idle);
|
||||
nd->delayed_register = NULL;
|
||||
|
||||
if (!mbim_device_register(nd->device, NETREG_GROUP,
|
||||
mbim_uuid_basic_connect,
|
||||
MBIM_CID_SIGNAL_STATE,
|
||||
mbim_signal_state_changed,
|
||||
netreg, NULL))
|
||||
goto error;
|
||||
|
||||
if (!mbim_device_register(nd->device, NETREG_GROUP,
|
||||
mbim_uuid_basic_connect,
|
||||
MBIM_CID_REGISTER_STATE,
|
||||
mbim_register_state_changed,
|
||||
netreg, NULL))
|
||||
goto error;
|
||||
|
||||
ofono_netreg_register(netreg);
|
||||
return;
|
||||
|
||||
error:
|
||||
ofono_netreg_remove(netreg);
|
||||
}
|
||||
|
||||
static int mbim_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct mbim_device *device = data;
|
||||
struct netreg_data *nd = l_new(struct netreg_data, 1);
|
||||
|
||||
DBG("");
|
||||
|
||||
nd->device = mbim_device_ref(device);
|
||||
nd->delayed_register = l_idle_create(delayed_register, netreg, NULL);
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_netreg_set_data(netreg, NULL);
|
||||
|
||||
l_idle_remove(nd->delayed_register);
|
||||
mbim_device_cancel_group(nd->device, NETREG_GROUP);
|
||||
mbim_device_unregister_group(nd->device, NETREG_GROUP);
|
||||
mbim_device_unref(nd->device);
|
||||
nd->device = NULL;
|
||||
l_free(nd);
|
||||
}
|
||||
|
||||
static struct ofono_netreg_driver driver = {
|
||||
.name = "mbim",
|
||||
.probe = mbim_netreg_probe,
|
||||
.remove = mbim_netreg_remove,
|
||||
.registration_status = mbim_registration_status,
|
||||
.current_operator = mbim_current_operator,
|
||||
.register_auto = mbim_register_auto,
|
||||
.strength = mbim_signal_strength,
|
||||
};
|
||||
|
||||
void mbim_netreg_init(void)
|
||||
{
|
||||
ofono_netreg_driver_register(&driver);
|
||||
}
|
||||
|
||||
void mbim_netreg_exit(void)
|
||||
{
|
||||
ofono_netreg_driver_unregister(&driver);
|
||||
}
|
||||
533
ofono/drivers/mbimmodem/sim.c
Normal file
533
ofono/drivers/mbimmodem/sim.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "drivers/mbimmodem/mbim.h"
|
||||
#include "drivers/mbimmodem/mbim-message.h"
|
||||
#include "drivers/mbimmodem/mbimmodem.h"
|
||||
|
||||
struct sim_data {
|
||||
struct mbim_device *device;
|
||||
char *iccid;
|
||||
char *imsi;
|
||||
uint32_t last_pin_type;
|
||||
bool present : 1;
|
||||
};
|
||||
|
||||
static void mbim_sim_state_changed(struct ofono_sim *sim, uint32_t ready_state)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
|
||||
DBG("ready_state: %u", ready_state);
|
||||
|
||||
switch (ready_state) {
|
||||
case 0: /* Not Initialized */
|
||||
break;
|
||||
case 1: /* Initialized */
|
||||
if (!sd->present)
|
||||
ofono_sim_inserted_notify(sim, true);
|
||||
|
||||
sd->present = true;
|
||||
ofono_sim_initialized_notify(sim);
|
||||
break;
|
||||
case 6: /* Device Locked */
|
||||
if (!sd->present)
|
||||
ofono_sim_inserted_notify(sim, true);
|
||||
|
||||
sd->present = true;
|
||||
break;
|
||||
case 2: /* Not inserted */
|
||||
case 3: /* Bad SIM */
|
||||
case 4: /* Failure */
|
||||
case 5: /* Not activated */
|
||||
if (sd->present)
|
||||
ofono_sim_inserted_notify(sim, false);
|
||||
|
||||
sd->present = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void mbim_read_imsi(struct ofono_sim *sim,
|
||||
ofono_sim_imsi_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
|
||||
DBG("");
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, sd->imsi, user_data);
|
||||
}
|
||||
|
||||
static enum ofono_sim_password_type mbim_pin_type_to_sim_password(
|
||||
uint32_t pin_type)
|
||||
{
|
||||
switch (pin_type) {
|
||||
case 0: /* No Pin */
|
||||
return OFONO_SIM_PASSWORD_NONE;
|
||||
case 2: /* PIN1 key */
|
||||
return OFONO_SIM_PASSWORD_SIM_PIN;
|
||||
case 3: /* PIN2 key */
|
||||
return OFONO_SIM_PASSWORD_SIM_PIN2;
|
||||
case 4: /* device to SIM key */
|
||||
return OFONO_SIM_PASSWORD_PHSIM_PIN;
|
||||
case 5: /* device to very first SIM key */
|
||||
return OFONO_SIM_PASSWORD_PHFSIM_PIN;
|
||||
case 6: /* network personalization key */
|
||||
return OFONO_SIM_PASSWORD_PHNET_PIN;
|
||||
case 7: /* network subset personalization key */
|
||||
return OFONO_SIM_PASSWORD_PHNETSUB_PIN;
|
||||
case 8: /* service provider (SP) personalization key */
|
||||
return OFONO_SIM_PASSWORD_PHSP_PIN;
|
||||
case 9: /* corporate personalization key */
|
||||
return OFONO_SIM_PASSWORD_PHCORP_PIN;
|
||||
case 11: /* PUK1 */
|
||||
return OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
case 12: /* PUK2 */
|
||||
return OFONO_SIM_PASSWORD_SIM_PUK2;
|
||||
case 13: /* device to very first SIM PIN unlock key */
|
||||
return OFONO_SIM_PASSWORD_PHFSIM_PUK;
|
||||
case 14: /* network personalization unlock key */
|
||||
return OFONO_SIM_PASSWORD_PHNET_PUK;
|
||||
case 15: /* network subset personaliation unlock key */
|
||||
return OFONO_SIM_PASSWORD_PHNETSUB_PUK;
|
||||
case 16: /* service provider (SP) personalization unlock key */
|
||||
return OFONO_SIM_PASSWORD_PHSP_PUK;
|
||||
case 17: /* corporate personalization unlock key */
|
||||
return OFONO_SIM_PASSWORD_PHCORP_PUK;
|
||||
}
|
||||
|
||||
return OFONO_SIM_PASSWORD_INVALID;
|
||||
}
|
||||
|
||||
static uint32_t mbim_pin_type_from_sim_password(
|
||||
enum ofono_sim_password_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case OFONO_SIM_PASSWORD_SIM_PIN:
|
||||
return 2; /* PIN1 key */
|
||||
case OFONO_SIM_PASSWORD_SIM_PIN2:
|
||||
return 3; /* PIN2 key */
|
||||
case OFONO_SIM_PASSWORD_PHSIM_PIN:
|
||||
return 4; /* device to SIM key */
|
||||
case OFONO_SIM_PASSWORD_PHFSIM_PIN:
|
||||
return 5; /* device to very first SIM key */
|
||||
case OFONO_SIM_PASSWORD_PHNET_PIN:
|
||||
return 6; /* network personalization key */
|
||||
case OFONO_SIM_PASSWORD_PHNETSUB_PIN:
|
||||
return 7; /* network subset personalization key */
|
||||
case OFONO_SIM_PASSWORD_PHSP_PIN:
|
||||
return 8; /* service provider (SP) personalization key */
|
||||
case OFONO_SIM_PASSWORD_PHCORP_PIN:
|
||||
return 9; /* corporate personalization key */
|
||||
case OFONO_SIM_PASSWORD_SIM_PUK:
|
||||
return 11; /* PUK1 */
|
||||
case OFONO_SIM_PASSWORD_SIM_PUK2:
|
||||
return 12; /* PUK2 */
|
||||
case OFONO_SIM_PASSWORD_PHFSIM_PUK:
|
||||
return 13; /* device to very first SIM PIN unlock key */
|
||||
case OFONO_SIM_PASSWORD_PHNET_PUK:
|
||||
return 14; /* network personalization unlock key */
|
||||
case OFONO_SIM_PASSWORD_PHNETSUB_PUK:
|
||||
return 15; /* network subset personaliation unlock key */
|
||||
case OFONO_SIM_PASSWORD_PHSP_PUK:
|
||||
return 16; /* service provider (SP) personalization unlock key */
|
||||
case OFONO_SIM_PASSWORD_PHCORP_PUK:
|
||||
return 17; /* corporate personalization unlock key */
|
||||
case OFONO_SIM_PASSWORD_NONE:
|
||||
case OFONO_SIM_PASSWORD_INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_pin_query_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
struct sim_data *sd = cbd->user;
|
||||
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||
uint32_t pin_type;
|
||||
uint32_t pin_state;
|
||||
enum ofono_sim_password_type sim_password;
|
||||
bool r;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
r = mbim_message_get_arguments(message, "uu",
|
||||
&pin_type, &pin_state);
|
||||
if (!r)
|
||||
goto error;
|
||||
|
||||
sim_password = mbim_pin_type_to_sim_password(pin_type);
|
||||
if (sim_password == OFONO_SIM_PASSWORD_INVALID)
|
||||
goto error;
|
||||
|
||||
if (pin_state == 0)
|
||||
sim_password = OFONO_SIM_PASSWORD_NONE;
|
||||
|
||||
sd->last_pin_type = pin_type;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_password, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_pin_query(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = sd;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_PIN,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (mbim_device_send(sd->device, SIM_GROUP, message,
|
||||
mbim_pin_query_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
}
|
||||
|
||||
static void mbim_pin_retries_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
size_t i;
|
||||
uint32_t pin_type;
|
||||
uint32_t pin_state;
|
||||
uint32_t remaining;
|
||||
enum ofono_sim_password_type sim_password;
|
||||
bool r;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
r = mbim_message_get_arguments(message, "uuu",
|
||||
&pin_type, &pin_state, &remaining);
|
||||
if (!r)
|
||||
goto error;
|
||||
|
||||
sim_password = mbim_pin_type_to_sim_password(pin_type);
|
||||
if (sim_password == OFONO_SIM_PASSWORD_INVALID)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
retries[i] = -1;
|
||||
|
||||
if (pin_state == 0 || sim_password == OFONO_SIM_PASSWORD_NONE) {
|
||||
CALLBACK_WITH_SUCCESS(cb, retries, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (remaining == 0xffffffff)
|
||||
retries[sim_password] = -1;
|
||||
else
|
||||
retries[sim_password] = remaining;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, retries, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_pin_retries_query(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("");
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_PIN,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (mbim_device_send(sd->device, SIM_GROUP, message,
|
||||
mbim_pin_retries_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
||||
}
|
||||
|
||||
static void mbim_pin_set_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
else
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_pin_set(struct ofono_sim *sim, uint32_t pin_type,
|
||||
uint32_t pin_operation,
|
||||
const char *old_passwd,
|
||||
const char *new_passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("%u %u %s %s", pin_type, pin_operation, old_passwd, new_passwd);
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_PIN,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(message, "uuss", pin_type, pin_operation,
|
||||
old_passwd, new_passwd);
|
||||
|
||||
if (mbim_device_send(sd->device, SIM_GROUP, message,
|
||||
mbim_pin_set_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void mbim_pin_enter(struct ofono_sim *sim, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
|
||||
/* Use MBIMPinOperationEnter (0) and NULL second PIN */
|
||||
mbim_pin_set(sim, sd->last_pin_type, 0, passwd, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void mbim_puk_enter(struct ofono_sim *sim, const char *puk,
|
||||
const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
|
||||
/* Use MBIMPinOperationEnter (0) and second PIN */
|
||||
mbim_pin_set(sim, sd->last_pin_type, 0, puk, passwd, cb, data);
|
||||
}
|
||||
|
||||
static void mbim_pin_enable(struct ofono_sim *sim,
|
||||
enum ofono_sim_password_type passwd_type,
|
||||
int enable, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
uint32_t pin_type = mbim_pin_type_from_sim_password(passwd_type);
|
||||
|
||||
if (pin_type == 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use MBIMPinOperationEnable (1) or MBIMPinOperationDisable (2) */
|
||||
mbim_pin_set(sim, pin_type, enable ? 1 : 2, passwd, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void mbim_pin_change(struct ofono_sim *sim,
|
||||
enum ofono_sim_password_type passwd_type,
|
||||
const char *old_passwd, const char *new_passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
uint32_t pin_type = mbim_pin_type_from_sim_password(passwd_type);
|
||||
|
||||
if (pin_type == 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use MBIMPinOperationChange (3) */
|
||||
mbim_pin_set(sim, pin_type, 3, old_passwd, new_passwd, cb, data);
|
||||
}
|
||||
|
||||
static void mbim_subscriber_ready_status_changed(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct ofono_sim *sim = user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
uint32_t ready_state;
|
||||
char *imsi;
|
||||
char *iccid;
|
||||
uint32_t ready_info;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_message_get_arguments(message, "ussu",
|
||||
&ready_state, &imsi,
|
||||
&iccid, &ready_info))
|
||||
return;
|
||||
|
||||
l_free(sd->iccid);
|
||||
sd->iccid = iccid;
|
||||
|
||||
l_free(sd->imsi);
|
||||
sd->imsi = imsi;
|
||||
|
||||
DBG("%s %s", iccid, imsi);
|
||||
|
||||
mbim_sim_state_changed(sim, ready_state);
|
||||
}
|
||||
|
||||
static void mbim_subscriber_ready_status_cb(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct ofono_sim *sim = user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
uint32_t ready_state;
|
||||
char *imsi;
|
||||
char *iccid;
|
||||
uint32_t ready_info;
|
||||
bool r;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
/* We don't bother parsing MSISDN/MDN array */
|
||||
r = mbim_message_get_arguments(message, "ussu",
|
||||
&ready_state, &imsi,
|
||||
&iccid, &ready_info);
|
||||
if (!r)
|
||||
goto error;
|
||||
|
||||
sd->iccid = iccid;
|
||||
sd->imsi = imsi;
|
||||
|
||||
if (!mbim_device_register(sd->device, SIM_GROUP,
|
||||
mbim_uuid_basic_connect,
|
||||
MBIM_CID_SUBSCRIBER_READY_STATUS,
|
||||
mbim_subscriber_ready_status_changed,
|
||||
sim, NULL))
|
||||
goto error;
|
||||
|
||||
ofono_sim_register(sim);
|
||||
DBG("%s %s", iccid, imsi);
|
||||
mbim_sim_state_changed(sim, ready_state);
|
||||
return;
|
||||
|
||||
error:
|
||||
ofono_sim_remove(sim);
|
||||
}
|
||||
|
||||
static int mbim_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct mbim_device *device = data;
|
||||
struct mbim_message *message;
|
||||
struct sim_data *sd;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_basic_connect,
|
||||
MBIM_CID_SUBSCRIBER_READY_STATUS,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
if (!message)
|
||||
return -ENOMEM;
|
||||
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (!mbim_device_send(device, SIM_GROUP, message,
|
||||
mbim_subscriber_ready_status_cb, sim, NULL)) {
|
||||
mbim_message_unref(message);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sd = l_new(struct sim_data, 1);
|
||||
sd->device = mbim_device_ref(device);
|
||||
ofono_sim_set_data(sim, sd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_sim_remove(struct ofono_sim *sim)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
mbim_device_cancel_group(sd->device, SIM_GROUP);
|
||||
mbim_device_unregister_group(sd->device, SIM_GROUP);
|
||||
mbim_device_unref(sd->device);
|
||||
sd->device = NULL;
|
||||
|
||||
l_free(sd->iccid);
|
||||
l_free(sd->imsi);
|
||||
l_free(sd);
|
||||
}
|
||||
|
||||
static struct ofono_sim_driver driver = {
|
||||
.name = "mbim",
|
||||
.probe = mbim_sim_probe,
|
||||
.remove = mbim_sim_remove,
|
||||
.read_imsi = mbim_read_imsi,
|
||||
.query_passwd_state = mbim_pin_query,
|
||||
.query_pin_retries = mbim_pin_retries_query,
|
||||
.send_passwd = mbim_pin_enter,
|
||||
.reset_passwd = mbim_puk_enter,
|
||||
.change_passwd = mbim_pin_change,
|
||||
.lock = mbim_pin_enable,
|
||||
};
|
||||
|
||||
void mbim_sim_init(void)
|
||||
{
|
||||
ofono_sim_driver_register(&driver);
|
||||
}
|
||||
|
||||
void mbim_sim_exit(void)
|
||||
{
|
||||
ofono_sim_driver_unregister(&driver);
|
||||
}
|
||||
516
ofono/drivers/mbimmodem/sms.c
Normal file
516
ofono/drivers/mbimmodem/sms.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/sms.h>
|
||||
#include "common.h"
|
||||
|
||||
#include "drivers/mbimmodem/mbim.h"
|
||||
#include "drivers/mbimmodem/mbim-message.h"
|
||||
#include "drivers/mbimmodem/mbimmodem.h"
|
||||
|
||||
struct sms_data {
|
||||
struct mbim_device *device;
|
||||
uint32_t configuration_notify_id;
|
||||
};
|
||||
|
||||
static void mbim_sca_set_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_sms_sca_set_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
else
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_sca_set(struct ofono_sms *sms,
|
||||
const struct ofono_phone_number *sca,
|
||||
ofono_sms_sca_set_cb_t cb, void *data)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
const char *numberstr = phone_number_to_string(sca);
|
||||
|
||||
message = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_CONFIGURATION,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(message, "us", 0, numberstr);
|
||||
|
||||
if (mbim_device_send(sd->device, SMS_GROUP, message,
|
||||
mbim_sca_set_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void mbim_sca_query_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
ofono_sms_sca_query_cb_t cb = cbd->cb;
|
||||
struct ofono_phone_number sca;
|
||||
uint32_t dummy;
|
||||
L_AUTO_FREE_VAR(char *, number) = NULL;
|
||||
const char *p;
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uuuus",
|
||||
&dummy, &dummy, &dummy, &dummy,
|
||||
&number))
|
||||
goto error;
|
||||
|
||||
if (number[0] == '+') {
|
||||
p = number + 1;
|
||||
sca.type = 145;
|
||||
} else {
|
||||
p = number;
|
||||
sca.type = 129;
|
||||
}
|
||||
|
||||
strncpy(sca.number, p, OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
CALLBACK_WITH_SUCCESS(cb, &sca, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_sca_query(struct ofono_sms *sms, ofono_sms_sca_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_CONFIGURATION,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (mbim_device_send(sd->device, SMS_GROUP, message,
|
||||
mbim_sca_query_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
|
||||
static void mbim_delete_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
DBG("%u", mbim_message_get_error(message));
|
||||
}
|
||||
|
||||
static void mbim_sms_send_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct cb_data *cbd = user;
|
||||
struct sms_data *sd = cbd->user;
|
||||
ofono_sms_submit_cb_t cb = cbd->cb;
|
||||
uint32_t mr;
|
||||
struct mbim_message *delete;
|
||||
|
||||
DBG("%u", mbim_message_get_error(message));
|
||||
|
||||
if (mbim_message_get_error(message) != 0)
|
||||
goto error;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "u", &mr))
|
||||
goto error;
|
||||
|
||||
/* Just in case, send an SMS DELETE command for Sent messages */
|
||||
delete = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_DELETE,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(delete, "uu", 4, 0);
|
||||
|
||||
if (!mbim_device_send(sd->device, SMS_GROUP, delete,
|
||||
mbim_delete_cb, NULL, NULL))
|
||||
mbim_message_unref(delete);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, mr, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void mbim_submit(struct ofono_sms *sms, const unsigned char *pdu,
|
||||
int pdu_len, int tpdu_len, int mms,
|
||||
ofono_sms_submit_cb_t cb, void *data)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("pdu_len: %d tpdu_len: %d mms: %d", pdu_len, tpdu_len, mms);
|
||||
|
||||
cbd->user = sd;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_SEND,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(message, "ud", 0, "ay", pdu_len, pdu);
|
||||
|
||||
if (mbim_device_send(sd->device, SMS_GROUP, message,
|
||||
mbim_sms_send_cb, cbd, l_free) > 0)
|
||||
return;
|
||||
|
||||
l_free(cbd);
|
||||
mbim_message_unref(message);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void mbim_sms_send_delete(struct sms_data *sd, uint32_t index)
|
||||
{
|
||||
struct mbim_message *delete;
|
||||
|
||||
DBG("%u", index);
|
||||
|
||||
delete = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_DELETE,
|
||||
MBIM_COMMAND_TYPE_SET);
|
||||
mbim_message_set_arguments(delete, "uu", 1, index);
|
||||
|
||||
if (!mbim_device_send(sd->device, SMS_GROUP, delete,
|
||||
mbim_delete_cb, NULL, NULL))
|
||||
mbim_message_unref(delete);
|
||||
}
|
||||
|
||||
static void mbim_parse_sms_read_info(struct mbim_message *message,
|
||||
struct ofono_sms *sms)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
uint32_t format;
|
||||
uint32_t n_sms;
|
||||
struct mbim_message_iter array;
|
||||
struct mbim_message_iter bytes;
|
||||
uint32_t index;
|
||||
uint32_t status;
|
||||
uint32_t pdu_len;
|
||||
|
||||
if (!mbim_message_get_arguments(message, "ua(uuay)",
|
||||
&format, &n_sms, &array))
|
||||
return;
|
||||
|
||||
if (format != 0)
|
||||
return;
|
||||
|
||||
while (mbim_message_iter_next_entry(&array, &index, &status,
|
||||
&pdu_len, &bytes)) {
|
||||
int i = 0;
|
||||
|
||||
/* Ignore Draft (2) and Sent (3) messages */
|
||||
if (status == 0 || status == 1) {
|
||||
uint8_t pdu[176];
|
||||
uint32_t tpdu_len;
|
||||
|
||||
while (mbim_message_iter_next_entry(&bytes, pdu + i))
|
||||
i++;
|
||||
|
||||
tpdu_len = pdu_len - pdu[0] - 1;
|
||||
ofono_sms_deliver_notify(sms, pdu, pdu_len, tpdu_len);
|
||||
}
|
||||
|
||||
mbim_sms_send_delete(sd, index);
|
||||
}
|
||||
}
|
||||
|
||||
static void mbim_sms_read_notify(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct ofono_sms *sms = user;
|
||||
|
||||
DBG("");
|
||||
|
||||
mbim_parse_sms_read_info(message, sms);
|
||||
}
|
||||
|
||||
static void mbim_sms_read_new_query_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct ofono_sms *sms = user;
|
||||
|
||||
DBG("");
|
||||
|
||||
mbim_parse_sms_read_info(message, sms);
|
||||
}
|
||||
|
||||
static void mbim_sms_message_store_status_changed(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct ofono_sms *sms = user;
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
uint32_t flag;
|
||||
uint32_t index;
|
||||
struct mbim_message *read_query;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_message_get_arguments(message, "uu", &flag, &index))
|
||||
return;
|
||||
|
||||
DBG("%u %u", flag, index);
|
||||
|
||||
/* MBIM_SMS_FLAG_NEW_MESSAGE not set */
|
||||
if ((flag & 2) == 0)
|
||||
return;
|
||||
|
||||
read_query = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_READ,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
if (!read_query)
|
||||
return;
|
||||
|
||||
/* Query using MBIMSmsFormatPdu(0) and MBIMSmsFlagNew (2) */
|
||||
mbim_message_set_arguments(read_query, "uuu", 0, 2, 0);
|
||||
|
||||
if (!mbim_device_send(sd->device, SMS_GROUP, read_query,
|
||||
mbim_sms_read_new_query_cb, sms, NULL))
|
||||
mbim_message_unref(read_query);
|
||||
}
|
||||
|
||||
static void mbim_sms_read_all_query_cb(struct mbim_message *message, void *user)
|
||||
{
|
||||
struct ofono_sms *sms = user;
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
|
||||
DBG("");
|
||||
|
||||
mbim_parse_sms_read_info(message, sms);
|
||||
|
||||
mbim_device_register(sd->device, SMS_GROUP, mbim_uuid_sms,
|
||||
MBIM_CID_SMS_MESSAGE_STORE_STATUS,
|
||||
mbim_sms_message_store_status_changed,
|
||||
sms, NULL);
|
||||
}
|
||||
|
||||
static bool mbim_sms_finish_init(struct ofono_sms *sms)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct mbim_message *message;
|
||||
|
||||
/*
|
||||
* Class 0 SMS comes via SMS_READ notification, so register for these
|
||||
* here. After that we send an SMS_READ request to retrieve any new
|
||||
* SMS messages. In the callback we will register to
|
||||
* MESSAGE_STORE_STATUS to receive notification that new SMS messages
|
||||
* have arrived
|
||||
*/
|
||||
if (!mbim_device_register(sd->device, SMS_GROUP,
|
||||
mbim_uuid_sms,
|
||||
MBIM_CID_SMS_READ,
|
||||
mbim_sms_read_notify, sms, NULL))
|
||||
return false;
|
||||
|
||||
message = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_READ,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
if (!message)
|
||||
return false;
|
||||
|
||||
/* Query using MBIMSmsFormatPdu(0) and MBIMSmsFlagAll (0) */
|
||||
mbim_message_set_arguments(message, "uuu", 0, 0, 0);
|
||||
|
||||
if (!mbim_device_send(sd->device, SMS_GROUP, message,
|
||||
mbim_sms_read_all_query_cb, sms, NULL)) {
|
||||
mbim_message_unref(message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mbim_sms_configuration_changed(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct ofono_sms *sms = user;
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
uint32_t storage_state;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!mbim_message_get_arguments(message, "u", &storage_state))
|
||||
goto error;
|
||||
|
||||
if (storage_state != 1)
|
||||
return;
|
||||
|
||||
mbim_device_unregister(sd->device, sd->configuration_notify_id);
|
||||
sd->configuration_notify_id = 0;
|
||||
|
||||
if (!mbim_sms_finish_init(sms))
|
||||
goto error;
|
||||
|
||||
ofono_sms_register(sms);
|
||||
return;
|
||||
|
||||
error:
|
||||
ofono_sms_remove(sms);
|
||||
}
|
||||
|
||||
static void mbim_sms_configuration_query_cb(struct mbim_message *message,
|
||||
void *user)
|
||||
{
|
||||
struct ofono_sms *sms = user;
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
uint32_t error;
|
||||
uint32_t storage_state;
|
||||
uint32_t format;
|
||||
uint32_t max_messages;
|
||||
|
||||
DBG("");
|
||||
|
||||
error = mbim_message_get_error(message);
|
||||
|
||||
/*
|
||||
* SUBSCRIBER_READY_STATUS tells us that a SIM is in ReadyState,
|
||||
* unfortunately that seems to be not enough to know that the SMS
|
||||
* state is initialized. Handle this here, if we get an error 14
|
||||
* 'MBIM_STATUS_NOT_INITIALIZED', then listen for the
|
||||
* SMS_CONFIGURATION notification. Why some devices return an error
|
||||
* here instead of responding with a 0 storage state is a mystery
|
||||
*/
|
||||
switch (error) {
|
||||
case 14: /* Seems SIM ReadyState is sometimes not enough */
|
||||
goto setup_notification;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* We don't bother parsing CdmaShortMessageSize or ScAddress array */
|
||||
if (!mbim_message_get_arguments(message, "uuu",
|
||||
&storage_state, &format, &max_messages))
|
||||
goto error;
|
||||
|
||||
DBG("storage_state: %u, format: %u, max_messages: %u",
|
||||
storage_state, format, max_messages);
|
||||
|
||||
if (format != 0) {
|
||||
DBG("Unsupported SMS Format, expect 0 (PDU)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (storage_state == 1) {
|
||||
if (!mbim_sms_finish_init(sms))
|
||||
goto error;
|
||||
|
||||
ofono_sms_register(sms);
|
||||
return;
|
||||
}
|
||||
|
||||
setup_notification:
|
||||
/* Wait for storage_state to go to Initialized before registering */
|
||||
sd->configuration_notify_id = mbim_device_register(sd->device,
|
||||
SMS_GROUP,
|
||||
mbim_uuid_sms,
|
||||
MBIM_CID_SMS_CONFIGURATION,
|
||||
mbim_sms_configuration_changed,
|
||||
sms, NULL);
|
||||
if (sd->configuration_notify_id > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
ofono_sms_remove(sms);
|
||||
}
|
||||
|
||||
static int mbim_sms_probe(struct ofono_sms *sms, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct mbim_device *device = data;
|
||||
struct sms_data *sd;
|
||||
struct mbim_message *message;
|
||||
|
||||
DBG("");
|
||||
|
||||
message = mbim_message_new(mbim_uuid_sms,
|
||||
MBIM_CID_SMS_CONFIGURATION,
|
||||
MBIM_COMMAND_TYPE_QUERY);
|
||||
if (!message)
|
||||
return -ENOMEM;
|
||||
|
||||
mbim_message_set_arguments(message, "");
|
||||
|
||||
if (!mbim_device_send(device, SMS_GROUP, message,
|
||||
mbim_sms_configuration_query_cb, sms, NULL)) {
|
||||
mbim_message_unref(message);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sd = l_new(struct sms_data, 1);
|
||||
sd->device = mbim_device_ref(device);
|
||||
ofono_sms_set_data(sms, sd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbim_sms_remove(struct ofono_sms *sms)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_sms_set_data(sms, NULL);
|
||||
|
||||
mbim_device_cancel_group(sd->device, SMS_GROUP);
|
||||
mbim_device_unregister_group(sd->device, SMS_GROUP);
|
||||
mbim_device_unref(sd->device);
|
||||
sd->device = NULL;
|
||||
l_free(sd);
|
||||
}
|
||||
|
||||
static struct ofono_sms_driver driver = {
|
||||
.name = "mbim",
|
||||
.probe = mbim_sms_probe,
|
||||
.remove = mbim_sms_remove,
|
||||
.sca_query = mbim_sca_query,
|
||||
.sca_set = mbim_sca_set,
|
||||
.submit = mbim_submit,
|
||||
};
|
||||
|
||||
void mbim_sms_init(void)
|
||||
{
|
||||
ofono_sms_driver_register(&driver);
|
||||
}
|
||||
|
||||
void mbim_sms_exit(void)
|
||||
{
|
||||
ofono_sms_driver_unregister(&driver);
|
||||
}
|
||||
54
ofono/drivers/mbimmodem/util.c
Normal file
54
ofono/drivers/mbimmodem/util.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "src/common.h"
|
||||
#include "mbim.h"
|
||||
#include "util.h"
|
||||
|
||||
int mbim_data_class_to_tech(uint32_t n)
|
||||
{
|
||||
if (n & MBIM_DATA_CLASS_LTE)
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
|
||||
if (n & (MBIM_DATA_CLASS_HSUPA | MBIM_DATA_CLASS_HSDPA))
|
||||
return ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
|
||||
|
||||
if (n & MBIM_DATA_CLASS_HSUPA)
|
||||
return ACCESS_TECHNOLOGY_UTRAN_HSUPA;
|
||||
|
||||
if (n & MBIM_DATA_CLASS_HSDPA)
|
||||
return ACCESS_TECHNOLOGY_UTRAN_HSDPA;
|
||||
|
||||
if (n & MBIM_DATA_CLASS_UMTS)
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
|
||||
if (n & MBIM_DATA_CLASS_EDGE)
|
||||
return ACCESS_TECHNOLOGY_GSM_EGPRS;
|
||||
|
||||
if (n & MBIM_DATA_CLASS_GPRS)
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
59
ofono/drivers/mbimmodem/util.h
Normal file
59
ofono/drivers/mbimmodem/util.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
*
|
||||
* 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 <ell/ell.h>
|
||||
|
||||
struct cb_data {
|
||||
void *cb;
|
||||
void *data;
|
||||
void *user;
|
||||
};
|
||||
|
||||
static inline struct cb_data *cb_data_new(void *cb, void *data)
|
||||
{
|
||||
struct cb_data *ret;
|
||||
|
||||
ret = l_new(struct cb_data, 1);
|
||||
ret->cb = cb;
|
||||
ret->data = data;
|
||||
ret->user = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CALLBACK_WITH_FAILURE(cb, args...) \
|
||||
do { \
|
||||
struct ofono_error cb_e; \
|
||||
cb_e.type = OFONO_ERROR_TYPE_FAILURE; \
|
||||
cb_e.error = 0; \
|
||||
\
|
||||
cb(&cb_e, ##args); \
|
||||
} while (0) \
|
||||
|
||||
#define CALLBACK_WITH_SUCCESS(f, args...) \
|
||||
do { \
|
||||
struct ofono_error e; \
|
||||
e.type = OFONO_ERROR_TYPE_NO_ERROR; \
|
||||
e.error = 0; \
|
||||
f(&e, ##args); \
|
||||
} while (0)
|
||||
|
||||
int mbim_data_class_to_tech(uint32_t n);
|
||||
@@ -29,12 +29,16 @@
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "src/common.h"
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_data {
|
||||
struct qmi_device *dev;
|
||||
struct qmi_service *nas;
|
||||
struct qmi_service *wds;
|
||||
unsigned int last_auto_context_id;
|
||||
};
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
@@ -64,8 +68,124 @@ static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
char *apn = NULL;
|
||||
uint16_t error;
|
||||
uint8_t iptype;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Failed to query LTE attach params: %hd", error);
|
||||
goto noapn;
|
||||
}
|
||||
|
||||
/* APN */
|
||||
apn = qmi_result_get_string(result, 0x10);
|
||||
if (!apn) {
|
||||
DBG("Default profile has no APN setting");
|
||||
goto noapn;
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, 0x11, &iptype))
|
||||
ofono_info("LTE attach IP type: %hhd", iptype);
|
||||
|
||||
ofono_gprs_cid_activated(gprs, data->last_auto_context_id, apn);
|
||||
g_free(apn);
|
||||
|
||||
return;
|
||||
|
||||
noapn:
|
||||
data->last_auto_context_id = 0;
|
||||
ofono_error("LTE bearer established but APN not set");
|
||||
}
|
||||
|
||||
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs* gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
uint16_t error;
|
||||
uint8_t index;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Get default profile error: %hd", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Profile index */
|
||||
if (!qmi_result_get_uint8(result, 0x01, &index)) {
|
||||
ofono_error("Failed query default profile");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG("Default profile index: %hhd", index);
|
||||
|
||||
data->last_auto_context_id = index;
|
||||
|
||||
/* Get LTE Attach Parameters */
|
||||
if (qmi_service_send(data->wds, 0x85, NULL,
|
||||
get_lte_attach_param_cb, gprs, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
data->last_auto_context_id = 0;
|
||||
ofono_error("LTE bearer established but APN not set");
|
||||
}
|
||||
|
||||
/*
|
||||
* Query the settings in effect on the default bearer. These may be
|
||||
* implicit or may even be something other than requested as the gateway
|
||||
* is allowed to override whatever was requested by the user.
|
||||
*/
|
||||
static void get_lte_attach_params(struct ofono_gprs* gprs)
|
||||
{
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t family;
|
||||
} __attribute((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
.family = 0, /* embedded */
|
||||
};
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->last_auto_context_id != 0)
|
||||
return; /* Established or in progress */
|
||||
|
||||
/* Set query in progress */
|
||||
data->last_auto_context_id = -1;
|
||||
|
||||
/* First we query the default profile in order to find out which
|
||||
* context the modem has activated.
|
||||
*/
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile type */
|
||||
qmi_param_append(param, 0x1, sizeof(p), &p);
|
||||
|
||||
/* Get default profile */
|
||||
if (qmi_service_send(data->wds, 0x49, param,
|
||||
get_default_profile_cb, gprs, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_warn("Unable to query LTE APN... will not activate context");
|
||||
}
|
||||
|
||||
static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||
{
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
int status;
|
||||
int tech;
|
||||
|
||||
@@ -74,17 +194,20 @@ static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||
if (!extract_ss_info(result, &status, &tech))
|
||||
return -1;
|
||||
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED)
|
||||
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.
|
||||
* network is joined. We just need to query the
|
||||
* parameters in effect on the default bearer and
|
||||
* let the ofono core know about the activated
|
||||
* context.
|
||||
*/
|
||||
/* FIXME: query default profile number and APN
|
||||
* instead of assuming profile 1 and ""
|
||||
*/
|
||||
ofono_gprs_cid_activated(gprs, 1 , "automatic");
|
||||
get_lte_attach_params(gprs);
|
||||
}
|
||||
} else {
|
||||
data->last_auto_context_id = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -198,7 +321,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
@@ -206,12 +329,12 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_gprs_remove(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
data->wds = qmi_service_ref(service);
|
||||
|
||||
/*
|
||||
* First get the SS info - the modem may already be connected,
|
||||
@@ -228,6 +351,25 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
ofono_gprs_register(gprs);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_gprs_remove(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS,
|
||||
create_wds_cb, gprs, NULL);
|
||||
}
|
||||
|
||||
static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
@@ -240,6 +382,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
|
||||
ofono_gprs_set_data(gprs, data);
|
||||
|
||||
data->dev = device;
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, gprs, NULL);
|
||||
|
||||
@@ -254,6 +398,9 @@ static void qmi_gprs_remove(struct ofono_gprs *gprs)
|
||||
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->wds);
|
||||
qmi_service_unref(data->wds);
|
||||
|
||||
qmi_service_unregister_all(data->nas);
|
||||
|
||||
qmi_service_unref(data->nas);
|
||||
|
||||
264
ofono/drivers/qmimodem/lte.c
Normal file
264
ofono/drivers/qmimodem/lte.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jonas Bonn. All rights reserved.
|
||||
* Copyright (C) 2018 Norrbonn AB. All rights reserved.
|
||||
* Copyright (C) 2018 Data Respons ASA. 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 "qmi.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct lte_data {
|
||||
struct qmi_service *wds;
|
||||
uint8_t default_profile;
|
||||
};
|
||||
|
||||
static void modify_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
DBG("Failed to modify profile: %d", error);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmimodem_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_data *ldd = ofono_lte_get_data(lte);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct qmi_param* param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
p.index = ldd->default_profile;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* WDS APN Name */
|
||||
qmi_param_append(param, QMI_WDS_PARAM_APN,
|
||||
strlen(info->apn), info->apn);
|
||||
|
||||
/* Modify profile */
|
||||
if (qmi_service_send(ldd->wds, 0x28, param,
|
||||
modify_profile_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void reset_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error))
|
||||
ofono_error("Reset profile error: %hd", error);
|
||||
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
uint16_t error;
|
||||
uint8_t index;
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Get default profile error: %hd", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Profile index */
|
||||
if (!qmi_result_get_uint8(result, 0x01, &index)) {
|
||||
ofono_error("Failed query default profile");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG("Default profile index: %hhd", index);
|
||||
|
||||
ldd->default_profile = index;
|
||||
|
||||
p.index = index;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* Reset profile */
|
||||
if (qmi_service_send(ldd->wds, 0x4b, param,
|
||||
reset_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to reset profile %hhd", index);
|
||||
ofono_lte_remove(lte);
|
||||
}
|
||||
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t family;
|
||||
} __attribute((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
.family = 0, /* embedded */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_lte_remove(lte);
|
||||
return;
|
||||
}
|
||||
|
||||
ldd->wds = qmi_service_ref(service);
|
||||
|
||||
/* Query the default profile */
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile type */
|
||||
qmi_param_append(param, 0x1, sizeof(p), &p);
|
||||
|
||||
/* Get default profile */
|
||||
if (qmi_service_send(ldd->wds, 0x49, param,
|
||||
get_default_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to query default profile");
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static int qmimodem_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
struct qmi_device *device = data;
|
||||
struct lte_data *ldd;
|
||||
|
||||
DBG("qmimodem lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_WDS,
|
||||
create_wds_cb, lte, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmimodem_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
qmi_service_unregister_all(ldd->wds);
|
||||
|
||||
qmi_service_unref(ldd->wds);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmimodem_lte_probe,
|
||||
.remove = qmimodem_lte_remove,
|
||||
.set_default_attach_info = qmimodem_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void qmi_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void qmi_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -332,6 +332,7 @@ static void register_net_cb(struct qmi_result *result, void *user_data)
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_netreg_register_cb_t cb = cbd->cb;
|
||||
uint16_t error;
|
||||
int cme_error;
|
||||
|
||||
DBG("");
|
||||
|
||||
@@ -341,7 +342,8 @@ static void register_net_cb(struct qmi_result *result, void *user_data)
|
||||
goto done;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
cme_error = qmi_error_to_ofono_cme(error);
|
||||
CALLBACK_WITH_CME_ERROR(cb, cme_error, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -476,6 +476,17 @@ static const char *__error_to_string(uint16_t error)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int qmi_error_to_ofono_cme(int qmi_error) {
|
||||
switch (qmi_error) {
|
||||
case 0x0019:
|
||||
return 4; /* Not Supported */
|
||||
case 0x0052:
|
||||
return 32; /* Access Denied */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void __debug_msg(const char dir, const void *buf, size_t len,
|
||||
qmi_debug_func_t function, void *user_data)
|
||||
{
|
||||
@@ -1073,6 +1084,7 @@ struct discover_data {
|
||||
qmi_discover_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
uint8_t tid;
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
@@ -1133,6 +1145,13 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
uint8_t type = service_list->services[i].type;
|
||||
const char *name = __service_type_to_string(type);
|
||||
|
||||
if (name)
|
||||
__debug_device(device, "found service [%s %d.%d]",
|
||||
name, major, minor);
|
||||
else
|
||||
__debug_device(device, "found service [%d %d.%d]",
|
||||
type, major, minor);
|
||||
|
||||
if (type == QMI_SERVICE_CONTROL) {
|
||||
device->control_major = major;
|
||||
device->control_minor = minor;
|
||||
@@ -1145,13 +1164,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
list[count].name = name;
|
||||
|
||||
count++;
|
||||
|
||||
if (name)
|
||||
__debug_device(device, "found service [%s %d.%d]",
|
||||
name, major, minor);
|
||||
else
|
||||
__debug_device(device, "found service [%d %d.%d]",
|
||||
type, major, minor);
|
||||
}
|
||||
|
||||
ptr = tlv_get(buffer, length, 0x10, &len);
|
||||
@@ -1160,13 +1172,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
|
||||
device->version_str = strndup(ptr + 1, *((uint8_t *) ptr));
|
||||
|
||||
service_list = ptr + *((uint8_t *) ptr) + 1;
|
||||
|
||||
for (i = 0; i < service_list->count; i++) {
|
||||
if (service_list->services[i].type == QMI_SERVICE_CONTROL)
|
||||
continue;
|
||||
}
|
||||
|
||||
done:
|
||||
device->version_list = list;
|
||||
device->version_count = count;
|
||||
@@ -1181,14 +1186,38 @@ static gboolean discover_reply(gpointer user_data)
|
||||
{
|
||||
struct discover_data *data = user_data;
|
||||
struct qmi_device *device = data->device;
|
||||
unsigned int tid = data->tid;
|
||||
GList *list;
|
||||
struct qmi_request *req = NULL;
|
||||
|
||||
data->timeout = 0;
|
||||
|
||||
/* remove request from queues */
|
||||
if (tid != 0) {
|
||||
list = g_queue_find_custom(device->req_queue,
|
||||
GUINT_TO_POINTER(tid), __request_compare);
|
||||
|
||||
if (list) {
|
||||
req = list->data;
|
||||
g_queue_delete_link(device->req_queue, list);
|
||||
} else {
|
||||
list = g_queue_find_custom(device->control_queue,
|
||||
GUINT_TO_POINTER(tid), __request_compare);
|
||||
|
||||
if (list) {
|
||||
req = list->data;
|
||||
g_queue_delete_link(device->control_queue,
|
||||
list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data->func)
|
||||
data->func(device->version_count,
|
||||
device->version_list, data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
__request_free(req, NULL);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1234,6 +1263,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_control_tid++;
|
||||
data->tid = hdr->transaction;
|
||||
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
|
||||
@@ -1323,6 +1353,65 @@ bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sync_data {
|
||||
qmi_sync_func_t func;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void qmi_device_sync_callback(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data)
|
||||
{
|
||||
struct sync_data *data = user_data;
|
||||
|
||||
if (data->func)
|
||||
data->func(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
/* sync will release all previous clients */
|
||||
bool qmi_device_sync(struct qmi_device *device,
|
||||
qmi_sync_func_t func, void *user_data)
|
||||
{
|
||||
struct qmi_request *req;
|
||||
struct qmi_control_hdr *hdr;
|
||||
struct sync_data *func_data;
|
||||
|
||||
if (!device)
|
||||
return false;
|
||||
|
||||
__debug_device(device, "Sending sync to reset QMI");
|
||||
|
||||
func_data = g_new0(struct sync_data, 1);
|
||||
func_data->func = func;
|
||||
func_data->user_data = user_data;
|
||||
|
||||
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
|
||||
QMI_CTL_SYNC, QMI_CONTROL_HDR_SIZE,
|
||||
NULL, 0,
|
||||
qmi_device_sync_callback, func_data, (void **) &hdr);
|
||||
|
||||
if (device->next_control_tid < 1)
|
||||
device->next_control_tid = 1;
|
||||
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_control_tid++;
|
||||
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if the device support the QMI call SYNC over the CTL interface */
|
||||
bool qmi_device_is_sync_supported(struct qmi_device *device)
|
||||
{
|
||||
if (device == NULL)
|
||||
return false;
|
||||
|
||||
return (device->control_major > 1 ||
|
||||
(device->control_major == 1 && device->control_minor >= 5));
|
||||
}
|
||||
|
||||
static bool get_device_file_name(struct qmi_device *device,
|
||||
char *file_name, int size)
|
||||
{
|
||||
|
||||
@@ -76,7 +76,7 @@ typedef void (*qmi_destroy_func_t)(void *user_data);
|
||||
struct qmi_device;
|
||||
|
||||
typedef void (*qmi_debug_func_t)(const char *str, void *user_data);
|
||||
|
||||
typedef void (*qmi_sync_func_t)(void *user_data);
|
||||
typedef void (*qmi_shutdown_func_t)(void *user_data);
|
||||
typedef void (*qmi_discover_func_t)(uint8_t count,
|
||||
const struct qmi_version *list, void *user_data);
|
||||
@@ -96,6 +96,10 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy);
|
||||
|
||||
bool qmi_device_sync(struct qmi_device *device,
|
||||
qmi_sync_func_t func, void *user_data);
|
||||
bool qmi_device_is_sync_supported(struct qmi_device *device);
|
||||
|
||||
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,
|
||||
@@ -140,6 +144,8 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
uint64_t *value);
|
||||
void qmi_result_print_tlvs(struct qmi_result *result);
|
||||
|
||||
int qmi_error_to_ofono_cme(int qmi_error);
|
||||
|
||||
struct qmi_service;
|
||||
|
||||
typedef void (*qmi_result_func_t)(struct qmi_result *result, void *user_data);
|
||||
|
||||
@@ -39,6 +39,7 @@ static int qmimodem_init(void)
|
||||
qmi_ussd_init();
|
||||
qmi_gprs_init();
|
||||
qmi_gprs_context_init();
|
||||
qmi_lte_init();
|
||||
qmi_radio_settings_init();
|
||||
qmi_location_reporting_init();
|
||||
qmi_netmon_init();
|
||||
@@ -51,6 +52,7 @@ static void qmimodem_exit(void)
|
||||
qmi_netmon_exit();
|
||||
qmi_location_reporting_exit();
|
||||
qmi_radio_settings_exit();
|
||||
qmi_lte_exit();
|
||||
qmi_gprs_context_exit();
|
||||
qmi_gprs_exit();
|
||||
qmi_ussd_exit();
|
||||
|
||||
@@ -48,6 +48,9 @@ extern void qmi_gprs_exit(void);
|
||||
extern void qmi_gprs_context_init(void);
|
||||
extern void qmi_gprs_context_exit(void);
|
||||
|
||||
extern void qmi_lte_init(void);
|
||||
extern void qmi_lte_exit(void);
|
||||
|
||||
extern void qmi_radio_settings_init(void);
|
||||
extern void qmi_radio_settings_exit(void);
|
||||
|
||||
|
||||
@@ -277,6 +277,9 @@ static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->dms);
|
||||
qmi_service_unref(data->dms);
|
||||
|
||||
qmi_service_unregister_all(data->nas);
|
||||
|
||||
qmi_service_unref(data->nas);
|
||||
|
||||
@@ -334,9 +334,38 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void raw_read_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_sms *sms = user_data;
|
||||
const struct qmi_wms_raw_message* msg;
|
||||
uint16_t len;
|
||||
uint16_t error;
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
DBG("Raw read error: %d (%s)", error,
|
||||
qmi_result_get_error(result));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Raw message data */
|
||||
msg = qmi_result_get(result, 0x01, &len);
|
||||
if (msg) {
|
||||
uint16_t plen;
|
||||
uint16_t tpdu_len;
|
||||
|
||||
plen = GUINT16_FROM_LE(msg->msg_length);
|
||||
tpdu_len = plen - msg->msg_data[0] - 1;
|
||||
|
||||
ofono_sms_deliver_notify(sms, msg->msg_data, plen, tpdu_len);
|
||||
} else {
|
||||
DBG("No message data available at requested position");
|
||||
}
|
||||
}
|
||||
|
||||
static void event_notify(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_sms *sms = user_data;
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
const struct qmi_wms_result_new_msg_notify *notify;
|
||||
const struct qmi_wms_result_message *message;
|
||||
uint16_t len;
|
||||
@@ -360,6 +389,34 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
||||
DBG("msg format %d PDU length %d", message->msg_format, plen);
|
||||
|
||||
ofono_sms_deliver_notify(sms, message->msg_data, plen, plen);
|
||||
} else {
|
||||
/* The Quectel EC21, at least, does not provide the
|
||||
* message data in the event notification, so a 'raw read'
|
||||
* needs to be issued in order to query the message itself
|
||||
*/
|
||||
struct qmi_param *param;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
return;
|
||||
|
||||
/* Message memory storage ID */
|
||||
qmi_param_append(param, 0x01, sizeof(*notify), notify);
|
||||
/* The 'message mode' parameter is documented as optional,
|
||||
* but the Quectel EC21 errors out with error 17 (missing
|
||||
* argument) if it is not provided... we default to 3GPP
|
||||
* here because that's what works for me and it's not clear
|
||||
* how to actually query what this should be otherwise...
|
||||
*/
|
||||
/* Message mode */
|
||||
qmi_param_append_uint8(param, 0x10,
|
||||
QMI_WMS_MESSAGE_MODE_GSMWCDMA);
|
||||
|
||||
if (qmi_service_send(data->wms, QMI_WMS_RAW_READ, param,
|
||||
raw_read_cb, sms, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2011-2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -23,20 +24,103 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/ussd.h>
|
||||
|
||||
#include <smsutil.h>
|
||||
#include "qmi.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
#include "voice.h"
|
||||
|
||||
struct ussd_data {
|
||||
struct qmi_service *voice;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
static int validate_ussd_data(const struct qmi_ussd_data *data, uint16_t size)
|
||||
{
|
||||
if (data == NULL)
|
||||
return 1;
|
||||
|
||||
if (size < sizeof(*data))
|
||||
return 1;
|
||||
|
||||
if (size < sizeof(*data) + data->length)
|
||||
return 1;
|
||||
|
||||
if (data->dcs < QMI_USSD_DCS_ASCII || data->dcs > QMI_USSD_DCS_UCS2)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int convert_qmi_dcs_gsm_dcs(int qmi_dcs, int *gsm_dcs)
|
||||
{
|
||||
switch (qmi_dcs) {
|
||||
case QMI_USSD_DCS_ASCII:
|
||||
*gsm_dcs = USSD_DCS_8BIT;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void async_orig_ind(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_ussd *ussd = user_data;
|
||||
const struct qmi_ussd_data *qmi_ussd;
|
||||
uint16_t error = 0;
|
||||
uint16_t len;
|
||||
int gsm_dcs;
|
||||
|
||||
DBG("");
|
||||
|
||||
qmi_result_get_uint16(result, QMI_VOICE_PARAM_ASYNC_USSD_ERROR, &error);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
/* no error */
|
||||
break;
|
||||
case 92:
|
||||
qmi_result_get_uint16(result,
|
||||
QMI_VOICE_PARAM_ASYNC_USSD_FAILURE_CASE,
|
||||
&error);
|
||||
DBG("Failure Cause: 0x%04x", error);
|
||||
goto error;
|
||||
default:
|
||||
DBG("USSD Error 0x%04x", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
qmi_ussd = qmi_result_get(result, QMI_VOICE_PARAM_ASYNC_USSD_DATA,
|
||||
&len);
|
||||
if (qmi_ussd == NULL)
|
||||
return;
|
||||
|
||||
if (validate_ussd_data(qmi_ussd, len))
|
||||
goto error;
|
||||
|
||||
if (convert_qmi_dcs_gsm_dcs(qmi_ussd->dcs, &gsm_dcs))
|
||||
goto error;
|
||||
|
||||
ofono_ussd_notify(ussd, OFONO_USSD_STATUS_NOTIFY, gsm_dcs,
|
||||
qmi_ussd->data, qmi_ussd->length);
|
||||
return;
|
||||
|
||||
error:
|
||||
ofono_ussd_notify(ussd, OFONO_USSD_STATUS_TERMINATED, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static void create_voice_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_ussd *ussd = user_data;
|
||||
@@ -44,7 +128,7 @@ static void create_voice_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
if (service == NULL) {
|
||||
ofono_error("Failed to request Voice service");
|
||||
ofono_ussd_remove(ussd);
|
||||
return;
|
||||
@@ -58,6 +142,9 @@ static void create_voice_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
data->voice = qmi_service_ref(service);
|
||||
|
||||
qmi_service_register(data->voice, QMI_VOICE_ASYNC_ORIG_USSD,
|
||||
async_orig_ind, ussd, NULL);
|
||||
|
||||
ofono_ussd_register(ussd);
|
||||
}
|
||||
|
||||
@@ -77,7 +164,6 @@ static int qmi_ussd_probe(struct ofono_ussd *ussd,
|
||||
create_voice_cb, ussd, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void qmi_ussd_remove(struct ofono_ussd *ussd)
|
||||
@@ -93,10 +179,103 @@ static void qmi_ussd_remove(struct ofono_ussd *ussd)
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void qmi_ussd_cancel(struct ofono_ussd *ussd,
|
||||
ofono_ussd_cb_t cb, void *user_data)
|
||||
{
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(ud->voice, QMI_VOICE_CANCEL_USSD, NULL,
|
||||
NULL, NULL, NULL) > 0)
|
||||
CALLBACK_WITH_SUCCESS(cb, user_data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* The cb is called when the request (on modem layer) reports success or
|
||||
* failure. It doesn't contain a network result. We get the network answer
|
||||
* via VOICE_IND.
|
||||
*/
|
||||
static void qmi_ussd_request_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_ussd_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
qmi_result_print_tlvs(result);
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
const unsigned char *pdu, int len,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct qmi_ussd_data *qmi_ussd;
|
||||
struct qmi_param *param;
|
||||
char *utf8 = NULL;
|
||||
long utf8_len = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (dcs) {
|
||||
case 0xf: /* 7bit GSM unspecific */
|
||||
utf8 = ussd_decode(dcs, len, pdu);
|
||||
if (!utf8)
|
||||
goto error;
|
||||
|
||||
utf8_len = strlen(utf8);
|
||||
break;
|
||||
default:
|
||||
DBG("Unsupported USSD Data Coding Scheme 0x%x", dcs);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* So far only DCS_ASCII works.
|
||||
* DCS_8BIT and DCS_UCS2 is broken, because the modem firmware
|
||||
* (least on a EC20) encodes those in-correctly onto the air interface,
|
||||
* resulting in wrong decoded USSD data.
|
||||
*/
|
||||
qmi_ussd = alloca(sizeof(struct qmi_ussd_data) + utf8_len);
|
||||
qmi_ussd->dcs = QMI_USSD_DCS_ASCII;
|
||||
qmi_ussd->length = len;
|
||||
memcpy(qmi_ussd->data, utf8, utf8_len);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (param == NULL)
|
||||
goto error;
|
||||
|
||||
qmi_param_append(param, QMI_VOICE_PARAM_USS_DATA,
|
||||
sizeof(struct qmi_ussd_data) + utf8_len, qmi_ussd);
|
||||
|
||||
if (qmi_service_send(ud->voice, QMI_VOICE_ASYNC_ORIG_USSD, param,
|
||||
qmi_ussd_request_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
error:
|
||||
g_free(utf8);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static struct ofono_ussd_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_ussd_probe,
|
||||
.remove = qmi_ussd_remove,
|
||||
.request = qmi_ussd_request,
|
||||
.cancel = qmi_ussd_cancel
|
||||
};
|
||||
|
||||
void qmi_ussd_init(void)
|
||||
|
||||
@@ -39,6 +39,15 @@ static inline struct cb_data *cb_data_new(void *cb, void *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CALLBACK_WITH_CME_ERROR(cb, err, args...) \
|
||||
do { \
|
||||
struct ofono_error cb_e; \
|
||||
cb_e.type = OFONO_ERROR_TYPE_CME; \
|
||||
cb_e.error = err; \
|
||||
\
|
||||
cb(&cb_e, ##args); \
|
||||
} while (0) \
|
||||
|
||||
#define CALLBACK_WITH_FAILURE(cb, args...) \
|
||||
do { \
|
||||
struct ofono_error cb_e; \
|
||||
|
||||
62
ofono/drivers/qmimodem/voice.h
Normal file
62
ofono/drivers/qmimodem/voice.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* 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_VOICE_PARAM_USS_DATA 0x01
|
||||
|
||||
#define QMI_VOICE_PARAM_ASYNC_USSD_ERROR 0x10
|
||||
#define QMI_VOICE_PARAM_ASYNC_USSD_FAILURE_CASE 0x11
|
||||
#define QMI_VOICE_PARAM_ASYNC_USSD_DATA 0x12
|
||||
|
||||
#define QMI_VOICE_PARAM_USSD_IND_USER_ACTION 0x01
|
||||
#define QMI_VOICE_PARAM_USSD_IND_DATA 0x10
|
||||
#define QMI_VOICE_PARAM_USSD_IND_UCS2 0x11
|
||||
|
||||
/* according to GSM TS 23.038 section 5
|
||||
* coding group 1111, No message class, 8 bit data
|
||||
*/
|
||||
#define USSD_DCS_8BIT 0xf4
|
||||
/* coding group 01xx, Class 0, UCS2 (16 bit) */
|
||||
#define USSD_DCS_UCS2 0x48
|
||||
/* default alphabet Language unspecific */
|
||||
#define USSD_DCS_UNSPECIFIC 0x0f
|
||||
|
||||
/* based on qmi ussd definition */
|
||||
enum qmi_ussd_dcs {
|
||||
QMI_USSD_DCS_ASCII = 0x1,
|
||||
QMI_USSD_DCS_8BIT,
|
||||
QMI_USSD_DCS_UCS2,
|
||||
};
|
||||
|
||||
enum qmi_ussd_user_required {
|
||||
QMI_USSD_NO_USER_ACTION_REQUIRED = 0x1,
|
||||
QMI_USSD_USER_ACTION_REQUIRED,
|
||||
};
|
||||
|
||||
/* QMI service voice. Using an enum to prevent doublicated entries */
|
||||
enum voice_commands {
|
||||
QMI_VOICE_CANCEL_USSD = 0x3c,
|
||||
QMI_VOICE_USSD_RELEASE_IND = 0x3d,
|
||||
QMI_VOICE_USSD_IND = 0x3e,
|
||||
QMI_VOICE_SUPS_IND = 0x42,
|
||||
QMI_VOICE_ASYNC_ORIG_USSD = 0x43,
|
||||
};
|
||||
|
||||
struct qmi_ussd_data {
|
||||
uint8_t dcs;
|
||||
uint8_t length;
|
||||
uint8_t data[0];
|
||||
} __attribute__((__packed__));
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#define QMI_WMS_RAW_SEND 32 /* Send a raw message */
|
||||
|
||||
#define QMI_WMS_RAW_READ 34 /* Read raw message from storage*/
|
||||
|
||||
#define QMI_WMS_GET_MSG_LIST 49 /* Get list of messages from the device */
|
||||
#define QMI_WMS_SET_ROUTES 50 /* Set routes for message memory storage */
|
||||
#define QMI_WMS_GET_ROUTES 51 /* Get routes for message memory storage */
|
||||
@@ -66,6 +68,13 @@ struct qmi_wms_param_message {
|
||||
|
||||
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
||||
|
||||
struct qmi_wms_raw_message {
|
||||
uint8_t msg_tag;
|
||||
uint8_t msg_format;
|
||||
uint16_t msg_length;
|
||||
uint8_t msg_data[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Get routes for message memory storage */
|
||||
#define QMI_WMS_RESULT_ROUTE_LIST 0x01
|
||||
#define QMI_WMS_PARAM_ROUTE_LIST 0x01
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -26,11 +27,11 @@
|
||||
* ril.h does not state that string count must be given, but that is
|
||||
* still expected by the modem
|
||||
*/
|
||||
#define RIL_QUERY_STRING_COUNT 4
|
||||
#define RIL_SET_STRING_COUNT 5
|
||||
#define RIL_SET_PW_STRING_COUNT 3
|
||||
|
||||
struct ril_call_barring {
|
||||
struct ril_sim_card *card;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
@@ -106,7 +107,7 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
GRilIoRequest *req;
|
||||
|
||||
DBG("lock: %s, services to query: %d", lock, cls);
|
||||
|
||||
@@ -123,15 +124,9 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
|
||||
/*
|
||||
* See 3GPP 27.007 7.4 for parameter descriptions.
|
||||
* According to ril.h password should be empty string "" when not
|
||||
* needed, but in reality we only need to give string length as 0
|
||||
*/
|
||||
grilio_request_append_int32(req, RIL_QUERY_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_int32(req, 0); /* Password length */
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
|
||||
req = grilio_request_array_utf8_new(4, lock, "", cls_textual,
|
||||
ril_sim_card_app_aid(bd->card));
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_call_barring_query_cb, cb, data);
|
||||
@@ -182,7 +177,7 @@ static void ril_call_barring_set(struct ofono_call_barring *b,
|
||||
RIL_FACILITY_UNLOCK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
grilio_request_append_utf8(req, ril_sim_card_app_aid(bd->card));
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
@@ -243,6 +238,7 @@ static int ril_call_barring_probe(struct ofono_call_barring *b,
|
||||
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
|
||||
|
||||
DBG("");
|
||||
bd->card = ril_sim_card_ref(modem->sim_card);
|
||||
bd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
bd->timer_id = g_idle_add(ril_call_barring_register, b);
|
||||
ofono_call_barring_set_data(b, bd);
|
||||
@@ -260,6 +256,7 @@ static void ril_call_barring_remove(struct ofono_call_barring *b)
|
||||
g_source_remove(bd->timer_id);
|
||||
}
|
||||
|
||||
ril_sim_card_unref(bd->card);
|
||||
grilio_queue_cancel_all(bd->q, FALSE);
|
||||
grilio_queue_unref(bd->q);
|
||||
g_free(bd);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -23,10 +24,10 @@
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_idlepool.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||
#define DEFAULT_UPDATE_RATE_MS (10000) /* 10 sec */
|
||||
#define MAX_RETRIES (5)
|
||||
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
@@ -36,13 +37,12 @@ struct ril_cell_info {
|
||||
GObject object;
|
||||
struct sailfish_cell_info info;
|
||||
GRilIoChannel *io;
|
||||
MceDisplay *display;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
gulong display_state_event_id;
|
||||
gulong radio_state_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gboolean sim_card_ready;
|
||||
int update_rate_ms;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
@@ -75,6 +75,20 @@ static void ril_cell_free1(gpointer cell)
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static const char *ril_cell_info_int_format(int value, const char *format)
|
||||
{
|
||||
if (value == SAILFISH_CELL_INVALID_VALUE) {
|
||||
return "";
|
||||
} else {
|
||||
static GUtilIdlePool *ril_cell_info_pool = NULL;
|
||||
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
|
||||
char *str = g_strdup_printf(format, value);
|
||||
|
||||
gutil_idle_pool_add(pool, str, g_free);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
@@ -123,11 +137,17 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
|
||||
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
|
||||
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,arfcn=%d,"
|
||||
"bsic=%d,strength=%d,err=%d,t=%d", registered,
|
||||
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
|
||||
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
|
||||
gsm->timingAdvance);
|
||||
DBG("[gsm] reg=%d%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
|
||||
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
|
||||
ril_cell_info_int_format(gsm->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
|
||||
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -155,10 +175,16 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
|
||||
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
|
||||
"strength=%d,err=%d", registered, wcdma->mcc,
|
||||
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
|
||||
wcdma->signalStrength, wcdma->bitErrorRate);
|
||||
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
|
||||
ril_cell_info_int_format(wcdma->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(wcdma->bitErrorRate,
|
||||
",err=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -190,11 +216,19 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, <e->rssnr) &&
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(lte->ci, ",ci=%d"),
|
||||
ril_cell_info_int_format(lte->pci, ",pci=%d"),
|
||||
ril_cell_info_int_format(lte->tac, ",tac=%d"),
|
||||
ril_cell_info_int_format(lte->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
|
||||
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
|
||||
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
|
||||
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
|
||||
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -311,11 +345,24 @@ static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_retry(GRilIoRequest* request, 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_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
@@ -323,13 +370,13 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1,
|
||||
(self->update_rate_ms > 0) ? self->update_rate_ms : INT_MAX);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
||||
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
@@ -337,20 +384,6 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
||||
{
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self,
|
||||
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
|
||||
{
|
||||
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
@@ -376,12 +409,15 @@ static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||
ril_cell_info_refresh(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
/* sailfish_cell_info interface callbacks */
|
||||
|
||||
struct ril_cell_info_signal_data {
|
||||
struct ril_cell_info_closure {
|
||||
GCClosure cclosure;
|
||||
sailfish_cell_info_cb_t cb;
|
||||
void *arg;
|
||||
};
|
||||
@@ -403,17 +439,9 @@ static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
|
||||
void *user_data)
|
||||
struct ril_cell_info_closure *closure)
|
||||
{
|
||||
struct ril_cell_info_signal_data *data = user_data;
|
||||
|
||||
data->cb(&self->info, data->arg);
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_disconnect_notify(gpointer data,
|
||||
GClosure *closure)
|
||||
{
|
||||
g_slice_free1(sizeof(struct ril_cell_info_signal_data), data);
|
||||
closure->cb(&self->info, closure->arg);
|
||||
}
|
||||
|
||||
static gulong ril_cell_info_add_cells_changed_handler_proc
|
||||
@@ -421,16 +449,18 @@ static gulong ril_cell_info_add_cells_changed_handler_proc
|
||||
sailfish_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
if (cb) {
|
||||
struct ril_cell_info_signal_data *data =
|
||||
g_slice_new(struct ril_cell_info_signal_data);
|
||||
struct ril_cell_info_closure *closure =
|
||||
(struct ril_cell_info_closure *) g_closure_new_simple
|
||||
(sizeof(struct ril_cell_info_closure), NULL);
|
||||
GCClosure* cc = &closure->cclosure;
|
||||
|
||||
data->cb = cb;
|
||||
data->arg = arg;
|
||||
return g_signal_connect_data(ril_cell_info_cast(info),
|
||||
SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_CALLBACK(ril_cell_info_cells_changed_cb),
|
||||
data, ril_cell_info_cells_disconnect_notify,
|
||||
G_CONNECT_AFTER);
|
||||
cc->closure.data = closure;
|
||||
cc->callback = G_CALLBACK(ril_cell_info_cells_changed_cb);
|
||||
closure->cb = cb;
|
||||
closure->arg = arg;
|
||||
return g_signal_connect_closure_by_id(ril_cell_info_cast(info),
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED], 0,
|
||||
&cc->closure, FALSE);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -444,22 +474,36 @@ static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_update_interval_proc
|
||||
(struct sailfish_cell_info *info, int ms)
|
||||
{
|
||||
struct ril_cell_info *self = ril_cell_info_cast(info);
|
||||
|
||||
if (self->update_rate_ms != ms) {
|
||||
self->update_rate_ms = ms;
|
||||
DBG_(self, "%d ms", ms);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, MceDisplay *display,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card)
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card)
|
||||
{
|
||||
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
|
||||
ril_cell_info_ref_proc,
|
||||
ril_cell_info_unref_proc,
|
||||
ril_cell_info_add_cells_changed_handler_proc,
|
||||
ril_cell_info_remove_handler_proc
|
||||
ril_cell_info_remove_handler_proc,
|
||||
ril_cell_info_set_update_interval_proc
|
||||
};
|
||||
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
|
||||
self->info.proc = &ril_cell_info_proc;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->display = mce_display_ref(display);
|
||||
self->radio = ril_radio_ref(radio);
|
||||
self->sim_card = ril_sim_card_ref(sim_card);
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
@@ -467,9 +511,6 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
DBG_(self, "");
|
||||
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
self->display_state_event_id =
|
||||
mce_display_add_state_changed_handler(display,
|
||||
ril_cell_info_display_state_cb, self);
|
||||
self->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(radio,
|
||||
ril_cell_info_radio_state_cb, self);
|
||||
@@ -478,12 +519,15 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
ril_cell_info_refresh(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||
{
|
||||
self->update_rate_ms = DEFAULT_UPDATE_RATE_MS;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
@@ -500,8 +544,6 @@ static void ril_cell_info_dispose(GObject *object)
|
||||
FALSE);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
gutil_disconnect_handlers(self->display,
|
||||
&self->display_state_event_id, 1);
|
||||
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(self->sim_card,
|
||||
&self->sim_status_event_id, 1);
|
||||
@@ -515,7 +557,6 @@ static void ril_cell_info_finalize(GObject *object)
|
||||
DBG_(self, "");
|
||||
g_free(self->log_prefix);
|
||||
grilio_channel_unref(self->io);
|
||||
mce_display_unref(self->display);
|
||||
ril_radio_unref(self->radio);
|
||||
ril_sim_card_unref(self->sim_card);
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,12 +17,12 @@
|
||||
#define RIL_CELL_INFO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, MceDisplay *display,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card);
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card);
|
||||
|
||||
#endif /* RIL_CELL_INFO_H */
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -19,6 +20,11 @@
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
@@ -180,20 +186,95 @@ gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (result) {
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
char **values, **ptr;
|
||||
|
||||
if (comment) *comment = 0;
|
||||
values = g_strsplit(str, "+", -1);
|
||||
|
||||
for (ok = TRUE, ptr = values; *ptr && ok; ptr++) {
|
||||
const char* found_str = NULL;
|
||||
const char* s = g_strstrip(*ptr);
|
||||
|
||||
if (!strcasecmp(s, name)) {
|
||||
found_str = name;
|
||||
if (result) {
|
||||
*result |= value;
|
||||
}
|
||||
} else {
|
||||
va_list args;
|
||||
const char* known;
|
||||
|
||||
va_start(args, value);
|
||||
while ((known = va_arg(args, char*)) != NULL) {
|
||||
const int bit = va_arg(args, int);
|
||||
|
||||
if (!strcasecmp(s, known)) {
|
||||
found_str = known;
|
||||
if (result) {
|
||||
*result |= bit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!found_str) {
|
||||
ofono_error("Unknown bit '%s' in %s", s, key);
|
||||
ok = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(values);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
if (!ok && result) {
|
||||
*result = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key)
|
||||
{
|
||||
char *value = ril_config_get_string(file, group, key);
|
||||
|
||||
if (value) {
|
||||
char **values = g_strsplit(value, ",", -1);
|
||||
char **ptr = values;
|
||||
GUtilIntArray *array = gutil_int_array_new();
|
||||
char **values, **ptr;
|
||||
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(value, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
values = g_strsplit(value, ",", -1);
|
||||
ptr = values;
|
||||
|
||||
while (*ptr) {
|
||||
int val;
|
||||
|
||||
if (ril_parse_int(*ptr++, 0, &val)) {
|
||||
if (gutil_parse_int(*ptr++, 0, &val)) {
|
||||
gutil_int_array_append(array, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -34,7 +35,12 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags);
|
||||
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...);
|
||||
const char *name, int value, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||
|
||||
622
ofono/drivers/ril/ril_connman.c
Normal file
622
ofono/drivers/ril/ril_connman.c
Normal file
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 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_connman.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define CONNMAN_BUS DBUS_BUS_SYSTEM
|
||||
#define CONNMAN_SERVICE "net.connman"
|
||||
#define CONNMAN_PATH "/"
|
||||
|
||||
#define CONNMAN_GET_PROPERTIES "GetProperties"
|
||||
#define CONNMAN_GET_TECHNOLOGIES "GetTechnologies"
|
||||
#define CONNMAN_PROPERTY_CHANGED "PropertyChanged"
|
||||
#define CONNMAN_TECH_CONNECTED "Connected"
|
||||
#define CONNMAN_TECH_TETHERING "Tethering"
|
||||
|
||||
#define CONNMAN_INTERFACE_(name) "net.connman." name
|
||||
#define CONNMAN_MANAGER_INTERFACE CONNMAN_INTERFACE_("Manager")
|
||||
#define CONNMAN_TECH_INTERFACE CONNMAN_INTERFACE_("Technology")
|
||||
|
||||
#define CONNMAN_TECH_PATH_(name) "/net/connman/technology/" name
|
||||
#define CONNMAN_TECH_PATH_WIFI CONNMAN_TECH_PATH_("wifi")
|
||||
|
||||
#define CONNMAN_TECH_CONNECTED_BIT (0x01)
|
||||
#define CONNMAN_TECH_TETHERING_BIT (0x02)
|
||||
#define CONNMAN_TECH_ALL_PROPERTY_BITS (\
|
||||
CONNMAN_TECH_CONNECTED_BIT | \
|
||||
CONNMAN_TECH_TETHERING_BIT)
|
||||
|
||||
typedef GObjectClass ConnManObjectClass;
|
||||
|
||||
typedef struct connman_tech ConnManTech;
|
||||
|
||||
typedef struct connman_object {
|
||||
GObject object;
|
||||
struct ril_connman pub;
|
||||
guint32 pending_signals;
|
||||
DBusConnection *connection;
|
||||
DBusPendingCall *call;
|
||||
guint service_watch;
|
||||
guint signal_watch;
|
||||
GHashTable *techs;
|
||||
ConnManTech *wifi;
|
||||
} ConnManObject;
|
||||
|
||||
G_DEFINE_TYPE(ConnManObject, connman_object, G_TYPE_OBJECT)
|
||||
#define CONNMAN_OBJECT_TYPE (connman_object_get_type())
|
||||
#define CONNMAN_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
CONNMAN_OBJECT_TYPE, ConnManObject))
|
||||
|
||||
struct connman_tech {
|
||||
ConnManObject *obj;
|
||||
const char *path;
|
||||
gboolean connected;
|
||||
gboolean tethering;
|
||||
};
|
||||
|
||||
typedef struct connman_closure {
|
||||
GCClosure cclosure;
|
||||
ril_connman_property_cb_t callback;
|
||||
gpointer user_data;
|
||||
} ConnManClosure;
|
||||
|
||||
#define connman_closure_new() ((ConnManClosure *) \
|
||||
g_closure_new_simple(sizeof(ConnManClosure), NULL))
|
||||
|
||||
#define SIGNAL_PROPERTY_CHANGED_NAME "ril-connman-property-changed"
|
||||
#define SIGNAL_PROPERTY_DETAIL "%x"
|
||||
#define SIGNAL_PROPERTY_DETAIL_MAX_LEN (8)
|
||||
|
||||
#define SIGNAL_BIT(property) (1 << (property - 1))
|
||||
#define SIGNAL_BIT_(name) SIGNAL_BIT(RIL_CONNMAN_PROPERTY_##name)
|
||||
|
||||
enum connman_object_signal {
|
||||
SIGNAL_PROPERTY_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
static guint connman_object_signals[SIGNAL_COUNT];
|
||||
static GQuark connman_object_property_quarks[RIL_CONNMAN_PROPERTY_COUNT - 1];
|
||||
|
||||
static inline ConnManObject *connman_object_cast(struct ril_connman *connman)
|
||||
{
|
||||
return G_LIKELY(connman) ?
|
||||
CONNMAN_OBJECT(G_CAST(connman, ConnManObject, pub)) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
static inline const char *connman_iter_get_string(DBusMessageIter *it)
|
||||
{
|
||||
const char *str = NULL;
|
||||
|
||||
dbus_message_iter_get_basic(it, &str);
|
||||
return str;
|
||||
}
|
||||
|
||||
static GQuark connman_object_property_quark(enum ril_connman_property p)
|
||||
{
|
||||
/* For ANY property this function is expected to return zero */
|
||||
if (p > RIL_CONNMAN_PROPERTY_ANY && p < RIL_CONNMAN_PROPERTY_COUNT) {
|
||||
const int i = p - 1;
|
||||
|
||||
if (G_UNLIKELY(!connman_object_property_quarks[i])) {
|
||||
char buf[SIGNAL_PROPERTY_DETAIL_MAX_LEN + 1];
|
||||
|
||||
snprintf(buf, sizeof(buf), SIGNAL_PROPERTY_DETAIL, p);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
connman_object_property_quarks[i] =
|
||||
g_quark_from_string(buf);
|
||||
}
|
||||
return connman_object_property_quarks[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connman_object_property_changed(ConnManObject *self,
|
||||
enum ril_connman_property property, ConnManClosure *closure)
|
||||
{
|
||||
closure->callback(&self->pub, property, closure->user_data);
|
||||
}
|
||||
|
||||
static void connman_object_emit_property_change(ConnManObject *self,
|
||||
enum ril_connman_property p)
|
||||
{
|
||||
self->pending_signals &= ~SIGNAL_BIT(p);
|
||||
g_signal_emit(self, connman_object_signals[SIGNAL_PROPERTY_CHANGED],
|
||||
connman_object_property_quark(p), p);
|
||||
}
|
||||
|
||||
static void connman_object_emit_pending_signals(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
gboolean valid_changed, present_changed;
|
||||
enum ril_connman_property p;
|
||||
|
||||
/* Handlers could drop their references to us */
|
||||
g_object_ref(self);
|
||||
|
||||
/*
|
||||
* PRESENT and VALID are the last signals to be emitted if the object
|
||||
* BECOMES present and/or valid.
|
||||
*/
|
||||
if ((self->pending_signals & SIGNAL_BIT_(VALID)) &&
|
||||
connman->valid) {
|
||||
self->pending_signals &= ~SIGNAL_BIT_(VALID);
|
||||
valid_changed = TRUE;
|
||||
} else {
|
||||
valid_changed = FALSE;
|
||||
}
|
||||
if ((self->pending_signals & SIGNAL_BIT_(PRESENT)) &&
|
||||
connman->present) {
|
||||
self->pending_signals &= ~SIGNAL_BIT_(PRESENT);
|
||||
present_changed = TRUE;
|
||||
} else {
|
||||
present_changed = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit the signals. Not that in case if valid has become FALSE,
|
||||
* then VALID is emitted first, otherwise it's emitted last.
|
||||
* Same thing with PRESENT.
|
||||
*/
|
||||
for (p = RIL_CONNMAN_PROPERTY_ANY + 1;
|
||||
p < RIL_CONNMAN_PROPERTY_COUNT && self->pending_signals;
|
||||
p++) {
|
||||
if (self->pending_signals & SIGNAL_BIT(p)) {
|
||||
connman_object_emit_property_change(self, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Then emit PRESENT and VALID if necessary */
|
||||
if (present_changed) {
|
||||
connman_object_emit_property_change(self,
|
||||
RIL_CONNMAN_PROPERTY_PRESENT);
|
||||
}
|
||||
if (valid_changed) {
|
||||
connman_object_emit_property_change(self,
|
||||
RIL_CONNMAN_PROPERTY_VALID);
|
||||
}
|
||||
|
||||
/* And release the temporary reference */
|
||||
g_object_unref(self);
|
||||
}
|
||||
|
||||
static void connman_cancel_call(ConnManObject *self)
|
||||
{
|
||||
if (self->call) {
|
||||
dbus_pending_call_cancel(self->call);
|
||||
dbus_pending_call_unref(self->call);
|
||||
self->call = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static ConnManTech *connman_tech_new(ConnManObject *self, const char *path)
|
||||
{
|
||||
ConnManTech *tech = g_new0(ConnManTech, 1);
|
||||
char *key = g_strdup(path);
|
||||
|
||||
tech->obj = self;
|
||||
tech->path = key;
|
||||
g_hash_table_replace(self->techs, key, tech);
|
||||
return tech;
|
||||
}
|
||||
|
||||
static void connman_invalidate(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (connman->valid) {
|
||||
connman->valid = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_update_valid(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
const gboolean valid = (connman->present && !self->call);
|
||||
|
||||
if (connman->valid != valid) {
|
||||
connman->valid = valid;
|
||||
self->pending_signals |= SIGNAL_BIT_(VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean connman_update_tethering(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
gboolean tethering = FALSE;
|
||||
GHashTableIter it;
|
||||
gpointer value;
|
||||
|
||||
g_hash_table_iter_init(&it, self->techs);
|
||||
while (g_hash_table_iter_next(&it, NULL, &value)) {
|
||||
const ConnManTech *tech = value;
|
||||
|
||||
if (tech->tethering) {
|
||||
tethering = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (connman->tethering != tethering) {
|
||||
connman->tethering = tethering;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_set_tech_tethering(ConnManTech *tech, gboolean tethering)
|
||||
{
|
||||
if (tech->tethering != tethering) {
|
||||
ConnManObject *self = tech->obj;
|
||||
|
||||
tech->tethering = tethering;
|
||||
DBG(CONNMAN_TECH_TETHERING " %s for %s",
|
||||
tethering ? "on" : "off", tech->path);
|
||||
if (tethering) {
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (G_LIKELY(!connman->tethering)) {
|
||||
/* Definitely tethering now */
|
||||
connman->tethering = TRUE;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
DBG("Tethering on");
|
||||
}
|
||||
} else if (connman_update_tethering(self)) {
|
||||
/* Not tethering anymore */
|
||||
DBG("Tethering off");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_set_tech_connected(ConnManTech *tech, gboolean connected)
|
||||
{
|
||||
if (tech->connected != connected) {
|
||||
ConnManObject *self = tech->obj;
|
||||
|
||||
tech->connected = connected;
|
||||
DBG(CONNMAN_TECH_CONNECTED " %s for %s",
|
||||
connected ? "on" : "off", tech->path);
|
||||
if (tech == self->wifi) {
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
connman->wifi_connected = connected;
|
||||
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
|
||||
DBG("WiFi %sconnected", connected ? "" : "dis");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int connman_tech_set_property(ConnManTech *tech, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter var;
|
||||
DBusBasicValue value;
|
||||
const char *key = connman_iter_get_string(it);
|
||||
|
||||
dbus_message_iter_next(it);
|
||||
dbus_message_iter_recurse(it, &var);
|
||||
dbus_message_iter_get_basic(&var, &value);
|
||||
if (!g_ascii_strcasecmp(key, CONNMAN_TECH_CONNECTED)) {
|
||||
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
|
||||
connman_set_tech_connected(tech, value.bool_val);
|
||||
return CONNMAN_TECH_CONNECTED_BIT;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(key, CONNMAN_TECH_TETHERING)) {
|
||||
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
|
||||
connman_set_tech_tethering(tech, value.bool_val);
|
||||
return CONNMAN_TECH_TETHERING_BIT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connman_tech_set_properties(ConnManTech *tech, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter dict;
|
||||
int handled = 0;
|
||||
|
||||
dbus_message_iter_recurse(it, &dict);
|
||||
while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
|
||||
DBusMessageIter entry;
|
||||
|
||||
dbus_message_iter_recurse(&dict, &entry);
|
||||
handled |= connman_tech_set_property(tech, &entry);
|
||||
if (handled == CONNMAN_TECH_ALL_PROPERTY_BITS) {
|
||||
/* Ignore the rest */
|
||||
break;
|
||||
}
|
||||
dbus_message_iter_next(&dict);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean connman_tech_property_changed(DBusConnection *conn,
|
||||
DBusMessage *msg, void *user_data)
|
||||
{
|
||||
const char *path = dbus_message_get_path(msg);
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
ConnManTech *tech = g_hash_table_lookup(self->techs, path);
|
||||
DBusMessageIter it;
|
||||
|
||||
if (tech && dbus_message_has_signature(msg, "sv") &&
|
||||
dbus_message_iter_init(msg, &it)) {
|
||||
const char* name = connman_iter_get_string(&it);
|
||||
|
||||
if (!connman_tech_set_property(tech, &it)) {
|
||||
DBG("%s changed for %s", name, path);
|
||||
}
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void connman_set_techs(ConnManObject *self, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter list;
|
||||
|
||||
dbus_message_iter_recurse(it, &list);
|
||||
while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
|
||||
DBusMessageIter entry;
|
||||
const char *path;
|
||||
ConnManTech *tech;
|
||||
|
||||
dbus_message_iter_recurse(&list, &entry);
|
||||
path = connman_iter_get_string(&entry);
|
||||
tech = connman_tech_new(self, path);
|
||||
|
||||
DBG("%s", path);
|
||||
if (!g_strcmp0(path, CONNMAN_TECH_PATH_WIFI)) {
|
||||
/* WiFi is a special case */
|
||||
self->wifi = tech;
|
||||
}
|
||||
|
||||
dbus_message_iter_next(&entry);
|
||||
connman_tech_set_properties(tech, &entry);
|
||||
dbus_message_iter_next(&list);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_techs_reply(DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusError error;
|
||||
DBusMessageIter array;
|
||||
|
||||
dbus_error_init(&error);
|
||||
if (dbus_set_error_from_message(&error, reply)) {
|
||||
DBG("Failed to get technologies: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
} else if (dbus_message_has_signature(reply, "a(oa{sv})") &&
|
||||
dbus_message_iter_init(reply, &array)) {
|
||||
connman_set_techs(self, &array);
|
||||
}
|
||||
|
||||
dbus_message_unref(reply);
|
||||
dbus_pending_call_unref(self->call);
|
||||
self->call = NULL;
|
||||
connman_update_valid(self);
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
|
||||
static void connman_get_techs(ConnManObject *self)
|
||||
{
|
||||
DBusMessage *msg = dbus_message_new_method_call(CONNMAN_SERVICE,
|
||||
CONNMAN_PATH, CONNMAN_MANAGER_INTERFACE,
|
||||
CONNMAN_GET_TECHNOLOGIES);
|
||||
|
||||
connman_cancel_call(self);
|
||||
if (g_dbus_send_message_with_reply(self->connection, msg,
|
||||
&self->call, DBUS_TIMEOUT_INFINITE)) {
|
||||
/* Not valid while any request is pending */
|
||||
connman_invalidate(self);
|
||||
dbus_pending_call_set_notify(self->call, connman_techs_reply,
|
||||
self, NULL);
|
||||
}
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void connman_appeared(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (!connman->present) {
|
||||
DBG("connman is there");
|
||||
connman->present = TRUE;
|
||||
self->pending_signals |= SIGNAL_BIT_(PRESENT);
|
||||
connman_get_techs(self);
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_vanished(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (connman->present) {
|
||||
|
||||
DBG("connman has disappeared");
|
||||
g_hash_table_remove_all(self->techs);
|
||||
self->wifi = NULL;
|
||||
connman->present = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(PRESENT);
|
||||
if (connman->wifi_connected) {
|
||||
connman->wifi_connected = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
|
||||
}
|
||||
if (connman->tethering) {
|
||||
connman->tethering = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
}
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_init(ConnManObject *self, DBusConnection *connection)
|
||||
{
|
||||
self->connection = dbus_connection_ref(connection);
|
||||
self->service_watch = g_dbus_add_service_watch(self->connection,
|
||||
CONNMAN_SERVICE, connman_appeared, connman_vanished,
|
||||
self, NULL);
|
||||
self->signal_watch = g_dbus_add_signal_watch(self->connection,
|
||||
CONNMAN_SERVICE, NULL, CONNMAN_TECH_INTERFACE,
|
||||
CONNMAN_PROPERTY_CHANGED, connman_tech_property_changed,
|
||||
self, NULL);
|
||||
}
|
||||
|
||||
struct ril_connman *ril_connman_new()
|
||||
{
|
||||
static ConnManObject *instance = NULL;
|
||||
|
||||
if (instance) {
|
||||
g_object_ref(instance);
|
||||
return &instance->pub;
|
||||
} else {
|
||||
DBusError error;
|
||||
DBusConnection *connection;
|
||||
|
||||
dbus_error_init(&error);
|
||||
connection = dbus_bus_get(CONNMAN_BUS, NULL);
|
||||
|
||||
if (connection) {
|
||||
instance = g_object_new(CONNMAN_OBJECT_TYPE, NULL);
|
||||
connman_init(instance, connection);
|
||||
dbus_connection_unref(connection);
|
||||
g_object_add_weak_pointer(G_OBJECT(instance),
|
||||
(gpointer*)(&instance));
|
||||
return &instance->pub;
|
||||
} else {
|
||||
ofono_error("Unable to attach to connman bus: %s",
|
||||
error.message);
|
||||
dbus_error_free(&error);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_connman *ril_connman_ref(struct ril_connman *connman)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(self);
|
||||
return connman;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_connman_unref(struct ril_connman *connman)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(self);
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
|
||||
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self) && G_LIKELY(cb)) {
|
||||
/*
|
||||
* We can't directly connect the provided callback because
|
||||
* it expects the first parameter to point to public part
|
||||
* of the object but glib will call it with ConnManObject
|
||||
* as the first parameter. connman_object_property_changed()
|
||||
* will do the conversion.
|
||||
*/
|
||||
ConnManClosure *closure = connman_closure_new();
|
||||
GCClosure *cc = &closure->cclosure;
|
||||
|
||||
cc->closure.data = closure;
|
||||
cc->callback = G_CALLBACK(connman_object_property_changed);
|
||||
closure->callback = cb;
|
||||
closure->user_data = arg;
|
||||
|
||||
return g_signal_connect_closure_by_id(self,
|
||||
connman_object_signals[SIGNAL_PROPERTY_CHANGED],
|
||||
connman_object_property_quark(p), &cc->closure, FALSE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ril_connman_remove_handler(struct ril_connman *connman, gulong id)
|
||||
{
|
||||
if (G_LIKELY(id)) {
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
|
||||
int n)
|
||||
{
|
||||
gutil_disconnect_handlers(connman_object_cast(connman), ids, n);
|
||||
}
|
||||
|
||||
static void connman_object_init(ConnManObject *self)
|
||||
{
|
||||
self->techs = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
}
|
||||
|
||||
static void connman_object_finalize(GObject *object)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(object);
|
||||
|
||||
connman_cancel_call(self);
|
||||
g_hash_table_destroy(self->techs);
|
||||
g_dbus_remove_watch(self->connection, self->service_watch);
|
||||
g_dbus_remove_watch(self->connection, self->signal_watch);
|
||||
dbus_connection_unref(self->connection);
|
||||
G_OBJECT_CLASS(connman_object_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void connman_object_class_init(ConnManObjectClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = connman_object_finalize;
|
||||
connman_object_signals[SIGNAL_PROPERTY_CHANGED] =
|
||||
g_signal_new(SIGNAL_PROPERTY_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass),
|
||||
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
61
ofono/drivers/ril/ril_connman.h
Normal file
61
ofono/drivers/ril/ril_connman.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 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_CONNMAN_H
|
||||
#define RIL_CONNMAN_H
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
struct ril_connman {
|
||||
gboolean valid; /* TRUE if other fields are valid */
|
||||
gboolean present; /* ConnMan is present on D-Bus */
|
||||
gboolean tethering; /* At least one technology is tethering */
|
||||
gboolean wifi_connected; /* WiFi network is connected */
|
||||
};
|
||||
|
||||
enum ril_connman_property {
|
||||
RIL_CONNMAN_PROPERTY_ANY,
|
||||
RIL_CONNMAN_PROPERTY_VALID,
|
||||
RIL_CONNMAN_PROPERTY_PRESENT,
|
||||
RIL_CONNMAN_PROPERTY_TETHERING,
|
||||
RIL_CONNMAN_PROPERTY_WIFI_CONNECTED,
|
||||
RIL_CONNMAN_PROPERTY_COUNT
|
||||
};
|
||||
|
||||
typedef void (*ril_connman_property_cb_t)(struct ril_connman *connman,
|
||||
enum ril_connman_property property, void *arg);
|
||||
|
||||
struct ril_connman *ril_connman_new(void);
|
||||
struct ril_connman *ril_connman_ref(struct ril_connman *connman);
|
||||
void ril_connman_unref(struct ril_connman *connman);
|
||||
|
||||
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
|
||||
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg);
|
||||
void ril_connman_remove_handler(struct ril_connman *connman, gulong id);
|
||||
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
|
||||
int n);
|
||||
|
||||
#define ril_connman_remove_all_handlers(connman, ids) \
|
||||
ril_connman_remove_handlers(connman, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_CONNMAN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,10 +1,6 @@
|
||||
/*
|
||||
* RIL constants adopted from AOSP's header:
|
||||
*
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2017 Jolla Ltd.
|
||||
* Copyright (C) 2013-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -19,81 +15,10 @@
|
||||
#ifndef __RIL_CONSTANTS_H
|
||||
#define __RIL_CONSTANTS_H 1
|
||||
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#define RIL_MAX_UUID_LENGTH 64
|
||||
|
||||
/* Error Codes */
|
||||
enum ril_status {
|
||||
RIL_E_SUCCESS = 0,
|
||||
RIL_E_RADIO_NOT_AVAILABLE = 1,
|
||||
RIL_E_GENERIC_FAILURE = 2,
|
||||
RIL_E_PASSWORD_INCORRECT = 3,
|
||||
RIL_E_SIM_PIN2 = 4,
|
||||
RIL_E_SIM_PUK2 = 5,
|
||||
RIL_E_REQUEST_NOT_SUPPORTED = 6,
|
||||
RIL_E_CANCELLED = 7,
|
||||
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
|
||||
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
|
||||
RIL_E_SMS_SEND_FAIL_RETRY = 10,
|
||||
RIL_E_SIM_ABSENT = 11,
|
||||
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
|
||||
RIL_E_MODE_NOT_SUPPORTED = 13,
|
||||
RIL_E_FDN_CHECK_FAILURE = 14,
|
||||
RIL_E_ILLEGAL_SIM_OR_ME = 15,
|
||||
RIL_E_MISSING_RESOURCE = 16,
|
||||
RIL_E_NO_SUCH_ELEMENT = 17,
|
||||
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
|
||||
RIL_E_DIAL_MODIFIED_TO_SS = 19,
|
||||
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
|
||||
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
|
||||
RIL_E_USSD_MODIFIED_TO_SS = 22,
|
||||
RIL_E_USSD_MODIFIED_TO_USSD = 23,
|
||||
RIL_E_SS_MODIFIED_TO_DIAL = 24,
|
||||
RIL_E_SS_MODIFIED_TO_USSD = 25,
|
||||
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
|
||||
RIL_E_SS_MODIFIED_TO_SS = 27,
|
||||
RIL_E_LCE_NOT_SUPPORTED = 36,
|
||||
RIL_E_NO_MEMORY = 37,
|
||||
RIL_E_INTERNAL_ERR = 38,
|
||||
RIL_E_SYSTEM_ERR = 39,
|
||||
RIL_E_MODEM_ERR = 40,
|
||||
RIL_E_INVALID_STATE = 41,
|
||||
RIL_E_NO_RESOURCES = 42,
|
||||
RIL_E_SIM_ERR = 43,
|
||||
RIL_E_INVALID_ARGUMENTS = 44,
|
||||
RIL_E_INVALID_SIM_STATE = 45,
|
||||
RIL_E_INVALID_MODEM_STATE = 46,
|
||||
RIL_E_INVALID_CALL_ID = 47,
|
||||
RIL_E_NO_SMS_TO_ACK = 48,
|
||||
RIL_E_NETWORK_ERR = 49,
|
||||
RIL_E_REQUEST_RATE_LIMITED = 50,
|
||||
RIL_E_SIM_BUSY = 51,
|
||||
RIL_E_SIM_FULL = 52,
|
||||
RIL_E_NETWORK_REJECT = 53,
|
||||
RIL_E_OPERATION_NOT_ALLOWED = 54,
|
||||
RIL_E_EMPTY_RECORD = 55,
|
||||
RIL_E_INVALID_SMS_FORMAT = 56,
|
||||
RIL_E_ENCODING_ERR = 57,
|
||||
RIL_E_INVALID_SMSC_ADDRESS = 58,
|
||||
RIL_E_NO_SUCH_ENTRY = 59,
|
||||
RIL_E_NETWORK_NOT_READY = 60,
|
||||
RIL_E_NOT_PROVISIONED = 61,
|
||||
RIL_E_NO_SUBSCRIPTION = 62,
|
||||
RIL_E_NO_NETWORK_FOUND = 63,
|
||||
RIL_E_DEVICE_IN_USE = 64,
|
||||
RIL_E_ABORTED = 65,
|
||||
RIL_E_INVALID_RESPONSE = 66
|
||||
};
|
||||
|
||||
/* call states */
|
||||
enum ril_call_state {
|
||||
RIL_CALL_ACTIVE = 0,
|
||||
RIL_CALL_HOLDING = 1,
|
||||
RIL_CALL_DIALING = 2,
|
||||
RIL_CALL_ALERTING = 3,
|
||||
RIL_CALL_INCOMING = 4,
|
||||
RIL_CALL_WAITING = 5
|
||||
};
|
||||
|
||||
/* Radio state */
|
||||
enum ril_radio_state {
|
||||
RADIO_STATE_OFF = 0,
|
||||
@@ -267,30 +192,64 @@ enum ril_call_fail_cause {
|
||||
};
|
||||
|
||||
enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_NONE = 0,
|
||||
PDP_FAIL_OPERATOR_BARRED = 0x08,
|
||||
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
|
||||
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
|
||||
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
|
||||
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
|
||||
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
|
||||
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
|
||||
PDP_FAIL_RADIO_POWER_OFF = -5,
|
||||
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
|
||||
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
|
||||
PDP_FAIL_NONE = 0,
|
||||
PDP_FAIL_OPERATOR_BARRED = 0x08,
|
||||
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
|
||||
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
|
||||
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
|
||||
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
|
||||
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
|
||||
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
|
||||
PDP_FAIL_NETWORK_FAILURE = 0x26,
|
||||
PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
|
||||
PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
|
||||
PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
|
||||
PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
|
||||
PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
|
||||
PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
|
||||
PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
|
||||
PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
|
||||
PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
|
||||
PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
|
||||
PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
|
||||
PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
|
||||
PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
|
||||
PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
|
||||
PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
|
||||
PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
|
||||
PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
|
||||
PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
|
||||
PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
|
||||
PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
|
||||
PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
|
||||
PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
|
||||
PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
|
||||
PDP_FAIL_IFACE_MISMATCH = 0x75,
|
||||
PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
|
||||
PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
|
||||
PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
|
||||
PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
|
||||
PDP_FAIL_RADIO_POWER_OFF = -5,
|
||||
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
|
||||
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
|
||||
@@ -308,6 +267,12 @@ enum ril_data_profile {
|
||||
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum ril_profile_type {
|
||||
RIL_PROFILE_COMMON = 0,
|
||||
RIL_PROFILE_3GPP = 1,
|
||||
RIL_PROFILE_3GPP2 = 2
|
||||
};
|
||||
|
||||
enum ril_auth {
|
||||
RIL_AUTH_NONE = 0,
|
||||
RIL_AUTH_PAP = 1,
|
||||
@@ -395,191 +360,13 @@ enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
/* RIL Request Messages, ofono -> rild */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK 3
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN2 4
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK2 5
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN 6
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
|
||||
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
|
||||
#define RIL_REQUEST_GET_CURRENT_CALLS 9
|
||||
#define RIL_REQUEST_DIAL 10
|
||||
#define RIL_REQUEST_GET_IMSI 11
|
||||
#define RIL_REQUEST_HANGUP 12
|
||||
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
|
||||
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
|
||||
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
|
||||
#define RIL_REQUEST_CONFERENCE 16
|
||||
#define RIL_REQUEST_UDUB 17
|
||||
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
|
||||
#define RIL_REQUEST_SIGNAL_STRENGTH 19
|
||||
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
|
||||
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
|
||||
#define RIL_REQUEST_OPERATOR 22
|
||||
#define RIL_REQUEST_RADIO_POWER 23
|
||||
#define RIL_REQUEST_DTMF 24
|
||||
#define RIL_REQUEST_SEND_SMS 25
|
||||
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
|
||||
#define RIL_REQUEST_SETUP_DATA_CALL 27
|
||||
#define RIL_REQUEST_SIM_IO 28
|
||||
#define RIL_REQUEST_SEND_USSD 29
|
||||
#define RIL_REQUEST_CANCEL_USSD 30
|
||||
#define RIL_REQUEST_GET_CLIR 31
|
||||
#define RIL_REQUEST_SET_CLIR 32
|
||||
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
|
||||
#define RIL_REQUEST_SET_CALL_FORWARD 34
|
||||
#define RIL_REQUEST_QUERY_CALL_WAITING 35
|
||||
#define RIL_REQUEST_SET_CALL_WAITING 36
|
||||
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
|
||||
#define RIL_REQUEST_GET_IMEI 38
|
||||
#define RIL_REQUEST_GET_IMEISV 39
|
||||
#define RIL_REQUEST_ANSWER 40
|
||||
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
|
||||
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
|
||||
#define RIL_REQUEST_SET_FACILITY_LOCK 43
|
||||
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
|
||||
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
|
||||
#define RIL_REQUEST_DTMF_START 49
|
||||
#define RIL_REQUEST_DTMF_STOP 50
|
||||
#define RIL_REQUEST_BASEBAND_VERSION 51
|
||||
#define RIL_REQUEST_SEPARATE_CONNECTION 52
|
||||
#define RIL_REQUEST_SET_MUTE 53
|
||||
#define RIL_REQUEST_GET_MUTE 54
|
||||
#define RIL_REQUEST_QUERY_CLIP 55
|
||||
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
|
||||
#define RIL_REQUEST_DATA_CALL_LIST 57
|
||||
#define RIL_REQUEST_RESET_RADIO 58
|
||||
#define RIL_REQUEST_OEM_HOOK_RAW 59
|
||||
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
|
||||
#define RIL_REQUEST_SCREEN_STATE 61
|
||||
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
|
||||
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
|
||||
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
|
||||
#define RIL_REQUEST_SET_BAND_MODE 65
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
|
||||
#define RIL_REQUEST_STK_GET_PROFILE 67
|
||||
#define RIL_REQUEST_STK_SET_PROFILE 68
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
|
||||
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
|
||||
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
|
||||
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
|
||||
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
|
||||
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
|
||||
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
|
||||
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
|
||||
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
|
||||
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
|
||||
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
|
||||
#define RIL_REQUEST_SET_TTY_MODE 80
|
||||
#define RIL_REQUEST_QUERY_TTY_MODE 81
|
||||
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
|
||||
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
|
||||
#define RIL_REQUEST_CDMA_FLASH 84
|
||||
#define RIL_REQUEST_CDMA_BURST_DTMF 85
|
||||
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
|
||||
#define RIL_REQUEST_CDMA_SEND_SMS 87
|
||||
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
|
||||
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
|
||||
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
|
||||
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
|
||||
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
|
||||
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
|
||||
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
|
||||
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
|
||||
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
|
||||
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
|
||||
#define RIL_REQUEST_DEVICE_IDENTITY 98
|
||||
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
|
||||
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
|
||||
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
|
||||
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
|
||||
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
|
||||
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
|
||||
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
|
||||
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
|
||||
#define RIL_REQUEST_VOICE_RADIO_TECH 108
|
||||
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
|
||||
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
|
||||
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
|
||||
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
|
||||
#define RIL_REQUEST_IMS_SEND_SMS 113
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
|
||||
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
|
||||
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
|
||||
#define RIL_REQUEST_NV_READ_ITEM 118
|
||||
#define RIL_REQUEST_NV_WRITE_ITEM 119
|
||||
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
|
||||
#define RIL_REQUEST_NV_RESET_CONFIG 121
|
||||
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
|
||||
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
|
||||
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
|
||||
#define RIL_REQUEST_ALLOW_DATA 123
|
||||
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
|
||||
#define RIL_REQUEST_SIM_AUTHENTICATION 125
|
||||
#define RIL_REQUEST_GET_DC_RT_INFO 126
|
||||
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
|
||||
#define RIL_REQUEST_SET_DATA_PROFILE 128
|
||||
#define RIL_REQUEST_SHUTDOWN 129
|
||||
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
|
||||
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
|
||||
|
||||
/* RIL Unsolicited Messages, rild -> ofono */
|
||||
#define RIL_UNSOL_RESPONSE_BASE 1000
|
||||
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
|
||||
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
|
||||
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
|
||||
#define RIL_UNSOL_ON_USSD 1006
|
||||
#define RIL_UNSOL_ON_USSD_REQUEST 1007
|
||||
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
|
||||
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
|
||||
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
|
||||
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
|
||||
#define RIL_UNSOL_STK_SESSION_END 1012
|
||||
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
|
||||
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
|
||||
#define RIL_UNSOL_STK_CALL_SETUP 1015
|
||||
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
|
||||
#define RIL_UNSOL_SIM_REFRESH 1017
|
||||
#define RIL_UNSOL_CALL_RING 1018
|
||||
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
|
||||
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
|
||||
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
|
||||
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
|
||||
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
|
||||
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
|
||||
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
|
||||
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
|
||||
#define RIL_UNSOL_CDMA_INFO_REC 1027
|
||||
#define RIL_UNSOL_OEM_HOOK_RAW 1028
|
||||
#define RIL_UNSOL_RINGBACK_TONE 1029
|
||||
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
|
||||
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
|
||||
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
|
||||
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
|
||||
#define RIL_UNSOL_RIL_CONNECTED 1034
|
||||
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
|
||||
#define RIL_UNSOL_CELL_INFO_LIST 1036
|
||||
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
|
||||
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
|
||||
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
|
||||
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
|
||||
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
|
||||
#define RIL_UNSOL_RADIO_CAPABILITY 1042
|
||||
#define RIL_UNSOL_ON_SS 1043
|
||||
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
|
||||
|
||||
/* A special request, ofono -> rild */
|
||||
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
|
||||
enum ril_restricted_state {
|
||||
RIL_RESTRICTED_STATE_NONE = 0x00,
|
||||
RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
|
||||
RIL_RESTRICTED_STATE_CS_NORMAL = 0x02,
|
||||
RIL_RESTRICTED_STATE_CS_ALL = 0x04,
|
||||
RIL_RESTRICTED_STATE_PS_ALL = 0x10
|
||||
};
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
@@ -588,6 +375,19 @@ enum ril_cell_info_type {
|
||||
#define RIL_FACILITY_UNLOCK "0"
|
||||
#define RIL_FACILITY_LOCK "1"
|
||||
|
||||
/* See RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER (RIL_VERSION >= 15) */
|
||||
enum ril_unsolicited_response_filter {
|
||||
RIL_UR_SIGNAL_STRENGTH = 0x01,
|
||||
RIL_UR_FULL_NETWORK_STATE = 0x02,
|
||||
RIL_UR_DATA_CALL_DORMANCY_CHANGED = 0x04
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE result */
|
||||
enum ril_network_selection_mode {
|
||||
RIL_NETWORK_SELECTION_MODE_AUTO = 0,
|
||||
RIL_NETWORK_SELECTION_MODE_MANUAL = 1
|
||||
};
|
||||
|
||||
#endif /*__RIL_CONSTANTS_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -13,6 +14,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_data.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_network.h"
|
||||
@@ -28,11 +31,10 @@
|
||||
#include <grilio_parser.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#define DATA_PROFILE_DEFAULT_STR "0"
|
||||
#include "common.h" /* ACCESS_TECHNOLOGY_EUTRAN */
|
||||
|
||||
#define PROTO_IP_STR "IP"
|
||||
#define PROTO_IPV6_STR "IPV6"
|
||||
#define PROTO_IPV4V6_STR "IPV4V6"
|
||||
/* Yes, it does sometimes take minutes in roaming */
|
||||
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
|
||||
|
||||
enum ril_data_priv_flags {
|
||||
RIL_DATA_FLAG_NONE = 0x00,
|
||||
@@ -76,6 +78,12 @@ enum ril_data_priv_flags {
|
||||
typedef GObjectClass RilDataClass;
|
||||
typedef struct ril_data RilData;
|
||||
|
||||
enum ril_data_io_event_id {
|
||||
IO_EVENT_DATA_CALL_LIST_CHANGED,
|
||||
IO_EVENT_RESTRICTED_STATE_CHANGED,
|
||||
IO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_data_settings_event_id {
|
||||
SETTINGS_EVENT_IMSI_CHANGED,
|
||||
SETTINGS_EVENT_PREF_MODE,
|
||||
@@ -94,18 +102,24 @@ struct ril_data_priv {
|
||||
struct ril_radio *radio;
|
||||
struct ril_network *network;
|
||||
struct ril_data_manager *dm;
|
||||
struct ril_vendor *vendor;
|
||||
|
||||
enum ril_data_priv_flags flags;
|
||||
struct ril_vendor_hook *vendor_hook;
|
||||
enum ril_restricted_state restricted_state;
|
||||
|
||||
struct ril_data_request *req_queue;
|
||||
struct ril_data_request *pending_req;
|
||||
|
||||
struct ril_data_options options;
|
||||
gboolean use_data_profiles;
|
||||
guint mms_data_profile_id;
|
||||
guint slot;
|
||||
char *log_prefix;
|
||||
guint query_id;
|
||||
gulong io_event_id;
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
gulong settings_event_id[SETTINGS_EVENT_COUNT];
|
||||
GHashTable* grab;
|
||||
gboolean downgraded_tech; /* Status 55 workaround */
|
||||
};
|
||||
|
||||
enum ril_data_signal {
|
||||
@@ -156,6 +170,7 @@ struct ril_data_request {
|
||||
|
||||
struct ril_data_request_setup {
|
||||
struct ril_data_request req;
|
||||
guint profile_id;
|
||||
char *apn;
|
||||
char *username;
|
||||
char *password;
|
||||
@@ -175,9 +190,8 @@ struct ril_data_request_allow_data {
|
||||
gboolean allow;
|
||||
};
|
||||
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
|
||||
|
||||
static void ril_data_call_deact_cid(struct ril_data *data, int cid);
|
||||
static void ril_data_power_update(struct ril_data *self);
|
||||
static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
|
||||
{
|
||||
@@ -276,34 +290,6 @@ static gint ril_data_call_compare(gconstpointer a, gconstpointer b)
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case OFONO_GPRS_PROTO_IPV6:
|
||||
return PROTO_IPV6_STR;
|
||||
case OFONO_GPRS_PROTO_IPV4V6:
|
||||
return PROTO_IPV4V6_STR;
|
||||
case OFONO_GPRS_PROTO_IP:
|
||||
return PROTO_IP_STR;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ril_data_protocol_to_ofono(const gchar *str)
|
||||
{
|
||||
if (str) {
|
||||
if (!strcmp(str, PROTO_IPV6_STR)) {
|
||||
return OFONO_GPRS_PROTO_IPV6;
|
||||
} else if (!strcmp(str, PROTO_IPV4V6_STR)) {
|
||||
return OFONO_GPRS_PROTO_IPV4V6;
|
||||
} else if (!strcmp(str, PROTO_IP_STR)) {
|
||||
return OFONO_GPRS_PROTO_IP;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gboolean ril_data_call_parse_default(struct ril_data_call *call,
|
||||
int version, GRilIoParser *rilp)
|
||||
{
|
||||
@@ -323,7 +309,7 @@ static gboolean ril_data_call_parse_default(struct ril_data_call *call,
|
||||
call->dnses = grilio_parser_split_utf8(rilp, " ");
|
||||
call->gateways = grilio_parser_split_utf8(rilp, " ");
|
||||
|
||||
prot = ril_data_protocol_to_ofono(prot_str);
|
||||
prot = ril_protocol_to_ofono(prot_str);
|
||||
if (prot < 0 && status == PDP_FAIL_NONE) {
|
||||
ofono_error("Invalid protocol: %s", prot_str);
|
||||
}
|
||||
@@ -348,19 +334,20 @@ static gboolean ril_data_call_parse_default(struct ril_data_call *call,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
|
||||
static struct ril_data_call *ril_data_call_parse(struct ril_vendor *vendor,
|
||||
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,
|
||||
gboolean parsed = ril_vendor_data_call_parse(vendor, call,
|
||||
version, parser);
|
||||
|
||||
if (!parsed) {
|
||||
/* Try the default parser */
|
||||
ril_data_call_destroy(call);
|
||||
memset(call, 0, sizeof(*call));
|
||||
parsed = ril_data_call_parse_default(call, version, ©);
|
||||
*parser = copy;
|
||||
parsed = ril_data_call_parse_default(call, version, parser);
|
||||
}
|
||||
|
||||
if (parsed) {
|
||||
@@ -368,7 +355,7 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
|
||||
"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),
|
||||
ril_protocol_from_ofono(call->prot),
|
||||
call->ifname, call->mtu,
|
||||
call->addresses ? call->addresses[0] : NULL,
|
||||
call->dnses ? call->dnses[0] : NULL,
|
||||
@@ -383,10 +370,10 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
|
||||
}
|
||||
|
||||
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
guint len, struct ril_vendor_hook *hook,
|
||||
guint len, struct ril_vendor *vendor,
|
||||
enum ril_data_call_format format)
|
||||
{
|
||||
guint32 version, n;
|
||||
guint32 version, n, i;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
@@ -403,22 +390,14 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
list->version = format;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
guint i, clen = grilio_parser_bytes_remaining(&rilp)/n;
|
||||
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
|
||||
struct ril_data_call *call = ril_data_call_parse(vendor,
|
||||
list->version, &rilp);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
GRilIoParser callp;
|
||||
struct ril_data_call *call;
|
||||
|
||||
grilio_parser_get_data(&rilp, &callp, clen);
|
||||
call = ril_data_call_parse(hook, list->version,
|
||||
&callp);
|
||||
if (call) {
|
||||
list->num++;
|
||||
list->calls = g_slist_insert_sorted
|
||||
(list->calls, call,
|
||||
ril_data_call_compare);
|
||||
}
|
||||
if (call) {
|
||||
list->num++;
|
||||
list->calls = g_slist_insert_sorted(list->calls,
|
||||
call, ril_data_call_compare);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,7 +439,7 @@ static gboolean ril_data_call_list_equal(const struct ril_data_call_list *l1,
|
||||
if (!l1 && !l2) {
|
||||
return TRUE;
|
||||
} else if (l1 && l2) {
|
||||
if (l1->version == l1->version && l1->num == l2->num) {
|
||||
if (l1->version == l2->version && l1->num == l2->num) {
|
||||
GSList *p1 = l1->calls;
|
||||
GSList *p2 = l2->calls;
|
||||
|
||||
@@ -544,6 +523,10 @@ struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
static void ril_data_set_calls(struct ril_data *self,
|
||||
struct ril_data_call_list *list)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
GHashTableIter it;
|
||||
gpointer key;
|
||||
|
||||
if (!ril_data_call_list_equal(self->data_calls, list)) {
|
||||
DBG("data calls changed");
|
||||
ril_data_call_list_free(self->data_calls);
|
||||
@@ -552,6 +535,63 @@ static void ril_data_set_calls(struct ril_data *self,
|
||||
} else {
|
||||
ril_data_call_list_free(list);
|
||||
}
|
||||
|
||||
/* Clean up the grab table */
|
||||
g_hash_table_iter_init(&it, priv->grab);
|
||||
while (g_hash_table_iter_next(&it, &key, NULL)) {
|
||||
const int cid = GPOINTER_TO_INT(key);
|
||||
|
||||
if (!ril_data_call_find(self->data_calls, cid)) {
|
||||
g_hash_table_iter_remove(&it);
|
||||
}
|
||||
}
|
||||
|
||||
if (self->data_calls) {
|
||||
GSList *l;
|
||||
|
||||
/* Disconnect stray calls (one at a time) */
|
||||
for (l = self->data_calls->calls; l; l = l->next) {
|
||||
struct ril_data_call *dc = l->data;
|
||||
|
||||
key = GINT_TO_POINTER(dc->cid);
|
||||
if (!g_hash_table_contains(priv->grab, key)) {
|
||||
DBG_(self, "stray call %u", dc->cid);
|
||||
ril_data_call_deact_cid(self, dc->cid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_check_allowed(struct ril_data *self, gboolean was_allowed)
|
||||
{
|
||||
if (ril_data_allowed(self) != was_allowed) {
|
||||
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_restricted_state_changed_cb(GRilIoChannel *io, guint event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_data *self = RIL_DATA(user_data);
|
||||
GRilIoParser rilp;
|
||||
guint32 count, state;
|
||||
|
||||
GASSERT(event == RIL_UNSOL_RESTRICTED_STATE_CHANGED);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &count) && count == 1 &&
|
||||
grilio_parser_get_uint32(&rilp, &state) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (priv->restricted_state != state) {
|
||||
const gboolean was_allowed = ril_data_allowed(self);
|
||||
|
||||
DBG_(self, "restricted state 0x%02x", state);
|
||||
priv->restricted_state = state;
|
||||
ril_data_check_allowed(self, was_allowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
|
||||
@@ -569,7 +609,7 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
|
||||
}
|
||||
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->vendor_hook, priv->options.data_call_format));
|
||||
priv->vendor, priv->options.data_call_format));
|
||||
}
|
||||
|
||||
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
@@ -586,7 +626,7 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
priv->query_id = 0;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->vendor_hook, priv->options.data_call_format));
|
||||
priv->vendor, priv->options.data_call_format));
|
||||
} else {
|
||||
/* RADIO_NOT_AVAILABLE == no calls */
|
||||
ril_data_set_calls(self, NULL);
|
||||
@@ -780,6 +820,31 @@ static gboolean ril_data_call_setup_retry(void *user_data)
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean ril_data_call_retry(struct ril_data_request_setup *setup)
|
||||
{
|
||||
struct ril_data_request *req = &setup->req;
|
||||
const struct ril_data_options *options = &req->data->priv->options;
|
||||
|
||||
if (setup->retry_count < options->data_call_retry_limit) {
|
||||
req->pending_id = 0;
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
/* No delay first time */
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
options->data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
const guint ms = options->data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -791,8 +856,8 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
struct ril_data_call *call = NULL;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
list = ril_data_call_list_parse(data, len,
|
||||
priv->vendor_hook, priv->options.data_call_format);
|
||||
list = ril_data_call_list_parse(data, len, priv->vendor,
|
||||
priv->options.data_call_format);
|
||||
}
|
||||
|
||||
if (list) {
|
||||
@@ -804,33 +869,49 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
}
|
||||
|
||||
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
|
||||
setup->retry_count < priv->options.data_call_retry_limit) {
|
||||
if (call) {
|
||||
switch (call->status) {
|
||||
/*
|
||||
* According to the comment from ril.h we should silently
|
||||
* retry. First time we retry immediately and if that doedsn't
|
||||
* retry. First time we retry immediately and if that doesn't
|
||||
* work, then after certain delay.
|
||||
*/
|
||||
req->pending_id = 0;
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
priv->options.data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
guint ms = priv->options.data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
case PDP_FAIL_ERROR_UNSPECIFIED:
|
||||
if (ril_data_call_retry(setup)) {
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* With some networks we sometimes start getting error 55
|
||||
* (Multiple PDN connections for a given APN not allowed)
|
||||
* when trying to setup an LTE data call and this error
|
||||
* doesn't go away until we successfully establish a data
|
||||
* call over 3G. Then we can switch back to LTE.
|
||||
*/
|
||||
case PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED:
|
||||
if (priv->network->data.access_tech ==
|
||||
ACCESS_TECHNOLOGY_EUTRAN &&
|
||||
!priv->downgraded_tech) {
|
||||
DBG("downgrading preferred technology");
|
||||
priv->downgraded_tech = TRUE;
|
||||
ril_data_manager_check_network_mode(priv->dm);
|
||||
/* And let this call fail */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
|
||||
ril_data_request_completed(req);
|
||||
|
||||
if (call && call->status == PDP_FAIL_NONE) {
|
||||
if (priv->downgraded_tech) {
|
||||
DBG("done with status 55 workaround");
|
||||
priv->downgraded_tech = FALSE;
|
||||
ril_data_manager_check_network_mode(priv->dm);
|
||||
}
|
||||
if (ril_data_call_list_move_calls(self->data_calls, list) > 0) {
|
||||
DBG("data call(s) added");
|
||||
ril_data_signal_emit(self, SIGNAL_CALLS_CHANGED);
|
||||
@@ -854,7 +935,7 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
struct ril_data_request_setup *setup =
|
||||
G_CAST(req, struct ril_data_request_setup, req);
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
const char *proto_str = ril_data_ofono_protocol_to_ril(setup->proto);
|
||||
const char *proto_str = ril_protocol_from_ofono(setup->proto);
|
||||
GRilIoRequest *ioreq;
|
||||
int tech, auth = RIL_AUTH_NONE;
|
||||
|
||||
@@ -880,25 +961,12 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
}
|
||||
|
||||
if (setup->username && setup->username[0]) {
|
||||
switch (setup->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;
|
||||
}
|
||||
auth = ril_auth_method_from_ofono(setup->auth_method);
|
||||
}
|
||||
|
||||
/* Give vendor code a chance to build a vendor specific packet */
|
||||
ioreq = ril_vendor_hook_data_call_req(priv->vendor_hook, tech,
|
||||
DATA_PROFILE_DEFAULT_STR, setup->apn, setup->username,
|
||||
ioreq = ril_vendor_data_call_req(priv->vendor, tech,
|
||||
setup->profile_id, setup->apn, setup->username,
|
||||
setup->password, auth, proto_str);
|
||||
|
||||
if (!ioreq) {
|
||||
@@ -906,7 +974,7 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
ioreq = grilio_request_new();
|
||||
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
|
||||
grilio_request_append_format(ioreq, "%d", tech);
|
||||
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
|
||||
grilio_request_append_format(ioreq, "%d", setup->profile_id);
|
||||
grilio_request_append_utf8(ioreq, setup->apn);
|
||||
grilio_request_append_utf8(ioreq, setup->username);
|
||||
grilio_request_append_utf8(ioreq, setup->password);
|
||||
@@ -915,6 +983,7 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
}
|
||||
|
||||
GASSERT(!req->pending_id);
|
||||
grilio_request_set_timeout(ioreq, SETUP_DATA_CALL_TIMEOUT);
|
||||
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
||||
RIL_REQUEST_SETUP_DATA_CALL, ril_data_call_setup_cb,
|
||||
NULL, setup);
|
||||
@@ -935,12 +1004,18 @@ static void ril_data_call_setup_free(struct ril_data_request *req)
|
||||
|
||||
static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
enum ofono_gprs_context_type context_type,
|
||||
ril_data_call_setup_cb_t cb, void *arg)
|
||||
{
|
||||
struct ril_data_priv *priv = data->priv;
|
||||
struct ril_data_request_setup *setup =
|
||||
g_new0(struct ril_data_request_setup, 1);
|
||||
struct ril_data_request *req = &setup->req;
|
||||
|
||||
setup->profile_id = (priv->use_data_profiles &&
|
||||
context_type == OFONO_GPRS_CONTEXT_TYPE_MMS) ?
|
||||
priv->mms_data_profile_id :
|
||||
RIL_DATA_PROFILE_DEFAULT;
|
||||
setup->apn = g_strdup(ctx->apn);
|
||||
setup->username = g_strdup(ctx->username);
|
||||
setup->password = g_strdup(ctx->password);
|
||||
@@ -1051,6 +1126,11 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_data_call_deact_cid(struct ril_data *data, int cid)
|
||||
{
|
||||
ril_data_request_queue(ril_data_call_deact_new(data, cid, NULL, NULL));
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ril_data_allow_request
|
||||
*==========================================================================*/
|
||||
@@ -1077,9 +1157,7 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
DBG_(data, "data off");
|
||||
}
|
||||
|
||||
if (ril_data_allowed(data) != was_allowed) {
|
||||
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
ril_data_check_allowed(data, was_allowed);
|
||||
}
|
||||
|
||||
ril_data_request_finish(req);
|
||||
@@ -1119,6 +1197,11 @@ static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
|
||||
/*==========================================================================*
|
||||
* ril_data
|
||||
*==========================================================================*/
|
||||
static enum ofono_radio_access_mode ril_data_max_mode(struct ril_data *self)
|
||||
{
|
||||
return self->priv->downgraded_tech ? OFONO_RADIO_ACCESS_MODE_UMTS :
|
||||
OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
|
||||
ril_data_cb_t cb, void *arg)
|
||||
@@ -1161,7 +1244,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_vendor_hook *vendor_hook)
|
||||
struct ril_vendor *vendor)
|
||||
{
|
||||
GASSERT(dm);
|
||||
if (G_LIKELY(dm)) {
|
||||
@@ -1188,16 +1271,24 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
priv->log_prefix = (name && name[0]) ?
|
||||
g_strconcat(name, " ", NULL) : g_strdup("");
|
||||
|
||||
priv->use_data_profiles = config->use_data_profiles;
|
||||
priv->mms_data_profile_id = config->mms_data_profile_id;
|
||||
priv->slot = config->slot;
|
||||
priv->q = grilio_queue_new(io);
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->dm = ril_data_manager_ref(dm);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->network = ril_network_ref(network);
|
||||
priv->vendor_hook = ril_vendor_hook_ref(vendor_hook);
|
||||
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
|
||||
priv->vendor = ril_vendor_ref(vendor);
|
||||
|
||||
priv->io_event_id[IO_EVENT_DATA_CALL_LIST_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_data_call_list_changed_cb,
|
||||
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
|
||||
priv->io_event_id[IO_EVENT_RESTRICTED_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_data_restricted_state_changed_cb,
|
||||
RIL_UNSOL_RESTRICTED_STATE_CHANGED, self);
|
||||
|
||||
priv->settings_event_id[SETTINGS_EVENT_IMSI_CHANGED] =
|
||||
ril_sim_settings_add_imsi_changed_handler(settings,
|
||||
@@ -1271,6 +1362,8 @@ void ril_data_unref(struct ril_data *self)
|
||||
gboolean ril_data_allowed(struct ril_data *self)
|
||||
{
|
||||
return G_LIKELY(self) &&
|
||||
(self->priv->restricted_state &
|
||||
RIL_RESTRICTED_STATE_PS_ALL) == 0 &&
|
||||
(self->priv->flags &
|
||||
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON)) ==
|
||||
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
|
||||
@@ -1285,9 +1378,7 @@ static void ril_data_deactivate_all(struct ril_data *self)
|
||||
struct ril_data_call *call = l->data;
|
||||
if (call->status == PDP_FAIL_NONE) {
|
||||
DBG_(self, "deactivating call %u", call->cid);
|
||||
ril_data_request_queue(
|
||||
ril_data_call_deact_new(self,
|
||||
call->cid, NULL, NULL));
|
||||
ril_data_call_deact_cid(self, call->cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1355,9 +1446,7 @@ static void ril_data_disallow(struct ril_data *self)
|
||||
ril_data_power_update(self);
|
||||
}
|
||||
|
||||
if (ril_data_allowed(self) != was_allowed) {
|
||||
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
ril_data_check_allowed(self, was_allowed);
|
||||
}
|
||||
|
||||
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
|
||||
@@ -1437,10 +1526,11 @@ void ril_data_allow(struct ril_data *self, enum ril_data_role role)
|
||||
|
||||
struct ril_data_request *ril_data_call_setup(struct ril_data *self,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
enum ofono_gprs_context_type context_type,
|
||||
ril_data_call_setup_cb_t cb, void *arg)
|
||||
{
|
||||
struct ril_data_request *req =
|
||||
ril_data_call_setup_new(self, ctx, cb, arg);
|
||||
ril_data_call_setup_new(self, ctx, context_type, cb, arg);
|
||||
|
||||
ril_data_request_queue(req);
|
||||
return req;
|
||||
@@ -1456,12 +1546,39 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *self,
|
||||
return req;
|
||||
}
|
||||
|
||||
gboolean ril_data_call_grab(struct ril_data *self, int cid, void *cookie)
|
||||
{
|
||||
if (self && cookie && ril_data_call_find(self->data_calls, cid)) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(cid);
|
||||
void *prev = g_hash_table_lookup(priv->grab, key);
|
||||
|
||||
if (!prev) {
|
||||
g_hash_table_insert(priv->grab, key, cookie);
|
||||
return TRUE;
|
||||
} else {
|
||||
return (prev == cookie);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ril_data_call_release(struct ril_data *self, int cid, void *cookie)
|
||||
{
|
||||
if (self && cookie) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
g_hash_table_remove(priv->grab, GUINT_TO_POINTER(cid));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_init(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_DATA_TYPE, struct ril_data_priv);
|
||||
|
||||
self->priv = priv;
|
||||
priv->grab = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void ril_data_dispose(GObject *object)
|
||||
@@ -1475,7 +1592,7 @@ static void ril_data_dispose(GObject *object)
|
||||
|
||||
ril_sim_settings_remove_handlers(settings, priv->settings_event_id,
|
||||
G_N_ELEMENTS(priv->settings_event_id));
|
||||
grilio_channel_remove_handlers(priv->io, &priv->io_event_id, 1);
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
priv->query_id = 0;
|
||||
|
||||
@@ -1489,6 +1606,7 @@ static void ril_data_dispose(GObject *object)
|
||||
|
||||
dm->data_list = g_slist_remove(dm->data_list, self);
|
||||
ril_data_manager_check_data(dm);
|
||||
g_hash_table_destroy(priv->grab);
|
||||
G_OBJECT_CLASS(ril_data_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
@@ -1505,7 +1623,7 @@ static void ril_data_finalize(GObject *object)
|
||||
ril_network_unref(priv->network);
|
||||
ril_data_manager_unref(priv->dm);
|
||||
ril_data_call_list_free(self->data_calls);
|
||||
ril_vendor_hook_unref(priv->vendor_hook);
|
||||
ril_vendor_unref(priv->vendor);
|
||||
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
@@ -1579,7 +1697,8 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
if ((self->flags & RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS) &&
|
||||
ril_data_manager_handover(self)) {
|
||||
struct ril_network *lte_network = NULL;
|
||||
int non_gsm_count = 0;
|
||||
|
||||
@@ -1616,7 +1735,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
|
||||
ril_network_set_max_pref_mode(network,
|
||||
(network == lte_network) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
ril_data_max_mode(data) :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
}
|
||||
@@ -1626,7 +1745,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
ril_network_set_max_pref_mode(data->priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
|
||||
ril_data_max_mode(data), FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1655,7 +1774,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
ril_network_set_max_pref_mode(priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
|
||||
ril_data_max_mode(data), TRUE);
|
||||
}
|
||||
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
@@ -1668,7 +1787,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
{
|
||||
/*
|
||||
* Don't do anything if there any requests pending.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,8 +18,11 @@
|
||||
#define RIL_DATA_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
enum ril_data_call_active {
|
||||
RIL_DATA_CALL_INACTIVE = 0,
|
||||
RIL_DATA_CALL_LINK_DOWN = 1,
|
||||
@@ -51,7 +55,8 @@ struct ril_data {
|
||||
};
|
||||
|
||||
enum ril_data_manager_flags {
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01,
|
||||
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS = 0x02
|
||||
};
|
||||
|
||||
enum ril_data_allow_data_opt {
|
||||
@@ -84,6 +89,7 @@ struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
@@ -97,7 +103,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_vendor_hook *vendor_hook);
|
||||
struct ril_vendor *vendor);
|
||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||
void ril_data_unref(struct ril_data *data);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
@@ -114,20 +120,21 @@ void ril_data_allow(struct ril_data *data, enum ril_data_role role);
|
||||
struct ril_data_request;
|
||||
struct ril_data_request *ril_data_call_setup(struct ril_data *data,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
enum ofono_gprs_context_type context_type,
|
||||
ril_data_call_setup_cb_t cb, void *arg);
|
||||
struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
|
||||
int cid, ril_data_call_deactivate_cb_t cb, void *arg);
|
||||
void ril_data_request_detach(struct ril_data_request *req);
|
||||
void ril_data_request_cancel(struct ril_data_request *req);
|
||||
|
||||
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
|
||||
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
|
||||
|
||||
void ril_data_call_free(struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
int cid);
|
||||
|
||||
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto);
|
||||
int ril_data_protocol_to_ofono(const gchar *str);
|
||||
|
||||
/* Constructors of various kinds of RIL requests */
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||
|
||||
44
ofono/drivers/ril/ril_devmon.c
Normal file
44
ofono/drivers/ril/ril_devmon.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 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_devmon.h"
|
||||
|
||||
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *channel, struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
return devmon ? devmon->start_io(devmon, channel, cell_info) : NULL;
|
||||
}
|
||||
|
||||
void ril_devmon_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
if (devmon_io) {
|
||||
devmon_io->free(devmon_io);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_devmon_free(struct ril_devmon *devmon)
|
||||
{
|
||||
if (devmon) {
|
||||
devmon->free(devmon);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
84
ofono/drivers/ril/ril_devmon.h
Normal file
84
ofono/drivers/ril/ril_devmon.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_DEVMON_H
|
||||
#define RIL_DEVMON_H
|
||||
|
||||
#include "ril_cell_info.h"
|
||||
|
||||
/*
|
||||
* Separate instance of ril_devmon is created for each modem.
|
||||
* Device monitor is started after RIL has been connected.
|
||||
*/
|
||||
|
||||
struct ril_devmon_io {
|
||||
void (*free)(struct ril_devmon_io *devmon_io);
|
||||
};
|
||||
|
||||
struct ril_devmon {
|
||||
void (*free)(struct ril_devmon *devmon);
|
||||
struct ril_devmon_io *(*start_io)(struct ril_devmon *devmon,
|
||||
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
|
||||
};
|
||||
|
||||
/* Cell info update intervals */
|
||||
#define RIL_CELL_INFO_INTERVAL_SHORT_MS (2000) /* 2 sec */
|
||||
#define RIL_CELL_INFO_INTERVAL_LONG_MS (30000) /* 30 sec */
|
||||
|
||||
/*
|
||||
* Legacy Device Monitor uses RIL_REQUEST_SCREEN_STATE to tell
|
||||
* the modem when screen turns on and off.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ss_new(void);
|
||||
|
||||
/*
|
||||
* This Device Monitor uses RIL_REQUEST_SEND_DEVICE_STATE to let
|
||||
* the modem choose the right power saving strategy. It basically
|
||||
* mirrors the logic of Android's DeviceStateMonitor class.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ds_new(void);
|
||||
|
||||
/*
|
||||
* This Device Monitor implementation controls network state updates
|
||||
* by sending SET_UNSOLICITED_RESPONSE_FILTER.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ur_new(void);
|
||||
|
||||
/*
|
||||
* This one selects the type based on the RIL version.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_auto_new(void);
|
||||
|
||||
/*
|
||||
* This one combines several methods. Takes ownership of ril_devmon objects.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_combine(struct ril_devmon *devmon[], guint n);
|
||||
|
||||
/* Utilities (NULL tolerant) */
|
||||
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
|
||||
void ril_devmon_io_free(struct ril_devmon_io *devmon_io);
|
||||
void ril_devmon_free(struct ril_devmon *devmon);
|
||||
|
||||
#endif /* RIL_CONNMAN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
92
ofono/drivers/ril/ril_devmon_auto.c
Normal file
92
ofono/drivers/ril/ril_devmon_auto.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
|
||||
typedef struct ril_devmon_ds {
|
||||
struct ril_devmon pub;
|
||||
struct ril_devmon *ss;
|
||||
struct ril_devmon *ds;
|
||||
} DevMon;
|
||||
|
||||
static inline DevMon *ril_devmon_auto_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_auto_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
DevMon *self = ril_devmon_auto_cast(devmon);
|
||||
|
||||
if (!self->ss) {
|
||||
/* We have already chosen SEND_DEVICE_STATE method */
|
||||
return ril_devmon_start_io(self->ds, io, cell_info);
|
||||
} else if (!self->ds) {
|
||||
/* We have already chosen SCREEN_STATE method */
|
||||
return ril_devmon_start_io(self->ss, io, cell_info);
|
||||
} else if (io->ril_version > 14 /* Covers binder implementation */) {
|
||||
/* Choose SEND_DEVICE_STATE method */
|
||||
DBG("%s: Will use SEND_DEVICE_STATE method", io->name);
|
||||
ril_devmon_free(self->ss);
|
||||
self->ss = NULL;
|
||||
return ril_devmon_start_io(self->ds, io, cell_info);
|
||||
} else {
|
||||
/* Choose legacy SCREEN_STATE method */
|
||||
DBG("%s: Will use SCREEN_STATE method", io->name);
|
||||
ril_devmon_free(self->ds);
|
||||
self->ds = NULL;
|
||||
return ril_devmon_start_io(self->ss, io, cell_info);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_auto_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_auto_cast(devmon);
|
||||
|
||||
ril_devmon_free(self->ss);
|
||||
ril_devmon_free(self->ds);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_auto_new()
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
/*
|
||||
* Allocate both implementations at startup. We need to do that
|
||||
* early so that connections to D-Bus daemon and services are
|
||||
* established before we drop privileges. This isn't much of
|
||||
* an overhead because those implementation don't do much until
|
||||
* we actually start the I/O (at which point we drop one of those).
|
||||
*/
|
||||
self->pub.free = ril_devmon_auto_free;
|
||||
self->pub.start_io = ril_devmon_auto_start_io;
|
||||
self->ss = ril_devmon_ss_new();
|
||||
self->ds = ril_devmon_ds_new();
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
104
ofono/drivers/ril/ril_devmon_combine.c
Normal file
104
ofono/drivers/ril/ril_devmon_combine.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
typedef struct ril_devmon_combine {
|
||||
struct ril_devmon pub;
|
||||
struct ril_devmon **impl;
|
||||
guint count;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_combine_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct ril_devmon_io **impl;
|
||||
guint count;
|
||||
} DevMonIo;
|
||||
|
||||
static inline DevMon *ril_devmon_combine_cast(struct ril_devmon *dm)
|
||||
{
|
||||
return G_CAST(dm, DevMon, pub);
|
||||
}
|
||||
|
||||
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *io)
|
||||
{
|
||||
return G_CAST(io, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static void ril_devmon_combine_io_free(struct ril_devmon_io *io)
|
||||
{
|
||||
guint i;
|
||||
DevMonIo *self = ril_devmon_ds_io_cast(io);
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
ril_devmon_io_free(self->impl[i]);
|
||||
}
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_combine_start_io(struct ril_devmon *dm,
|
||||
GRilIoChannel *chan, struct sailfish_cell_info *ci)
|
||||
{
|
||||
guint i;
|
||||
DevMon *self = ril_devmon_combine_cast(dm);
|
||||
DevMonIo *io = g_malloc0(sizeof(DevMonIo) +
|
||||
sizeof(struct ril_devmon_io *) * self->count);
|
||||
|
||||
io->pub.free = ril_devmon_combine_io_free;
|
||||
io->impl = (struct ril_devmon_io**)(io + 1);
|
||||
io->count = self->count;
|
||||
for (i = 0; i < io->count; i++) {
|
||||
io->impl[i] = ril_devmon_start_io(self->impl[i], chan, ci);
|
||||
}
|
||||
return &io->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_combine_free(struct ril_devmon *dm)
|
||||
{
|
||||
DevMon *self = ril_devmon_combine_cast(dm);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
ril_devmon_free(self->impl[i]);
|
||||
}
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_combine(struct ril_devmon *dm[], guint n)
|
||||
{
|
||||
guint i;
|
||||
DevMon *self = g_malloc0(sizeof(DevMon) +
|
||||
sizeof(struct ril_devmon *) * n);
|
||||
|
||||
self->pub.free = ril_devmon_combine_free;
|
||||
self->pub.start_io = ril_devmon_combine_start_io;
|
||||
self->impl = (struct ril_devmon **)(self + 1);
|
||||
self->count = n;
|
||||
for (i = 0; i < n; i++) {
|
||||
self->impl[i] = dm[i];
|
||||
}
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
342
ofono/drivers/ril/ril_devmon_ds.c
Normal file
342
ofono/drivers/ril/ril_devmon_ds.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 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_devmon.h"
|
||||
#include "ril_connman.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#include <mce_battery.h>
|
||||
#include <mce_charger.h>
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
enum device_state_type {
|
||||
/* Mirrors RIL_DeviceStateType from ril.h */
|
||||
POWER_SAVE_MODE,
|
||||
CHARGING_STATE,
|
||||
LOW_DATA_EXPECTED
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_battery_event {
|
||||
BATTERY_EVENT_VALID,
|
||||
BATTERY_EVENT_STATUS,
|
||||
BATTERY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_charger_event {
|
||||
CHARGER_EVENT_VALID,
|
||||
CHARGER_EVENT_STATE,
|
||||
CHARGER_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_display_event {
|
||||
DISPLAY_EVENT_VALID,
|
||||
DISPLAY_EVENT_STATE,
|
||||
DISPLAY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_connman_event {
|
||||
CONNMAN_EVENT_VALID,
|
||||
CONNMAN_EVENT_TETHERING,
|
||||
CONNMAN_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_devmon_ds {
|
||||
struct ril_devmon pub;
|
||||
struct ril_connman *connman;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ds_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct ril_connman *connman;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
GRilIoChannel *io;
|
||||
guint low_data_req_id;
|
||||
guint charging_req_id;
|
||||
gboolean low_data;
|
||||
gboolean charging;
|
||||
gboolean low_data_supported;
|
||||
gboolean charging_supported;
|
||||
gulong connman_event_id[CONNMAN_EVENT_COUNT];
|
||||
gulong battery_event_id[BATTERY_EVENT_COUNT];
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
} DevMonIo;
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
|
||||
|
||||
static inline DevMon *ril_devmon_ds_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_tethering_on(struct ril_connman *connman)
|
||||
{
|
||||
return connman->valid && connman->tethering;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_battery_ok(MceBattery *battery)
|
||||
{
|
||||
return battery->valid && battery->status >= MCE_BATTERY_OK;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_charging(MceCharger *charger)
|
||||
{
|
||||
return charger->valid && charger->state == MCE_CHARGER_ON;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_display_on(MceDisplay *display)
|
||||
{
|
||||
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
|
||||
}
|
||||
|
||||
static guint ril_devmon_ds_io_send_device_state(DevMonIo *self,
|
||||
enum device_state_type type, gboolean state,
|
||||
GRilIoChannelResponseFunc callback)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(2, type, state);
|
||||
const guint id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SEND_DEVICE_STATE, callback, NULL, self);
|
||||
|
||||
grilio_request_unref(req);
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_low_data_state_sent(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->low_data_req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
DBG_(self, "LOW_DATA_EXPECTED state is not supported");
|
||||
self->low_data_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_charging_state_sent(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->charging_req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
DBG_(self, "CHARGING state is not supported");
|
||||
self->charging_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_update_charging(DevMonIo *self)
|
||||
{
|
||||
const gboolean charging = ril_devmon_ds_charging(self->charger);
|
||||
|
||||
if (self->charging != charging) {
|
||||
self->charging = charging;
|
||||
DBG_(self, "Charging %s", charging ? "on" : "off");
|
||||
if (self->charging_supported) {
|
||||
grilio_channel_cancel_request(self->io,
|
||||
self->charging_req_id, FALSE);
|
||||
self->charging_req_id =
|
||||
ril_devmon_ds_io_send_device_state(self,
|
||||
CHARGING_STATE, charging,
|
||||
ril_devmon_ds_io_charging_state_sent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_update_low_data(DevMonIo *self)
|
||||
{
|
||||
const gboolean low_data =
|
||||
!ril_devmon_ds_tethering_on(self->connman) &&
|
||||
!ril_devmon_ds_charging(self->charger) &&
|
||||
!ril_devmon_ds_display_on(self->display);
|
||||
|
||||
if (self->low_data != low_data) {
|
||||
self->low_data = low_data;
|
||||
DBG_(self, "Low data is%s expected", low_data ? "" : " not");
|
||||
if (self->low_data_supported) {
|
||||
grilio_channel_cancel_request(self->io,
|
||||
self->low_data_req_id, FALSE);
|
||||
self->low_data_req_id =
|
||||
ril_devmon_ds_io_send_device_state(self,
|
||||
LOW_DATA_EXPECTED, low_data,
|
||||
ril_devmon_ds_io_low_data_state_sent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
{
|
||||
sailfish_cell_info_set_update_interval(self->cell_info,
|
||||
(ril_devmon_ds_display_on(self->display) &&
|
||||
(ril_devmon_ds_charging(self->charger) ||
|
||||
ril_devmon_ds_battery_ok(self->battery))) ?
|
||||
RIL_CELL_INFO_INTERVAL_SHORT_MS :
|
||||
RIL_CELL_INFO_INTERVAL_LONG_MS);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_connman_cb(struct ril_connman *connman,
|
||||
enum ril_connman_property property, void *user_data)
|
||||
{
|
||||
ril_devmon_ds_io_update_low_data((DevMonIo *)user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
{
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_display_cb(MceDisplay *display, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
ril_devmon_ds_io_update_low_data(self);
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_charger_cb(MceCharger *charger, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
ril_devmon_ds_io_update_low_data(self);
|
||||
ril_devmon_ds_io_update_charging(self);
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
DevMonIo *self = ril_devmon_ds_io_cast(devmon_io);
|
||||
|
||||
ril_connman_remove_all_handlers(self->connman, self->connman_event_id);
|
||||
ril_connman_unref(self->connman);
|
||||
|
||||
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
|
||||
mce_battery_unref(self->battery);
|
||||
|
||||
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
|
||||
mce_charger_unref(self->charger);
|
||||
|
||||
mce_display_remove_all_handlers(self->display, self->display_event_id);
|
||||
mce_display_unref(self->display);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->low_data_req_id, FALSE);
|
||||
grilio_channel_cancel_request(self->io, self->charging_req_id, FALSE);
|
||||
grilio_channel_unref(self->io);
|
||||
|
||||
sailfish_cell_info_unref(self->cell_info);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_ds_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
DevMon *ds = ril_devmon_ds_cast(devmon);
|
||||
DevMonIo *self = g_new0(DevMonIo, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ds_io_free;
|
||||
self->low_data_supported = TRUE;
|
||||
self->charging_supported = TRUE;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
|
||||
self->connman = ril_connman_ref(ds->connman);
|
||||
self->connman_event_id[CONNMAN_EVENT_VALID] =
|
||||
ril_connman_add_property_changed_handler(self->connman,
|
||||
RIL_CONNMAN_PROPERTY_VALID,
|
||||
ril_devmon_ds_io_connman_cb, self);
|
||||
self->connman_event_id[CONNMAN_EVENT_TETHERING] =
|
||||
ril_connman_add_property_changed_handler(self->connman,
|
||||
RIL_CONNMAN_PROPERTY_TETHERING,
|
||||
ril_devmon_ds_io_connman_cb, self);
|
||||
|
||||
self->battery = mce_battery_ref(ds->battery);
|
||||
self->battery_event_id[BATTERY_EVENT_VALID] =
|
||||
mce_battery_add_valid_changed_handler(self->battery,
|
||||
ril_devmon_ds_io_battery_cb, self);
|
||||
self->battery_event_id[BATTERY_EVENT_STATUS] =
|
||||
mce_battery_add_status_changed_handler(self->battery,
|
||||
ril_devmon_ds_io_battery_cb, self);
|
||||
|
||||
self->charger = mce_charger_ref(ds->charger);
|
||||
self->charger_event_id[CHARGER_EVENT_VALID] =
|
||||
mce_charger_add_valid_changed_handler(self->charger,
|
||||
ril_devmon_ds_io_charger_cb, self);
|
||||
self->charger_event_id[CHARGER_EVENT_STATE] =
|
||||
mce_charger_add_state_changed_handler(self->charger,
|
||||
ril_devmon_ds_io_charger_cb, self);
|
||||
|
||||
self->display = mce_display_ref(ds->display);
|
||||
self->display_event_id[DISPLAY_EVENT_VALID] =
|
||||
mce_display_add_valid_changed_handler(self->display,
|
||||
ril_devmon_ds_io_display_cb, self);
|
||||
self->display_event_id[DISPLAY_EVENT_STATE] =
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ds_io_display_cb, self);
|
||||
|
||||
ril_devmon_ds_io_update_low_data(self);
|
||||
ril_devmon_ds_io_update_charging(self);
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_ds_cast(devmon);
|
||||
|
||||
ril_connman_unref(self->connman);
|
||||
mce_battery_unref(self->battery);
|
||||
mce_charger_unref(self->charger);
|
||||
mce_display_unref(self->display);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ds_new()
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ds_free;
|
||||
self->pub.start_io = ril_devmon_ds_start_io;
|
||||
self->connman = ril_connman_new();
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
248
ofono/drivers/ril/ril_devmon_ss.c
Normal file
248
ofono/drivers/ril/ril_devmon_ss.c
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#include <mce_battery.h>
|
||||
#include <mce_charger.h>
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
enum ril_devmon_ss_battery_event {
|
||||
BATTERY_EVENT_VALID,
|
||||
BATTERY_EVENT_STATUS,
|
||||
BATTERY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ss_charger_event {
|
||||
CHARGER_EVENT_VALID,
|
||||
CHARGER_EVENT_STATE,
|
||||
CHARGER_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ss_display_event {
|
||||
DISPLAY_EVENT_VALID,
|
||||
DISPLAY_EVENT_STATE,
|
||||
DISPLAY_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_devmon_ss {
|
||||
struct ril_devmon pub;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ss_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
GRilIoChannel *io;
|
||||
gboolean display_on;
|
||||
gboolean screen_state_supported;
|
||||
gulong battery_event_id[BATTERY_EVENT_COUNT];
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
} DevMonIo;
|
||||
|
||||
inline static DevMon *ril_devmon_ss_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
inline static DevMonIo *ril_devmon_ss_io_cast(struct ril_devmon_io *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ss_battery_ok(MceBattery *battery)
|
||||
{
|
||||
return battery->valid && battery->status >= MCE_BATTERY_OK;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ss_charging(MceCharger *charger)
|
||||
{
|
||||
return charger->valid && charger->state == MCE_CHARGER_ON;
|
||||
}
|
||||
|
||||
static gboolean ril_devmon_ss_display_on(MceDisplay *display)
|
||||
{
|
||||
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_state_sent(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
/* This is a permanent failure */
|
||||
DBG("RIL_REQUEST_SCREEN_STATE is not supported");
|
||||
self->screen_state_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_send_screen_state(DevMonIo *self)
|
||||
{
|
||||
/*
|
||||
* RIL_REQUEST_SCREEN_STATE (deprecated on 2017-01-10)
|
||||
*
|
||||
* ((int *)data)[0] is == 1 for "Screen On"
|
||||
* ((int *)data)[0] is == 0 for "Screen Off"
|
||||
*/
|
||||
if (self->screen_state_supported) {
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1,
|
||||
self->display_on);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
self->req_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SCREEN_STATE, ril_devmon_ss_io_state_sent,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
{
|
||||
sailfish_cell_info_set_update_interval(self->cell_info,
|
||||
(self->display_on && (ril_devmon_ss_charging(self->charger) ||
|
||||
ril_devmon_ss_battery_ok(self->battery))) ?
|
||||
RIL_CELL_INFO_INTERVAL_SHORT_MS :
|
||||
RIL_CELL_INFO_INTERVAL_LONG_MS);
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
{
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_charger_cb(MceCharger *charger, void *user_data)
|
||||
{
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_display_cb(MceDisplay *display, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
const gboolean display_on = ril_devmon_ss_display_on(display);
|
||||
|
||||
if (self->display_on != display_on) {
|
||||
self->display_on = display_on;
|
||||
ril_devmon_ss_io_send_screen_state(self);
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
DevMonIo *self = ril_devmon_ss_io_cast(devmon_io);
|
||||
|
||||
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
|
||||
mce_battery_unref(self->battery);
|
||||
|
||||
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
|
||||
mce_charger_unref(self->charger);
|
||||
|
||||
mce_display_remove_all_handlers(self->display, self->display_event_id);
|
||||
mce_display_unref(self->display);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
grilio_channel_unref(self->io);
|
||||
|
||||
sailfish_cell_info_unref(self->cell_info);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_ss_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
DevMon *ss = ril_devmon_ss_cast(devmon);
|
||||
DevMonIo *self = g_new0(DevMonIo, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ss_io_free;
|
||||
self->screen_state_supported = TRUE;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
|
||||
self->battery = mce_battery_ref(ss->battery);
|
||||
self->battery_event_id[BATTERY_EVENT_VALID] =
|
||||
mce_battery_add_valid_changed_handler(self->battery,
|
||||
ril_devmon_ss_io_battery_cb, self);
|
||||
self->battery_event_id[BATTERY_EVENT_STATUS] =
|
||||
mce_battery_add_status_changed_handler(self->battery,
|
||||
ril_devmon_ss_io_battery_cb, self);
|
||||
|
||||
self->charger = mce_charger_ref(ss->charger);
|
||||
self->charger_event_id[CHARGER_EVENT_VALID] =
|
||||
mce_charger_add_valid_changed_handler(self->charger,
|
||||
ril_devmon_ss_io_charger_cb, self);
|
||||
self->charger_event_id[CHARGER_EVENT_STATE] =
|
||||
mce_charger_add_state_changed_handler(self->charger,
|
||||
ril_devmon_ss_io_charger_cb, self);
|
||||
|
||||
self->display = mce_display_ref(ss->display);
|
||||
self->display_on = ril_devmon_ss_display_on(self->display);
|
||||
self->display_event_id[DISPLAY_EVENT_VALID] =
|
||||
mce_display_add_valid_changed_handler(self->display,
|
||||
ril_devmon_ss_io_display_cb, self);
|
||||
self->display_event_id[DISPLAY_EVENT_STATE] =
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ss_io_display_cb, self);
|
||||
|
||||
ril_devmon_ss_io_send_screen_state(self);
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_ss_cast(devmon);
|
||||
|
||||
mce_battery_unref(self->battery);
|
||||
mce_charger_unref(self->charger);
|
||||
mce_display_unref(self->display);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ss_new()
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ss_free;
|
||||
self->pub.start_io = ril_devmon_ss_start_io;
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
254
ofono/drivers/ril/ril_devmon_ur.c
Normal file
254
ofono/drivers/ril/ril_devmon_ur.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC
|
||||
*
|
||||
* 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#include <mce_battery.h>
|
||||
#include <mce_charger.h>
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#define RIL_UR_ENABLE_ALL (RIL_UR_SIGNAL_STRENGTH | \
|
||||
RIL_UR_FULL_NETWORK_STATE | \
|
||||
RIL_UR_DATA_CALL_DORMANCY_CHANGED)
|
||||
|
||||
enum ril_devmon_ur_battery_event {
|
||||
BATTERY_EVENT_VALID,
|
||||
BATTERY_EVENT_STATUS,
|
||||
BATTERY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ur_charger_event {
|
||||
CHARGER_EVENT_VALID,
|
||||
CHARGER_EVENT_STATE,
|
||||
CHARGER_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ur_display_event {
|
||||
DISPLAY_EVENT_VALID,
|
||||
DISPLAY_EVENT_STATE,
|
||||
DISPLAY_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_devmon_ur {
|
||||
struct ril_devmon pub;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ur_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
GRilIoChannel *io;
|
||||
gboolean display_on;
|
||||
gboolean unsol_filter_supported;
|
||||
gulong battery_event_id[BATTERY_EVENT_COUNT];
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
} DevMonIo;
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
|
||||
|
||||
inline static DevMon *ril_devmon_ur_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
inline static DevMonIo *ril_devmon_ur_io_cast(struct ril_devmon_io *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ur_battery_ok(MceBattery *battery)
|
||||
{
|
||||
return battery->valid && battery->status >= MCE_BATTERY_OK;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ur_charging(MceCharger *charger)
|
||||
{
|
||||
return charger->valid && charger->state == MCE_CHARGER_ON;
|
||||
}
|
||||
|
||||
static gboolean ril_devmon_ur_display_on(MceDisplay *display)
|
||||
{
|
||||
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_unsol_response_filter_sent(GRilIoChannel *io,
|
||||
int status, const void *data, guint len,
|
||||
void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
/* This is a permanent failure */
|
||||
DBG_(self, "Unsolicited response filter is not supported");
|
||||
self->unsol_filter_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_set_unsol_response_filter(DevMonIo *self)
|
||||
{
|
||||
if (self->unsol_filter_supported) {
|
||||
const gint32 value = self->display_on ? RIL_UR_ENABLE_ALL : 0;
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, value);
|
||||
|
||||
DBG_(self, "Setting unsolicited response filter: %u", value);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
self->req_id =
|
||||
grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER,
|
||||
ril_devmon_ur_io_unsol_response_filter_sent,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
{
|
||||
sailfish_cell_info_set_update_interval(self->cell_info,
|
||||
(self->display_on && (ril_devmon_ur_charging(self->charger) ||
|
||||
ril_devmon_ur_battery_ok(self->battery))) ?
|
||||
RIL_CELL_INFO_INTERVAL_SHORT_MS :
|
||||
RIL_CELL_INFO_INTERVAL_LONG_MS);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
{
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_charger_cb(MceCharger *charger, void *user_data)
|
||||
{
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_display_cb(MceDisplay *display, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
const gboolean display_on = ril_devmon_ur_display_on(display);
|
||||
|
||||
if (self->display_on != display_on) {
|
||||
self->display_on = display_on;
|
||||
ril_devmon_ur_io_set_unsol_response_filter(self);
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
DevMonIo *self = ril_devmon_ur_io_cast(devmon_io);
|
||||
|
||||
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
|
||||
mce_battery_unref(self->battery);
|
||||
|
||||
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
|
||||
mce_charger_unref(self->charger);
|
||||
|
||||
mce_display_remove_all_handlers(self->display, self->display_event_id);
|
||||
mce_display_unref(self->display);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
grilio_channel_unref(self->io);
|
||||
|
||||
sailfish_cell_info_unref(self->cell_info);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_ur_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
DevMon *ur = ril_devmon_ur_cast(devmon);
|
||||
DevMonIo *self = g_new0(DevMonIo, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ur_io_free;
|
||||
self->unsol_filter_supported = TRUE;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
|
||||
self->battery = mce_battery_ref(ur->battery);
|
||||
self->battery_event_id[BATTERY_EVENT_VALID] =
|
||||
mce_battery_add_valid_changed_handler(self->battery,
|
||||
ril_devmon_ur_io_battery_cb, self);
|
||||
self->battery_event_id[BATTERY_EVENT_STATUS] =
|
||||
mce_battery_add_status_changed_handler(self->battery,
|
||||
ril_devmon_ur_io_battery_cb, self);
|
||||
|
||||
self->charger = mce_charger_ref(ur->charger);
|
||||
self->charger_event_id[CHARGER_EVENT_VALID] =
|
||||
mce_charger_add_valid_changed_handler(self->charger,
|
||||
ril_devmon_ur_io_charger_cb, self);
|
||||
self->charger_event_id[CHARGER_EVENT_STATE] =
|
||||
mce_charger_add_state_changed_handler(self->charger,
|
||||
ril_devmon_ur_io_charger_cb, self);
|
||||
|
||||
self->display = mce_display_ref(ur->display);
|
||||
self->display_on = ril_devmon_ur_display_on(self->display);
|
||||
self->display_event_id[DISPLAY_EVENT_VALID] =
|
||||
mce_display_add_valid_changed_handler(self->display,
|
||||
ril_devmon_ur_io_display_cb, self);
|
||||
self->display_event_id[DISPLAY_EVENT_STATE] =
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ur_io_display_cb, self);
|
||||
|
||||
ril_devmon_ur_io_set_unsol_response_filter(self);
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_ur_cast(devmon);
|
||||
|
||||
mce_battery_unref(self->battery);
|
||||
mce_charger_unref(self->charger);
|
||||
mce_display_unref(self->display);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ur_new()
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ur_free;
|
||||
self->pub.start_io = ril_devmon_ur_start_io;
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -13,6 +14,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -47,6 +50,53 @@ G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
|
||||
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_ECCLIST_TYPE, RilEccList))
|
||||
|
||||
static char **ril_ecclist_parse(const char *content)
|
||||
{
|
||||
char **ptr;
|
||||
char **list = NULL;
|
||||
guint i;
|
||||
|
||||
/*
|
||||
* Some MediaTek devices use ECC,CAT;ECC,CAT kind of syntax
|
||||
*/
|
||||
if (strchr(content, ';')) {
|
||||
list = g_strsplit(content, ";", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
char* comma;
|
||||
|
||||
*ptr = g_strstrip(*ptr);
|
||||
|
||||
/* Strip service category */
|
||||
comma = strchr(*ptr, ',');
|
||||
if (comma) {
|
||||
*comma = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The right ECC,ECC syntax is handled here */
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
gutil_strv_sort(list, TRUE);
|
||||
|
||||
/* Remove empty strings (those are at the beginning after sorting) */
|
||||
while (list[0] && !list[0][0]) {
|
||||
list = gutil_strv_remove_at(list, 0, TRUE);
|
||||
}
|
||||
|
||||
/* Remove duplicates */
|
||||
for (i = 0; list[i] && list[i+1]; i++) {
|
||||
while (list[i+1] && !strcmp(list[i], list[i+1])) {
|
||||
list = gutil_strv_remove_at(list, i+1, TRUE);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
@@ -58,16 +108,9 @@ static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
GError *error = NULL;
|
||||
|
||||
if (g_file_get_contents(priv->path, &content, &len, &error)) {
|
||||
char **ptr;
|
||||
|
||||
DBG("%s = %s", priv->name, content);
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
|
||||
gutil_strv_sort(list, TRUE);
|
||||
} else if (error) {
|
||||
list = ril_ecclist_parse(content);
|
||||
} else {
|
||||
DBG("%s: %s", priv->path, GERRMSG(error));
|
||||
g_error_free(error);
|
||||
}
|
||||
@@ -89,7 +132,8 @@ static void ril_ecclist_update(struct ril_ecclist *self)
|
||||
DBG("%s changed", priv->name);
|
||||
g_strfreev(self->list);
|
||||
self->list = list;
|
||||
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0);
|
||||
g_signal_emit(self, ril_ecclist_signals
|
||||
[SIGNAL_LIST_CHANGED], 0);
|
||||
} else {
|
||||
g_strfreev(list);
|
||||
}
|
||||
@@ -121,10 +165,9 @@ static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||
IN_MODIFY | IN_CLOSE_WRITE,
|
||||
ril_ecclist_changed, self);
|
||||
if (priv->file_watch) {
|
||||
DBG("watching %s", priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
DBG("%swatching %s", priv->file_watch ? "" : "not ",
|
||||
priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_ecclist_priv;
|
||||
|
||||
struct ril_ecclist {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -88,6 +88,7 @@ static int ril_gprs_context_address_family(const char *addr)
|
||||
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = NULL;
|
||||
}
|
||||
@@ -111,6 +112,7 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||
}
|
||||
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
ril_data_call_grab(gcd->data, call->cid, gcd);
|
||||
} else {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
}
|
||||
@@ -396,6 +398,8 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("GPRS context: Reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
} else if (!call) {
|
||||
ofono_error("Unexpected data call failure");
|
||||
} else if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_error("Unexpected data call status %d", call->status);
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
@@ -464,6 +468,7 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
gcd->activate.cb = cb;
|
||||
gcd->activate.data = data;
|
||||
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
|
||||
__ofono_gprs_context_get_assigned_type(gc),
|
||||
ril_gprs_context_activate_primary_cb, gcd);
|
||||
}
|
||||
|
||||
@@ -478,24 +483,23 @@ static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
|
||||
* invoked and gcd->deactivate.req will be NULL.
|
||||
*/
|
||||
if (gcd->deactivate.req) {
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
|
||||
gpointer cb_data = gcd->deactivate.data;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
GASSERT(gcd->active_call);
|
||||
ril_error_init_ok(&error);
|
||||
ofono_info("Deactivated data call");
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
ofono_error("Deactivate failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
if (cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(&error, cb_data);
|
||||
cb(ril_error_ok(&error), cb_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -509,7 +513,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
|
||||
GASSERT(gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -19,15 +20,15 @@
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#define MAX_PDP_CONTEXTS (2)
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
enum ril_modem_power_state {
|
||||
@@ -43,7 +44,15 @@ enum ril_modem_online_state {
|
||||
GOING_OFFLINE
|
||||
};
|
||||
|
||||
enum ril_modem_watch_event {
|
||||
WATCH_IMSI,
|
||||
WATCH_ICCID,
|
||||
WATCH_SIM_STATE,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_modem_online_request {
|
||||
const char *name;
|
||||
ofono_modem_online_cb_t cb;
|
||||
struct ril_modem_data *md;
|
||||
void *data;
|
||||
@@ -52,13 +61,16 @@ struct ril_modem_online_request {
|
||||
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_watch *watch;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gulong imsi_event_id;
|
||||
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
char* last_known_iccid;
|
||||
char* reset_iccid;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
@@ -122,13 +134,8 @@ void ril_modem_delete(struct ril_modem *md)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
static void ril_modem_online_request_done(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
req->timeout_id = 0;
|
||||
}
|
||||
|
||||
if (req->cb) {
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
@@ -136,21 +143,32 @@ static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
DBG_(req->md, "%s", req->name);
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
req->timeout_id = 0;
|
||||
}
|
||||
|
||||
ril_modem_online_request_done(req);
|
||||
}
|
||||
|
||||
static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||
{
|
||||
switch (md->modem.radio->state) {
|
||||
case RADIO_STATE_ON:
|
||||
DBG("online");
|
||||
DBG_(md, "online");
|
||||
ril_modem_online_request_ok(&md->set_online);
|
||||
break;
|
||||
|
||||
case RADIO_STATE_OFF:
|
||||
case RADIO_STATE_UNAVAILABLE:
|
||||
DBG("offline");
|
||||
DBG_(md, "offline");
|
||||
ril_modem_online_request_ok(&md->set_offline);
|
||||
break;
|
||||
|
||||
@@ -170,17 +188,11 @@ static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||
static gboolean ril_modem_online_request_timeout(gpointer data)
|
||||
{
|
||||
struct ril_modem_online_request *req = data;
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *cb_data = req->data;
|
||||
|
||||
GASSERT(req->timeout_id);
|
||||
GASSERT(cb);
|
||||
|
||||
req->timeout_id = 0;
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_failure(&error), cb_data);
|
||||
DBG_(req->md, "%s", req->name);
|
||||
ril_modem_online_request_done(req);
|
||||
ril_modem_update_online_state(req->md);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
@@ -206,22 +218,21 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
struct ril_modem *m = &md->modem;
|
||||
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
|
||||
if (md->watch->imsi) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!ril_modem_radio_settings(m)) {
|
||||
if (!rs) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
ofono_radio_settings_create(m->ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
} else if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
/* ofono core may remove radio settings atom internally */
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,11 +241,10 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.radio == radio);
|
||||
ril_modem_update_radio_settings(md);
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
|
||||
static void ril_modem_imsi_cb(struct ofono_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
@@ -242,6 +252,32 @@ static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
|
||||
ril_modem_update_radio_settings(md);
|
||||
}
|
||||
|
||||
static void ril_modem_iccid_cb(struct ofono_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
if (watch->iccid) {
|
||||
g_free(md->last_known_iccid);
|
||||
md->last_known_iccid = g_strdup(watch->iccid);
|
||||
DBG_(md, "%s", md->last_known_iccid);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_sim_state_cb(struct ofono_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
if (state == OFONO_SIM_STATE_RESETTING) {
|
||||
g_free(md->reset_iccid);
|
||||
md->reset_iccid = md->last_known_iccid;
|
||||
md->last_known_iccid = NULL;
|
||||
DBG_(md, "%s is resetting", md->reset_iccid);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
@@ -268,15 +304,22 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (gprs) {
|
||||
int i;
|
||||
guint i;
|
||||
static const enum ofono_gprs_context_type ap_types[] = {
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET,
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS,
|
||||
OFONO_GPRS_CONTEXT_TYPE_IMS
|
||||
};
|
||||
|
||||
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
|
||||
/* Create a context for each type */
|
||||
for (i = 0; i < G_N_ELEMENTS(ap_types); i++) {
|
||||
struct ofono_gprs_context *gc =
|
||||
ofono_gprs_context_create(modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
if (gc == NULL)
|
||||
break;
|
||||
|
||||
ofono_gprs_context_set_type(gc, ap_types[i]);
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
}
|
||||
@@ -284,9 +327,19 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
ofono_phonebook_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_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||
if (md->modem.config.enable_stk) {
|
||||
if (!md->reset_iccid ||
|
||||
g_strcmp0(md->reset_iccid, md->watch->iccid)) {
|
||||
/* This SIM was never reset */
|
||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
} else {
|
||||
ofono_warn("Disabling STK after SIM reset");
|
||||
}
|
||||
}
|
||||
if (md->modem.config.enable_cbs) {
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
@@ -369,11 +422,12 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
|
||||
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_set_online(modem->radio, FALSE);
|
||||
ril_radio_unref(modem->radio);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
|
||||
sailfish_watch_remove_handler(md->watch, md->imsi_event_id);
|
||||
sailfish_watch_unref(md->watch);
|
||||
ofono_watch_remove_all_handlers(md->watch, md->watch_event_id);
|
||||
ofono_watch_unref(md->watch);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
@@ -387,6 +441,7 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_vendor_unref(modem->vendor);
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_data_unref(modem->data);
|
||||
@@ -394,6 +449,8 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
grilio_channel_unref(modem->io);
|
||||
grilio_queue_cancel_all(md->q, FALSE);
|
||||
grilio_queue_unref(md->q);
|
||||
g_free(md->last_known_iccid);
|
||||
g_free(md->reset_iccid);
|
||||
g_free(md->ecclist_file);
|
||||
g_free(md->log_prefix);
|
||||
g_free(md->imeisv);
|
||||
@@ -406,7 +463,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
@@ -433,6 +490,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
modem->ofono = ofono;
|
||||
modem->vendor = ril_vendor_ref(vendor);
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
@@ -441,19 +499,30 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
md->watch = sailfish_watch_new(path);
|
||||
md->watch = ofono_watch_new(path);
|
||||
md->last_known_iccid = g_strdup(md->watch->iccid);
|
||||
|
||||
md->imsi_event_id =
|
||||
sailfish_watch_add_imsi_changed_handler(md->watch,
|
||||
md->watch_event_id[WATCH_IMSI] =
|
||||
ofono_watch_add_imsi_changed_handler(md->watch,
|
||||
ril_modem_imsi_cb, md);
|
||||
md->watch_event_id[WATCH_ICCID] =
|
||||
ofono_watch_add_iccid_changed_handler(md->watch,
|
||||
ril_modem_iccid_cb, md);
|
||||
md->watch_event_id[WATCH_SIM_STATE] =
|
||||
ofono_watch_add_sim_state_changed_handler(md->watch,
|
||||
ril_modem_sim_state_cb, md);
|
||||
|
||||
md->set_online.name = "online";
|
||||
md->set_online.md = md;
|
||||
md->set_offline.name = "offline";
|
||||
md->set_offline.md = md;
|
||||
ofono_modem_set_data(ofono, md);
|
||||
err = ofono_modem_register(ofono);
|
||||
if (!err) {
|
||||
ril_radio_power_cycle(modem->radio);
|
||||
GASSERT(io->connected);
|
||||
if (config->radio_power_cycle) {
|
||||
ril_radio_power_cycle(modem->radio);
|
||||
}
|
||||
|
||||
/*
|
||||
* ofono_modem_reset sets Powered to TRUE without
|
||||
@@ -466,11 +535,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
/*
|
||||
* With some RIL implementations, querying available
|
||||
* band modes causes some magic Android properties to
|
||||
* appear. Otherwise this request is pretty harmless
|
||||
* and useless.
|
||||
* appear.
|
||||
*/
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
if (config->query_available_band_mode) {
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
}
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,11 +17,14 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "simutil.h"
|
||||
|
||||
#define REGISTRATION_MAX_RETRIES (2)
|
||||
|
||||
enum ril_netreg_events {
|
||||
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||
@@ -36,14 +40,19 @@ enum ril_netreg_network_events {
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean network_selection_manual_0;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
struct ofono_netreg *netreg;
|
||||
struct ril_network *network;
|
||||
struct ril_vendor *vendor;
|
||||
char *log_prefix;
|
||||
guint timer_id;
|
||||
guint notify_id;
|
||||
guint current_operator_id;
|
||||
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
|
||||
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
|
||||
int network_selection_timeout;
|
||||
};
|
||||
|
||||
struct ril_netreg_cbd {
|
||||
@@ -61,6 +70,8 @@ struct ril_netreg_cbd {
|
||||
|
||||
#define ril_netreg_cbd_free g_free
|
||||
|
||||
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
|
||||
|
||||
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
|
||||
{
|
||||
return ofono ? ofono_netreg_get_data(ofono) : NULL;
|
||||
@@ -109,7 +120,7 @@ static gboolean ril_netreg_status_notify_cb(gpointer user_data)
|
||||
struct ril_netreg *nd = user_data;
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
DBG_(nd, "");
|
||||
GASSERT(nd->notify_id);
|
||||
nd->notify_id = 0;
|
||||
ofono_netreg_status_notify(nd->netreg,
|
||||
@@ -124,9 +135,9 @@ static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
|
||||
|
||||
/* Coalesce multiple notifications into one */
|
||||
if (nd->notify_id) {
|
||||
DBG("%snotification aready queued", nd->log_prefix);
|
||||
DBG_(nd, "notification aready queued");
|
||||
} else {
|
||||
DBG("%squeuing notification", nd->log_prefix);
|
||||
DBG_(nd, "queuing notification");
|
||||
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
|
||||
}
|
||||
}
|
||||
@@ -138,7 +149,7 @@ static void ril_netreg_registration_status(struct ofono_netreg *netreg,
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
DBG_(nd, "");
|
||||
cb(ril_error_ok(&error),
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech, data);
|
||||
@@ -151,7 +162,7 @@ static gboolean ril_netreg_current_operator_cb(void *user_data)
|
||||
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
DBG_(nd, "");
|
||||
GASSERT(nd->current_operator_id);
|
||||
nd->current_operator_id = 0;
|
||||
|
||||
@@ -290,16 +301,57 @@ static void ril_netreg_register_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_set_register_auto(struct ril_netreg *nd,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("nw select automatic");
|
||||
grilio_request_set_timeout(req, nd->network_selection_timeout);
|
||||
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_query_register_auto_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_register_cb_t cb = cbd->cb.reg;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
gint32 net_mode;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, NULL) /* Array length */ &&
|
||||
grilio_parser_get_int32(&rilp, &net_mode) &&
|
||||
net_mode == RIL_NETWORK_SELECTION_MODE_AUTO) {
|
||||
struct ofono_error error;
|
||||
ofono_info("nw selection is already auto");
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ril_netreg_set_register_auto(cbd->nd, cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_netreg_register_auto(struct ofono_netreg *netreg,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("nw select automatic");
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
|
||||
ril_netreg_query_register_auto_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
@@ -308,9 +360,12 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
const char *suffix = nd->network_selection_manual_0 ? "+0" : "";
|
||||
|
||||
ofono_info("nw select manual: %s%s", mcc, mnc);
|
||||
grilio_request_append_format(req, "%s%s+0", mcc, mnc);
|
||||
ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix);
|
||||
grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix);
|
||||
grilio_request_set_timeout(req, nd->network_selection_timeout);
|
||||
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
@@ -318,56 +373,92 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
static int ril_netreg_qdbm_to_percentage(struct ril_netreg *nd, int qdbm)
|
||||
{
|
||||
const int min_qdbm = 4 * nd->signal_strength_dbm_weak; /* 4*dBm */
|
||||
const int max_qdbm = 4 * nd->signal_strength_dbm_strong; /* 4*dBm */
|
||||
|
||||
return (qdbm <= min_qdbm) ? 1 :
|
||||
(qdbm >= max_qdbm) ? 100 :
|
||||
(100 * (qdbm - min_qdbm) / (max_qdbm - min_qdbm));
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
|
||||
const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||
struct ril_vendor_signal_strength signal;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
/* RIL_SignalStrength_v6 */
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &gw_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
if (!ril_vendor_signal_strength_parse(nd->vendor, &signal, &rilp)) {
|
||||
gint32 rsrp = 0, tdscdma_dbm = 0;
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &cdma_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
/* Apply default parsing algorithm */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &evdo_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.gsm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, <e_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rsrp */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* cqi */
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
|
||||
evdo_dbm, lte_signal);
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.lte);
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
|
||||
/* The rest is considered optional */
|
||||
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* timingAdv */
|
||||
/* TD_SCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &tdscdma_dbm) &&
|
||||
/* RSCP range: 25 to 120 dBm per 3GPP TS 25.123 */
|
||||
tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
|
||||
signal.qdbm = -4 * tdscdma_dbm;
|
||||
} else if (signal.lte == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
/* RSRP range: 44 to 140 dBm per 3GPP TS 36.133 */
|
||||
signal.qdbm = -rsrp;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("gw: %d, lte: %d, qdbm: %d", signal.gsm, signal.lte, signal.qdbm);
|
||||
|
||||
/* Return the first valid one */
|
||||
if (gw_signal != 99 && gw_signal != -1) {
|
||||
return (gw_signal * 100) / 31;
|
||||
|
||||
/* 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 (signal.gsm >= 1 && signal.gsm <= 31) {
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
return (signal.gsm * 100) / 31;
|
||||
}
|
||||
|
||||
if (lte_signal != 99 && lte_signal != -1) {
|
||||
return (lte_signal * 100) / 31;
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
if (signal.lte >= 0 && signal.lte <= 31) {
|
||||
return (signal.lte * 100) / 31;
|
||||
}
|
||||
|
||||
/* In case of dbm, return the value directly */
|
||||
if (cdma_dbm != -1) {
|
||||
return MIN(cdma_dbm, 100);
|
||||
if (signal.qdbm < 0) {
|
||||
return ril_netreg_qdbm_to_percentage(nd, signal.qdbm);
|
||||
} else if (signal.gsm == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (evdo_dbm != -1) {
|
||||
return MIN(evdo_dbm, 100);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
@@ -377,9 +468,11 @@ static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
int strength;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
|
||||
strength = ril_netreg_get_signal_strength(data, len);
|
||||
DBG("%d", strength);
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
strength = ril_netreg_get_signal_strength(nd, data, len);
|
||||
DBG_(nd, "%d", strength);
|
||||
if (strength >= 0) {
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
@@ -390,8 +483,8 @@ static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int strength = ril_netreg_get_signal_strength(data, len);
|
||||
cb(ril_error_ok(&error), strength, cbd->data);
|
||||
cb(ril_error_ok(&error), ril_netreg_get_signal_strength
|
||||
(cbd->nd, data, len), cbd->data);
|
||||
} else {
|
||||
ofono_error("Failed to retrive the signal strength: %s",
|
||||
ril_error_to_string(status));
|
||||
@@ -417,9 +510,8 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
GRilIoParser rilp;
|
||||
struct ofono_network_time time;
|
||||
int year, mon, mday, hour, min, sec, dst, tzi;
|
||||
char tzs, tz[4];
|
||||
int year, mon, mday, hour, min, sec, tzi, dst = 0;
|
||||
char tzs;
|
||||
gchar *nitz;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
||||
@@ -427,21 +519,33 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
nitz = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
DBG("%s", nitz);
|
||||
sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday,
|
||||
&hour, &min, &sec, &tzs, &tzi, &dst);
|
||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||
DBG_(nd, "%s", nitz);
|
||||
|
||||
time.utcoff = atoi(tz) * 15 * 60;
|
||||
time.dst = dst;
|
||||
time.sec = sec;
|
||||
time.min = min;
|
||||
time.hour = hour;
|
||||
time.mday = mday;
|
||||
time.mon = mon;
|
||||
time.year = 2000 + year;
|
||||
/*
|
||||
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
|
||||
* The ds part is considered optional, initialized to zero.
|
||||
*/
|
||||
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
|
||||
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
|
||||
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
|
||||
struct ofono_network_time time;
|
||||
char tz[4];
|
||||
|
||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||
time.utcoff = atoi(tz) * 15 * 60;
|
||||
time.dst = dst;
|
||||
time.sec = sec;
|
||||
time.min = min;
|
||||
time.hour = hour;
|
||||
time.mday = mday;
|
||||
time.mon = mon;
|
||||
time.year = 2000 + year;
|
||||
|
||||
ofono_netreg_time_notify(nd->netreg, &time);
|
||||
} else {
|
||||
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
|
||||
}
|
||||
|
||||
ofono_netreg_time_notify(nd->netreg, &time);
|
||||
g_free(nitz);
|
||||
}
|
||||
|
||||
@@ -482,14 +586,21 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
|
||||
guint slot = ril_modem_slot(modem);
|
||||
const struct ril_slot_config *config = &modem->config;
|
||||
|
||||
DBG("[%u] %p", slot, netreg);
|
||||
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
|
||||
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
DBG_(nd, "%p", netreg);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->vendor = ril_vendor_ref(modem->vendor);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
nd->network_selection_manual_0 = config->network_selection_manual_0;
|
||||
nd->signal_strength_dbm_weak = config->signal_strength_dbm_weak;
|
||||
nd->signal_strength_dbm_strong = config->signal_strength_dbm_strong;
|
||||
nd->network_selection_timeout = config->network_selection_timeout;
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||
@@ -499,9 +610,8 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
unsigned int i;
|
||||
|
||||
DBG("%p", netreg);
|
||||
DBG_(nd, "%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
ofono_netreg_set_data(netreg, NULL);
|
||||
|
||||
@@ -517,14 +627,11 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
|
||||
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
|
||||
}
|
||||
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
|
||||
ril_network_unref(nd->network);
|
||||
ril_vendor_unref(nd->vendor);
|
||||
|
||||
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
|
||||
G_N_ELEMENTS(nd->ril_event_id));
|
||||
|
||||
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
|
||||
grilio_channel_unref(nd->io);
|
||||
grilio_queue_unref(nd->q);
|
||||
g_free(nd->log_prefix);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -13,10 +14,13 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -25,8 +29,11 @@
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/watch.h>
|
||||
#include <ofono/gprs.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -47,18 +54,49 @@ enum ril_network_radio_event {
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_sim_events {
|
||||
SIM_EVENT_STATUS_CHANGED,
|
||||
SIM_EVENT_IO_ACTIVE_CHANGED,
|
||||
SIM_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_unsol_event {
|
||||
UNSOL_EVENT_NETWORK_STATE,
|
||||
UNSOL_EVENT_RADIO_CAPABILITY,
|
||||
UNSOL_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_watch_event {
|
||||
WATCH_EVENT_GPRS,
|
||||
WATCH_EVENT_GPRS_SETTINGS,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_network_data_profile {
|
||||
enum ril_data_profile profile_id;
|
||||
enum ril_profile_type type;
|
||||
const char *apn;
|
||||
const char *user;
|
||||
const char *password;
|
||||
enum ofono_gprs_auth_method auth_method;
|
||||
enum ofono_gprs_proto proto;
|
||||
int max_conns_time;
|
||||
int max_conns;
|
||||
int wait_time;
|
||||
gboolean enabled;
|
||||
};
|
||||
|
||||
struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_card *simcard;
|
||||
struct ril_vendor *vendor;
|
||||
struct ofono_watch *watch;
|
||||
int rat;
|
||||
enum ril_pref_net_type lte_network_mode;
|
||||
enum ril_pref_net_type umts_network_mode;
|
||||
int network_mode_timeout;
|
||||
char *log_prefix;
|
||||
guint operator_poll_id;
|
||||
guint voice_poll_id;
|
||||
@@ -68,10 +106,18 @@ struct ril_network_priv {
|
||||
gulong set_rat_id;
|
||||
gulong unsol_event_id[UNSOL_EVENT_COUNT];
|
||||
gulong settings_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
gulong simcard_event_id[SIM_EVENT_COUNT];
|
||||
gulong watch_ids[WATCH_EVENT_COUNT];
|
||||
gboolean need_initial_attach_apn;
|
||||
gboolean set_initial_attach_apn;
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
gboolean use_data_profiles;
|
||||
int mms_data_profile_id;
|
||||
GSList *data_profiles;
|
||||
guint set_data_profiles_id;
|
||||
};
|
||||
|
||||
enum ril_network_signal {
|
||||
@@ -111,7 +157,8 @@ G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self);
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat);
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean immediate);
|
||||
|
||||
static void ril_network_emit(struct ril_network *self,
|
||||
enum ril_network_signal sig)
|
||||
@@ -208,11 +255,11 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(slac, 16, ®->lac)) {
|
||||
if (!gutil_parse_int(slac, 16, ®->lac)) {
|
||||
reg->lac = -1;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(sci, 16, ®->ci)) {
|
||||
if (!gutil_parse_int(sci, 16, ®->ci)) {
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
@@ -372,6 +419,18 @@ static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_network_retry(GRilIoRequest* request, 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 guint ril_network_poll_and_retry(struct ril_network *self, guint id,
|
||||
int code, GRilIoChannelResponseFunc fn)
|
||||
{
|
||||
@@ -384,6 +443,7 @@ static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_retry_func(req, ril_network_retry);
|
||||
id = grilio_queue_send_request_full(priv->q, req, code, fn,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -444,17 +504,20 @@ static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
|
||||
static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
struct ril_sim_settings *settings = self->settings;
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
return PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
if (settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
return priv->lte_network_mode;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
|
||||
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
if (settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
|
||||
return priv->umts_network_mode;
|
||||
}
|
||||
/* no break */
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
@@ -462,19 +525,19 @@ static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_pref_mode_expected(struct ril_network *self)
|
||||
static enum ofono_radio_access_mode ril_network_actual_pref_mode
|
||||
(struct ril_network *self)
|
||||
{
|
||||
struct ril_sim_settings *settings = self->settings;
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* On dual-SIM phones such as Jolla C only one slot at a time
|
||||
* is allowed to use LTE. Even if the slot which has been using
|
||||
* LTE gets powered off, we still need to explicitely set its
|
||||
* preferred mode to GSM, to make LTE machinery available to
|
||||
* the other slot. This sort of behaviour might not be necessary
|
||||
* on some hardware and can (should) be made configurable when
|
||||
* it becomes necessary.
|
||||
* On most dual-SIM phones only one slot at a time is allowed
|
||||
* to use LTE. On some phones (such as Jolla C), even if the
|
||||
* slot which has been using LTE gets powered off, we still
|
||||
* need to explicitly set its preferred mode to GSM, to make
|
||||
* LTE machinery available to the other slot. This behavior is
|
||||
* configurable.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
|
||||
@@ -485,49 +548,313 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
|
||||
* and max_pref_mode are not ANY, we pick the smallest value.
|
||||
* Otherwise we take any non-zero value if there is one.
|
||||
*/
|
||||
const enum ofono_radio_access_mode pref_mode =
|
||||
(settings->pref_mode && max_pref_mode) ?
|
||||
return (settings->pref_mode && max_pref_mode) ?
|
||||
MIN(settings->pref_mode, max_pref_mode) :
|
||||
settings->pref_mode ? settings->pref_mode :
|
||||
max_pref_mode;
|
||||
return ril_network_mode_to_rat(self, pref_mode);
|
||||
settings->pref_mode ? settings->pref_mode : max_pref_mode;
|
||||
}
|
||||
|
||||
static gboolean ril_network_need_initial_attach_apn(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
struct ril_radio *radio = priv->radio;
|
||||
struct ofono_watch *watch = priv->watch;
|
||||
|
||||
if (watch->gprs && radio->state == RADIO_STATE_ON) {
|
||||
switch (ril_network_actual_pref_mode(self)) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
return TRUE;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_network_set_initial_attach_apn(struct ril_network *self,
|
||||
const struct ofono_gprs_primary_context *ctx)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const char *proto = ril_protocol_from_ofono(ctx->proto);
|
||||
const char *username;
|
||||
const char *password;
|
||||
enum ril_auth auth;
|
||||
GRilIoRequest *req;
|
||||
|
||||
if (ctx->username[0] || ctx->password[0]) {
|
||||
auth = ril_auth_method_from_ofono(ctx->auth_method);
|
||||
username = ctx->username;
|
||||
password = ctx->password;
|
||||
} else {
|
||||
auth = RIL_AUTH_NONE;
|
||||
username = "";
|
||||
password = "";
|
||||
}
|
||||
|
||||
req = ril_vendor_set_attach_apn_req(priv->vendor,ctx->apn,
|
||||
username, password, auth, proto);
|
||||
|
||||
if (!req) {
|
||||
/* Default format */
|
||||
req = grilio_request_new();
|
||||
grilio_request_append_utf8(req, ctx->apn);
|
||||
grilio_request_append_utf8(req, proto);
|
||||
grilio_request_append_int32(req, auth);
|
||||
grilio_request_append_utf8(req, username);
|
||||
grilio_request_append_utf8(req, password);
|
||||
}
|
||||
|
||||
DBG_(self, "\"%s\"", ctx->apn);
|
||||
grilio_queue_send_request(priv->q, req,
|
||||
RIL_REQUEST_SET_INITIAL_ATTACH_APN);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_network_try_set_initial_attach_apn(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->need_initial_attach_apn && priv->set_initial_attach_apn) {
|
||||
struct ofono_gprs *gprs = priv->watch->gprs;
|
||||
const struct ofono_gprs_primary_context *ctx =
|
||||
ofono_gprs_context_settings_by_type(gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
|
||||
if (ctx) {
|
||||
priv->set_initial_attach_apn = FALSE;
|
||||
ril_network_set_initial_attach_apn(self, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_check_initial_attach_apn(struct ril_network *self)
|
||||
{
|
||||
const gboolean need = ril_network_need_initial_attach_apn(self);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->need_initial_attach_apn != need) {
|
||||
DBG_(self, "%sneed initial attach apn", need ? "" : "don't ");
|
||||
priv->need_initial_attach_apn = need;
|
||||
if (need) {
|
||||
/* We didn't need initial attach APN and now we do */
|
||||
priv->set_initial_attach_apn = TRUE;
|
||||
}
|
||||
}
|
||||
ril_network_try_set_initial_attach_apn(self);
|
||||
}
|
||||
|
||||
struct ril_network_data_profile *ril_network_data_profile_new
|
||||
(const struct ofono_gprs_primary_context* context,
|
||||
enum ril_data_profile profile_id)
|
||||
{
|
||||
/* Allocate the whole thing as a single memory block */
|
||||
struct ril_network_data_profile *profile;
|
||||
const enum ofono_gprs_auth_method auth_method =
|
||||
(context->username[0] || context->password[0]) ?
|
||||
context->auth_method : OFONO_GPRS_AUTH_METHOD_NONE;
|
||||
const gsize apn_size = strlen(context->apn) + 1;
|
||||
gsize username_size = 0;
|
||||
gsize password_size = 0;
|
||||
gsize size = G_ALIGN8(sizeof(*profile)) + G_ALIGN8(apn_size);
|
||||
char* ptr;
|
||||
|
||||
if (auth_method != OFONO_GPRS_AUTH_METHOD_NONE) {
|
||||
username_size = strlen(context->username) + 1;
|
||||
password_size = strlen(context->password) + 1;
|
||||
size += G_ALIGN8(username_size) + G_ALIGN8(password_size);
|
||||
}
|
||||
|
||||
ptr = g_malloc0(size);
|
||||
|
||||
profile = (struct ril_network_data_profile*)ptr;
|
||||
ptr += G_ALIGN8(sizeof(*profile));
|
||||
|
||||
profile->profile_id = profile_id;
|
||||
profile->type = RIL_PROFILE_3GPP;
|
||||
profile->auth_method = auth_method;
|
||||
profile->proto = context->proto;
|
||||
profile->enabled = TRUE;
|
||||
|
||||
/* Copy strings */
|
||||
profile->apn = ptr;
|
||||
memcpy(ptr, context->apn, apn_size - 1);
|
||||
ptr += G_ALIGN8(apn_size);
|
||||
|
||||
if (auth_method == OFONO_GPRS_AUTH_METHOD_NONE) {
|
||||
profile->user = "";
|
||||
profile->password = "";
|
||||
} else {
|
||||
profile->user = ptr;
|
||||
memcpy(ptr, context->username, username_size - 1);
|
||||
ptr += G_ALIGN8(username_size);
|
||||
|
||||
profile->password = ptr;
|
||||
memcpy(ptr, context->password, password_size - 1);
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
static gboolean ril_network_data_profile_equal
|
||||
(const struct ril_network_data_profile *profile1,
|
||||
const struct ril_network_data_profile *profile2)
|
||||
{
|
||||
if (profile1 == profile2) {
|
||||
return TRUE;
|
||||
} else if (!profile1 || !profile2) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return profile1->profile_id == profile2->profile_id &&
|
||||
profile1->type == profile2->type &&
|
||||
profile1->auth_method == profile2->auth_method &&
|
||||
profile1->proto == profile2->proto &&
|
||||
profile1->enabled == profile2->enabled &&
|
||||
!g_strcmp0(profile1->apn, profile2->apn) &&
|
||||
!g_strcmp0(profile1->user, profile2->user) &&
|
||||
!g_strcmp0(profile1->password, profile2->password);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_network_data_profiles_equal(GSList *list1, GSList *list2)
|
||||
{
|
||||
if (g_slist_length(list1) != g_slist_length(list2)) {
|
||||
return FALSE;
|
||||
} else {
|
||||
GSList *l1 = list1;
|
||||
GSList *l2 = list2;
|
||||
|
||||
while (l1 && l2) {
|
||||
const struct ril_network_data_profile *p1 = l1->data;
|
||||
const struct ril_network_data_profile *p2 = l2->data;
|
||||
|
||||
if (!ril_network_data_profile_equal(p1, p2)) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
l2 = l2->next;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ril_network_data_profiles_free(GSList *list)
|
||||
{
|
||||
/* Profiles are allocated as single memory blocks */
|
||||
g_slist_free_full(list, g_free);
|
||||
}
|
||||
|
||||
static void ril_network_set_data_profiles_done(GRilIoChannel *channel,
|
||||
int status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->set_data_profiles_id);
|
||||
priv->set_data_profiles_id = 0;
|
||||
}
|
||||
|
||||
static void ril_network_set_data_profiles(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
GSList *l = priv->data_profiles;
|
||||
|
||||
grilio_request_append_int32(req, g_slist_length(l));
|
||||
while (l) {
|
||||
const struct ril_network_data_profile *p = l->data;
|
||||
|
||||
grilio_request_append_int32(req, p->profile_id);
|
||||
grilio_request_append_utf8(req, p->apn);
|
||||
grilio_request_append_utf8(req, ril_protocol_from_ofono
|
||||
(p->proto));
|
||||
grilio_request_append_int32(req, ril_auth_method_from_ofono
|
||||
(p->auth_method));
|
||||
grilio_request_append_utf8(req, p->user);
|
||||
grilio_request_append_utf8(req, p->password);
|
||||
grilio_request_append_int32(req, p->type);
|
||||
grilio_request_append_int32(req, p->max_conns_time);
|
||||
grilio_request_append_int32(req, p->max_conns);
|
||||
grilio_request_append_int32(req, p->wait_time);
|
||||
grilio_request_append_int32(req, p->enabled);
|
||||
l = l->next;
|
||||
}
|
||||
grilio_queue_cancel_request(priv->q, priv->set_data_profiles_id, FALSE);
|
||||
priv->set_data_profiles_id = grilio_queue_send_request_full(priv->q,
|
||||
req, RIL_REQUEST_SET_DATA_PROFILE,
|
||||
ril_network_set_data_profiles_done,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_network_check_data_profiles(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
struct ofono_gprs *gprs = priv->watch->gprs;
|
||||
|
||||
if (gprs) {
|
||||
const struct ofono_gprs_primary_context* internet =
|
||||
ofono_gprs_context_settings_by_type(gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
const struct ofono_gprs_primary_context* mms =
|
||||
ofono_gprs_context_settings_by_type(gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS);
|
||||
GSList *l = NULL;
|
||||
|
||||
if (internet) {
|
||||
DBG_(self, "internet apn \"%s\"", internet->apn);
|
||||
l = g_slist_append(l,
|
||||
ril_network_data_profile_new(internet,
|
||||
RIL_DATA_PROFILE_DEFAULT));
|
||||
}
|
||||
|
||||
if (mms) {
|
||||
DBG_(self, "mms apn \"%s\"", mms->apn);
|
||||
l = g_slist_append(l,
|
||||
ril_network_data_profile_new(mms,
|
||||
priv->mms_data_profile_id));
|
||||
}
|
||||
|
||||
if (ril_network_data_profiles_equal(priv->data_profiles, l)) {
|
||||
ril_network_data_profiles_free(l);
|
||||
} else {
|
||||
ril_network_data_profiles_free(priv->data_profiles);
|
||||
priv->data_profiles = l;
|
||||
ril_network_set_data_profiles(self);
|
||||
}
|
||||
} else {
|
||||
ril_network_data_profiles_free(priv->data_profiles);
|
||||
priv->data_profiles = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
|
||||
/*
|
||||
* With some modems an attempt to set rat significantly slows
|
||||
* down SIM I/O, let's avoid that.
|
||||
*/
|
||||
return priv->radio->online && ril_sim_card_ready(priv->simcard) &&
|
||||
!priv->simcard->sim_io_active &&
|
||||
!priv->timer[TIMER_SET_RAT_HOLDOFF] ;
|
||||
}
|
||||
|
||||
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
|
||||
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
|
||||
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
|
||||
|
||||
/*
|
||||
* Don't retry the request if modem is offline or SIM card isn't
|
||||
* ready, to avoid spamming system log with error messages. Radio
|
||||
* and SIM card state change callbacks will schedule a new check
|
||||
* when it's appropriate.
|
||||
*/
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
DBG_(self, "giving up");
|
||||
}
|
||||
}
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
static void ril_network_set_rat_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
@@ -542,57 +869,101 @@ static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
ril_network_query_pref_mode(self);
|
||||
}
|
||||
|
||||
static void ril_network_set_rat(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (!priv->set_rat_id && priv->radio->online &&
|
||||
ril_sim_card_ready(priv->simcard) &&
|
||||
/*
|
||||
* With some modems an attempt to set rat significantly
|
||||
* slows down SIM I/O, let's avoid that.
|
||||
*/
|
||||
!priv->simcard->sim_io_active &&
|
||||
!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG_(self, "setting rat mode %d", rat);
|
||||
grilio_request_append_int32(req, 1); /* count */
|
||||
grilio_request_append_int32(req, rat);
|
||||
|
||||
grilio_request_set_timeout(req, priv->network_mode_timeout);
|
||||
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_set_rat_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* And don't do it too often */
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
|
||||
ril_network_set_rat_holdoff_cb, self);
|
||||
} else {
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG_(self, "setting rat mode %d", rat);
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, rat);
|
||||
|
||||
grilio_queue_cancel_request(priv->q, priv->set_rat_id, FALSE);
|
||||
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_set_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* Don't do it too often */
|
||||
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
|
||||
ril_network_set_rat_holdoff_cb, self);
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
ril_network_set_rat(self, rat);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean force)
|
||||
gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
struct ril_radio *radio = priv->radio;
|
||||
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
force = TRUE;
|
||||
}
|
||||
/*
|
||||
* On most dual-SIM phones only one slot at a time is allowed
|
||||
* to use LTE. On some phones (such as Jolla C), even if the
|
||||
* slot which has been using LTE gets powered off, we still
|
||||
* need to explicitly set its preferred mode to GSM, to make
|
||||
* LTE machinery available to the other slot. This behavior is
|
||||
* configurable.
|
||||
*/
|
||||
if (radio->state == RADIO_STATE_ON || priv->force_gsm_when_radio_off) {
|
||||
const enum ofono_radio_access_mode expected =
|
||||
ril_network_actual_pref_mode(self);
|
||||
const enum ofono_radio_access_mode actual =
|
||||
ril_network_rat_to_mode(priv->rat);
|
||||
|
||||
if (priv->rat == rat || force) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self,
|
||||
TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
immediate = TRUE;
|
||||
}
|
||||
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
if (priv->rat >= 0 && actual != expected) {
|
||||
DBG_(self, "rat %d (%s), expected %s", priv->rat,
|
||||
ofono_radio_access_mode_to_string(actual),
|
||||
ofono_radio_access_mode_to_string(expected));
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (actual != expected || priv->assert_rat) {
|
||||
const int rat = ril_network_mode_to_rat(self, expected);
|
||||
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -640,22 +1011,22 @@ static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
/* This request never fails because in case of error it gets retried */
|
||||
GASSERT(status == RIL_E_SUCCESS);
|
||||
GASSERT(priv->query_rat_id);
|
||||
|
||||
priv->query_rat_id = 0;
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,6 +1036,7 @@ static void ril_network_query_pref_mode(struct ril_network *self)
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_retry_func(req, ril_network_retry);
|
||||
grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE);
|
||||
priv->query_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
@@ -682,6 +1054,7 @@ void ril_network_set_max_pref_mode(struct ril_network *self,
|
||||
ofono_radio_access_mode_to_string(max_mode));
|
||||
self->max_pref_mode = max_mode;
|
||||
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
|
||||
ril_network_check_initial_attach_apn(self);
|
||||
}
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
@@ -767,6 +1140,7 @@ static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
ril_network_check_initial_attach_apn(self);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
@@ -791,6 +1165,7 @@ static gboolean ril_network_check_pref_mode_cb(gpointer user_data)
|
||||
|
||||
DBG_(self, "checking pref mode");
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
ril_network_check_initial_attach_apn(self);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
@@ -824,10 +1199,46 @@ static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_watch_gprs_cb(struct ofono_watch *watch,
|
||||
void* user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "gprs %s", watch->gprs ? "appeared" : "is gone");
|
||||
priv->set_initial_attach_apn = TRUE;
|
||||
if (priv->use_data_profiles) {
|
||||
ril_network_check_data_profiles(self);
|
||||
}
|
||||
ril_network_check_initial_attach_apn(self);
|
||||
}
|
||||
|
||||
static void ril_network_watch_gprs_settings_cb(struct ofono_watch *watch,
|
||||
enum ofono_gprs_context_type type,
|
||||
const struct ofono_gprs_primary_context *settings,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->use_data_profiles) {
|
||||
ril_network_check_data_profiles(self);
|
||||
}
|
||||
|
||||
if (type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
priv->set_initial_attach_apn = TRUE;
|
||||
ril_network_check_initial_attach_apn(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings)
|
||||
struct ril_sim_card *simcard,
|
||||
struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_vendor *vendor)
|
||||
{
|
||||
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
@@ -836,10 +1247,22 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->simcard = ril_sim_card_ref(simcard);
|
||||
priv->vendor = ril_vendor_ref(vendor);
|
||||
priv->watch = ofono_watch_new(path);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
|
||||
/* Copy relevant config values */
|
||||
priv->lte_network_mode = config->lte_network_mode;
|
||||
priv->umts_network_mode = config->umts_network_mode;
|
||||
priv->network_mode_timeout = config->network_mode_timeout;
|
||||
priv->force_gsm_when_radio_off = config->force_gsm_when_radio_off;
|
||||
priv->use_data_profiles = config->use_data_profiles;
|
||||
priv->mms_data_profile_id = config->mms_data_profile_id;
|
||||
|
||||
/* Register listeners */
|
||||
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_state_changed_cb,
|
||||
@@ -848,18 +1271,30 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_radio_capability_changed_cb,
|
||||
RIL_UNSOL_RADIO_CAPABILITY, self);
|
||||
|
||||
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
|
||||
ril_radio_add_state_changed_handler(priv->radio,
|
||||
ril_network_radio_state_cb, self);
|
||||
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
|
||||
ril_radio_add_online_changed_handler(priv->radio,
|
||||
ril_network_radio_online_cb, self);
|
||||
|
||||
priv->simcard_event_id[SIM_EVENT_STATUS_CHANGED] =
|
||||
ril_sim_card_add_status_changed_handler(priv->simcard,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
priv->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
|
||||
ril_sim_card_add_sim_io_active_changed_handler(priv->simcard,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
priv->settings_event_id =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(settings,
|
||||
ril_network_pref_mode_changed_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
|
||||
priv->watch_ids[WATCH_EVENT_GPRS] =
|
||||
ofono_watch_add_gprs_changed_handler(priv->watch,
|
||||
ril_network_watch_gprs_cb, self);
|
||||
priv->watch_ids[WATCH_EVENT_GPRS_SETTINGS] =
|
||||
ofono_watch_add_gprs_settings_changed_handler(priv->watch,
|
||||
ril_network_watch_gprs_settings_cb, self);
|
||||
|
||||
/*
|
||||
* Query the initial state. Querying network state before the radio
|
||||
@@ -872,6 +1307,15 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
priv->set_initial_attach_apn =
|
||||
priv->need_initial_attach_apn =
|
||||
ril_network_need_initial_attach_apn(self);
|
||||
|
||||
ril_vendor_set_network(vendor, self);
|
||||
if (priv->use_data_profiles) {
|
||||
ril_network_check_data_profiles(self);
|
||||
}
|
||||
ril_network_try_set_initial_attach_apn(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -915,20 +1359,21 @@ static void ril_network_finalize(GObject *object)
|
||||
ril_network_stop_timer(self, tid);
|
||||
}
|
||||
|
||||
ofono_watch_remove_all_handlers(priv->watch, priv->watch_ids);
|
||||
ofono_watch_unref(priv->watch);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
|
||||
G_N_ELEMENTS(priv->unsol_event_id));
|
||||
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->unsol_event_id);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_handler(priv->sim_card,
|
||||
priv->sim_status_event_id);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id);
|
||||
ril_sim_card_unref(priv->simcard);
|
||||
ril_sim_settings_remove_handler(self->settings,
|
||||
priv->settings_event_id);
|
||||
ril_sim_settings_unref(self->settings);
|
||||
ril_vendor_unref(priv->vendor);
|
||||
g_slist_free_full(priv->data_profiles, g_free);
|
||||
g_free(priv->log_prefix);
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
@@ -46,7 +48,9 @@ typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings);
|
||||
struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *ril_slot_config,
|
||||
struct ril_vendor *vendor);
|
||||
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -52,6 +53,7 @@ struct ril_modem {
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
struct ril_vendor *vendor;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
@@ -70,7 +72,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct sailfish_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 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
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
@@ -71,14 +73,16 @@ G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
|
||||
#define RIL_RADIO_TYPE (ril_radio_get_type())
|
||||
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
|
||||
|
||||
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
return self->online && !priv->power_cycle &&
|
||||
g_hash_table_size(priv->req_table) > 0;
|
||||
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
|
||||
!priv->power_cycle;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
@@ -102,7 +106,7 @@ static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self,
|
||||
@@ -116,7 +120,7 @@ static void ril_radio_cancel_retry(struct ril_radio *self)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->retry_id) {
|
||||
DBG("%sretry cancelled", priv->log_prefix);
|
||||
DBG_(self, "retry cancelled");
|
||||
g_source_remove(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
}
|
||||
@@ -129,8 +133,8 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
if (!priv->pending_id) {
|
||||
gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
if (ril_radio_state_on(self->priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
if (ril_radio_state_on(priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
/* All is good, cancel pending retry if there is one */
|
||||
ril_radio_cancel_retry(self);
|
||||
} else if (priv->state_changed_while_request_pending) {
|
||||
@@ -138,7 +142,7 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
ril_radio_submit_power_request(self, should_be_on);
|
||||
} else if (!priv->retry_id) {
|
||||
/* There has been no reaction so far, wait a bit */
|
||||
DBG("%sretry scheduled", priv->log_prefix);
|
||||
DBG_(self, "retry scheduled");
|
||||
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
|
||||
ril_radio_power_request_retry_cb, self);
|
||||
}
|
||||
@@ -147,33 +151,38 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
/* Don't update public state while something is pending */
|
||||
if (!priv->pending_id && !priv->retry_id &&
|
||||
self->state != priv->last_known_state) {
|
||||
DBG("%s%s -> %s", priv->log_prefix,
|
||||
ril_radio_state_to_string(self->state),
|
||||
DBG_(self, "%s -> %s", ril_radio_state_to_string(self->state),
|
||||
ril_radio_state_to_string(priv->last_known_state));
|
||||
self->state = priv->last_known_state;
|
||||
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_done(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
priv->pending_id = 0;
|
||||
|
||||
if (priv->next_state_valid) {
|
||||
ril_radio_submit_power_request(self, priv->next_state);
|
||||
} else {
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
priv->pending_id = 0;
|
||||
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("Power request failed: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
if (priv->next_state_valid) {
|
||||
ril_radio_submit_power_request(self, priv->next_state);
|
||||
} else {
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
ril_radio_power_request_done(self);
|
||||
}
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
@@ -214,20 +223,37 @@ static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = on;
|
||||
DBG("%s%s (queued)", priv->log_prefix, on_off);
|
||||
DBG_(self, "%s (queued)", on_off);
|
||||
} else {
|
||||
DBG("%s%s (ignored)", priv->log_prefix, on_off);
|
||||
DBG_(self, "%s (ignored)", on_off);
|
||||
}
|
||||
} else {
|
||||
DBG("%s%s", priv->log_prefix, on_off);
|
||||
ril_radio_submit_power_request(self, on);
|
||||
if (ril_radio_state_on(priv->last_known_state) == on) {
|
||||
DBG_(self, "%s (already)", on_off);
|
||||
ril_radio_check_state(self);
|
||||
} else {
|
||||
DBG_(self, "%s", on_off);
|
||||
ril_radio_submit_power_request(self, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_confirm_power_on(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, TRUE);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (!priv->next_state) {
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = TRUE;
|
||||
DBG_(self, "on (queued)");
|
||||
}
|
||||
} else {
|
||||
DBG_(self, "on");
|
||||
ril_radio_submit_power_request(self, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,12 +263,12 @@ void ril_radio_power_cycle(struct ril_radio *self)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (ril_radio_state_off(priv->last_known_state)) {
|
||||
DBG("%spower is already off", priv->log_prefix);
|
||||
DBG_(self, "power is already off");
|
||||
GASSERT(!priv->power_cycle);
|
||||
} else if (priv->power_cycle) {
|
||||
DBG("%salready in progress", priv->log_prefix);
|
||||
DBG_(self, "already in progress");
|
||||
} else {
|
||||
DBG("%sinitiated", priv->log_prefix);
|
||||
DBG_(self, "initiated");
|
||||
priv->power_cycle = TRUE;
|
||||
if (!priv->pending_id) {
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
@@ -259,7 +285,7 @@ void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||
if (!g_hash_table_contains(priv->req_table, tag)) {
|
||||
gboolean was_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
DBG_(self, "%p", tag);
|
||||
g_hash_table_insert(priv->req_table, tag, tag);
|
||||
if (!was_on && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, FALSE);
|
||||
@@ -274,7 +300,7 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (g_hash_table_remove(priv->req_table, tag)) {
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
DBG_(self, "%p", tag);
|
||||
if (!ril_radio_power_should_be_on(self)) {
|
||||
/* The last one turns the lights off */
|
||||
ril_radio_power_request(self, FALSE, FALSE);
|
||||
@@ -346,20 +372,41 @@ static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
if (radio_state != RADIO_STATE_UNAVAILABLE) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s%s", priv->log_prefix,
|
||||
ril_radio_state_to_string(radio_state));
|
||||
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
|
||||
GASSERT(!priv->pending_id || !priv->retry_id);
|
||||
|
||||
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
|
||||
DBG("%sswitched off for power cycle", priv->log_prefix);
|
||||
DBG_(self, "switched off for power cycle");
|
||||
priv->power_cycle = FALSE;
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
|
||||
if (priv->pending_id) {
|
||||
priv->state_changed_while_request_pending++;
|
||||
if (ril_radio_state_on(radio_state) ==
|
||||
ril_radio_power_should_be_on(self)) {
|
||||
DBG_(self, "dropping pending request");
|
||||
/*
|
||||
* All right, the modem has switched to the
|
||||
* desired state, drop the request.
|
||||
*/
|
||||
grilio_queue_cancel_request(priv->q,
|
||||
priv->pending_id, FALSE);
|
||||
|
||||
/*
|
||||
* This will zero pending_id and call
|
||||
* ril_radio_check_state() if necesary:
|
||||
*/
|
||||
ril_radio_power_request_done(self);
|
||||
|
||||
/* We are done */
|
||||
return;
|
||||
} else {
|
||||
/* Something weird is going on */
|
||||
priv->state_changed_while_request_pending++;
|
||||
}
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
@@ -374,10 +421,15 @@ struct ril_radio *ril_radio_new(GRilIoChannel *io)
|
||||
priv->log_prefix =
|
||||
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
|
||||
g_strconcat(io->name, " ", NULL) : g_strdup("");
|
||||
DBG("%s", priv->log_prefix);
|
||||
DBG_(self, "");
|
||||
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
|
||||
/*
|
||||
* Some RILs like to receive power off request at startup even if
|
||||
* radio is already off. Make those happy.
|
||||
*/
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -431,7 +483,7 @@ static void ril_radio_finalize(GObject *object)
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_radio {
|
||||
GObject object;
|
||||
struct ril_radio_priv *priv;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -71,6 +71,7 @@ struct ril_radio_caps {
|
||||
gulong max_pref_mode_event_id;
|
||||
gulong radio_event_id;
|
||||
int tx_id;
|
||||
int tx_pending;
|
||||
struct ril_data *data;
|
||||
struct ril_radio *radio;
|
||||
struct ril_network *network;
|
||||
@@ -85,7 +86,6 @@ typedef struct ril_radio_caps_manager {
|
||||
GObject object;
|
||||
GPtrArray *caps_list;
|
||||
guint check_id;
|
||||
int tx_pending;
|
||||
int tx_id;
|
||||
int tx_phase_index;
|
||||
gboolean tx_failed;
|
||||
@@ -453,7 +453,7 @@ struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
struct ril_radio_caps *self =
|
||||
g_slice_new0(struct ril_radio_caps);
|
||||
|
||||
self->ref_count = 1;
|
||||
g_atomic_int_set(&self->ref_count, 1);
|
||||
self->slot = config->slot;
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
@@ -471,13 +471,16 @@ struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
self->simcard_event_id[SIM_EVENT_STATE_CHANGED] =
|
||||
ril_sim_card_add_state_changed_handler(sim,
|
||||
ril_radio_caps_simcard_event, self);
|
||||
self->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
|
||||
ril_sim_card_add_sim_io_active_changed_handler(sim,
|
||||
ril_radio_caps_simcard_event, self);
|
||||
|
||||
self->network = ril_network_ref(net);
|
||||
self->settings_event_id[SETTINGS_EVENT_PREF_MODE] =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(
|
||||
settings, ril_radio_caps_settings_event, self);
|
||||
self->settings_event_id[SETTINGS_EVENT_IMSI] =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(
|
||||
ril_sim_settings_add_imsi_changed_handler(
|
||||
settings, ril_radio_caps_settings_event, self);
|
||||
|
||||
self->max_pref_mode_event_id =
|
||||
@@ -560,6 +563,24 @@ static void ril_radio_caps_manager_foreach_tx
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_radio_caps_manager_tx_pending
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
guint i;
|
||||
const GPtrArray *list = self->caps_list;
|
||||
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const struct ril_radio_caps *caps = list->pdata[i];
|
||||
|
||||
/* Ignore the modems not associated with this transaction */
|
||||
if (caps->tx_id == self->tx_id && caps->tx_pending > 0) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all radio caps have been initialized (i.e. all the initial
|
||||
* GET_RADIO_CAPABILITY requests have completed) and there's no transaction
|
||||
@@ -568,7 +589,7 @@ static void ril_radio_caps_manager_foreach_tx
|
||||
static gboolean ril_radio_caps_manager_can_check
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
if (self->caps_list && !self->tx_pending) {
|
||||
if (self->caps_list && !ril_radio_caps_manager_tx_pending(self)) {
|
||||
const GPtrArray *list = self->caps_list;
|
||||
const struct ril_radio_caps *prev_caps = NULL;
|
||||
gboolean all_modes_equal = TRUE;
|
||||
@@ -753,6 +774,10 @@ static void ril_radio_caps_manager_issue_requests
|
||||
phase->send_new_cap ? &caps->new_cap :
|
||||
&caps->old_cap;
|
||||
|
||||
/* Count it */
|
||||
caps->tx_pending++;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
|
||||
/* Encode and send the request */
|
||||
grilio_request_append_int32(req,
|
||||
RIL_RADIO_CAPABILITY_VERSION);
|
||||
@@ -766,9 +791,6 @@ static void ril_radio_caps_manager_issue_requests
|
||||
RIL_REQUEST_SET_RADIO_CAPABILITY,
|
||||
handler, NULL, caps);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Count it */
|
||||
self->tx_pending++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -791,7 +813,6 @@ static void ril_radio_caps_manager_next_transaction
|
||||
{
|
||||
ril_radio_caps_manager_foreach(self,
|
||||
ril_radio_caps_manager_next_transaction_cb);
|
||||
self->tx_pending = 0;
|
||||
self->tx_failed = FALSE;
|
||||
self->tx_phase_index = -1;
|
||||
self->tx_id++;
|
||||
@@ -829,8 +850,10 @@ static void ril_radio_caps_manager_abort_cb(GRilIoChannel *io,
|
||||
struct ril_radio_caps *caps = user_data;
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
|
||||
GASSERT(self->tx_pending > 0);
|
||||
if (!(--self->tx_pending)) {
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
DBG("transaction aborted");
|
||||
ril_radio_caps_manager_transaction_done(self);
|
||||
}
|
||||
@@ -875,7 +898,7 @@ static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
gboolean ok = FALSE;
|
||||
|
||||
GASSERT(self->tx_pending > 0);
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
struct ril_radio_capability cap;
|
||||
if (ril_radio_caps_parse(caps->log_prefix, data, len, &cap) &&
|
||||
@@ -892,7 +915,9 @@ static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(--self->tx_pending)) {
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->tx_failed) {
|
||||
ril_radio_caps_manager_abort_transaction(self);
|
||||
} else {
|
||||
@@ -907,7 +932,7 @@ static void ril_radio_caps_manager_next_phase
|
||||
/* Note: -1 > 2 if 2 is unsigned (which turns -1 into 4294967295) */
|
||||
const int max_index = G_N_ELEMENTS(ril_radio_caps_tx_phase) - 1;
|
||||
|
||||
GASSERT(!self->tx_pending);
|
||||
GASSERT(!ril_radio_caps_manager_tx_pending(self));
|
||||
if (self->tx_phase_index >= max_index) {
|
||||
DBG("transaction %d is done", self->tx_id);
|
||||
ril_radio_caps_manager_transaction_done(self);
|
||||
@@ -924,14 +949,16 @@ static void ril_radio_caps_manager_next_phase
|
||||
static void ril_radio_caps_manager_data_off_done(GRilIoChannel *io,
|
||||
int status, const void *req_data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio_caps_manager *self = RADIO_CAPS_MANAGER(user_data);
|
||||
struct ril_radio_caps *caps = user_data;
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
|
||||
DBG("%d", self->tx_pending);
|
||||
GASSERT(self->tx_pending > 0);
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
if (status != GRILIO_STATUS_OK) {
|
||||
self->tx_failed = TRUE;
|
||||
}
|
||||
if (!(--self->tx_pending)) {
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->tx_failed) {
|
||||
DBG("failed to start the transaction");
|
||||
ril_data_manager_assert_data_on(self->data_manager);
|
||||
@@ -951,13 +978,13 @@ static void ril_radio_caps_manager_data_off
|
||||
{
|
||||
GRilIoRequest *req = ril_request_allow_data_new(FALSE);
|
||||
|
||||
self->tx_pending++;
|
||||
DBG_(caps, "disallowing data");
|
||||
caps->tx_pending++;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
grilio_request_set_timeout(req, DATA_OFF_TIMEOUT_MS);
|
||||
grilio_queue_send_request_full(caps->q, req,
|
||||
RIL_REQUEST_ALLOW_DATA,
|
||||
ril_radio_caps_manager_data_off_done,
|
||||
NULL, self);
|
||||
NULL, caps);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -967,14 +994,16 @@ static void ril_radio_caps_manager_deactivate_data_call_done(GRilIoChannel *io,
|
||||
struct ril_radio_caps *caps = user_data;
|
||||
struct ril_radio_caps_manager *self = caps->mgr;
|
||||
|
||||
GASSERT(self->tx_pending > 0);
|
||||
GASSERT(caps->tx_pending > 0);
|
||||
if (status != GRILIO_STATUS_OK) {
|
||||
self->tx_failed = TRUE;
|
||||
/* Something seems to be slightly broken, try requesting the
|
||||
* current state (later, after we release the transaction). */
|
||||
ril_data_poll_call_state(caps->data);
|
||||
}
|
||||
if (!(--self->tx_pending)) {
|
||||
caps->tx_pending--;
|
||||
DBG_(caps, "tx_pending=%d", caps->tx_pending);
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->tx_failed) {
|
||||
DBG("failed to start the transaction");
|
||||
ril_radio_caps_manager_recheck_later(self);
|
||||
@@ -992,8 +1021,8 @@ static void ril_radio_caps_deactivate_data_call(struct ril_radio_caps *caps,
|
||||
{
|
||||
GRilIoRequest *req = ril_request_deactivate_data_call_new(cid);
|
||||
|
||||
caps->mgr->tx_pending++;
|
||||
DBG_(caps, "deactivating call %u", cid);
|
||||
caps->tx_pending++;
|
||||
DBG_(caps, "cid=%u, tx_pending=%d", cid, caps->tx_pending);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_request_set_timeout(req, DEACTIVATE_TIMEOUT_MS);
|
||||
grilio_queue_send_request_full(caps->q, req,
|
||||
@@ -1028,11 +1057,11 @@ static void ril_radio_caps_manager_deactivate_all
|
||||
{
|
||||
ril_radio_caps_manager_foreach_tx(self,
|
||||
ril_radio_caps_manager_deactivate_all_cb);
|
||||
if (!self->tx_pending) {
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
/* No data calls, submit ALLOW_DATA requests right away */
|
||||
ril_radio_caps_manager_foreach_tx(self,
|
||||
ril_radio_caps_manager_data_off);
|
||||
GASSERT(self->tx_pending);
|
||||
GASSERT(ril_radio_caps_manager_tx_pending(self));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,6 +1284,24 @@ static GSList *ril_radio_caps_manager_empty_slots
|
||||
return found;
|
||||
}
|
||||
|
||||
static guint ril_radio_caps_manager_sim_count
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
const GPtrArray *list = self->caps_list;
|
||||
guint i, count = 0;
|
||||
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const struct ril_radio_caps *caps = list->pdata[i];
|
||||
|
||||
if (caps->simcard->status->card_state ==
|
||||
RIL_CARDSTATE_PRESENT) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* There could be no capability mismatch but LTE could be enabled for
|
||||
* the slot that has no SIM card in it. That's a waste, fix it.
|
||||
@@ -1298,7 +1345,7 @@ static void ril_radio_caps_manager_check(struct ril_radio_caps_manager *self)
|
||||
if (ril_radio_caps_manager_can_check(self)) {
|
||||
const int first = ril_radio_caps_manager_first_mismatch(self);
|
||||
|
||||
if (first >= 0) {
|
||||
if (first >= 0 && ril_radio_caps_manager_sim_count(self) > 1) {
|
||||
if (ril_radio_caps_manager_update_caps(self, first)) {
|
||||
ril_radio_caps_manager_start_transaction(self);
|
||||
}
|
||||
@@ -1321,7 +1368,7 @@ static gboolean ril_radio_caps_manager_check_cb(gpointer data)
|
||||
static void ril_radio_caps_manager_recheck_later
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
if (!self->tx_pending) {
|
||||
if (!ril_radio_caps_manager_tx_pending(self)) {
|
||||
if (self->check_id) {
|
||||
g_source_remove(self->check_id);
|
||||
self->check_id = 0;
|
||||
@@ -1334,7 +1381,7 @@ static void ril_radio_caps_manager_recheck_later
|
||||
static void ril_radio_caps_manager_schedule_check
|
||||
(struct ril_radio_caps_manager *self)
|
||||
{
|
||||
if (!self->check_id && !self->tx_pending) {
|
||||
if (!self->check_id && !ril_radio_caps_manager_tx_pending(self)) {
|
||||
self->check_id = g_idle_add(ril_radio_caps_manager_check_cb,
|
||||
self);
|
||||
}
|
||||
@@ -1367,7 +1414,7 @@ RilRadioCapsManager *ril_radio_caps_manager_ref(RilRadioCapsManager *self)
|
||||
void ril_radio_caps_manager_unref(RilRadioCapsManager *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RADIO_CAPS_MANAGER(self));
|
||||
g_object_unref(RADIO_CAPS_MANAGER(self));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,7 +18,8 @@
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include "simutil.h"
|
||||
#include "util.h"
|
||||
#include "ofono.h"
|
||||
@@ -69,6 +70,11 @@ enum ril_sim_card_event {
|
||||
SIM_CARD_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_sim_io_event {
|
||||
IO_EVENT_SIM_REFRESH,
|
||||
IO_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
@@ -81,12 +87,13 @@ struct ril_sim {
|
||||
gboolean inserted;
|
||||
guint idle_id; /* Used by register and SIM reset callbacks */
|
||||
gulong card_event_id[SIM_CARD_EVENT_COUNT];
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
guint query_pin_retries_id;
|
||||
|
||||
const char *log_prefix;
|
||||
char *allocated_log_prefix;
|
||||
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_watch *watch;
|
||||
gulong sim_state_watch_id;
|
||||
|
||||
/* query_passwd_state context */
|
||||
@@ -102,8 +109,9 @@ struct ril_sim_io_response {
|
||||
guint data_len;
|
||||
};
|
||||
|
||||
struct ril_sim_cbd {
|
||||
struct ril_sim_cbd_io {
|
||||
struct ril_sim *sd;
|
||||
struct ril_sim_card *card;
|
||||
union _ofono_sim_cb {
|
||||
ofono_sim_file_info_cb_t file_info;
|
||||
ofono_sim_read_cb_t read;
|
||||
@@ -173,24 +181,43 @@ static const struct ril_sim_retry_query ril_sim_retry_query_types[] = {
|
||||
|
||||
#define DBG_(sd,fmt,args...) DBG("%s" fmt, (sd)->log_prefix, ##args)
|
||||
|
||||
#define ril_sim_cbd_free g_free
|
||||
|
||||
static inline struct ril_sim *ril_sim_get_data(struct ofono_sim *sim)
|
||||
{
|
||||
return ofono_sim_get_data(sim);
|
||||
}
|
||||
|
||||
static struct ril_sim_cbd *ril_sim_cbd_new(struct ril_sim *sd, void *cb,
|
||||
static struct ril_sim_cbd_io *ril_sim_cbd_io_new(struct ril_sim *sd, void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = g_new0(struct ril_sim_cbd, 1);
|
||||
struct ril_sim_cbd_io *cbd = g_new0(struct ril_sim_cbd_io, 1);
|
||||
|
||||
cbd->sd = sd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
cbd->card = ril_sim_card_ref(sd->card);
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_sim_cbd_io_free(void *data)
|
||||
{
|
||||
|
||||
struct ril_sim_cbd_io *cbd = data;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->card, cbd->req_id);
|
||||
ril_sim_card_unref(cbd->card);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_sim_cbd_io_start(struct ril_sim_cbd_io *cbd, GRilIoRequest* req,
|
||||
guint code, GRilIoChannelResponseFunc cb)
|
||||
{
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req, code,
|
||||
cb, ril_sim_cbd_io_free, cbd);
|
||||
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
|
||||
}
|
||||
|
||||
static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
@@ -249,11 +276,6 @@ static void ril_sim_pin_req_done(gpointer ptr)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_sim_app_id(struct ril_sim *sd)
|
||||
{
|
||||
return sd->card->app ? sd->card->app->aid : NULL;
|
||||
}
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
@@ -423,14 +445,13 @@ static void ril_sim_io_response_free(struct ril_sim_io_response *res)
|
||||
static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_file_info_cb_t cb = cbd->cb.file_info;
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
struct ril_sim_io_response *res = NULL;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(sd, "");
|
||||
ril_sim_card_sim_io_finished(sd->card, cbd->req_id);
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
@@ -474,12 +495,13 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
|
||||
static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
|
||||
guint p1, guint p2, guint p3, const char *hex_data,
|
||||
const guchar *path, guint path_len,
|
||||
GRilIoChannelResponseFunc cb, struct ril_sim_cbd *cbd)
|
||||
GRilIoChannelResponseFunc cb, struct ril_sim_cbd_io *cbd)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG_(sd, "cmd=0x%.2X,efid=0x%.4X,%d,%d,%d,%s,pin2=(null),aid=%s",
|
||||
cmd, fileid, p1, p2, p3, hex_data, ril_sim_app_id(sd));
|
||||
cmd, fileid, p1, p2, p3, hex_data,
|
||||
ril_sim_card_app_aid(sd->card));
|
||||
|
||||
grilio_request_append_int32(req, cmd);
|
||||
grilio_request_append_int32(req, fileid);
|
||||
@@ -489,13 +511,11 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
|
||||
grilio_request_append_int32(req, p3); /* P3 */
|
||||
grilio_request_append_utf8(req, hex_data); /* data; only for writes */
|
||||
grilio_request_append_utf8(req, NULL); /* pin2; only for writes */
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
grilio_request_append_utf8(req, ril_sim_card_app_aid(sd->card));
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_IO, cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -505,19 +525,19 @@ static void ril_sim_ofono_read_file_info(struct ofono_sim *sim, int fileid,
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
ril_sim_request_io(sd, CMD_GET_RESPONSE, fileid, 0, 0, 15, NULL,
|
||||
path, len, ril_sim_file_info_cb, ril_sim_cbd_new(sd, cb, data));
|
||||
path, len, ril_sim_file_info_cb,
|
||||
ril_sim_cbd_io_new(sd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_sim_read_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_read_cb_t cb = cbd->cb.read;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error err;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
@@ -536,7 +556,7 @@ static void ril_sim_read(struct ofono_sim *sim, guint cmd, int fileid,
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
ril_sim_request_io(sd, cmd, fileid, p1, p2, p3, NULL, path, path_len,
|
||||
ril_sim_read_cb, ril_sim_cbd_new(sd, cb, data));
|
||||
ril_sim_read_cb, ril_sim_cbd_io_new(sd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_sim_ofono_read_file_transparent(struct ofono_sim *sim,
|
||||
@@ -566,13 +586,12 @@ static void ril_sim_ofono_read_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
static void ril_sim_write_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_write_cb_t cb = cbd->cb.write;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error err;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
@@ -593,7 +612,7 @@ static void ril_sim_write(struct ofono_sim *sim, guint cmd, int fileid,
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
char *hex_data = encode_hex(value, length, 0);
|
||||
ril_sim_request_io(sd, cmd, fileid, p1, p2, length, hex_data, path,
|
||||
path_len, ril_sim_write_cb, ril_sim_cbd_new(sd, cb, data));
|
||||
path_len, ril_sim_write_cb, ril_sim_cbd_io_new(sd, cb, data));
|
||||
g_free(hex_data);
|
||||
}
|
||||
|
||||
@@ -630,12 +649,10 @@ static void ril_sim_write_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
static void ril_sim_get_imsi_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_imsi_cb_t cb = cbd->cb.imsi;
|
||||
struct ofono_error error;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
gchar *imsi;
|
||||
GRilIoParser rilp;
|
||||
@@ -660,8 +677,8 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(1, app_id);
|
||||
|
||||
DBG_(sd, "%s", app_id);
|
||||
@@ -673,10 +690,8 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_GET_IMSI, ril_sim_get_imsi_cb,
|
||||
ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_GET_IMSI,
|
||||
ril_sim_get_imsi_cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -858,31 +873,15 @@ static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_reinsert_cb(gpointer data)
|
||||
{
|
||||
struct ril_sim *sd = data;
|
||||
const enum ofono_sim_state state = ofono_sim_get_state(sd->watch->sim);
|
||||
|
||||
GASSERT(sd->idle_id);
|
||||
sd->idle_id = 0;
|
||||
|
||||
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
|
||||
DBG_(sd, "reinserting SIM");
|
||||
ofono_sim_inserted_notify(sd->sim, TRUE);
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_sim_state_changed_cb(struct sailfish_watch *watch, void *data)
|
||||
static void ril_sim_state_changed_cb(struct ofono_watch *watch, void *data)
|
||||
{
|
||||
struct ril_sim *sd = data;
|
||||
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
|
||||
|
||||
DBG_(sd, "%d %d", state, sd->inserted);
|
||||
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted &&
|
||||
!sd->idle_id) {
|
||||
sd->idle_id = g_idle_add(ril_sim_reinsert_cb, sd);
|
||||
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
|
||||
/* That will simulate SIM card removal: */
|
||||
ril_sim_card_reset(sd->card);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -900,25 +899,22 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
|
||||
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
|
||||
const char *pin)
|
||||
{
|
||||
if (sd->card->app) {
|
||||
/*
|
||||
* If there's no AID then so be it... Some
|
||||
* adaptations (namely, MTK) don't provide it
|
||||
* but don't seem to require it either.
|
||||
*/
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(2,
|
||||
pin, sd->card->app->aid);
|
||||
/*
|
||||
* If there's no AID then so be it... Some
|
||||
* adaptations (namely, MTK) don't provide it
|
||||
* but don't seem to require it either.
|
||||
*/
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(2, pin,
|
||||
ril_sim_card_app_aid(sd->card));
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
return req;
|
||||
}
|
||||
return NULL;
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
return req;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_sim_enter_sim_puk_req(struct ril_sim *sd,
|
||||
const char *puk, const char *pin)
|
||||
{
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
if (app_id) {
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(3,
|
||||
puk, pin, app_id);
|
||||
@@ -1137,6 +1133,7 @@ static void ril_sim_pin_change_state_status_cb(struct ril_sim_card *sc,
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
}
|
||||
|
||||
ofono_sim_initialized_notify(sd->sim);
|
||||
sd->pin_cbd_list = g_list_remove(sd->pin_cbd_list, cbd);
|
||||
ril_sim_pin_cbd_free(cbd);
|
||||
} else {
|
||||
@@ -1175,7 +1172,10 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
ril_sim_check_perm_lock(sd);
|
||||
cbd->ril_status = ril_status;
|
||||
if (cbd->card_status_id && (!cbd->state_event_count ||
|
||||
|
||||
/* RIL_E_PASSWORD_INCORRECT is the final result, no need to wait */
|
||||
if (ril_status != RIL_E_PASSWORD_INCORRECT &&
|
||||
cbd->card_status_id && (!cbd->state_event_count ||
|
||||
ril_sim_app_in_transient_state(sd))) {
|
||||
|
||||
GASSERT(!g_list_find(sd->pin_cbd_list, cbd));
|
||||
@@ -1210,6 +1210,9 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
|
||||
cbd->card_status_id);
|
||||
cbd->card_status_id = 0;
|
||||
}
|
||||
|
||||
/* Tell the core that we are ready to accept more requests */
|
||||
ofono_sim_initialized_notify(sd->sim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,7 +1223,7 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
GRilIoRequest *req = ril_sim_enter_sim_pin_req(sd, passwd);
|
||||
|
||||
if (req) {
|
||||
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
|
||||
DBG_(sd, "%s,aid=%s", passwd, ril_sim_card_app_aid(sd->card));
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PIN, ril_sim_pin_change_state_cb,
|
||||
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
|
||||
@@ -1247,10 +1250,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
|
||||
case OFONO_SIM_PASSWORD_PHNET_PIN:
|
||||
if (!enable) {
|
||||
code = RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION;
|
||||
req = grilio_request_sized_new(12);
|
||||
grilio_request_append_int32(req,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
req = grilio_request_array_utf8_new(1, passwd);
|
||||
} else {
|
||||
DBG_(sd, "Not supported, enable=%d", enable);
|
||||
}
|
||||
@@ -1263,7 +1263,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
|
||||
if (req) {
|
||||
id = grilio_queue_send_request_full(sd->q, req, code,
|
||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -1299,7 +1299,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
|
||||
const char *passwd, ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
const char *type_str = ril_sim_facility_code(passwd_type);
|
||||
struct ofono_error error;
|
||||
guint id = 0;
|
||||
@@ -1319,7 +1319,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
|
||||
id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
|
||||
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -1337,7 +1337,7 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
|
||||
|
||||
if (req) {
|
||||
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd,
|
||||
ril_sim_app_id(sd));
|
||||
ril_sim_card_app_aid(sd->card));
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PUK, ril_sim_pin_change_state_cb,
|
||||
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
|
||||
@@ -1357,7 +1357,7 @@ static void ril_sim_change_passwd(struct ofono_sim *sim,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
const char *app_id = ril_sim_card_app_aid(sd->card);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(3,
|
||||
old_passwd, new_passwd, app_id);
|
||||
|
||||
@@ -1375,11 +1375,9 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_query_facility_lock_cb_t cb = cbd->cb.query_facility_lock;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int locked = 0;
|
||||
GRilIoParser rilp;
|
||||
@@ -1409,9 +1407,9 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char *type_str = ril_sim_facility_code(type);
|
||||
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(4,
|
||||
type_str, "", "0" /* class */, ril_sim_app_id(sd));
|
||||
type_str, "", "0" /* class */, ril_sim_card_app_aid(sd->card));
|
||||
|
||||
/* Make sure that this request gets completed sooner or later */
|
||||
grilio_request_set_timeout(req, FAC_LOCK_QUERY_TIMEOUT_SECS * 1000);
|
||||
@@ -1419,13 +1417,24 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
grilio_request_set_retry_func(req, ril_sim_query_facility_lock_retry);
|
||||
|
||||
DBG_(sd, "%s", type_str);
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
|
||||
ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_sim_query_facility_lock_cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim *sd = user_data;
|
||||
|
||||
/*
|
||||
* RIL_UNSOL_SIM_REFRESH may contain the EFID of the updated file,
|
||||
* so we could be more descrete here. However I have't actually
|
||||
* seen that in real life, let's just refresh everything for now.
|
||||
*/
|
||||
__ofono_sim_refresh(sd->sim, NULL, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_register(gpointer user)
|
||||
{
|
||||
struct ril_sim *sd = user;
|
||||
@@ -1444,9 +1453,14 @@ static gboolean ril_sim_register(gpointer user)
|
||||
ril_sim_card_add_app_changed_handler(sd->card,
|
||||
ril_sim_app_changed_cb, sd);
|
||||
sd->sim_state_watch_id =
|
||||
sailfish_watch_add_sim_state_changed_handler(sd->watch,
|
||||
ofono_watch_add_sim_state_changed_handler(sd->watch,
|
||||
ril_sim_state_changed_cb, sd);
|
||||
|
||||
/* And RIL events */
|
||||
sd->io_event_id[IO_EVENT_SIM_REFRESH] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_sim_refresh_cb, RIL_UNSOL_SIM_REFRESH, sd);
|
||||
|
||||
/* Check the current state */
|
||||
ril_sim_status_changed_cb(sd->card, sd);
|
||||
return FALSE;
|
||||
@@ -1464,7 +1478,7 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->card = ril_sim_card_ref(modem->sim_card);
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
sd->watch = sailfish_watch_new(ril_modem_get_path(modem));
|
||||
sd->watch = ofono_watch_new(ril_modem_get_path(modem));
|
||||
|
||||
if (modem->log_prefix && modem->log_prefix[0]) {
|
||||
sd->log_prefix = sd->allocated_log_prefix =
|
||||
@@ -1485,6 +1499,7 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
|
||||
DBG_(sd, "");
|
||||
g_list_free_full(sd->pin_cbd_list, ril_sim_pin_cbd_list_free_cb);
|
||||
grilio_channel_remove_all_handlers(sd->io, sd->io_event_id);
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
@@ -1501,8 +1516,8 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
}
|
||||
|
||||
sailfish_watch_remove_handler(sd->watch, sd->sim_state_watch_id);
|
||||
sailfish_watch_unref(sd->watch);
|
||||
ofono_watch_remove_handler(sd->watch, sd->sim_state_watch_id);
|
||||
ofono_watch_unref(sd->watch);
|
||||
|
||||
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
|
||||
G_N_ELEMENTS(sd->card_event_id));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 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
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
@@ -24,6 +26,17 @@
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
/*
|
||||
* First we wait for USIM app to get activated by itself. If that
|
||||
* doesn't happen within UICC_SUBSCRIPTION_START_MS we poke the SIM
|
||||
* with SET_UICC_SUBSCRIPTION request, resubmitting it if it times out.
|
||||
* If nothing happens within UICC_SUBSCRIPTION_TIMEOUT_MS we give up.
|
||||
*
|
||||
* Submitting SET_UICC_SUBSCRIPTION request when rild doesn't expect
|
||||
* it sometimes breaks pretty much everything. Unfortunately, there no
|
||||
* reliable way to find out when rild expects it and when it doesn't :/
|
||||
*/
|
||||
#define UICC_SUBSCRIPTION_START_MS (5000)
|
||||
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
|
||||
|
||||
/* SIM I/O idle timeout is measured in the number of idle loops.
|
||||
@@ -48,6 +61,7 @@ struct ril_sim_card_priv {
|
||||
int flags;
|
||||
guint status_req_id;
|
||||
guint sub_req_id;
|
||||
guint sub_start_timer;
|
||||
gulong event_id[EVENT_COUNT];
|
||||
guint sim_io_idle_id;
|
||||
guint sim_io_idle_count;
|
||||
@@ -157,10 +171,55 @@ static void ril_sim_card_status_free(struct ril_sim_card_status *status)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_tx_start(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRILIO_TRANSACTION_STATE tx_state =
|
||||
grilio_queue_transaction_state(priv->q);
|
||||
|
||||
if (tx_state == GRILIO_TRANSACTION_NONE) {
|
||||
tx_state = grilio_queue_transaction_start(priv->q);
|
||||
DBG("status tx for slot %u %s", self->slot,
|
||||
(tx_state == GRILIO_TRANSACTION_STARTED) ?
|
||||
"started" : "starting");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_tx_check(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (grilio_queue_transaction_state(priv->q) !=
|
||||
GRILIO_TRANSACTION_NONE) {
|
||||
const struct ril_sim_card_status *status = self->status;
|
||||
|
||||
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
/* Transaction (if there is any) is finished when
|
||||
* both GET_SIM_STATUS and SET_UICC_SUBSCRIPTION
|
||||
* complete or get dropped */
|
||||
if (!priv->status_req_id && !priv->sub_req_id &&
|
||||
status->gsm_umts_index >= 0 &&
|
||||
status->gsm_umts_index < status->num_apps) {
|
||||
DBG("status tx for slot %u finished",
|
||||
self->slot);
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
} else {
|
||||
DBG("status tx for slot %u cancelled", self->slot);
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->sub_start_timer) {
|
||||
/* Don't need this timer anymore */
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
priv->sub_start_timer = 0;
|
||||
}
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
@@ -168,7 +227,7 @@ static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
}
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
ril_sim_card_tx_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||
@@ -184,19 +243,18 @@ static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
||||
enum ril_uicc_subscription_action sub_action)
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||
const guint sub_id = self->slot;
|
||||
guint code;
|
||||
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
|
||||
DBG("%u,%d,%u", self->slot, app_index, sub_id);
|
||||
grilio_request_append_int32(req, self->slot);
|
||||
grilio_request_append_int32(req, app_index);
|
||||
grilio_request_append_int32(req, sub_id);
|
||||
grilio_request_append_int32(req, sub_action);
|
||||
grilio_request_append_int32(req, RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||
|
||||
grilio_request_set_retry(req, 0, -1);
|
||||
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
|
||||
@@ -213,7 +271,7 @@ static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
||||
|
||||
/* Don't allow any requests other that GET_SIM_STATUS until
|
||||
* we are done with the subscription */
|
||||
grilio_queue_transaction_start(priv->q);
|
||||
ril_sim_card_tx_start(self);
|
||||
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
|
||||
req, code, ril_sim_card_subscribe_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -250,9 +308,8 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
ril_sim_card_subscription_done(self);
|
||||
} else {
|
||||
app_index = ril_sim_card_select_app(status);
|
||||
if (app_index >= 0) {
|
||||
ril_sim_card_subscribe(self, app_index,
|
||||
RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||
if (app_index >= 0 && !self->priv->sub_start_timer) {
|
||||
ril_sim_card_subscribe(self, app_index);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -273,6 +330,18 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_card_sub_start_timeout(gpointer user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
DBG("%u", self->slot);
|
||||
GASSERT(priv->sub_start_timer);
|
||||
priv->sub_start_timer = 0;
|
||||
ril_sim_card_update_app(self);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
struct ril_sim_card_status *status)
|
||||
{
|
||||
@@ -282,6 +351,23 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
struct ril_sim_card_status *old_status = self->status;
|
||||
|
||||
self->status = status;
|
||||
if (diff & RIL_SIMCARD_STATE_CHANGED &&
|
||||
status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* SIM card has just appeared, give it some time to
|
||||
* activate the USIM app
|
||||
*/
|
||||
if (priv->sub_start_timer) {
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
}
|
||||
DBG("started subscription timeout for slot %u",
|
||||
self->slot);
|
||||
priv->sub_start_timer =
|
||||
g_timeout_add(UICC_SUBSCRIPTION_START_MS,
|
||||
ril_sim_card_sub_start_timeout, self);
|
||||
}
|
||||
ril_sim_card_update_app(self);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
@@ -297,6 +383,7 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
}
|
||||
ril_sim_card_status_free(old_status);
|
||||
} else {
|
||||
ril_sim_card_update_app(self);
|
||||
ril_sim_card_status_free(status);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
@@ -430,6 +517,24 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
ril_sim_card_update_status(self, status);
|
||||
}
|
||||
}
|
||||
|
||||
ril_sim_card_tx_check(self);
|
||||
}
|
||||
|
||||
void ril_sim_card_reset(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_card_status *status =
|
||||
g_new0(struct ril_sim_card_status, 1);
|
||||
|
||||
/* Simulate removal and re-submit the SIM status query */
|
||||
status->card_state = RIL_CARDSTATE_ABSENT;
|
||||
status->gsm_umts_index = -1;
|
||||
status->cdma_index = -1;
|
||||
status->ims_index = -1;
|
||||
ril_sim_card_update_status(self, status);
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
@@ -445,6 +550,9 @@ void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
/* Start the transaction to not allow any other
|
||||
* requests to interfere with SIM status query */
|
||||
ril_sim_card_tx_start(self);
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->status_req_id =
|
||||
grilio_queue_send_request_full(priv->q,
|
||||
@@ -664,6 +772,9 @@ static void ril_sim_card_finalize(GObject *object)
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
}
|
||||
if (priv->sub_start_timer) {
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
}
|
||||
g_hash_table_destroy(priv->sim_io_pending);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_sim_card_app {
|
||||
enum ril_app_type app_type;
|
||||
enum ril_app_state app_state;
|
||||
@@ -56,6 +58,7 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_unref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_reset(struct ril_sim_card *sc);
|
||||
void ril_sim_card_request_status(struct ril_sim_card *sc);
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
|
||||
@@ -74,9 +77,13 @@ void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
|
||||
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
|
||||
|
||||
/* Inline wrappers */
|
||||
static inline enum ril_app_type
|
||||
ril_sim_card_app_type(struct ril_sim_card *sc)
|
||||
static inline enum ril_app_type ril_sim_card_app_type(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
|
||||
static inline const char *ril_sim_card_app_aid(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->aid : NULL; }
|
||||
|
||||
#define ril_sim_card_remove_all_handlers(net, ids) \
|
||||
ril_sim_card_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_SIM_CARD_H */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 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
|
||||
@@ -13,10 +13,12 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
@@ -30,14 +32,14 @@
|
||||
typedef GObjectClass RilSimSettingsClass;
|
||||
typedef struct ril_sim_settings RilSimSettings;
|
||||
|
||||
enum sailfish_watch_events {
|
||||
enum ofono_watch_events {
|
||||
WATCH_EVENT_IMSI,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_settings_priv {
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_watch *watch;
|
||||
char *imsi;
|
||||
};
|
||||
|
||||
@@ -81,7 +83,7 @@ void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_imsi_changed(struct sailfish_watch *watch,
|
||||
static void ril_sim_settings_imsi_changed(struct ofono_watch *watch,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
|
||||
@@ -106,9 +108,9 @@ struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
priv = self->priv;
|
||||
self->techs = techs;
|
||||
self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
|
||||
priv->watch = sailfish_watch_new(path);
|
||||
priv->watch = ofono_watch_new(path);
|
||||
priv->watch_event_id[WATCH_EVENT_IMSI] =
|
||||
sailfish_watch_add_imsi_changed_handler(priv->watch,
|
||||
ofono_watch_add_imsi_changed_handler(priv->watch,
|
||||
ril_sim_settings_imsi_changed, self);
|
||||
self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
|
||||
}
|
||||
@@ -173,8 +175,8 @@ static void ril_sim_settings_finalize(GObject *object)
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
|
||||
sailfish_watch_unref(priv->watch);
|
||||
ofono_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
|
||||
ofono_watch_unref(priv->watch);
|
||||
g_free(priv->imsi);
|
||||
G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_sim_settings_priv;
|
||||
|
||||
struct ril_sim_settings {
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
# If it's set to true, all [ril_x] sections are ignored even
|
||||
# if they are present, and no default configurtation is created.
|
||||
#
|
||||
# Default is false
|
||||
# Default false
|
||||
#
|
||||
#EmptyConfig=false
|
||||
|
||||
# User and group for the ofono process. RIL clients are typically
|
||||
# expected to run under radio:radio.
|
||||
#
|
||||
# Default is radio:radio
|
||||
# Default radio:radio
|
||||
#
|
||||
#Identity=radio:radio
|
||||
|
||||
@@ -37,11 +37,18 @@
|
||||
# 3G/LTE modules for each slot or you don't need 4G for both slots).
|
||||
# Obviously, it only has any effect if you have more than one SIM.
|
||||
#
|
||||
# Default is true (switch the current data modem to 2G when changing
|
||||
# Defaults to true (switch the current data modem to 2G when changing
|
||||
# the data modems)
|
||||
#
|
||||
#3GLTEHandover=true
|
||||
|
||||
# If this option is on, preferred technology is set to GSM for non-data
|
||||
# slots.
|
||||
#
|
||||
# Default true (for historical reasons)
|
||||
#
|
||||
#ForceGsmForNonDataSlots=true
|
||||
|
||||
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# It's involved in 3G/LTE handover between the modems, meaning that it only
|
||||
@@ -49,7 +56,7 @@
|
||||
#
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default is auto (enable for RIL version >= 11)
|
||||
# Default auto (enable for RIL version >= 11)
|
||||
#
|
||||
#SetRadioCapability=auto
|
||||
|
||||
@@ -81,7 +88,7 @@ socket=/dev/socket/rild
|
||||
|
||||
# RIL request timeout, in milliseconds.
|
||||
#
|
||||
# The default is zero (no timeout)
|
||||
# Default zero (no timeout)
|
||||
#
|
||||
#timeout=0
|
||||
|
||||
@@ -89,7 +96,7 @@ socket=/dev/socket/rild
|
||||
# Valid technologies are "gsm", "umts" and "lte". The special value
|
||||
# "all" means that all technologies are supported.
|
||||
#
|
||||
# The default is all
|
||||
# Default all
|
||||
#
|
||||
#technologies=all
|
||||
|
||||
@@ -102,7 +109,7 @@ socket=/dev/socket/rild
|
||||
# which RIL version it's dealing with, it makes the decision at runtime.
|
||||
# Settings it to false disables the workaround and always sends 122.
|
||||
#
|
||||
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
|
||||
# Default true (select SET_UICC_SUBSCRIPTION based on the RIL version)
|
||||
#
|
||||
#uiccWorkaround=true
|
||||
|
||||
@@ -124,7 +131,7 @@ socket=/dev/socket/rild
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default is auto (enable for RIL version >= 11)
|
||||
# Default auto (enable for RIL version >= 11)
|
||||
#
|
||||
#allowDataReq=auto
|
||||
|
||||
@@ -134,7 +141,7 @@ socket=/dev/socket/rild
|
||||
# actually does check the empty pin (and decrements the retry count)
|
||||
# then you should turn this feature off.
|
||||
#
|
||||
# Default is true
|
||||
# Default true
|
||||
#
|
||||
#emptyPinQuery=true
|
||||
|
||||
@@ -146,7 +153,7 @@ socket=/dev/socket/rild
|
||||
# but sometimes you have to explicitly tell ofono which one to use.
|
||||
# Possible values are 6, 9, 11 and auto.
|
||||
#
|
||||
# Default is auto
|
||||
# Default auto
|
||||
#
|
||||
#dataCallFormat=auto
|
||||
|
||||
@@ -155,7 +162,7 @@ socket=/dev/socket/rild
|
||||
# this parameter. Usually, one retry is enough. The first retry occurs
|
||||
# immediately, the subsequent ones after dataCallRetryDelay (see below)
|
||||
#
|
||||
# Default is 4
|
||||
# Default 4
|
||||
#
|
||||
#dataCallRetryLimit=4
|
||||
|
||||
@@ -163,7 +170,7 @@ socket=/dev/socket/rild
|
||||
# retry occurs immediately after the first failure, the delays are only
|
||||
# applied if the first retry fails too.
|
||||
#
|
||||
# Default is 200 ms
|
||||
# Default 200 ms
|
||||
#
|
||||
#dataCallRetryDelay=200
|
||||
|
||||
@@ -184,6 +191,20 @@ socket=/dev/socket/rild
|
||||
#
|
||||
#enableVoicecall=true
|
||||
|
||||
# Support for Cell Broadcast System (CBS). By default, its enabled but if
|
||||
# your rild and/or modem is not happy about it, you can turn it off.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableCellBroadcast=true
|
||||
|
||||
# Support for Sim Toolkit (STK). By default, its enabled but if your rild
|
||||
# and/or modem is not happy about it, you can turn it off.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableSimToolkit=true
|
||||
|
||||
# Timeout for the modem to show up, in milliseconds. Those that don't
|
||||
# show up before this timeout expires, will be dropped (ignored).
|
||||
#
|
||||
@@ -191,7 +212,7 @@ socket=/dev/socket/rild
|
||||
# optional modems (which may or may not be available), to speed up the
|
||||
# boot up process.
|
||||
#
|
||||
# The default is 20000 (20 seconds)
|
||||
# Default 20000 (20 seconds)
|
||||
#
|
||||
#startTimeout=20000
|
||||
|
||||
@@ -199,6 +220,112 @@ socket=/dev/socket/rild
|
||||
# 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)
|
||||
# Default false (use RIL_REQUEST_DEVICE_IDENTITY)
|
||||
#
|
||||
#legacyImeiQuery=false
|
||||
|
||||
# Some devices don't support LTE RAT mode PREF_NET_TYPE_LTE_GSM_WCDMA.
|
||||
# This option allows to set a custom LTE mode.
|
||||
#
|
||||
# Default 9 (PREF_NET_TYPE_LTE_GSM_WCDMA)
|
||||
#
|
||||
#lteNetworkMode=9
|
||||
|
||||
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
|
||||
#
|
||||
# Default 20000 (20 seconds)
|
||||
#
|
||||
#networkModeTimeout=20000
|
||||
|
||||
# Timeout for RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC and
|
||||
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, in milliseconds.
|
||||
#
|
||||
# Default 100000 (100 seconds)
|
||||
#
|
||||
#networkSelectionTimeout=100000
|
||||
|
||||
# Comma-separated signal strength range, in dBm.
|
||||
#
|
||||
# These values are used for translating dBm values returned by the modem in
|
||||
# LTE mode into signal strength percentage. If you are getting significantly
|
||||
# different signal strength readings in GSM and LTE modes, you may need to
|
||||
# tweak those.
|
||||
#
|
||||
# Default -100,-60
|
||||
#
|
||||
#signalStrengthRange=-100,-60
|
||||
|
||||
# Cycle radio power at startup.
|
||||
#
|
||||
# Default true (cycle the power)
|
||||
#
|
||||
#radioPowerCycle=true
|
||||
|
||||
# With some RILs it seems to be necessary to kick (RIL_REQUEST_RADIO_POWER)
|
||||
# the modems with power on after one of the modems has been powered off.
|
||||
# Otherwise bad things may happen (like the modem never registering
|
||||
# on the network).
|
||||
#
|
||||
# On the other hand, with some RILs it's causing some trouble (like this
|
||||
# extra RIL_REQUEST_RADIO_POWER getting stuck indefinitely).
|
||||
#
|
||||
# Default true (for historical reasons)
|
||||
#
|
||||
#confirmRadioPowerOn=true
|
||||
|
||||
# Normally we should be able to have two simultaneously active data
|
||||
# contexts - one for mobile data and one for MMS. Some devices however
|
||||
# require that mobile data is disconnected before we can send or receive
|
||||
# MMS. In other words, activation of the second data context fails.
|
||||
#
|
||||
# Default false (more than one context is supported)
|
||||
#
|
||||
#singleDataContext=false
|
||||
|
||||
# Configures whether +0 is added to MCCMNC string passed to
|
||||
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL. Some Qualcomm RILs
|
||||
# require it, some MediaTek RILs don't like it.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#networkSelectionManual0=true
|
||||
|
||||
# Enables use of SET_DATA_PROFILE requests. Everything used to work without
|
||||
# profiles, that's why it's disabled by default.
|
||||
#
|
||||
# Default false
|
||||
#
|
||||
#useDataProfiles=false
|
||||
|
||||
# Configures MMS data profile ID. Must be non-zero.
|
||||
# This option is ignored if useDataProfiles is false.
|
||||
#
|
||||
# Default 2 (RIL_DATA_PROFILE_IMS)
|
||||
#
|
||||
#mmsDataProfileId=2
|
||||
|
||||
# Configures device state tracking (basically, power saving strategy).
|
||||
# Possible values are:
|
||||
#
|
||||
# ss = Use legacy device state management (RIL_REQUEST_SCREEN_STATE)
|
||||
# ds = Use newer device state management (RIL_REQUEST_SEND_DEVICE_STATE)
|
||||
# ur = Use URC filter (RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER)
|
||||
# This may be useful on devices with RIL version >= 15 if auto
|
||||
# method fails
|
||||
# auto = Choose ss or ds based on the RIL version
|
||||
# none = Disable device state management
|
||||
#
|
||||
# In addition to specifying ss, ds or ur method, one can specify a
|
||||
# combination of methods, e.g. ds+ur
|
||||
#
|
||||
# Default auto
|
||||
#
|
||||
#deviceStateTracking=auto
|
||||
|
||||
# On some phones (such as Jolla C), even if the slot which has been
|
||||
# using LTE gets powered off, we still need to explicitely set its
|
||||
# preferred mode to GSM, to make LTE machinery available to the other slot.
|
||||
#
|
||||
# Default true (false for MTK RILs)
|
||||
#
|
||||
#forceGsmWhenRadioOff=true
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -46,13 +47,28 @@ struct ril_modem;
|
||||
struct ril_radio;
|
||||
struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_vendor_hook;
|
||||
struct ril_vendor;
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
enum ofono_radio_access_mode techs;
|
||||
enum ril_pref_net_type lte_network_mode;
|
||||
enum ril_pref_net_type umts_network_mode;
|
||||
int network_mode_timeout;
|
||||
int network_selection_timeout;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean empty_pin_query;
|
||||
gboolean radio_power_cycle;
|
||||
gboolean confirm_radio_power_on;
|
||||
gboolean enable_voicecall;
|
||||
gboolean enable_cbs;
|
||||
gboolean enable_stk;
|
||||
gboolean network_selection_manual_0;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
gboolean use_data_profiles;
|
||||
guint mms_data_profile_id;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,46 +21,77 @@
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
|
||||
#define USSD_REQUEST_TIMEOUT_SEC (30)
|
||||
#define USSD_CANCEL_TIMEOUT_SEC (20)
|
||||
|
||||
struct ril_ussd {
|
||||
struct ofono_ussd *ussd;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
guint request_id;
|
||||
guint cancel_id;
|
||||
guint timer_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
struct ril_ussd_cbd {
|
||||
struct ril_ussd *ud;
|
||||
ofono_ussd_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_ussd_cbd_free g_free
|
||||
|
||||
static inline struct ril_ussd *ril_ussd_get_data(struct ofono_ussd *ussd)
|
||||
{
|
||||
return ofono_ussd_get_data(ussd);
|
||||
}
|
||||
|
||||
static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data)
|
||||
static struct ril_ussd_cbd *ril_ussd_cbd_new(struct ril_ussd *ud,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd_cbd *cbd = g_new0(struct ril_ussd_cbd, 1);
|
||||
struct ril_ussd_cbd *cbd = g_slice_new(struct ril_ussd_cbd);
|
||||
|
||||
cbd->ud = ud;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_ussd_cbd_free(void *cbd)
|
||||
{
|
||||
g_slice_free(struct ril_ussd_cbd, cbd);
|
||||
}
|
||||
|
||||
static void ril_ussd_cancel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
struct ril_ussd *ud = cbd->ud;
|
||||
|
||||
/* Always report sucessful completion, otherwise ofono may get
|
||||
* stuck in the USSD_STATE_ACTIVE state */
|
||||
GASSERT(ud->cancel_id);
|
||||
ud->cancel_id = 0;
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_response(GRilIoChannel* channel, int status,
|
||||
const void* data, guint len, void* user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
struct ril_ussd *ud = cbd->ud;
|
||||
|
||||
GASSERT(ud->request_id);
|
||||
ud->request_id = 0;
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
cbd->cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
const unsigned char *pdu, int len, ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
@@ -68,6 +100,12 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
|
||||
ofono_info("send ussd, len:%d", len);
|
||||
GASSERT(!ud->request_id);
|
||||
if (ud->request_id) {
|
||||
grilio_queue_cancel_request(ud->q, ud->request_id, FALSE);
|
||||
ud->request_id = 0;
|
||||
}
|
||||
|
||||
if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) {
|
||||
if (charset == SMS_CHARSET_7BIT) {
|
||||
unsigned char unpacked_buf[182];
|
||||
@@ -98,10 +136,15 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
}
|
||||
grilio_request_append_utf8_chars(req, (char*)
|
||||
unpacked_buf, length);
|
||||
grilio_queue_send_request(ud->q, req,
|
||||
RIL_REQUEST_SEND_USSD);
|
||||
grilio_request_set_timeout(req,
|
||||
USSD_REQUEST_TIMEOUT_SEC * 1000);
|
||||
ud->request_id =
|
||||
grilio_queue_send_request_full(ud->q,
|
||||
req, RIL_REQUEST_SEND_USSD,
|
||||
ril_ussd_response,
|
||||
ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(ud, cb, data));
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -114,11 +157,16 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
|
||||
ril_ussd_cancel_cb, ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(cb, data));
|
||||
GASSERT(!ud->cancel_id);
|
||||
grilio_queue_cancel_request(ud->q, ud->cancel_id, FALSE);
|
||||
grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000);
|
||||
ud->cancel_id = grilio_queue_send_request_full(ud->q, req,
|
||||
RIL_REQUEST_CANCEL_USSD, ril_ussd_cancel_cb,
|
||||
ril_ussd_cbd_free, ril_ussd_cbd_new(ud, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,14 +18,18 @@
|
||||
|
||||
#include <grilio_channel.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "netreg.h"
|
||||
|
||||
#define RIL_PROTO_IP_STR "IP"
|
||||
#define RIL_PROTO_IPV6_STR "IPV6"
|
||||
#define RIL_PROTO_IPV4V6_STR "IPV4V6"
|
||||
|
||||
const char *ril_error_to_string(int error)
|
||||
{
|
||||
#define RIL_E_(name) case RIL_E_##name: return #name
|
||||
@@ -235,6 +239,18 @@ const char *ril_request_to_string(guint request)
|
||||
RIL_REQUEST_(SHUTDOWN);
|
||||
RIL_REQUEST_(GET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(SET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(START_LCE);
|
||||
RIL_REQUEST_(STOP_LCE);
|
||||
RIL_REQUEST_(GET_ACTIVITY_INFO);
|
||||
RIL_REQUEST_(GET_CARRIER_RESTRICTIONS);
|
||||
RIL_REQUEST_(SEND_DEVICE_STATE);
|
||||
RIL_REQUEST_(SET_UNSOLICITED_RESPONSE_FILTER);
|
||||
RIL_REQUEST_(SET_SIM_CARD_POWER);
|
||||
RIL_REQUEST_(SET_CARRIER_INFO_IMSI_ENCRYPTION);
|
||||
RIL_REQUEST_(START_NETWORK_SCAN);
|
||||
RIL_REQUEST_(STOP_NETWORK_SCAN);
|
||||
RIL_REQUEST_(START_KEEPALIVE);
|
||||
RIL_REQUEST_(STOP_KEEPALIVE);
|
||||
case RIL_RESPONSE_ACKNOWLEDGEMENT:
|
||||
return "RESPONSE_ACK";
|
||||
default:
|
||||
@@ -321,12 +337,56 @@ const char *ril_radio_state_to_string(int radio_state)
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case OFONO_GPRS_PROTO_IPV6:
|
||||
return RIL_PROTO_IPV6_STR;
|
||||
case OFONO_GPRS_PROTO_IPV4V6:
|
||||
return RIL_PROTO_IPV4V6_STR;
|
||||
case OFONO_GPRS_PROTO_IP:
|
||||
return RIL_PROTO_IP_STR;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ril_protocol_to_ofono(const gchar *str)
|
||||
{
|
||||
if (str) {
|
||||
if (!strcmp(str, RIL_PROTO_IPV6_STR)) {
|
||||
return OFONO_GPRS_PROTO_IPV6;
|
||||
} else if (!strcmp(str, RIL_PROTO_IPV4V6_STR)) {
|
||||
return OFONO_GPRS_PROTO_IPV4V6;
|
||||
} else if (!strcmp(str, RIL_PROTO_IP_STR)) {
|
||||
return OFONO_GPRS_PROTO_IP;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth)
|
||||
{
|
||||
switch (auth) {
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
return RIL_AUTH_NONE;
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
return RIL_AUTH_CHAP;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
return RIL_AUTH_PAP;
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
/* Use default */
|
||||
break;
|
||||
}
|
||||
/* Default */
|
||||
return RIL_AUTH_BOTH;
|
||||
}
|
||||
|
||||
/* Returns enum access_technology or -1 on failure. */
|
||||
int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
int access_tech = -1;
|
||||
int tech = -1;
|
||||
if (ril_parse_int(stech, 0, &tech)) {
|
||||
if (gutil_parse_int(stech, 0, &tech)) {
|
||||
switch (tech) {
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
@@ -349,6 +409,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_LTE:
|
||||
case RADIO_TECH_LTE_CA:
|
||||
access_tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
break;
|
||||
default:
|
||||
@@ -411,26 +472,6 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_parse_int(const char *str, int base, int *value)
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (str && str[0]) {
|
||||
char *str2 = g_strstrip(g_strdup(str));
|
||||
char *end = str2;
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(str2, &end, base);
|
||||
ok = !*end && errno != ERANGE && l >= INT_MIN && l <= INT_MAX;
|
||||
if (ok && value) {
|
||||
*value = (int)l;
|
||||
}
|
||||
g_free(str2);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,15 +18,19 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
const char *ril_error_to_string(int error);
|
||||
const char *ril_request_to_string(guint request);
|
||||
const char *ril_unsol_event_to_string(guint event);
|
||||
const char *ril_radio_state_to_string(int radio_state);
|
||||
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto);
|
||||
int ril_protocol_to_ofono(const char *str);
|
||||
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth);
|
||||
int ril_parse_tech(const char *stech, int *ril_tech);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
gboolean ril_parse_int(const char *str, int base, int *value);
|
||||
|
||||
#define ril_error_init_ok(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,150 +15,200 @@
|
||||
*/
|
||||
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_vendor_impl.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;
|
||||
#include <grilio_channel.h>
|
||||
|
||||
/*
|
||||
* 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);
|
||||
G_DEFINE_ABSTRACT_TYPE(RilVendor, ril_vendor, G_TYPE_OBJECT)
|
||||
|
||||
/* Vendor driver descriptors are in the "__vendor" section */
|
||||
extern const struct ril_vendor_driver __start___vendor[];
|
||||
extern const struct ril_vendor_driver __stop___vendor[];
|
||||
|
||||
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name)
|
||||
{
|
||||
if (name) {
|
||||
const struct ril_vendor_driver *d;
|
||||
|
||||
for (d = __start___vendor; d < __stop___vendor; d++) {
|
||||
if (!strcasecmp(d->name, name)) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *self,
|
||||
const struct ril_vendor_hook_proc *proc)
|
||||
RilVendor *ril_vendor_create(const struct ril_vendor_driver *driver,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
self->proc = proc;
|
||||
g_atomic_int_set(&self->ref_count, 1);
|
||||
return self;
|
||||
return (driver && driver->create_vendor) ?
|
||||
driver->create_vendor(driver->driver_data, io, path, config) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *self)
|
||||
RilVendor *ril_vendor_ref(RilVendor *self)
|
||||
{
|
||||
if (self) {
|
||||
GASSERT(self->ref_count > 0);
|
||||
g_atomic_int_inc(&self->ref_count);
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_VENDOR(self));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static void ril_vendor_hook_free(struct ril_vendor_hook *self)
|
||||
void ril_vendor_unref(RilVendor *self)
|
||||
{
|
||||
const struct ril_vendor_hook_proc *proc = self->proc;
|
||||
|
||||
while (!proc->free && proc->base) {
|
||||
proc = proc->base;
|
||||
}
|
||||
if (proc->free) {
|
||||
proc->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);
|
||||
}
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_VENDOR(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);
|
||||
}
|
||||
if (vendor && vendor->get_defaults) {
|
||||
vendor->get_defaults(defaults);
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *self,
|
||||
guint request)
|
||||
const char *ril_vendor_request_to_string(RilVendor *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;
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
request_to_string(self, request) : NULL;
|
||||
}
|
||||
|
||||
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *self,
|
||||
guint event)
|
||||
const char *ril_vendor_event_to_string(RilVendor *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;
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
event_to_string(self, event) : NULL;
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *self,
|
||||
int tech, const char *profile, const char *apn,
|
||||
void ril_vendor_set_network(RilVendor *self, struct ril_network *nw)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
RIL_VENDOR_GET_CLASS(self)->set_network(self, nw);
|
||||
}
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_vendor_set_attach_apn_req(RilVendor *self, const char *apn,
|
||||
const char *user, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
set_attach_apn_req(self, apn, user, password, auth, proto) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_vendor_data_call_req(RilVendor *self, int tech,
|
||||
enum ril_data_profile 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;
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
data_call_req(self, tech, profile, apn, username, password,
|
||||
auth, proto) : NULL;
|
||||
}
|
||||
|
||||
while (!proc->data_call_req && proc->base) {
|
||||
proc = proc->base;
|
||||
gboolean ril_vendor_data_call_parse(RilVendor *self,
|
||||
struct ril_data_call *call, int ver, GRilIoParser *rilp)
|
||||
{
|
||||
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
|
||||
data_call_parse(self, call, ver, rilp);
|
||||
}
|
||||
|
||||
gboolean ril_vendor_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
|
||||
signal_strength_parse(self, signal_strength, rilp);
|
||||
}
|
||||
|
||||
static void ril_vendor_default_set_network(RilVendor *self,
|
||||
struct ril_network *network)
|
||||
{
|
||||
if (self->network != network) {
|
||||
if (self->network) {
|
||||
g_object_remove_weak_pointer(G_OBJECT(self->network),
|
||||
(gpointer*) &self->network);
|
||||
}
|
||||
if (proc->data_call_req) {
|
||||
return proc->data_call_req(self, tech, profile, apn,
|
||||
username, password, auth, proto);
|
||||
self->network = network;
|
||||
if (self->network) {
|
||||
g_object_add_weak_pointer(G_OBJECT(network),
|
||||
(gpointer*) &self->network);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_vendor_default_id_to_string(RilVendor *self, guint id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *self,
|
||||
struct ril_data_call *call, int ver, GRilIoParser *rilp)
|
||||
static GRilIoRequest *ril_vendor_default_set_attach_apn_req(RilVendor *self,
|
||||
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;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (!proc->data_call_parse && proc->base) {
|
||||
proc = proc->base;
|
||||
}
|
||||
if (proc->data_call_parse) {
|
||||
return proc->data_call_parse(self, call, ver, rilp);
|
||||
}
|
||||
}
|
||||
static GRilIoRequest *ril_vendor_default_data_call_req(RilVendor *self,
|
||||
int tech, enum ril_data_profile profile,
|
||||
const char *apn, const char *user, const char *passwd,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_default_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io)
|
||||
{
|
||||
self->io = grilio_channel_ref(io);
|
||||
}
|
||||
|
||||
static void ril_vendor_init(RilVendor *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void ril_vendor_finalize(GObject* object)
|
||||
{
|
||||
RilVendor *self = RIL_VENDOR(object);
|
||||
|
||||
if (self->network) {
|
||||
g_object_remove_weak_pointer(G_OBJECT(self->network),
|
||||
(gpointer*) &self->network);
|
||||
}
|
||||
grilio_channel_unref(self->io);
|
||||
G_OBJECT_CLASS(ril_vendor_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_vendor_class_init(RilVendorClass* klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_vendor_finalize;
|
||||
klass->set_network = ril_vendor_default_set_network;
|
||||
klass->request_to_string = ril_vendor_default_id_to_string;
|
||||
klass->event_to_string = ril_vendor_default_id_to_string;
|
||||
klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req;
|
||||
klass->data_call_req = ril_vendor_default_data_call_req;
|
||||
klass->data_call_parse = ril_vendor_default_data_call_parse;
|
||||
klass->signal_strength_parse = ril_vendor_default_signal_strength_parse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -21,72 +22,62 @@
|
||||
struct ril_vendor_defaults {
|
||||
gboolean empty_pin_query;
|
||||
gboolean legacy_imei_query;
|
||||
gboolean enable_cbs;
|
||||
gboolean enable_stk;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean use_data_profiles;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
guint mms_data_profile_id;
|
||||
};
|
||||
|
||||
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,
|
||||
struct ril_vendor *(*create_vendor)(const void *driver_data,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *cfg,
|
||||
struct ril_network *network);
|
||||
const struct ril_slot_config *cfg);
|
||||
};
|
||||
|
||||
struct ril_vendor_hook_proc {
|
||||
const struct ril_vendor_hook_proc *base;
|
||||
void (*free)(struct ril_vendor_hook *hook);
|
||||
const char *(*request_to_string)(struct ril_vendor_hook *hook,
|
||||
guint request);
|
||||
const char *(*event_to_string)(struct ril_vendor_hook *hook,
|
||||
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);
|
||||
struct ril_vendor_signal_strength {
|
||||
gint32 gsm; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 lte; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 qdbm; /* 4*dBm, 0 if none */
|
||||
};
|
||||
|
||||
struct ril_vendor_hook {
|
||||
const struct ril_vendor_hook_proc *proc;
|
||||
gint ref_count;
|
||||
};
|
||||
|
||||
struct ril_vendor_hook *ril_vendor_create_hook
|
||||
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
|
||||
struct ril_vendor *ril_vendor_create
|
||||
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||
const char *path, const struct ril_slot_config *cfg,
|
||||
struct ril_network *network);
|
||||
const char *path, const struct ril_slot_config *cfg);
|
||||
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);
|
||||
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *hook);
|
||||
void ril_vendor_hook_unref(struct ril_vendor_hook *hook);
|
||||
struct ril_vendor *ril_vendor_ref(struct ril_vendor *vendor);
|
||||
void ril_vendor_unref(struct ril_vendor *vendor);
|
||||
|
||||
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *hook,
|
||||
const char *ril_vendor_request_to_string(struct ril_vendor *vendor,
|
||||
guint request);
|
||||
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *hook,
|
||||
const char *ril_vendor_event_to_string(struct ril_vendor *vendor,
|
||||
guint event);
|
||||
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *hook,
|
||||
int tech, const char *profile, const char *apn,
|
||||
void ril_vendor_set_network(struct ril_vendor *vendor, struct ril_network *nw);
|
||||
GRilIoRequest *ril_vendor_set_attach_apn_req(struct ril_vendor *vendor,
|
||||
const char *apn, const char *username,
|
||||
const char *password, enum ril_auth auth,
|
||||
const char *proto);
|
||||
GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor, int tech,
|
||||
enum ril_data_profile 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,
|
||||
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean ril_vendor_signal_strength_parse(struct ril_vendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
|
||||
/* Put vendor driver descriptors to the "__vendor" section */
|
||||
#define RIL_VENDOR_DRIVER_DEFINE(name) \
|
||||
const struct ril_vendor_driver name \
|
||||
#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 */
|
||||
|
||||
|
||||
70
ofono/drivers/ril/ril_vendor_impl.h
Normal file
70
ofono/drivers/ril/ril_vendor_impl.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_IMPL_H
|
||||
#define RIL_VENDOR_IMPL_H
|
||||
|
||||
#include "ril_vendor.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
typedef struct ril_vendor {
|
||||
GObject parent;
|
||||
GRilIoChannel *io;
|
||||
struct ril_network *network;
|
||||
} RilVendor;
|
||||
|
||||
typedef struct ril_vendor_class {
|
||||
GObjectClass parent;
|
||||
void (*set_network)(RilVendor *vendor, struct ril_network *network);
|
||||
const char *(*request_to_string)(RilVendor *vendor, guint request);
|
||||
const char *(*event_to_string)(RilVendor *vendor, guint event);
|
||||
GRilIoRequest *(*set_attach_apn_req)(RilVendor *vendor,
|
||||
const char *apn, const char *username,
|
||||
const char *password, enum ril_auth auth,
|
||||
const char *proto);
|
||||
GRilIoRequest *(*data_call_req)(RilVendor *vendor, int tech,
|
||||
enum ril_data_profile profile, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto);
|
||||
gboolean (*data_call_parse)(RilVendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean (*signal_strength_parse)(RilVendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
} RilVendorClass;
|
||||
|
||||
GType ril_vendor_get_type(void);
|
||||
#define RIL_VENDOR_TYPE (ril_vendor_get_type())
|
||||
#define RIL_VENDOR(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_VENDOR_TYPE, RilVendor)
|
||||
#define RIL_VENDOR_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
RIL_VENDOR_TYPE, RilVendorClass)
|
||||
#define RIL_VENDOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
RIL_VENDOR_TYPE, RilVendorClass)
|
||||
|
||||
void ril_vendor_init_base(RilVendor *vendor, GRilIoChannel *io);
|
||||
|
||||
#endif /* RIL_VENDOR_IMPL_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -587,39 +587,75 @@ static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
|
||||
grilio_request_unref(ioreq);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
|
||||
static void ril_voicecall_hangup(struct ofono_voicecall *vc,
|
||||
gboolean (*filter)(struct ofono_call *call),
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall_request_data *req = NULL;
|
||||
GSList *l;
|
||||
|
||||
if (vd->calls) {
|
||||
GSList *l;
|
||||
struct ril_voicecall_request_data *req =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
/*
|
||||
* Here the idea is that we submit (potentially) multiple
|
||||
* hangup requests to RIL and invoke the callback after
|
||||
* the last request has completed (pending call count
|
||||
* becomes zero).
|
||||
*/
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
|
||||
/*
|
||||
* Here the idea is that we submit (potentially) multiple
|
||||
* hangup requests to RIL and invoke the callback after
|
||||
* the last request has completed (pending call count
|
||||
* becomes zero).
|
||||
*/
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
if (!filter || filter(call)) {
|
||||
if (!req) {
|
||||
req = ril_voicecall_request_data_new(vc, cb,
|
||||
data);
|
||||
}
|
||||
|
||||
/* Send request to RIL */
|
||||
DBG("Hanging up call with id %d", call->id);
|
||||
ril_voicecall_submit_hangup_req(vc, call->id, req);
|
||||
} else {
|
||||
DBG("Skipping call with id %d", call->id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Release our reference */
|
||||
if (req) {
|
||||
/* Release our reference (if any) */
|
||||
ril_voicecall_request_data_unref(req);
|
||||
} else {
|
||||
/* No calls */
|
||||
/* No requests were submitted */
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_voicecall_hangup_active_filter(struct ofono_call *call)
|
||||
{
|
||||
switch (call->status) {
|
||||
case CALL_STATUS_ACTIVE:
|
||||
case CALL_STATUS_DIALING:
|
||||
case CALL_STATUS_ALERTING:
|
||||
case CALL_STATUS_INCOMING:
|
||||
return TRUE;
|
||||
case CALL_STATUS_HELD:
|
||||
case CALL_STATUS_WAITING:
|
||||
case CALL_STATUS_DISCONNECTED:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_hangup(vc, ril_voicecall_hangup_active_filter, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_hangup(vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
|
||||
int id, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
@@ -657,7 +693,7 @@ static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
|
||||
grilio_parser_get_int32(&rilp, &type);
|
||||
grilio_parser_get_int32(&rilp, &code);
|
||||
grilio_parser_get_int32(&rilp, &index);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &phone.type);
|
||||
tmp = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
if (tmp) {
|
||||
@@ -668,13 +704,18 @@ static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
|
||||
phone.number[0] = 0;
|
||||
}
|
||||
|
||||
DBG("RIL data: MT/MO: %i, code: %i, index: %i", type, code, index);
|
||||
DBG("RIL data: MT/MO: %d, code: %d, index: %d", type, code, index);
|
||||
|
||||
/* 0 stands for MO intermediate (support TBD), 1 for MT unsolicited */
|
||||
if (type == 1) {
|
||||
switch (type) {
|
||||
case 0: /* MO intermediate result code */
|
||||
ofono_voicecall_ssn_mo_notify(vd->vc, 0, code, index);
|
||||
break;
|
||||
case 1: /* MT unsolicited result code */
|
||||
ofono_voicecall_ssn_mt_notify(vd->vc, 0, code, index, &phone);
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
ofono_error("Unknown SS notification");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,8 +852,7 @@ static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, NULL, cb, data);
|
||||
ril_voicecall_request(RIL_REQUEST_UDUB, vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
|
||||
@@ -946,6 +986,7 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
|
||||
.remove = ril_voicecall_remove,
|
||||
.dial = ril_voicecall_dial,
|
||||
.answer = ril_voicecall_answer,
|
||||
.hangup_active = ril_voicecall_hangup_active,
|
||||
.hangup_all = ril_voicecall_hangup_all,
|
||||
.release_specific = ril_voicecall_release_specific,
|
||||
.send_tones = ril_voicecall_send_dtmf,
|
||||
|
||||
255
ofono/drivers/xmm7modem/ims.c
Normal file
255
ofono/drivers/xmm7modem/ims.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
*
|
||||
* 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/log.h>
|
||||
#include <ofono/ims.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "xmm7modem.h"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *cireg_prefix[] = { "+CIREG:", NULL };
|
||||
|
||||
struct ims_driver_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void xmm_cireg_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_ims_status_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
GAtResultIter iter;
|
||||
int reg_info, ext_info;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (g_at_result_iter_next(&iter, "+CIREG:") == FALSE)
|
||||
goto error;
|
||||
|
||||
/* skip value of n */
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
if (g_at_result_iter_next_number(&iter, ®_info) == FALSE)
|
||||
goto error;
|
||||
|
||||
if (reg_info == 0)
|
||||
ext_info = -1;
|
||||
else
|
||||
if (g_at_result_iter_next_number(&iter, &ext_info) == FALSE)
|
||||
goto error;
|
||||
|
||||
cb(&error, reg_info, ext_info, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void xmm_ims_registration_status(struct ofono_ims *ims,
|
||||
ofono_ims_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ims_driver_data *idd = ofono_ims_get_data(ims);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(idd->chat, "AT+CIREG?", cireg_prefix,
|
||||
xmm_cireg_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void xmm_ims_register_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_ims_register_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 xmm_ims_register(struct ofono_ims *ims,
|
||||
ofono_ims_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ims_driver_data *idd = ofono_ims_get_data(ims);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(idd->chat, "AT+XIREG=1", none_prefix,
|
||||
xmm_ims_register_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void xmm_ims_unregister(struct ofono_ims *ims,
|
||||
ofono_ims_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ims_driver_data *idd = ofono_ims_get_data(ims);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(idd->chat, "AT+XIREG=0", none_prefix,
|
||||
xmm_ims_register_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ciregu_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_ims *ims = user_data;
|
||||
int reg_info, ext_info;
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CIREGU:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, ®_info))
|
||||
return;
|
||||
|
||||
if (reg_info == 0)
|
||||
ext_info = -1;
|
||||
else
|
||||
if (!g_at_result_iter_next_number(&iter, &ext_info))
|
||||
return;
|
||||
|
||||
DBG("reg_info:%d, ext_info:%d", reg_info, ext_info);
|
||||
|
||||
ofono_ims_status_notify(ims, reg_info, ext_info);
|
||||
}
|
||||
|
||||
static void xmm_cireg_set_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_ims *ims = user_data;
|
||||
|
||||
if (!ok) {
|
||||
ofono_ims_remove(ims);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_ims_register(ims);
|
||||
}
|
||||
|
||||
static void cireg_support_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_ims *ims = user_data;
|
||||
struct ims_driver_data *idd = ofono_ims_get_data(ims);
|
||||
|
||||
if (!ok) {
|
||||
ofono_ims_remove(ims);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_chat_register(idd->chat, "+CIREGU:", ciregu_notify,
|
||||
FALSE, ims, NULL);
|
||||
|
||||
g_at_chat_send(idd->chat, "AT+CIREG=2", none_prefix,
|
||||
xmm_cireg_set_cb, ims, NULL);
|
||||
}
|
||||
|
||||
static int xmm_ims_probe(struct ofono_ims *ims, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct ims_driver_data *idd;
|
||||
|
||||
DBG("at ims probe");
|
||||
|
||||
idd = g_try_new0(struct ims_driver_data, 1);
|
||||
if (!idd)
|
||||
return -ENOMEM;
|
||||
|
||||
idd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_ims_set_data(ims, idd);
|
||||
|
||||
g_at_chat_send(idd->chat, "AT+CIREG=?", cireg_prefix,
|
||||
cireg_support_cb, ims, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xmm_ims_remove(struct ofono_ims *ims)
|
||||
{
|
||||
struct ims_driver_data *idd = ofono_ims_get_data(ims);
|
||||
|
||||
DBG("at ims remove");
|
||||
|
||||
g_at_chat_unref(idd->chat);
|
||||
|
||||
ofono_ims_set_data(ims, NULL);
|
||||
|
||||
g_free(idd);
|
||||
}
|
||||
|
||||
static struct ofono_ims_driver driver = {
|
||||
.name = "xmm7modem",
|
||||
.probe = xmm_ims_probe,
|
||||
.remove = xmm_ims_remove,
|
||||
.ims_register = xmm_ims_register,
|
||||
.ims_unregister = xmm_ims_unregister,
|
||||
.registration_status = xmm_ims_registration_status,
|
||||
};
|
||||
|
||||
void xmm_ims_init(void)
|
||||
{
|
||||
ofono_ims_driver_register(&driver);
|
||||
}
|
||||
|
||||
void xmm_ims_exit(void)
|
||||
{
|
||||
ofono_ims_driver_unregister(&driver);
|
||||
}
|
||||
@@ -36,6 +36,7 @@
|
||||
static int xmm7modem_init(void)
|
||||
{
|
||||
xmm_radio_settings_init();
|
||||
xmm_ims_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -43,6 +44,7 @@ static int xmm7modem_init(void)
|
||||
static void xmm7modem_exit(void)
|
||||
{
|
||||
xmm_radio_settings_exit();
|
||||
xmm_ims_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(xmm7modem, "Intel xmm7xxx series modem driver",
|
||||
|
||||
@@ -25,3 +25,6 @@
|
||||
|
||||
extern void xmm_radio_settings_init(void);
|
||||
extern void xmm_radio_settings_exit(void);
|
||||
|
||||
extern void xmm_ims_init(void);
|
||||
extern void xmm_ims_exit(void);
|
||||
|
||||
@@ -54,7 +54,7 @@ static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
|
||||
unsigned int len = sizeof(saddr);
|
||||
int fd;
|
||||
struct ofono_emulator *em;
|
||||
struct ofono_modem *modem;
|
||||
GList *i;
|
||||
|
||||
if (cond != G_IO_IN)
|
||||
return FALSE;
|
||||
@@ -63,15 +63,16 @@ static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
|
||||
if (fd == -1)
|
||||
return FALSE;
|
||||
|
||||
/* Pick the first powered modem */
|
||||
modem = modems->data;
|
||||
DBG("Picked modem %p for emulator", modem);
|
||||
DBG("Using all modems for emulator.");
|
||||
|
||||
em = ofono_emulator_create(modem, GPOINTER_TO_INT(user));
|
||||
if (em == NULL)
|
||||
close(fd);
|
||||
else
|
||||
em = ofono_emulator_create(GPOINTER_TO_INT(user));
|
||||
|
||||
if (em) {
|
||||
for (i = modems; i; i = i->next)
|
||||
ofono_emulator_add_modem(em, i->data);
|
||||
ofono_emulator_register(em, fd);
|
||||
} else
|
||||
close(fd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
166
ofono/include/dbus-access.h
Normal file
166
ofono/include/dbus-access.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_DBUS_ACCESS_H
|
||||
#define __OFONO_DBUS_ACCESS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
enum ofono_dbus_access {
|
||||
OFONO_DBUS_ACCESS_DENY, /* Deny access */
|
||||
OFONO_DBUS_ACCESS_ALLOW, /* Allow access */
|
||||
OFONO_DBUS_ACCESS_DONT_CARE /* No decision */
|
||||
};
|
||||
|
||||
enum ofono_dbus_access_intf {
|
||||
OFONO_DBUS_ACCESS_INTF_MESSAGE, /* org.ofono.Message */
|
||||
OFONO_DBUS_ACCESS_INTF_MESSAGEMGR, /* org.ofono.MessageManager */
|
||||
OFONO_DBUS_ACCESS_INTF_VOICECALL, /* org.ofono.VoiceCall */
|
||||
OFONO_DBUS_ACCESS_INTF_VOICECALLMGR, /* org.ofono.VoiceCallManager */
|
||||
OFONO_DBUS_ACCESS_INTF_CONNCTX, /* org.ofono.ConnectionContext */
|
||||
OFONO_DBUS_ACCESS_INTF_CONNMGR, /* org.ofono.ConnectionManager */
|
||||
OFONO_DBUS_ACCESS_INTF_SIMMGR, /* org.ofono.SimManager */
|
||||
OFONO_DBUS_ACCESS_INTF_MODEM, /* org.ofono.Modem */
|
||||
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */
|
||||
OFONO_DBUS_ACCESS_INTF_STK, /* org.ofono.SimToolkit */
|
||||
OFONO_DBUS_ACCESS_INTF_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_MESSAGE */
|
||||
enum ofono_dbus_access_message_method {
|
||||
OFONO_DBUS_ACCESS_MESSAGE_CANCEL,
|
||||
OFONO_DBUS_ACCESS_MESSAGE_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_MESSAGEMGR */
|
||||
enum ofono_dbus_access_messagemgr_method {
|
||||
OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_MESSAGE,
|
||||
OFONO_DBUS_ACCESS_MESSAGEMGR_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_VOICECALL */
|
||||
enum ofono_dbus_access_voicecall_method {
|
||||
OFONO_DBUS_ACCESS_VOICECALL_DEFLECT,
|
||||
OFONO_DBUS_ACCESS_VOICECALL_HANGUP,
|
||||
OFONO_DBUS_ACCESS_VOICECALL_ANSWER,
|
||||
OFONO_DBUS_ACCESS_VOICECALL_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_VOICECALLMGR */
|
||||
enum ofono_dbus_access_voicecallmgr_method {
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_DIAL,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_TRANSFER,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_SWAP_CALLS,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_RELEASE_AND_ANSWER,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_RELEASE_AND_SWAP,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_HOLD_AND_ANSWER,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_HANGUP_ALL,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_CREATE_MULTIPARTY,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_HANGUP_MULTIPARTY,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_SEND_TONES,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_REGISTER_VOICECALL_AGENT,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_UNREGISTER_VOICECALL_AGENT,
|
||||
OFONO_DBUS_ACCESS_VOICECALLMGR_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_CONNCTX */
|
||||
enum ofono_dbus_access_connctx_method {
|
||||
OFONO_DBUS_ACCESS_CONNCTX_SET_PROPERTY,
|
||||
OFONO_DBUS_ACCESS_CONNCTX_PROVISION_CONTEXT,
|
||||
OFONO_DBUS_ACCESS_CONNCTX_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_CONNMGR */
|
||||
enum ofono_dbus_access_connmgr_method {
|
||||
OFONO_DBUS_ACCESS_CONNMGR_SET_PROPERTY,
|
||||
OFONO_DBUS_ACCESS_CONNMGR_DEACTIVATE_ALL,
|
||||
OFONO_DBUS_ACCESS_CONNMGR_RESET_CONTEXTS,
|
||||
OFONO_DBUS_ACCESS_CONNMGR_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_SIMMGR */
|
||||
enum ofono_dbus_access_simmgr_method {
|
||||
OFONO_DBUS_ACCESS_SIMMGR_SET_PROPERTY,
|
||||
OFONO_DBUS_ACCESS_SIMMGR_CHANGE_PIN,
|
||||
OFONO_DBUS_ACCESS_SIMMGR_ENTER_PIN,
|
||||
OFONO_DBUS_ACCESS_SIMMGR_RESET_PIN,
|
||||
OFONO_DBUS_ACCESS_SIMMGR_LOCK_PIN,
|
||||
OFONO_DBUS_ACCESS_SIMMGR_UNLOCK_PIN,
|
||||
OFONO_DBUS_ACCESS_SIMMGR_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_MODEM */
|
||||
enum ofono_dbus_access_modem_method {
|
||||
OFONO_DBUS_ACCESS_MODEM_SET_PROPERTY,
|
||||
OFONO_DBUS_ACCESS_MODEM_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS */
|
||||
enum ofono_dbus_access_radiosettings_method {
|
||||
OFONO_DBUS_ACCESS_RADIOSETTINGS_SET_PROPERTY,
|
||||
OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_STK */
|
||||
enum ofono_dbus_access_stk_method {
|
||||
OFONO_DBUS_ACCESS_STK_REGISTER_AGENT,
|
||||
OFONO_DBUS_ACCESS_STK_METHOD_COUNT
|
||||
};
|
||||
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100)
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100)
|
||||
|
||||
struct ofono_dbus_access_plugin {
|
||||
const char *name;
|
||||
int priority;
|
||||
enum ofono_dbus_access (*method_access)(const char *sender,
|
||||
enum ofono_dbus_access_intf intf,
|
||||
int method, const char *arg);
|
||||
|
||||
void (*_reserved[10])(void);
|
||||
|
||||
/* api_level will remain zero (and ignored) until we run out of
|
||||
* the above placeholders. */
|
||||
int api_level;
|
||||
};
|
||||
|
||||
int ofono_dbus_access_plugin_register
|
||||
(const struct ofono_dbus_access_plugin *plugin);
|
||||
void ofono_dbus_access_plugin_unregister
|
||||
(const struct ofono_dbus_access_plugin *plugin);
|
||||
|
||||
const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf);
|
||||
const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
|
||||
int method);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_DBUS_ACCESS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -59,12 +59,16 @@ extern "C" {
|
||||
#define OFONO_LOCATION_REPORTING_INTERFACE OFONO_SERVICE ".LocationReporting"
|
||||
#define OFONO_GNSS_INTERFACE "org.ofono.AssistedSatelliteNavigation"
|
||||
#define OFONO_GNSS_POSR_AGENT_INTERFACE "org.ofono.PositioningRequestAgent"
|
||||
#define OFONO_USIM_APPLICATION_INTERFACE "org.ofono.USimApplication"
|
||||
#define OFONO_ISIM_APPLICATION_INTERFACE "org.ofono.ISimApplication"
|
||||
#define OFONO_SIM_AUTHENTICATION_INTERFACE "org.ofono.SimAuthentication"
|
||||
#define OFONO_HANDSFREE_INTERFACE OFONO_SERVICE ".Handsfree"
|
||||
#define OFONO_NETWORK_TIME_INTERFACE OFONO_SERVICE ".NetworkTime"
|
||||
#define OFONO_SIRI_INTERFACE OFONO_SERVICE ".Siri"
|
||||
#define OFONO_NETMON_INTERFACE OFONO_SERVICE ".NetworkMonitor"
|
||||
#define OFONO_NETMON_AGENT_INTERFACE OFONO_SERVICE ".NetworkMonitorAgent"
|
||||
#define OFONO_LTE_INTERFACE OFONO_SERVICE ".LongTermEvolution"
|
||||
#define OFONO_IMS_INTERFACE OFONO_SERVICE ".IpMultimediaSystem"
|
||||
|
||||
/* CDMA Interfaces */
|
||||
#define OFONO_CDMA_VOICECALL_MANAGER_INTERFACE "org.ofono.cdma.VoiceCallManager"
|
||||
|
||||
@@ -63,6 +63,8 @@ void ofono_devinfo_remove(struct ofono_devinfo *info);
|
||||
void ofono_devinfo_set_data(struct ofono_devinfo *info, void *data);
|
||||
void *ofono_devinfo_get_data(struct ofono_devinfo *info);
|
||||
|
||||
struct ofono_modem *ofono_devinfo_get_modem(struct ofono_devinfo *info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -68,8 +68,9 @@ typedef void (*ofono_emulator_request_cb_t)(struct ofono_emulator *em,
|
||||
struct ofono_emulator_request *req,
|
||||
void *data);
|
||||
|
||||
struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
|
||||
enum ofono_emulator_type type);
|
||||
struct ofono_emulator *ofono_emulator_create(enum ofono_emulator_type type);
|
||||
void ofono_emulator_add_modem(struct ofono_emulator *em,
|
||||
struct ofono_modem *modem);
|
||||
|
||||
void ofono_emulator_register(struct ofono_emulator *em, int fd);
|
||||
|
||||
|
||||
@@ -122,6 +122,8 @@ void ofono_gprs_context_set_ipv4_address(struct ofono_gprs_context *gc,
|
||||
ofono_bool_t static_ip);
|
||||
void ofono_gprs_context_set_ipv4_netmask(struct ofono_gprs_context *gc,
|
||||
const char *netmask);
|
||||
void ofono_gprs_context_set_ipv4_prefix_length(struct ofono_gprs_context *gc,
|
||||
unsigned int prefix);
|
||||
void ofono_gprs_context_set_ipv4_gateway(struct ofono_gprs_context *gc,
|
||||
const char *gateway);
|
||||
void ofono_gprs_context_set_ipv4_dns_servers(struct ofono_gprs_context *gc,
|
||||
|
||||
84
ofono/include/gprs-filter.h
Normal file
84
ofono/include/gprs-filter.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_GPRS_FILTER_H
|
||||
#define __OFONO_GPRS_FILTER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_gprs;
|
||||
struct ofono_gprs_context;
|
||||
struct ofono_gprs_primary_context;
|
||||
|
||||
/* If ctx is NULL then activation gets cancelled */
|
||||
typedef void (*ofono_gprs_filter_activate_cb_t)
|
||||
(const struct ofono_gprs_primary_context *ctx, void *data);
|
||||
typedef void (*ofono_gprs_filter_check_cb_t)(ofono_bool_t allow, void *data);
|
||||
|
||||
#define OFONO_GPRS_FILTER_PRIORITY_LOW (-100)
|
||||
#define OFONO_GPRS_FILTER_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_GPRS_FILTER_PRIORITY_HIGH (100)
|
||||
|
||||
/*
|
||||
* The api_version field makes it possible to keep using old plugins
|
||||
* even if struct ofono_gprs_filter gets extended with new callbacks.
|
||||
*/
|
||||
|
||||
#define OFONO_GPRS_FILTER_API_VERSION (1)
|
||||
|
||||
/*
|
||||
* The filter callbacks either invoke the completion callback directly
|
||||
* or return the id of the cancellable asynchronous operation (but never
|
||||
* both). If non-zero value is returned, the completion callback has to
|
||||
* be invoked later on a fresh stack. Once the asynchronous filtering
|
||||
* operation is cancelled, the associated completion callback must not
|
||||
* be invoked.
|
||||
*
|
||||
* Please avoid making blocking D-Bus calls from the filter callbacks.
|
||||
*/
|
||||
struct ofono_gprs_filter {
|
||||
const char *name;
|
||||
int api_version; /* OFONO_GPRS_FILTER_API_VERSION */
|
||||
int priority;
|
||||
void (*cancel)(unsigned int id);
|
||||
unsigned int (*filter_activate)(struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ofono_gprs_filter_activate_cb_t cb,
|
||||
void *data);
|
||||
/* API version 1 */
|
||||
unsigned int (*filter_check)(struct ofono_gprs *gprs,
|
||||
ofono_gprs_filter_check_cb_t cb, void *data);
|
||||
};
|
||||
|
||||
int ofono_gprs_filter_register(const struct ofono_gprs_filter *filter);
|
||||
void ofono_gprs_filter_unregister(const struct ofono_gprs_filter *filter);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OFONO_GPRS_FILTER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user