mirror of
https://github.com/sailfishos/ofono
synced 2025-11-24 11:29:46 +08:00
Compare commits
703 Commits
mer/1.20+g
...
upgrade-4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deecd829a6 | ||
|
|
3acf91c6a9 | ||
|
|
85b61c8964 | ||
|
|
8986749585 | ||
|
|
1c0f5094a6 | ||
|
|
4208b6d9ea | ||
|
|
59e304d474 | ||
|
|
30a2424507 | ||
|
|
e4f3ec6322 | ||
|
|
95fd4efc37 | ||
|
|
ef5ee98508 | ||
|
|
4220e7d5e8 | ||
|
|
33c067a75f | ||
|
|
29616c04d0 | ||
|
|
beb997d914 | ||
|
|
cefc03e5ed | ||
|
|
85d99536ee | ||
|
|
ea36baa4c1 | ||
|
|
b95a089c00 | ||
|
|
c8dbf5494b | ||
|
|
cfb75f473d | ||
|
|
edd91c94eb | ||
|
|
af0ab142e1 | ||
|
|
dffc04d404 | ||
|
|
97b5fcbd87 | ||
|
|
d7e740347f | ||
|
|
1116ca2481 | ||
|
|
3d147843c4 | ||
|
|
c01dc63cbc | ||
|
|
297926ed24 | ||
|
|
6ef1174ea8 | ||
|
|
4ad02792db | ||
|
|
eddcb88af4 | ||
|
|
f91df7f0fd | ||
|
|
9d220ff9be | ||
|
|
deefa2c454 | ||
|
|
80224b283d | ||
|
|
07e07b6ddc | ||
|
|
bd836b4499 | ||
|
|
6c289b1432 | ||
|
|
296e46487f | ||
|
|
09e98234aa | ||
|
|
0f4cdba932 | ||
|
|
870bac93e9 | ||
|
|
246cd4e1d2 | ||
|
|
ca20b65098 | ||
|
|
8e35a047da | ||
|
|
2b4b5a224d | ||
|
|
50a5f2547e | ||
|
|
d682fcd5fe | ||
|
|
5799320480 | ||
|
|
3eea7c868e | ||
|
|
4844fc6cf9 | ||
|
|
6976366051 | ||
|
|
d3d776837b | ||
|
|
f56c8a33b0 | ||
|
|
ed2f625b8b | ||
|
|
ed62d38632 | ||
|
|
3f433c97c5 | ||
|
|
86d8149c79 | ||
|
|
f3eb9b868b | ||
|
|
4e067fa827 | ||
|
|
2ee5e4c827 | ||
|
|
1366e426be | ||
|
|
586c9b9262 | ||
|
|
83554e071a | ||
|
|
dc41c2d003 | ||
|
|
550d41ae37 | ||
|
|
60e4246d93 | ||
|
|
50619607b0 | ||
|
|
98b357f365 | ||
|
|
56c488d10c | ||
|
|
944cd603e8 | ||
|
|
77be0d5e98 | ||
|
|
d8dd20092c | ||
|
|
c7faa21172 | ||
|
|
98ffc61a03 | ||
|
|
f2b1625872 | ||
|
|
2d5a22284e | ||
|
|
9d742180ab | ||
|
|
f8b0ccc1b4 | ||
|
|
7a54bb8cbe | ||
|
|
56e0923dc3 | ||
|
|
6dfce4b5e9 | ||
|
|
4ec3568d71 | ||
|
|
9b2b7127ef | ||
|
|
1053577376 | ||
|
|
22197b5e04 | ||
|
|
3a358ddc9d | ||
|
|
53929f9f1a | ||
|
|
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 | ||
|
|
9bf50bb3e3 | ||
|
|
d2353c46a8 | ||
|
|
6701b53737 | ||
|
|
6612bfa1da | ||
|
|
c732d5192d | ||
|
|
6815772b17 | ||
|
|
e4766ef2c4 | ||
|
|
7aa396636b | ||
|
|
096cd04044 | ||
|
|
5eabe96602 | ||
|
|
05dec021c0 | ||
|
|
6f7209b045 | ||
|
|
a766281a02 | ||
|
|
13b4802bec | ||
|
|
e1547fdaf4 | ||
|
|
08c36b2885 | ||
|
|
0180c9febf | ||
|
|
49034cfc69 | ||
|
|
4685e3f0de | ||
|
|
72be5bdff2 | ||
|
|
79c1abfdd3 | ||
|
|
c88cffaa2e | ||
|
|
17e66090ec | ||
|
|
100cf7df1d | ||
|
|
280ed19215 | ||
|
|
ae0f5b0ff6 | ||
|
|
dbfc642eb3 | ||
|
|
e5e5108913 | ||
|
|
9035db3129 | ||
|
|
81391a4101 | ||
|
|
60d449c01d | ||
|
|
b0ccc39866 | ||
|
|
bd2aa28405 | ||
|
|
67e31bb519 | ||
|
|
b848827976 | ||
|
|
ab6764dcc0 | ||
|
|
da42039c80 | ||
|
|
392c00c65e | ||
|
|
7a0fe98d95 | ||
|
|
d508a2f2bb | ||
|
|
8f070cf583 | ||
|
|
d2d8117723 | ||
|
|
6897e57353 | ||
|
|
6a8c2aa9c1 | ||
|
|
076e388d45 | ||
|
|
bcafe0dc3d | ||
|
|
9272075f55 | ||
|
|
526072d7a3 | ||
|
|
0680063527 | ||
|
|
4e08680e5f | ||
|
|
1d85caa7f9 | ||
|
|
db0ef91c81 | ||
|
|
54d8c78a50 | ||
|
|
905c886269 | ||
|
|
f0c7a373ae | ||
|
|
4673da16d5 | ||
|
|
0dc2acee4e | ||
|
|
f749284029 | ||
|
|
778b9f08aa | ||
|
|
40db3f7067 | ||
|
|
e198cf04c0 | ||
|
|
fbd59ba56f | ||
|
|
cff9ded7e6 | ||
|
|
c74386b5e6 | ||
|
|
028f54c26f | ||
|
|
c066f34ea1 | ||
|
|
b1c79d5cae | ||
|
|
0cc61dcfe8 | ||
|
|
5852bebda0 | ||
|
|
768c028a11 | ||
|
|
6b93ea0cc6 | ||
|
|
4a485a7aa0 | ||
|
|
f6fb277cf4 | ||
|
|
03f150838b | ||
|
|
9731ca1a87 | ||
|
|
a09f4c070d | ||
|
|
f018f5a255 | ||
|
|
286396bf91 | ||
|
|
5d6baccced | ||
|
|
514f4cf9cc | ||
|
|
ff8408e6dd | ||
|
|
df1294d77c | ||
|
|
2323ebacb3 | ||
|
|
c780eff0ce | ||
|
|
373248a35b | ||
|
|
fe219b648d | ||
|
|
33f55c569f | ||
|
|
d6cf954354 | ||
|
|
d8e852cb5e | ||
|
|
83e3ec0e98 | ||
|
|
e35f537f72 | ||
|
|
c7daf5aa43 | ||
|
|
490a9c06f4 | ||
|
|
320b3f4605 | ||
|
|
e35dae17d9 | ||
|
|
f4522f4a00 | ||
|
|
ce85c94426 | ||
|
|
4027bdc04e | ||
|
|
c57f99bf01 | ||
|
|
54d610ce6a | ||
|
|
f7f9e32743 | ||
|
|
8c9e370486 | ||
|
|
19b80236f6 | ||
|
|
2ec6fc749d | ||
|
|
0a3bdd20f4 | ||
|
|
284919e76a | ||
|
|
ddcbb89fa1 | ||
|
|
5ec6b8e7ec | ||
|
|
f94681f6f6 | ||
|
|
de8edc84fa | ||
|
|
90faf1b3a5 | ||
|
|
2b139b6974 | ||
|
|
168f193efb | ||
|
|
32d8b5ccfc | ||
|
|
f400ceff80 | ||
|
|
2186c60630 | ||
|
|
d5fb195e2f | ||
|
|
cbb08079d2 | ||
|
|
0583a831fb | ||
|
|
a8a0758e90 | ||
|
|
9e267487f4 | ||
|
|
c8a774dfee | ||
|
|
b88518d0f3 | ||
|
|
b223ccc675 | ||
|
|
947a41a5fc | ||
|
|
e0b4e8694d | ||
|
|
c8db770c99 | ||
|
|
1534143e31 | ||
|
|
d9ad9caf30 | ||
|
|
71de574e87 |
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>
|
||||
17
ofono/.gitignore
vendored
17
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,17 +44,32 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-dbus-access
|
||||
unit/test-dbus-clients
|
||||
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-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>
|
||||
@@ -123,3 +124,9 @@ Piotr Haber <gluedig@gmail.com>
|
||||
André Draszik <git@andred.net>
|
||||
Lukasz Nowak <lnowak@tycoint.com>
|
||||
Jonas Bonn <jonas@southpole.se>
|
||||
Matthijs Kooijman <matthijs@stdin.nl>
|
||||
Clayton Craft <clayton@craftyguy.net>
|
||||
Joey Hewitt <joey@joeyhewitt.com>
|
||||
Richard Röjfors <richard.rojfors@gmail.com>
|
||||
Philippe De Swert <philippe.deswert@nomovok.com>
|
||||
Gabriel Lucas <gabriel.lucas@smile.fr>
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
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.
|
||||
Fix issue with LTE bearer reporting and Huawei modems.
|
||||
Fix issue with invalid memory access and QMI.
|
||||
Add support for QMI SIM writing functionality.
|
||||
Add support for RAT selection for QMI modems.
|
||||
Add support for network monitor agent interface.
|
||||
Add support for Cinterion Hardware Monitor interface.
|
||||
Add support for LTE atom driver for Huawei modems.
|
||||
Add support for LTE atom driver for AT modems.
|
||||
Add support for Intel xmm7xxx series modems.
|
||||
|
||||
ver 1.20:
|
||||
Fix issue with context removal before activation.
|
||||
Fix issue with update during GPRS context activation.
|
||||
|
||||
@@ -23,16 +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/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/dbus-clients.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)))
|
||||
@@ -64,7 +63,7 @@ endif
|
||||
builtin_modules =
|
||||
builtin_sources =
|
||||
builtin_libadd =
|
||||
builtin_cflags =
|
||||
builtin_cflags = -DSAILFISH_OS
|
||||
|
||||
noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
|
||||
|
||||
@@ -127,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
|
||||
@@ -141,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 \
|
||||
@@ -164,8 +175,12 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
drivers/ril/ril_ussd.c \
|
||||
drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_vendor.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
# Vendor specific extensions
|
||||
builtin_sources += drivers/ril/ril_vendor_mtk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
@@ -275,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) \
|
||||
@@ -291,8 +307,10 @@ 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/location-reporting.c \
|
||||
drivers/qmimodem/netmon.c
|
||||
|
||||
builtin_modules += gobi
|
||||
builtin_sources += plugins/gobi.c
|
||||
@@ -322,8 +340,8 @@ 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/gnss.c \
|
||||
drivers/atmodem/lte.c
|
||||
|
||||
builtin_modules += nwmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
@@ -454,6 +472,12 @@ builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/gemaltomodem/gemaltomodem.c \
|
||||
drivers/gemaltomodem/location-reporting.c
|
||||
|
||||
builtin_modules += xmm7modem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/xmm7modem/xmm7modem.h \
|
||||
drivers/xmm7modem/xmm7modem.c \
|
||||
drivers/xmm7modem/radio-settings.c \
|
||||
drivers/xmm7modem/ims.c
|
||||
|
||||
if PHONESIM
|
||||
builtin_modules += phonesim
|
||||
@@ -549,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
|
||||
|
||||
@@ -561,8 +582,8 @@ builtin_sources += plugins/quectel.c
|
||||
builtin_modules += ublox
|
||||
builtin_sources += plugins/ublox.c
|
||||
|
||||
builtin_modules += he910
|
||||
builtin_sources += plugins/he910.c
|
||||
builtin_modules += xmm7xxx
|
||||
builtin_sources += plugins/xmm7xxx.c
|
||||
endif
|
||||
|
||||
builtin_modules += connman
|
||||
@@ -694,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 \
|
||||
@@ -723,9 +774,13 @@ 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-clients.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) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -735,7 +790,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
|
||||
|
||||
@@ -751,7 +807,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 \
|
||||
@@ -774,7 +831,9 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/telit-modem.txt \
|
||||
doc/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt \
|
||||
doc/lte-api.txt
|
||||
doc/lte-api.txt \
|
||||
doc/cinterion-hardware-monitor-api.txt \
|
||||
doc/ims-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -882,7 +941,12 @@ test_scripts = test/backtrace \
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling \
|
||||
test/set-lte-property
|
||||
test/set-lte-property \
|
||||
test/test-serving-cell-info \
|
||||
test/ims-register \
|
||||
test/ims-unregister \
|
||||
test/list-applications
|
||||
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -902,46 +966,114 @@ unit_objects =
|
||||
|
||||
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
||||
unit/test-simutil unit/test-stkutil \
|
||||
unit/test-sms unit/test-cdmasms \
|
||||
unit/test-provision unit/test-sms-filter
|
||||
unit/test-sms unit/test-cdmasms
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-Iplugins/sailfish_cell_info
|
||||
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
|
||||
|
||||
unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||
unit/test-sailfish_cell_info_dbus.c \
|
||||
unit/fake_sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
gdbus/object.c src/dbus-clients.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@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_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/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
@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_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)
|
||||
@@ -949,6 +1081,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 \
|
||||
@@ -959,6 +1099,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
|
||||
|
||||
@@ -1018,6 +1165,22 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_dbus_clients_SOURCES = unit/test-dbus-clients.c unit/test-dbus.c \
|
||||
src/dbus-clients.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_clients_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_clients_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_clients_OBJECTS)
|
||||
unit_tests += unit/test-dbus-clients
|
||||
|
||||
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||
src/dbus-queue.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_queue_OBJECTS)
|
||||
unit_tests += unit/test-dbus-queue
|
||||
|
||||
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
plugins/provision.h plugins/mbpi.c \
|
||||
plugins/sailfish_provision.c \
|
||||
@@ -1025,12 +1188,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 \
|
||||
@@ -1069,6 +1256,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
|
||||
@@ -1163,6 +1356,10 @@ include/ofono/version.h: include/version.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
|
||||
|
||||
include/ofono/gdbus.h: $(abs_top_srcdir)/gdbus/gdbus.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $< $@
|
||||
|
||||
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $< $@
|
||||
|
||||
@@ -22,6 +22,7 @@ AC_DEFUN([COMPILER_FLAGS], [
|
||||
CFLAGS="$CFLAGS -Wmissing-declarations"
|
||||
CFLAGS="$CFLAGS -Wredundant-decls"
|
||||
CFLAGS="$CFLAGS -Wcast-align"
|
||||
CFLAGS="$CFLAGS -Wno-format-truncation"
|
||||
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.20)
|
||||
AC_INIT(ofono, 1.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.18, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.18 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.38, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.38 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,6 +204,11 @@ AC_ARG_ENABLE(sailfish-manager,
|
||||
[enable_sailfish_manager=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
|
||||
|
||||
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]), [
|
||||
if (test "${enableval}" = "no"); then
|
||||
@@ -285,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}])
|
||||
@@ -296,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],
|
||||
@@ -317,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
|
||||
|
||||
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
HardwareMonitor hierarchy
|
||||
=========================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.cinterion.HardwareMonitor
|
||||
Object path /{device0,device1,...}
|
||||
|
||||
Methods array{string,variant} GetStatistics
|
||||
|
||||
Returns an array of dict entries representing the
|
||||
current temperature and supply voltage of the modem.
|
||||
|
||||
Units:
|
||||
Temperature: Celsius
|
||||
Voltage: mV
|
||||
@@ -278,6 +278,13 @@ Properties boolean Active [readwrite]
|
||||
via this proxy. All other values are left
|
||||
out in this case.
|
||||
|
||||
array{string} ProxyCSCF [readonly, optional]
|
||||
|
||||
Holds the list of P-CSCF (SIP proxy) for this
|
||||
context. Only used by IMS connections.
|
||||
|
||||
This is a Sailfish OS specific extension.
|
||||
|
||||
dict IPv6.Settings [readonly, optional]
|
||||
|
||||
Holds all the IPv6 network settings
|
||||
@@ -304,6 +311,13 @@ Properties boolean Active [readwrite]
|
||||
|
||||
Holds the gateway IP for this connection.
|
||||
|
||||
array{string} ProxyCSCF [readonly, optional]
|
||||
|
||||
Holds the list of P-CSCF (SIP proxy) for this
|
||||
context. Only used by IMS connections.
|
||||
|
||||
This is a Sailfish OS specific extension.
|
||||
|
||||
string MessageProxy [readwrite, MMS only]
|
||||
|
||||
Holds the MMS Proxy setting.
|
||||
|
||||
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
|
||||
|
||||
@@ -22,6 +22,34 @@ Methods a{sv} GetServingCellInformation()
|
||||
are available, their valid value ranges and
|
||||
applicability to different cell types.
|
||||
|
||||
void RegisterAgent(object path)
|
||||
|
||||
Registers an agent which will be called whenever the
|
||||
modem registers to or moves to a new cell.
|
||||
|
||||
void UnregisterAgent(object path)
|
||||
|
||||
Unregisters an agent.
|
||||
|
||||
NetworkMonitorAgent Hierarchy [experimental]
|
||||
=============================
|
||||
|
||||
Service unique name
|
||||
Interface org.ofono.NetworkMonitorAgent
|
||||
Object path freely definable
|
||||
|
||||
Methods void ServingCellInformationChanged(a{sv}) [noreply]
|
||||
|
||||
This method is called whenever the serving cell
|
||||
information has been updated.
|
||||
|
||||
Possible Errors: None
|
||||
|
||||
void Release() [noreply]
|
||||
|
||||
Agent is being released, possibly because of oFono
|
||||
terminating, NetworkMonitor interface is being torn
|
||||
down or modem off. No UnregisterAgent call is needed.
|
||||
|
||||
Network Monitor Property Types
|
||||
==============================
|
||||
@@ -77,7 +105,7 @@ byte TimingAdvance [optional, gsm]
|
||||
|
||||
Contains the Timing Advance. Valid range of values is 0-219.
|
||||
|
||||
byte Strength [optional, gsm, umts]
|
||||
byte Strength [optional, gsm, umts, lte]
|
||||
|
||||
Contains the signal strength. Valid values are 0-31. Refer to <rssi>
|
||||
in 27.007, Section 8.5.
|
||||
|
||||
@@ -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,15 +50,14 @@ 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();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmodem_exit(void)
|
||||
{
|
||||
at_sim_auth_exit();
|
||||
at_stk_exit();
|
||||
at_sim_exit();
|
||||
at_sms_exit();
|
||||
@@ -76,6 +75,7 @@ static void atmodem_exit(void)
|
||||
at_gprs_exit();
|
||||
at_gprs_context_exit();
|
||||
at_gnss_exit();
|
||||
at_lte_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
||||
|
||||
@@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void);
|
||||
|
||||
extern void at_gnss_init(void);
|
||||
extern void at_gnss_exit(void);
|
||||
|
||||
extern void at_lte_init(void);
|
||||
extern void at_lte_exit(void);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gatchat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/log.h>
|
||||
@@ -614,3 +615,42 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req)
|
||||
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||
* of "a.b.c.d.m.m.m.m" for IPv4.
|
||||
* address/netmask must be able to hold
|
||||
* 255.255.255.255 + null = 16 characters
|
||||
*/
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask)
|
||||
{
|
||||
const char *s = addrnetmask;
|
||||
const char *net = NULL;
|
||||
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
/* Count 7 dots for ipv4, less or more means error. */
|
||||
for (i = 0; i < 9; i++, s++) {
|
||||
s = strchr(s, '.');
|
||||
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
if (i == 3) {
|
||||
/* set netmask ptr and break the string */
|
||||
net = s + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 7) {
|
||||
memcpy(address, addrnetmask, net - addrnetmask);
|
||||
address[net - addrnetmask - 1] = '\0';
|
||||
strcpy(netmask, net);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@ struct at_util_sim_state_query *at_util_sim_state_query_new(GAtChat *chat,
|
||||
GDestroyNotify destroy);
|
||||
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
||||
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask);
|
||||
|
||||
struct cb_data {
|
||||
void *cb;
|
||||
void *data;
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "atmodem.h"
|
||||
#include "vendor.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
@@ -430,7 +430,7 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -327,6 +327,26 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
||||
ofono_gprs_bearer_notify(gprs, bearer);
|
||||
}
|
||||
|
||||
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
GAtResultIter iter;
|
||||
const char *mode;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!strcmp("LTE", mode))
|
||||
ofono_gprs_bearer_notify(gprs, 7); /* LTE */
|
||||
|
||||
/* in other modes, notification ^MODE is used */
|
||||
}
|
||||
|
||||
static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -432,6 +452,8 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
case OFONO_VENDOR_HUAWEI:
|
||||
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_register(gd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||
FALSE, gprs, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
@@ -445,6 +467,7 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
|
||||
FALSE, gprs, NULL);
|
||||
|
||||
142
ofono/drivers/atmodem/lte.c
Normal file
142
ofono/drivers/atmodem/lte.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
struct lte_driver_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("LTE config with APN: %s", info->apn);
|
||||
|
||||
if (strlen(info->apn) > 0)
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"",
|
||||
info->apn);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\"");
|
||||
|
||||
/* We can't do much in case of failure so don't check response. */
|
||||
if (g_at_chat_send(ldd->chat, buf, NULL,
|
||||
at_lte_set_default_attach_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static gboolean lte_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
|
||||
ofono_lte_register(lte);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct lte_driver_data *ldd;
|
||||
|
||||
DBG("at lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_driver_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ldd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
g_idle_add(lte_delayed_register, lte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("at lte remove");
|
||||
|
||||
g_at_chat_unref(ldd->chat);
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "atmodem",
|
||||
.probe = at_lte_probe,
|
||||
.remove = at_lte_remove,
|
||||
.set_default_attach_info = at_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void at_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void at_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -1088,6 +1088,27 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
GAtResultIter iter;
|
||||
const char *mode;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!strcmp("LTE", mode))
|
||||
nd->tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
|
||||
/* for other technologies, notification ^MODE is used */
|
||||
}
|
||||
|
||||
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
@@ -1896,6 +1917,10 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for 4G system mode reports */
|
||||
g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for network time reports */
|
||||
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -104,7 +104,7 @@ static void at_csca_set(struct ofono_sms *sms,
|
||||
{
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
char buf[64];
|
||||
char buf[128];
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CSCA=\"%s\",%d", sca->number, sca->type);
|
||||
|
||||
|
||||
@@ -47,4 +47,5 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_UBLOX,
|
||||
OFONO_VENDOR_UBLOX_TOBY_L2,
|
||||
OFONO_VENDOR_CINTERION,
|
||||
OFONO_VENDOR_XMM,
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "cdmamodem.h"
|
||||
#include "drivers/atmodem/vendor.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
@@ -285,7 +285,7 @@ static int cdma_connman_probe(struct ofono_cdma_connman *cm,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -42,11 +42,13 @@
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
|
||||
static const char *syscfgex_prefix[] = { "^SYSCFGEX:", NULL };
|
||||
|
||||
#define HUAWEI_BAND_ANY 0x3FFFFFFF
|
||||
|
||||
struct radio_settings_data {
|
||||
GAtChat *chat;
|
||||
ofono_bool_t syscfgex_cap;
|
||||
};
|
||||
|
||||
static const struct huawei_band_gsm_table {
|
||||
@@ -176,20 +178,76 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void syscfgex_query_mode_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode;
|
||||
struct ofono_error error;
|
||||
GAtResultIter iter;
|
||||
const char *acqorder;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (g_at_result_iter_next(&iter, "^SYSCFGEX:") == FALSE)
|
||||
goto error;
|
||||
|
||||
if (g_at_result_iter_next_string(&iter, &acqorder) == FALSE)
|
||||
goto error;
|
||||
|
||||
if ((strcmp(acqorder, "00") == 0) ||
|
||||
(strstr(acqorder, "01") &&
|
||||
strstr(acqorder, "02") &&
|
||||
strstr(acqorder, "03")))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
else if (strstr(acqorder, "03"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
else if (strstr(acqorder, "02"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
else if (strstr(acqorder, "01"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
else
|
||||
goto error;
|
||||
|
||||
cb(&error, mode, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, "AT^SYSCFG?", syscfg_prefix,
|
||||
syscfg_query_mode_cb, cbd, g_free) == 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
if (rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFGEX?",
|
||||
syscfgex_prefix,
|
||||
syscfgex_query_mode_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
if (!rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFG?",
|
||||
syscfg_prefix,
|
||||
syscfg_query_mode_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
static void syscfgxx_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -200,12 +258,11 @@ static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
static void syscfg_set_rat_mode(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[40];
|
||||
unsigned int value = 2, acq_order = 0;
|
||||
@@ -231,7 +288,7 @@ static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
value, acq_order);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfg_modify_mode_cb, cbd, g_free) > 0)
|
||||
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -239,7 +296,55 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
static void syscfgex_set_rat_mode(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[50];
|
||||
char *atcmd = "AT^SYSCFGEX=\"%s\",40000000,2,4,40000000,,";
|
||||
char *acqorder = "030201";
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
acqorder = "00";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
acqorder = "01";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
acqorder = "02";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
acqorder = "03";
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), atcmd, acqorder);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (rsd->syscfgex_cap)
|
||||
syscfgex_set_rat_mode(rsd, mode, cb, data);
|
||||
else
|
||||
syscfg_set_rat_mode(rsd, mode, cb, data);
|
||||
}
|
||||
|
||||
static void syscfgxx_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -250,13 +355,54 @@ static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
static void syscfgex_set_band(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[50];
|
||||
char *atcmd = "AT^SYSCFGEX=\"99\",%x,2,4,40000000,,";
|
||||
unsigned int huawei_band;
|
||||
|
||||
if (band_gsm == OFONO_RADIO_BAND_GSM_ANY
|
||||
&& band_umts == OFONO_RADIO_BAND_UMTS_ANY) {
|
||||
huawei_band = HUAWEI_BAND_ANY;
|
||||
} else {
|
||||
unsigned int huawei_band_gsm;
|
||||
unsigned int huawei_band_umts;
|
||||
|
||||
huawei_band_gsm = band_gsm_to_huawei(band_gsm);
|
||||
|
||||
if (!huawei_band_gsm)
|
||||
goto error;
|
||||
|
||||
huawei_band_umts = band_umts_to_huawei(band_umts);
|
||||
|
||||
if (!huawei_band_umts)
|
||||
goto error;
|
||||
|
||||
huawei_band = huawei_band_gsm | huawei_band_umts;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), atcmd, huawei_band);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_set_band(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[40];
|
||||
unsigned int huawei_band;
|
||||
@@ -284,7 +430,7 @@ static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfg_modify_band_cb, cbd, g_free) > 0)
|
||||
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -292,6 +438,20 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (rsd->syscfgex_cap)
|
||||
syscfgex_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||
else
|
||||
syscfg_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||
}
|
||||
|
||||
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
@@ -364,6 +524,21 @@ static void syscfg_support_cb(gboolean ok, GAtResult *result,
|
||||
ofono_radio_settings_register(rs);
|
||||
}
|
||||
|
||||
static void syscfgex_support_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (!ok) {
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||
syscfg_support_cb, rs, NULL);
|
||||
}
|
||||
|
||||
rsd->syscfgex_cap = 1;
|
||||
ofono_radio_settings_register(rs);
|
||||
}
|
||||
|
||||
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
@@ -378,8 +553,8 @@ static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||
syscfg_support_cb, rs, NULL);
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFGEX=?", syscfgex_prefix,
|
||||
syscfgex_support_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -400,8 +575,8 @@ static struct ofono_radio_settings_driver driver = {
|
||||
.remove = huawei_radio_settings_remove,
|
||||
.query_rat_mode = huawei_query_rat_mode,
|
||||
.set_rat_mode = huawei_set_rat_mode,
|
||||
.query_band = huawei_query_band,
|
||||
.set_band = huawei_set_band,
|
||||
.query_band = huawei_query_band,
|
||||
.set_band = huawei_set_band,
|
||||
};
|
||||
|
||||
void huawei_radio_settings_init(void)
|
||||
|
||||
@@ -42,13 +42,14 @@
|
||||
|
||||
#include "ifxmodem.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *xdns_prefix[] = { "+XDNS:", NULL };
|
||||
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
||||
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||
|
||||
enum state {
|
||||
STATE_IDLE,
|
||||
@@ -59,17 +60,20 @@ enum state {
|
||||
|
||||
struct gprs_context_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
unsigned int active_context;
|
||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||
GAtRawIP *rawip;
|
||||
enum state state;
|
||||
enum ofono_gprs_proto proto;
|
||||
char address[32];
|
||||
char dns1[32];
|
||||
char dns2[32];
|
||||
char address[64];
|
||||
char gateway[64];
|
||||
char netmask[64];
|
||||
char dns1[64];
|
||||
char dns2[64];
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data; /* Callback data */
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static void rawip_debug(const char *str, void *data)
|
||||
@@ -257,11 +261,136 @@ error:
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
GAtResultIter iter;
|
||||
|
||||
const char *laddrnetmask = NULL;
|
||||
const char *gw = NULL;
|
||||
const char *interface;
|
||||
const char *dns[3];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
gcd->cb(&error, gcd->cb_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
|
||||
/* skip cid, bearer_id, apn */
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &laddrnetmask))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[0]))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[1]))
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(gcd->dns1, dns[0], sizeof(gcd->dns1));
|
||||
strncpy(gcd->dns2, dns[1], sizeof(gcd->dns2));
|
||||
dns[2] = 0;
|
||||
|
||||
DBG("DNS: %s, %s\n", gcd->dns1, gcd->dns2);
|
||||
|
||||
if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
|
||||
gcd->address, gcd->netmask) < 0) {
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw)
|
||||
strncpy(gcd->gateway, gw, sizeof(gcd->gateway));
|
||||
|
||||
gcd->state = STATE_ACTIVE;
|
||||
|
||||
DBG("address: %s\n", gcd->address);
|
||||
DBG("netmask: %s\n", gcd->netmask);
|
||||
DBG("DNS1: %s\n", gcd->dns1);
|
||||
DBG("DNS2: %s\n", gcd->dns2);
|
||||
DBG("Gateway: %s\n", gcd->gateway);
|
||||
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
|
||||
|
||||
if (gcd->netmask[0])
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
|
||||
|
||||
if (gcd->gateway[0])
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void ifx_read_settings(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
gcd->address[0] = '\0';
|
||||
gcd->gateway[0] = '\0';
|
||||
gcd->netmask[0] = '\0';
|
||||
gcd->dns1[0] = '\0';
|
||||
gcd->dns2[0] = '\0';
|
||||
|
||||
/* read IP configuration info */
|
||||
if(gcd->vendor == OFONO_VENDOR_XMM) {
|
||||
snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%u",
|
||||
gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
|
||||
cgcontrdp_cb, gc, NULL) > 0)
|
||||
return;
|
||||
} else {
|
||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||
address_cb, gc, NULL) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void ifx_gprs_read_settings(struct ofono_gprs_context *gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
DBG("cid %u", cid);
|
||||
|
||||
gcd->active_context = cid;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
ifx_read_settings(gc);
|
||||
}
|
||||
|
||||
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
@@ -271,19 +400,14 @@ static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||
address_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
ifx_read_settings(gc);
|
||||
}
|
||||
|
||||
static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[128];
|
||||
char buf[384];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
@@ -387,7 +511,8 @@ static void deactivate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
g_at_chat_resume(gcd->chat);
|
||||
if (gcd->vendor != OFONO_VENDOR_XMM)
|
||||
g_at_chat_resume(gcd->chat);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
@@ -409,11 +534,25 @@ static void ifx_gprs_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
g_at_rawip_shutdown(gcd->rawip);
|
||||
|
||||
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
||||
if (g_at_chat_send(chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
if (gcd->vendor == OFONO_VENDOR_XMM) {
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
} else {
|
||||
if (g_at_chat_send(chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ifx_gprs_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
DBG("");
|
||||
ifx_gprs_deactivate_primary(gc, cid, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
@@ -451,14 +590,13 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
g_at_rawip_unref(gcd->rawip);
|
||||
gcd->rawip = NULL;
|
||||
g_at_chat_resume(gcd->chat);
|
||||
}
|
||||
|
||||
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
||||
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
g_at_chat_resume(gcd->chat);
|
||||
}
|
||||
|
||||
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
@@ -470,23 +608,27 @@ static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (g_at_chat_get_slave(chat) == NULL)
|
||||
return -EINVAL;
|
||||
if (vendor != OFONO_VENDOR_XMM) {
|
||||
if (g_at_chat_get_slave(chat) == NULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gcd = g_try_new0(struct gprs_context_data, 1);
|
||||
if (gcd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gcd->vendor = vendor;
|
||||
gcd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
|
||||
chat = g_at_chat_get_slave(gcd->chat);
|
||||
if (vendor != OFONO_VENDOR_XMM)
|
||||
chat = g_at_chat_get_slave(gcd->chat);
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
@@ -516,6 +658,8 @@ static struct ofono_gprs_context_driver driver = {
|
||||
.remove = ifx_gprs_context_remove,
|
||||
.activate_primary = ifx_gprs_activate_primary,
|
||||
.deactivate_primary = ifx_gprs_deactivate_primary,
|
||||
.read_settings = ifx_gprs_read_settings,
|
||||
.detach_shutdown = ifx_gprs_detach_shutdown
|
||||
};
|
||||
|
||||
void ifx_gprs_context_init(void)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
extern void ifx_voicecall_init(void);
|
||||
extern void ifx_voicecall_exit(void);
|
||||
|
||||
@@ -646,8 +646,31 @@ error:
|
||||
/* ISI callback: PIN state (enabled/disabled) query */
|
||||
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
||||
{
|
||||
check_sec_response(msg, opaque, SEC_CODE_STATE_OK_RESP,
|
||||
SEC_CODE_STATE_FAIL_RESP);
|
||||
struct isi_cb_data *cbd = opaque;
|
||||
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
||||
int locked;
|
||||
uint8_t state;
|
||||
uint8_t status;
|
||||
|
||||
if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
|
||||
!g_isi_msg_data_get_byte(msg, 1, &status))
|
||||
goto error;
|
||||
|
||||
if (state != SEC_CODE_STATE_OK_RESP)
|
||||
goto error;
|
||||
|
||||
if (status == SEC_CODE_ENABLE)
|
||||
locked = 1;
|
||||
else if (status == SEC_CODE_DISABLE)
|
||||
locked = 0;
|
||||
else
|
||||
goto error;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, locked, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void isi_query_locked(struct ofono_sim *sim,
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -35,6 +35,8 @@
|
||||
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
|
||||
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
|
||||
|
||||
#define QMI_NAS_SET_SYSTEM_SELECTION_PREF 51
|
||||
#define QMI_NAS_GET_SYSTEM_SELECTION_PREF 52
|
||||
|
||||
/* Set NAS state report conditions */
|
||||
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
|
||||
@@ -97,6 +99,7 @@ struct qmi_nas_network_rat {
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define QMI_NAS_NETWORK_RAT_NONE 0x00
|
||||
#define QMI_NAS_NETWORK_RAT_GSM 0x04
|
||||
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
|
||||
#define QMI_NAS_NETWORK_RAT_LTE 0x08
|
||||
@@ -149,6 +152,18 @@ struct qmi_nas_current_plmn {
|
||||
#define QMI_NAS_REGISTRATION_STATE_DENIED 0x03
|
||||
#define QMI_NAS_REGISTRATION_STATE_UNKNOWN 0x04
|
||||
|
||||
#define QMI_NAS_RESULT_3GGP_DST 0x1b
|
||||
#define QMI_NAS_RESULT_3GPP_TIME 0x1c
|
||||
struct qmi_nas_3gpp_time {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t timezone;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* cs_state/ps_state */
|
||||
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
|
||||
@@ -163,4 +178,13 @@ struct qmi_nas_home_network {
|
||||
char desc[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define QMI_NAS_RAT_MODE_PREF_ANY (-1)
|
||||
#define QMI_NAS_RAT_MODE_PREF_GSM (1 << 2)
|
||||
#define QMI_NAS_RAT_MODE_PREF_UMTS (1 << 3)
|
||||
#define QMI_NAS_RAT_MODE_PREF_LTE (1 << 4)
|
||||
|
||||
#define QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||
|
||||
#define QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||
|
||||
int qmi_nas_rat_to_tech(uint8_t rat);
|
||||
|
||||
286
ofono/drivers/qmimodem/netmon.c
Normal file
286
ofono/drivers/qmimodem/netmon.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
#include "src/common.h"
|
||||
|
||||
struct netmon_data {
|
||||
struct qmi_service *nas;
|
||||
};
|
||||
|
||||
static void get_rssi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_netmon *netmon = cbd->user;
|
||||
ofono_netmon_cb_t cb = cbd->cb;
|
||||
struct {
|
||||
enum ofono_netmon_cell_type type;
|
||||
int rssi;
|
||||
int ber;
|
||||
int rsrq;
|
||||
int rsrp;
|
||||
} props;
|
||||
uint16_t len;
|
||||
int16_t rsrp;
|
||||
const struct {
|
||||
int8_t value;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) *rsrq;
|
||||
const struct {
|
||||
uint16_t count;
|
||||
struct {
|
||||
uint8_t rssi;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__)) *rssi;
|
||||
const struct {
|
||||
uint16_t count;
|
||||
struct {
|
||||
uint16_t rate;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__)) *ber;
|
||||
int i;
|
||||
uint16_t num;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* RSSI */
|
||||
rssi = qmi_result_get(result, 0x11, &len);
|
||||
num = GUINT16_FROM_LE(rssi->count);
|
||||
if (rssi) {
|
||||
for (i = 0; i < num; i++) {
|
||||
DBG("RSSI: %hhu on RAT %hhd",
|
||||
rssi->info[i].rssi,
|
||||
rssi->info[i].rat);
|
||||
}
|
||||
|
||||
/* Get cell type from RSSI info... it will be the same
|
||||
* for all the other entries
|
||||
*/
|
||||
props.type = qmi_nas_rat_to_tech(rssi->info[0].rat);
|
||||
switch (rssi->info[0].rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||
break;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_UMTS;
|
||||
break;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_LTE;
|
||||
break;
|
||||
default:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||
break;
|
||||
}
|
||||
|
||||
props.rssi = (rssi->info[0].rssi + 113) / 2;
|
||||
if (props.rssi > 31) props.rssi = 31;
|
||||
if (props.rssi < 0) props.rssi = 0;
|
||||
} else {
|
||||
props.type = QMI_NAS_NETWORK_RAT_GSM;
|
||||
props.rssi = -1;
|
||||
}
|
||||
|
||||
/* Bit error rate */
|
||||
ber = qmi_result_get(result, 0x15, &len);
|
||||
num = GUINT16_FROM_LE(ber->count);
|
||||
if (ber) {
|
||||
for (i = 0; i < ber->count; i++) {
|
||||
DBG("Bit error rate: %hu on RAT %hhd",
|
||||
GUINT16_FROM_LE(ber->info[i].rate),
|
||||
ber->info[i].rat);
|
||||
}
|
||||
|
||||
props.ber = GUINT16_FROM_LE(ber->info[0].rate);
|
||||
if (props.ber > 7)
|
||||
props.ber = -1;
|
||||
} else {
|
||||
props.ber = -1;
|
||||
}
|
||||
|
||||
/* LTE RSRQ */
|
||||
rsrq = qmi_result_get(result, 0x16, &len);
|
||||
if (rsrq) {
|
||||
DBG("RSRQ: %hhd on RAT %hhd",
|
||||
rsrq->value,
|
||||
rsrq->rat);
|
||||
|
||||
if (rsrq->value == 0) {
|
||||
props.rsrq = -1;
|
||||
} else {
|
||||
props.rsrq = (rsrq->value + 19) * 2;
|
||||
if (props.rsrq > 34) props.rsrq = 34;
|
||||
if (props.rsrq < 0) props.rsrq = 0;
|
||||
}
|
||||
} else {
|
||||
props.rsrq = -1;
|
||||
}
|
||||
|
||||
/* LTE RSRP */
|
||||
if (qmi_result_get_int16(result, 0x18, &rsrp)) {
|
||||
DBG("Got LTE RSRP: %hd", rsrp);
|
||||
|
||||
if (rsrp == 0) {
|
||||
props.rsrp = -1;
|
||||
} else {
|
||||
props.rsrp = rsrp + 140;
|
||||
if (props.rsrp > 97) props.rsrp = 97;
|
||||
if (props.rsrp < 0) props.rsrp = 0;
|
||||
}
|
||||
} else {
|
||||
props.rsrp = -1;
|
||||
}
|
||||
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
props.type,
|
||||
OFONO_NETMON_INFO_RSSI, props.rssi,
|
||||
OFONO_NETMON_INFO_BER, props.ber,
|
||||
OFONO_NETMON_INFO_RSRQ, props.rsrq,
|
||||
OFONO_NETMON_INFO_RSRP, props.rsrp,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct netmon_data *data = ofono_netmon_get_data(netmon);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = netmon;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto out;
|
||||
|
||||
/* Request all signal strength items: mask=0xff */
|
||||
qmi_param_append_uint16(param, 0x10, 255);
|
||||
|
||||
if (qmi_service_send(data->nas, QMI_NAS_GET_RSSI, param,
|
||||
get_rssi_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
out:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_netmon *netmon = user_data;
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_netmon_remove(netmon);
|
||||
return;
|
||||
}
|
||||
|
||||
nmd->nas = qmi_service_ref(service);
|
||||
|
||||
ofono_netmon_register(netmon);
|
||||
}
|
||||
|
||||
static int qmi_netmon_probe(struct ofono_netmon *netmon,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
struct qmi_device *device = user_data;
|
||||
struct netmon_data *nmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
nmd = g_new0(struct netmon_data, 1);
|
||||
|
||||
ofono_netmon_set_data(netmon, nmd);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, netmon, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmi_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
|
||||
qmi_service_unregister_all(nmd->nas);
|
||||
|
||||
qmi_service_unref(nmd->nas);
|
||||
|
||||
g_free(nmd);
|
||||
}
|
||||
|
||||
static struct ofono_netmon_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_netmon_probe,
|
||||
.remove = qmi_netmon_remove,
|
||||
.request_update = qmi_netmon_request_update,
|
||||
};
|
||||
|
||||
void qmi_netmon_init(void)
|
||||
{
|
||||
ofono_netmon_driver_register(&driver);
|
||||
}
|
||||
|
||||
void qmi_netmon_exit(void)
|
||||
{
|
||||
ofono_netmon_driver_unregister(&driver);
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -43,6 +44,38 @@ struct netreg_data {
|
||||
uint8_t current_rat;
|
||||
};
|
||||
|
||||
static bool extract_ss_info_time(
|
||||
struct qmi_result *result,
|
||||
struct ofono_network_time *time)
|
||||
{
|
||||
const struct qmi_nas_3gpp_time *time_3gpp = NULL;
|
||||
uint8_t dst_3gpp;
|
||||
bool dst_3gpp_valid;
|
||||
uint16_t len;
|
||||
|
||||
/* parse 3gpp time & dst */
|
||||
dst_3gpp_valid = qmi_result_get_uint8(result, QMI_NAS_RESULT_3GGP_DST,
|
||||
&dst_3gpp);
|
||||
|
||||
time_3gpp = qmi_result_get(result, QMI_NAS_RESULT_3GPP_TIME, &len);
|
||||
if (time_3gpp && len == sizeof(struct qmi_nas_3gpp_time) &&
|
||||
dst_3gpp_valid) {
|
||||
time->year = le16toh(time_3gpp->year);
|
||||
time->mon = time_3gpp->month;
|
||||
time->mday = time_3gpp->day;
|
||||
time->hour = time_3gpp->hour;
|
||||
time->min = time_3gpp->minute;
|
||||
time->sec = time_3gpp->second;
|
||||
time->utcoff = time_3gpp->timezone * 15 * 60;
|
||||
time->dst = dst_3gpp;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: 3gpp2 */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
int *lac, int *cellid, int *tech,
|
||||
struct ofono_network_operator *operator)
|
||||
@@ -124,11 +157,15 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct ofono_network_time net_time;
|
||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||
int status, lac, cellid, tech;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (extract_ss_info_time(result, &net_time))
|
||||
ofono_netreg_time_notify(netreg, &net_time);
|
||||
|
||||
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
|
||||
&data->operator))
|
||||
return;
|
||||
@@ -295,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("");
|
||||
|
||||
@@ -304,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;
|
||||
}
|
||||
|
||||
@@ -356,7 +395,7 @@ static void qmi_register_manual(struct ofono_netreg *netreg,
|
||||
|
||||
info.mcc = atoi(mcc);
|
||||
info.mnc = atoi(mnc);
|
||||
info.rat = data->current_rat;
|
||||
info.rat = QMI_NAS_NETWORK_RAT_NO_CHANGE;
|
||||
|
||||
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
|
||||
sizeof(info), &info);
|
||||
@@ -450,10 +489,11 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
||||
if (ss) {
|
||||
int strength;
|
||||
|
||||
DBG("signal with %d dBm on %d", ss->dbm, ss->rat);
|
||||
|
||||
strength = dbm_to_strength(ss->dbm);
|
||||
|
||||
DBG("signal with %d%%(%d dBm) on %d",
|
||||
strength, ss->dbm, ss->rat);
|
||||
|
||||
ofono_netreg_strength_notify(netreg, strength);
|
||||
}
|
||||
|
||||
@@ -473,10 +513,17 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
||||
static void set_event_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_netreg_register(netreg);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||
event_notify, netreg, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, netreg, NULL);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
@@ -498,12 +545,6 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||
event_notify, netreg, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, netreg, NULL);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto done;
|
||||
|
||||
@@ -73,6 +73,8 @@ struct qmi_device {
|
||||
void *shutdown_user_data;
|
||||
qmi_destroy_func_t shutdown_destroy;
|
||||
guint shutdown_source;
|
||||
bool shutting_down : 1;
|
||||
bool destroyed : 1;
|
||||
};
|
||||
|
||||
struct qmi_service {
|
||||
@@ -474,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)
|
||||
{
|
||||
@@ -1000,7 +1013,10 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
g_free(device->version_str);
|
||||
g_free(device->version_list);
|
||||
|
||||
g_free(device);
|
||||
if (device->shutting_down)
|
||||
device->destroyed = true;
|
||||
else
|
||||
g_free(device);
|
||||
}
|
||||
|
||||
void qmi_device_set_debug(struct qmi_device *device,
|
||||
@@ -1021,6 +1037,23 @@ void qmi_device_set_close_on_unref(struct qmi_device *device, bool do_close)
|
||||
device->close_on_unref = do_close;
|
||||
}
|
||||
|
||||
void qmi_result_print_tlvs(struct qmi_result *result)
|
||||
{
|
||||
const void *ptr = result->data;
|
||||
uint16_t len = result->length;
|
||||
|
||||
while (len > QMI_TLV_HDR_SIZE) {
|
||||
const struct qmi_tlv_hdr *tlv = ptr;
|
||||
uint16_t tlv_length = GUINT16_FROM_LE(tlv->length);
|
||||
|
||||
DBG("tlv: 0x%02x len 0x%04x", tlv->type, tlv->length);
|
||||
|
||||
ptr += QMI_TLV_HDR_SIZE + tlv_length;
|
||||
len -= QMI_TLV_HDR_SIZE + tlv_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const void *tlv_get(const void *data, uint16_t size,
|
||||
uint8_t type, uint16_t *length)
|
||||
{
|
||||
@@ -1051,6 +1084,7 @@ struct discover_data {
|
||||
qmi_discover_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
uint8_t tid;
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
@@ -1111,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;
|
||||
@@ -1123,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);
|
||||
@@ -1138,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;
|
||||
@@ -1159,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;
|
||||
}
|
||||
@@ -1212,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);
|
||||
|
||||
@@ -1255,6 +1307,9 @@ static void shutdown_destroy(gpointer user_data)
|
||||
device->shutdown_destroy(device->shutdown_user_data);
|
||||
|
||||
device->shutdown_source = 0;
|
||||
|
||||
if (device->destroyed)
|
||||
g_free(device);
|
||||
}
|
||||
|
||||
static gboolean shutdown_callback(gpointer user_data)
|
||||
@@ -1264,9 +1319,13 @@ static gboolean shutdown_callback(gpointer user_data)
|
||||
if (device->release_users > 0)
|
||||
return TRUE;
|
||||
|
||||
device->shutting_down = true;
|
||||
|
||||
if (device->shutdown_func)
|
||||
device->shutdown_func(device->shutdown_user_data);
|
||||
|
||||
device->shutting_down = true;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1294,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)
|
||||
{
|
||||
@@ -1691,6 +1809,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
uint16_t len, tmp;
|
||||
|
||||
if (!result || !type)
|
||||
return false;
|
||||
|
||||
ptr = tlv_get(result->data, result->length, type, &len);
|
||||
if (!ptr)
|
||||
return false;
|
||||
|
||||
memcpy(&tmp, ptr, 2);
|
||||
|
||||
if (value)
|
||||
*value = GINT16_FROM_LE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
@@ -130,13 +134,17 @@ const void *qmi_result_get(struct qmi_result *result, uint8_t type,
|
||||
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
|
||||
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
uint8_t *value);
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value);
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value);
|
||||
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
||||
uint32_t *value);
|
||||
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
uint64_t *value);
|
||||
void qmi_result_print_tlvs(struct qmi_result *result);
|
||||
|
||||
int qmi_error_to_ofono_cme(int qmi_error);
|
||||
|
||||
struct qmi_service;
|
||||
|
||||
|
||||
@@ -39,16 +39,20 @@ 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();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,8 +48,14 @@ 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);
|
||||
|
||||
extern void qmi_location_reporting_init(void);
|
||||
extern void qmi_location_reporting_exit(void);
|
||||
|
||||
extern void qmi_netmon_init(void);
|
||||
extern void qmi_netmon_exit(void);
|
||||
|
||||
@@ -29,15 +29,202 @@
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
#include "dms.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct settings_data {
|
||||
struct qmi_service *nas;
|
||||
struct qmi_service *dms;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
static void get_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
uint16_t pref;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_result_get_uint16(result,
|
||||
QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref);
|
||||
|
||||
switch (pref) {
|
||||
case QMI_NAS_RAT_MODE_PREF_GSM:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_UMTS:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_LTE:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL,
|
||||
get_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void set_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_GSM;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_UMTS;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param) {
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE,
|
||||
pref);
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_SET_SYSTEM_SELECTION_PREF, param,
|
||||
set_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void get_caps_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
|
||||
const struct qmi_dms_device_caps *caps;
|
||||
unsigned int available_rats;
|
||||
uint16_t len;
|
||||
uint8_t i;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto error;
|
||||
|
||||
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
|
||||
if (!caps)
|
||||
goto error;
|
||||
|
||||
available_rats = 0;
|
||||
for (i = 0; i < caps->radio_if_count; i++) {
|
||||
switch (caps->radio_if[i]) {
|
||||
case QMI_DMS_RADIO_IF_GSM:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_UMTS:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_LTE:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_available_rats(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (!rsd->dms)
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL,
|
||||
get_caps_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service)
|
||||
return;
|
||||
|
||||
data->dms = qmi_service_ref(service);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
@@ -74,11 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, data);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||
create_dms_cb, rs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
@@ -89,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);
|
||||
@@ -100,6 +291,9 @@ static struct ofono_radio_settings_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_radio_settings_probe,
|
||||
.remove = qmi_radio_settings_remove,
|
||||
.set_rat_mode = qmi_set_rat_mode,
|
||||
.query_rat_mode = qmi_query_rat_mode,
|
||||
.query_available_rats = qmi_query_available_rats,
|
||||
};
|
||||
|
||||
void qmi_radio_settings_init(void)
|
||||
|
||||
@@ -317,6 +317,124 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void write_generic_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_write_cb_t cb = cbd->cb;
|
||||
uint16_t len;
|
||||
const uint8_t *card_result;
|
||||
uint8_t sw1, sw2;
|
||||
|
||||
card_result = qmi_result_get(result, 0x10, &len);
|
||||
if (card_result == NULL || len != 2) {
|
||||
DBG("card_result: %p, len: %d", card_result, (int) len);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
sw1 = card_result[0];
|
||||
sw2 = card_result[1];
|
||||
|
||||
DBG("%02x, %02x", sw1, sw2);
|
||||
|
||||
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
||||
(sw1 == 0x90 && sw2 != 0x00)) {
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("%s: error sw1 %02x sw2 %02x", __func__, sw1, sw2);
|
||||
|
||||
error.type = OFONO_ERROR_TYPE_SIM;
|
||||
error.error = (sw1 << 8) | sw2;
|
||||
|
||||
cb(&error, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void write_generic(struct ofono_sim *sim,
|
||||
uint16_t qmi_message, int fileid,
|
||||
int start_or_recordnum,
|
||||
int length, const unsigned char *value,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char write_data[4 + length];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("file id 0x%04x path len %d", fileid, path_len);
|
||||
|
||||
fileid_len = create_fileid_data(data->app_type, fileid,
|
||||
path, path_len, fileid_data);
|
||||
|
||||
if (fileid_len < 0)
|
||||
goto error;
|
||||
|
||||
write_data[0] = start_or_recordnum & 0xff;
|
||||
write_data[1] = (start_or_recordnum & 0xff00) >> 8;
|
||||
write_data[2] = length & 0xff;
|
||||
write_data[3] = (length & 0xff00) >> 8;
|
||||
memcpy(&write_data[4], value, length);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
|
||||
qmi_param_append(param, 0x02, fileid_len, fileid_data);
|
||||
qmi_param_append(param, 0x03, 4 + length, write_data);
|
||||
|
||||
if (qmi_service_send(data->uim, qmi_message, param,
|
||||
write_generic_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_write_transparent(struct ofono_sim *sim,
|
||||
int fileid, int start, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_TRANSPARENT, fileid, start,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_linear(struct ofono_sim *sim,
|
||||
int fileid, int record, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, record,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_cyclic(struct ofono_sim *sim,
|
||||
int fileid, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, 0,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void get_imsi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -777,6 +895,9 @@ static struct ofono_sim_driver driver = {
|
||||
.read_file_transparent = qmi_read_transparent,
|
||||
.read_file_linear = qmi_read_record,
|
||||
.read_file_cyclic = qmi_read_record,
|
||||
.write_file_transparent = qmi_write_transparent,
|
||||
.write_file_linear = qmi_write_linear,
|
||||
.write_file_cyclic = qmi_write_cyclic,
|
||||
.read_imsi = qmi_read_imsi,
|
||||
.query_passwd_state = qmi_query_passwd_state,
|
||||
.query_pin_retries = qmi_query_pin_retries,
|
||||
|
||||
@@ -277,7 +277,7 @@ static void qmi_bearer_query(struct ofono_sms *sms,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->major < 1 && data->minor < 2)
|
||||
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
|
||||
@@ -315,7 +315,7 @@ static void qmi_bearer_set(struct ofono_sms *sms, int bearer,
|
||||
|
||||
DBG("bearer %d", bearer);
|
||||
|
||||
if (data->major < 1 && data->minor < 2)
|
||||
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||
goto error;
|
||||
|
||||
domain = bearer_to_domain(bearer);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +468,7 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
|
||||
new_list->count = GUINT16_TO_LE(1);
|
||||
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
|
||||
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
|
||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NV;
|
||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NONE;
|
||||
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
|
||||
|
||||
param = qmi_param_new();
|
||||
|
||||
@@ -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 */
|
||||
@@ -62,9 +64,17 @@ struct qmi_wms_param_message {
|
||||
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
||||
#define QMI_WMS_STORAGE_TYPE_NV 1
|
||||
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
||||
#define QMI_WMS_STORAGE_TYPE_NONE 255
|
||||
|
||||
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
||||
|
||||
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,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
|
||||
@@ -24,6 +24,7 @@ struct ril_cbs {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
guint register_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
@@ -51,6 +52,12 @@ static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_retry(GRilIoRequest *request, int ril_status,
|
||||
const void *resp_data, guint resp_len, void *user_data)
|
||||
{
|
||||
return ril_status == RIL_E_INVALID_STATE;
|
||||
}
|
||||
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
@@ -61,6 +68,9 @@ static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
grilio_request_append_int32(req, activate ? 0 :1);
|
||||
|
||||
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||
grilio_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
@@ -97,6 +107,9 @@ static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||
}
|
||||
|
||||
DBG_(cd, "configuring CB");
|
||||
grilio_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
@@ -144,27 +157,41 @@ static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
GRilIoParser rilp;
|
||||
guint32 pdu_len;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
DBG_(cd, "%u bytes", len);
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &pdu_len)) {
|
||||
const void* pdu = grilio_parser_get_bytes(&rilp, pdu_len);
|
||||
|
||||
/*
|
||||
* By default assume that it's a length followed by the
|
||||
* binary PDU data.
|
||||
*/
|
||||
if (pdu && grilio_parser_bytes_remaining(&rilp) < 4) {
|
||||
DBG_(cd, "%u bytes", pdu_len);
|
||||
ofono_cbs_notify(cd->cbs, pdu, pdu_len);
|
||||
} else {
|
||||
/*
|
||||
* But I've seen cell broadcasts arriving without
|
||||
* the length, simply as a blob.
|
||||
*/
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static gboolean ril_cbs_register(void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||
cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
} else {
|
||||
DBG_(cd, "failed to query CB config");
|
||||
ofono_cbs_remove(cd->cbs);
|
||||
}
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->register_id = 0;
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
@@ -172,7 +199,6 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
@@ -182,20 +208,7 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
DBG_(cd, "");
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
|
||||
/*
|
||||
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup
|
||||
* especially if other RIL requests are running in parallel. We may
|
||||
* have to retry a few times. Also, make it blocking in order to
|
||||
* improve the chance of success.
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
|
||||
ril_cbs_probe_done_cb, NULL, cd);
|
||||
grilio_request_unref(req);
|
||||
cd->register_id = g_idle_add(ril_cbs_register, cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -204,6 +217,9 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
if (cd->register_id) {
|
||||
g_source_remove(cd->register_id);
|
||||
}
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
|
||||
@@ -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) 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,11 @@
|
||||
#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;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
@@ -35,17 +37,17 @@ 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;
|
||||
guint set_rate_id;
|
||||
gboolean enabled;
|
||||
};
|
||||
|
||||
enum ril_cell_info_signal {
|
||||
@@ -74,6 +76,20 @@ static void ril_cell_free1(gpointer cell)
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static const char *ril_cell_info_int_format(int value, const char *format)
|
||||
{
|
||||
if (value == SAILFISH_CELL_INVALID_VALUE) {
|
||||
return "";
|
||||
} else {
|
||||
static GUtilIdlePool *ril_cell_info_pool = NULL;
|
||||
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
|
||||
char *str = g_strdup_printf(format, value);
|
||||
|
||||
gutil_idle_pool_add(pool, str, g_free);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
@@ -105,10 +121,10 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = INT_MAX;
|
||||
gsm->bsic = INT_MAX;
|
||||
gsm->arfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
|
||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||
gsm->timingAdvance = INT_MAX;
|
||||
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
|
||||
/* RIL_CellIdentityGsm */
|
||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||
@@ -122,11 +138,17 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
|
||||
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
|
||||
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,arfcn=%d,"
|
||||
"bsic=%d,strength=%d,err=%d,t=%d", registered,
|
||||
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
|
||||
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
|
||||
gsm->timingAdvance);
|
||||
DBG("[gsm] reg=%d%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
|
||||
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
|
||||
ril_cell_info_int_format(gsm->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
|
||||
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -144,7 +166,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = INT_MAX;
|
||||
wcdma->uarfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
@@ -154,10 +176,16 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
|
||||
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
|
||||
"strength=%d,err=%d", registered, wcdma->mcc,
|
||||
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
|
||||
wcdma->signalStrength, wcdma->bitErrorRate);
|
||||
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
|
||||
ril_cell_info_int_format(wcdma->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(wcdma->bitErrorRate,
|
||||
",err=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -175,7 +203,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = INT_MAX;
|
||||
lte->earfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
@@ -189,11 +217,19 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, <e->rssnr) &&
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(lte->ci, ",ci=%d"),
|
||||
ril_cell_info_int_format(lte->pci, ",pci=%d"),
|
||||
ril_cell_info_int_format(lte->tac, ",tac=%d"),
|
||||
ril_cell_info_int_format(lte->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
|
||||
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
|
||||
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
|
||||
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
|
||||
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
@@ -296,8 +332,9 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
DBG_(self, "");
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
ril_cell_info_update_cells(self,
|
||||
(status == RIL_E_SUCCESS && self->enabled) ?
|
||||
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
@@ -310,11 +347,26 @@ 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)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return self->enabled;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_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,
|
||||
@@ -322,13 +374,14 @@ 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->enabled) ?
|
||||
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, -1);
|
||||
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,
|
||||
@@ -336,26 +389,11 @@ 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)
|
||||
{
|
||||
ril_cell_info_set_rate(self,
|
||||
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
}
|
||||
|
||||
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||
if (self->enabled && self->radio->state == RADIO_STATE_ON &&
|
||||
self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
@@ -373,21 +411,19 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
const gboolean sim_card_was_ready = self->sim_card_ready;
|
||||
|
||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (self->sim_card_ready != sim_card_was_ready) {
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||
ril_cell_info_refresh(self);
|
||||
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;
|
||||
};
|
||||
@@ -409,17 +445,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
|
||||
@@ -427,16 +455,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;
|
||||
}
|
||||
@@ -450,22 +480,52 @@ 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->enabled && self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_set_enabled_proc(struct sailfish_cell_info *info,
|
||||
gboolean enabled)
|
||||
{
|
||||
struct ril_cell_info *self = ril_cell_info_cast(info);
|
||||
|
||||
if (self->enabled != enabled) {
|
||||
self->enabled = enabled;
|
||||
DBG_(self, "%d", enabled);
|
||||
ril_cell_info_refresh(self);
|
||||
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,
|
||||
ril_cell_info_set_enabled_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]) ?
|
||||
@@ -473,9 +533,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);
|
||||
@@ -483,15 +540,19 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
ril_cell_info_refresh(self);
|
||||
|
||||
/* Disable updates by default */
|
||||
self->enabled = FALSE;
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
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)
|
||||
@@ -508,8 +569,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);
|
||||
@@ -523,7 +582,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 */
|
||||
|
||||
/*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2021 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,
|
||||
@@ -36,6 +40,7 @@ struct ril_data_call {
|
||||
char **dnses;
|
||||
char **gateways;
|
||||
char **addresses;
|
||||
char **pcscf;
|
||||
};
|
||||
|
||||
struct ril_data_call_list {
|
||||
@@ -51,7 +56,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 {
|
||||
@@ -74,16 +80,11 @@ struct ril_data_options {
|
||||
unsigned int data_call_retry_delay_ms;
|
||||
};
|
||||
|
||||
enum ril_data_role {
|
||||
RIL_DATA_ROLE_NONE, /* Data not allowed */
|
||||
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
|
||||
RIL_DATA_ROLE_INTERNET /* Data is allowed at full speed */
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -96,7 +97,8 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config);
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_vendor *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);
|
||||
@@ -113,12 +115,16 @@ 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,
|
||||
|
||||
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:
|
||||
*/
|
||||
80
ofono/drivers/ril/ril_devmon.h
Normal file
80
ofono/drivers/ril/ril_devmon.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* 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(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This Device Monitor implementation controls network state updates
|
||||
* by sending SET_UNSOLICITED_RESPONSE_FILTER.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This one selects the type based on the RIL version.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* 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(const struct ril_slot_config *config)
|
||||
{
|
||||
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(config);
|
||||
self->ds = ril_devmon_ds_new(config);
|
||||
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:
|
||||
*/
|
||||
355
ofono/drivers/ril/ril_devmon_ds.c
Normal file
355
ofono/drivers/ril/ril_devmon_ds.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* 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;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} 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;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} 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))) ?
|
||||
self->cell_info_interval_short_ms :
|
||||
self->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);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ds->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ds->cell_info_interval_long_ms;
|
||||
|
||||
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(const struct ril_slot_config *config)
|
||||
{
|
||||
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();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
261
ofono/drivers/ril/ril_devmon_ss.c
Normal file
261
ofono/drivers/ril/ril_devmon_ss.c
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} 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;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} 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))) ?
|
||||
self->cell_info_interval_short_ms :
|
||||
self->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);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ss->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ss->cell_info_interval_long_ms;
|
||||
|
||||
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(const struct ril_slot_config *config)
|
||||
{
|
||||
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();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
267
ofono/drivers/ril/ril_devmon_ur.c
Normal file
267
ofono/drivers/ril/ril_devmon_ur.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} 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;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} 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))) ?
|
||||
self->cell_info_interval_short_ms :
|
||||
self->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);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ur->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ur->cell_info_interval_long_ms;
|
||||
|
||||
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(const struct ril_slot_config *config)
|
||||
{
|
||||
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();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
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-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -23,12 +23,13 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
#include "mtu-watch.h"
|
||||
|
||||
#define CTX_ID_NONE ((unsigned int)(-1))
|
||||
|
||||
#define MAX_MTU 1280
|
||||
#define MAX_MMS_MTU 1280
|
||||
|
||||
struct ril_gprs_context_call {
|
||||
struct ril_data_request *req;
|
||||
@@ -87,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;
|
||||
}
|
||||
@@ -106,10 +108,18 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
if (call) {
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = ril_data_call_dup(call);
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||
if (ofono_gprs_context_get_type(gcd->gc) ==
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
/*
|
||||
* Some MMS providers have a problem with MTU
|
||||
* greater than 1280. Let's be safe.
|
||||
*/
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MMS_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);
|
||||
}
|
||||
@@ -244,34 +254,59 @@ static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
typedef void (*ofono_gprs_context_list_setter_t)(struct ofono_gprs_context *gc,
|
||||
const char **list);
|
||||
|
||||
static void ril_gprs_context_set_servers(struct ofono_gprs_context *gc,
|
||||
char * const *list, ofono_gprs_context_list_setter_t set_ipv4,
|
||||
ofono_gprs_context_list_setter_t set_ipv6)
|
||||
{
|
||||
int i;
|
||||
char * const *list = call->dnses;
|
||||
const char **ip_list = NULL, **ip_ptr = NULL;
|
||||
const char **ipv6_list = NULL, **ipv6_ptr = NULL;
|
||||
const int n = gutil_strv_length(list);
|
||||
const char **ip_dns = g_new0(const char *, n+1);
|
||||
const char **ipv6_dns = g_new0(const char *, n+1);
|
||||
const char **ip_ptr = ip_dns;
|
||||
const char **ipv6_ptr = ipv6_dns;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_ptr) {
|
||||
ip_list = g_new0(const char *, n - i + 1);
|
||||
ip_ptr = ip_list;
|
||||
}
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_ptr) {
|
||||
ipv6_list = g_new0(const char *, n - i + 1);
|
||||
ipv6_ptr = ipv6_list;
|
||||
}
|
||||
*ipv6_ptr++ = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
|
||||
set_ipv4(gc, ip_list);
|
||||
set_ipv6(gc, ipv6_list);
|
||||
|
||||
g_free(ip_dns);
|
||||
g_free(ipv6_dns);
|
||||
g_free(ip_list);
|
||||
g_free(ipv6_list);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->dnses,
|
||||
ofono_gprs_context_set_ipv4_dns_servers,
|
||||
ofono_gprs_context_set_ipv6_dns_servers);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->pcscf,
|
||||
ofono_gprs_context_set_ipv4_proxy_cscf,
|
||||
ofono_gprs_context_set_ipv6_proxy_cscf);
|
||||
}
|
||||
|
||||
/* Only compares the stuff that's important to us */
|
||||
@@ -279,7 +314,8 @@ static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||
#define DATA_CALL_ALL_CHANGED (0x0f)
|
||||
#define DATA_CALL_PCSCF_CHANGED (0x10)
|
||||
#define DATA_CALL_ALL_CHANGED (0x1f)
|
||||
static int ril_gprs_context_data_call_change(
|
||||
const struct ril_data_call *c1,
|
||||
const struct ril_data_call *c2)
|
||||
@@ -305,6 +341,10 @@ static int ril_gprs_context_data_call_change(
|
||||
changes |= DATA_CALL_DNS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->pcscf, c2->pcscf)) {
|
||||
changes |= DATA_CALL_PCSCF_CHANGED;
|
||||
}
|
||||
|
||||
return changes;
|
||||
} else {
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
@@ -377,7 +417,12 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
if (change & DATA_CALL_PCSCF_CHANGED) {
|
||||
DBG("P-CSCF changed");
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
|
||||
@@ -395,6 +440,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;
|
||||
@@ -416,6 +463,7 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
ril_error_init_ok(&error);
|
||||
}
|
||||
|
||||
@@ -463,6 +511,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);
|
||||
}
|
||||
|
||||
@@ -477,24 +526,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;
|
||||
}
|
||||
}
|
||||
@@ -508,7 +556,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-2021 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,15 +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;
|
||||
gboolean pre_sim_done;
|
||||
gboolean allow_data;
|
||||
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;
|
||||
@@ -124,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;
|
||||
@@ -138,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;
|
||||
|
||||
@@ -172,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;
|
||||
@@ -208,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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,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;
|
||||
|
||||
@@ -244,12 +252,37 @@ 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);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->pre_sim_done = TRUE;
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (md->modem.config.enable_voicecall) {
|
||||
@@ -271,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);
|
||||
}
|
||||
}
|
||||
@@ -287,9 +327,20 @@ 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);
|
||||
}
|
||||
ofono_sim_auth_create(modem);
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
@@ -371,12 +422,14 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
ofono_modem_set_data(ofono, NULL);
|
||||
|
||||
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||
ril_radio_set_online(modem->radio, FALSE);
|
||||
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);
|
||||
@@ -390,6 +443,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);
|
||||
@@ -397,6 +451,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);
|
||||
@@ -409,7 +465,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" */
|
||||
@@ -436,6 +492,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);
|
||||
@@ -444,19 +501,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
|
||||
@@ -469,11 +537,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
/*
|
||||
* With some RIL implementations, querying available
|
||||
* band modes causes some magic Android properties to
|
||||
* appear. Otherwise this request is pretty harmless
|
||||
* and useless.
|
||||
* appear.
|
||||
*/
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
if (config->query_available_band_mode) {
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
}
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -27,6 +27,14 @@ struct ril_netmon {
|
||||
guint register_id;
|
||||
};
|
||||
|
||||
/* This number must be in sync with ril_netmon_notify_ofono: */
|
||||
#define RIL_NETMON_MAX_OFONO_PARAMS (8)
|
||||
|
||||
struct ril_netmon_ofono_param {
|
||||
enum ofono_netmon_info type;
|
||||
int value;
|
||||
};
|
||||
|
||||
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
||||
{
|
||||
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
||||
@@ -50,58 +58,171 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
|
||||
enum ofono_netmon_cell_type type, int mcc, int mnc,
|
||||
struct ril_netmon_ofono_param *params, int nparams)
|
||||
{
|
||||
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
int i;
|
||||
|
||||
/* Better not to push uninitialized data to the stack ... */
|
||||
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
|
||||
params[i].type = OFONO_NETMON_INFO_INVALID;
|
||||
params[i].value = SAILFISH_CELL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon, type,
|
||||
OFONO_NETMON_INFO_MCC, s_mcc,
|
||||
OFONO_NETMON_INFO_MNC, s_mnc,
|
||||
params[0].type, params[0].value,
|
||||
params[1].type, params[1].value,
|
||||
params[2].type, params[2].value,
|
||||
params[3].type, params[3].value,
|
||||
params[4].type, params[4].value,
|
||||
params[5].type, params[5].value,
|
||||
params[6].type, params[6].value,
|
||||
params[7].type, params[7].value,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_gsm *gsm)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, gsm->mcc, gsm->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_GSM,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_LAC, gsm->lac,
|
||||
OFONO_NETMON_INFO_CI, gsm->cid,
|
||||
OFONO_NETMON_INFO_RSSI, gsm->signalStrength,
|
||||
OFONO_NETMON_INFO_BER, gsm->bitErrorRate,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
if (gsm->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||
params[n].value = gsm->lac;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = gsm->cid;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->arfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||
params[n].value = gsm->arfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = gsm->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_BER;
|
||||
params[n].value = gsm->bitErrorRate;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_GSM,
|
||||
gsm->mcc, gsm->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_wcdma *wcdma)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, wcdma->mcc, wcdma->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_UMTS,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_LAC, wcdma->lac,
|
||||
OFONO_NETMON_INFO_CI, wcdma->cid,
|
||||
OFONO_NETMON_INFO_PSC, wcdma->psc,
|
||||
OFONO_NETMON_INFO_RSSI, wcdma->signalStrength,
|
||||
OFONO_NETMON_INFO_BER, wcdma->bitErrorRate,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
if (wcdma->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||
params[n].value = wcdma->lac;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = wcdma->cid;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->psc != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_PSC;
|
||||
params[n].value = wcdma->psc;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->uarfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||
params[n].value = wcdma->uarfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = wcdma->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_BER;
|
||||
params[n].value = wcdma->bitErrorRate;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_UMTS,
|
||||
wcdma->mcc, wcdma->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_lte *lte)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, lte->mcc, lte->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_LTE,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_CI, lte->ci,
|
||||
OFONO_NETMON_INFO_RSSI, lte->signalStrength,
|
||||
OFONO_NETMON_INFO_TIMING_ADVANCE, lte->timingAdvance,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
if (lte->ci != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = lte->ci;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->earfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_EARFCN;
|
||||
params[n].value = lte->earfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = lte->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->rsrp != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSRQ;
|
||||
params[n].value = lte->rsrp;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->rsrq != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSRP;
|
||||
params[n].value = lte->rsrq;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->cqi != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CQI;
|
||||
params[n].value = lte->cqi;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->timingAdvance != SAILFISH_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
|
||||
params[n].value = lte->timingAdvance;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_LTE,
|
||||
lte->mcc, lte->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
|
||||
@@ -1,7 +1,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,17 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
#include "simutil.h"
|
||||
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#define REGISTRATION_MAX_RETRIES (2)
|
||||
|
||||
enum ril_netreg_events {
|
||||
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||
@@ -36,14 +43,21 @@ enum ril_netreg_network_events {
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean replace_strange_oper;
|
||||
gboolean network_selection_manual_0;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
struct ofono_watch *watch;
|
||||
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 +75,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 +125,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 +140,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 +154,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 +167,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;
|
||||
|
||||
@@ -181,11 +197,74 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
ril_netreg_cbd_free);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_strange(const struct ofono_network_operator *op,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
gsize mcclen;
|
||||
|
||||
if (sim && op->status != OPERATOR_STATUS_CURRENT) {
|
||||
const char *spn = ofono_sim_get_spn(sim);
|
||||
const char *mcc = ofono_sim_get_mcc(sim);
|
||||
const char *mnc = ofono_sim_get_mnc(sim);
|
||||
|
||||
if (spn && mcc && mnc && !strcmp(op->name, spn) &&
|
||||
(strcmp(op->mcc, mcc) || strcmp(op->mnc, mnc))) {
|
||||
/*
|
||||
* Status is not "current", SPN matches the SIM, but
|
||||
* MCC and/or MNC don't (e.g. Sony Xperia X where all
|
||||
* operators could be reported with the same name
|
||||
* which equals SPN).
|
||||
*/
|
||||
DBG("%s %s%s (sim spn?)", op->name, op->mcc, op->mnc);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
mcclen = strlen(op->mcc);
|
||||
if (!strncmp(op->name, op->mcc, mcclen) &&
|
||||
!strcmp(op->name + mcclen, op->mnc)) {
|
||||
/* Some MediaTek RILs only report numeric operator name */
|
||||
DBG("%s %s%s (numeric?)", op->name, op->mcc, op->mnc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_process_operators(struct ril_netreg *nd,
|
||||
struct ofono_network_operator *ops, int nops)
|
||||
{
|
||||
if (nd->replace_strange_oper) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nops; i++) {
|
||||
struct ofono_network_operator *op = ops + i;
|
||||
struct ofono_gprs_provision_data *prov = NULL;
|
||||
int np = 0;
|
||||
|
||||
if (ril_netreg_strange(op, nd->watch->sim) &&
|
||||
__ofono_gprs_provision_get_settings(op->mcc,
|
||||
op->mnc, NULL, &prov, &np)) {
|
||||
/* Use the first entry */
|
||||
if (np > 0 && prov->provider_name &&
|
||||
prov->provider_name[0]) {
|
||||
DBG("%s %s%s -> %s", op->name, op->mcc,
|
||||
op->mnc, prov->provider_name);
|
||||
strncpy(op->name, prov->provider_name,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
}
|
||||
__ofono_gprs_provision_free_settings(prov, np);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
struct ofono_network_operator *list;
|
||||
struct ofono_error error;
|
||||
int noperators = 0, i;
|
||||
@@ -227,21 +306,23 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
|
||||
/* Set the proper status */
|
||||
if (!strcmp(status, "available")) {
|
||||
list[i].status = OPERATOR_STATUS_AVAILABLE;
|
||||
if (!status) {
|
||||
op->status = OPERATOR_STATUS_UNKNOWN;
|
||||
} else if (!strcmp(status, "available")) {
|
||||
op->status = OPERATOR_STATUS_AVAILABLE;
|
||||
} else if (!strcmp(status, "current")) {
|
||||
list[i].status = OPERATOR_STATUS_CURRENT;
|
||||
op->status = OPERATOR_STATUS_CURRENT;
|
||||
} else if (!strcmp(status, "forbidden")) {
|
||||
list[i].status = OPERATOR_STATUS_FORBIDDEN;
|
||||
op->status = OPERATOR_STATUS_FORBIDDEN;
|
||||
} else {
|
||||
list[i].status = OPERATOR_STATUS_UNKNOWN;
|
||||
op->status = OPERATOR_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
op->tech = -1;
|
||||
ok = ril_parse_mcc_mnc(numeric, op);
|
||||
if (ok) {
|
||||
if (op->tech < 0) {
|
||||
op->tech = cbd->nd->network->voice.access_tech;
|
||||
op->tech = nd->network->voice.access_tech;
|
||||
}
|
||||
DBG("[operator=%s, %s, %s, status: %s]", op->name,
|
||||
op->mcc, op->mnc, status);
|
||||
@@ -256,6 +337,7 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
ril_netreg_process_operators(nd, list, noperators);
|
||||
cb(ril_error_ok(&error), noperators, list, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
@@ -290,16 +372,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 +431,11 @@ 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_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
@@ -318,56 +443,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 = -4 * 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 +538,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 +553,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 +580,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 +589,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 +656,23 @@ 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->watch = ofono_watch_new(ril_modem_get_path(modem));
|
||||
nd->vendor = ril_vendor_ref(modem->vendor);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
nd->replace_strange_oper = config->replace_strange_oper;
|
||||
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 +682,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 +699,12 @@ 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]);
|
||||
}
|
||||
ofono_watch_unref(nd->watch);
|
||||
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);
|
||||
|
||||
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-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
|
||||
@@ -18,7 +19,10 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
struct ril_radio_caps;
|
||||
|
||||
struct ril_registration_state {
|
||||
int status; /* enum network_registration_status */
|
||||
@@ -40,20 +44,25 @@ struct ril_network {
|
||||
struct ril_sim_settings *settings;
|
||||
};
|
||||
|
||||
struct ofono_sim;
|
||||
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);
|
||||
|
||||
void ril_network_set_radio_caps(struct ril_network *net,
|
||||
struct ril_radio_caps *caps);
|
||||
void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||
enum ofono_radio_access_mode max_pref_mode,
|
||||
gboolean force_check);
|
||||
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
||||
enum ofono_radio_access_mode ril_network_max_supported_mode
|
||||
(struct ril_network *self);
|
||||
void ril_network_query_registration_state(struct ril_network *net);
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||
@@ -62,11 +71,12 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||
|
||||
#define ril_network_remove_all_handlers(net, ids) \
|
||||
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_NETWORK_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -32,6 +33,11 @@ struct ril_oem_raw {
|
||||
|
||||
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
|
||||
|
||||
static void ril_oem_raw_send_done(void *msg)
|
||||
{
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -40,20 +46,13 @@ static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBusMessageIter it, array;
|
||||
const guchar* bytes = data;
|
||||
guint i;
|
||||
|
||||
reply = dbus_message_new_method_return(msg);
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_BYTE_AS_STRING, &array);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
guchar byte = bytes[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
|
||||
&byte);
|
||||
}
|
||||
|
||||
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
|
||||
&data, len);
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
|
||||
DBG("Timed out");
|
||||
@@ -63,7 +62,7 @@ static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
reply = __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, reply);
|
||||
g_dbus_send_message(ofono_dbus_get_connection(), reply);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
@@ -72,6 +71,12 @@ static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
DBusMessageIter it;
|
||||
struct ril_oem_raw *oem = user_data;
|
||||
|
||||
if (!__ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
|
||||
OFONO_DBUS_ACCESS_INTF_OEMRAW,
|
||||
OFONO_DBUS_ACCESS_OEMRAW_SEND, NULL)) {
|
||||
return __ofono_error_access_denied(msg);
|
||||
}
|
||||
|
||||
dbus_message_iter_init(msg, &it);
|
||||
if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY &&
|
||||
dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) {
|
||||
@@ -94,7 +99,7 @@ static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
grilio_request_append_bytes(req, data, data_len);
|
||||
grilio_queue_send_request_full(oem->q, req,
|
||||
RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb,
|
||||
NULL, dbus_message_ref(msg));
|
||||
ril_oem_raw_send_done, dbus_message_ref(msg));
|
||||
grilio_request_unref(req);
|
||||
return NULL;
|
||||
} else {
|
||||
|
||||
@@ -998,8 +998,9 @@ static void ril_export_entries(struct ofono_phonebook *pb,
|
||||
pbd->df_path = usim_path;
|
||||
pbd->df_size = sizeof(usim_path);
|
||||
|
||||
ofono_sim_read(pbd->sim_context, SIM_EFPBR_FILEID,
|
||||
ofono_sim_read_path(pbd->sim_context, SIM_EFPBR_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pbd->df_path, pbd->df_size,
|
||||
pb_reference_data_cb, pb);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user