forked from sailfishos/ofono
Compare commits
755 Commits
mer/1.20+g
...
mer/1.24+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09e6f35a23 | ||
|
|
6dddf527d5 | ||
|
|
a9de07c2bb | ||
|
|
ecf14f5165 | ||
|
|
bc4c860a86 | ||
|
|
7684dd4295 | ||
|
|
f24a5be4ec | ||
|
|
c45e207f12 | ||
|
|
005f36bb89 | ||
|
|
3d01485a05 | ||
|
|
cc7b30414f | ||
|
|
1617b325de | ||
|
|
a8838c2287 | ||
|
|
c8cd552851 | ||
|
|
6995d8c42c | ||
|
|
17052d41de | ||
|
|
70a93dcc5b | ||
|
|
e3ea3abaa0 | ||
|
|
f60c44b034 | ||
|
|
a679258b4a | ||
|
|
0ed72bcffa | ||
|
|
7d5a660604 | ||
|
|
d67240c717 | ||
|
|
b12016eb45 | ||
|
|
bfec98afdf | ||
|
|
7376781211 | ||
|
|
732160519a | ||
|
|
f71d2a2b70 | ||
|
|
793e9fcae4 | ||
|
|
ae204ebf82 | ||
|
|
30b09b35af | ||
|
|
1495f222b0 | ||
|
|
b9b2765b21 | ||
|
|
29ecf1a59a | ||
|
|
f1d3367e0a | ||
|
|
7131403177 | ||
|
|
ff99f16ccb | ||
|
|
ccec9504a5 | ||
|
|
e37ca6d384 | ||
|
|
ab5b76d6cf | ||
|
|
35ef8fb8a1 | ||
|
|
d0a617d469 | ||
|
|
1ba3b32273 | ||
|
|
14b764ac64 | ||
|
|
b808bfad17 | ||
|
|
82d62a8f50 | ||
|
|
23d6263e3c | ||
|
|
ac3192204c | ||
|
|
5ad2617ecd | ||
|
|
890842b3af | ||
|
|
06de44299a | ||
|
|
77b2eec613 | ||
|
|
12ccd7cd46 | ||
|
|
8f09880d52 | ||
|
|
ee5f91221b | ||
|
|
c03c6f4215 | ||
|
|
c49e2d8723 | ||
|
|
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 |
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>
|
||||
25
ofono/.gitignore
vendored
25
ofono/.gitignore
vendored
@@ -9,7 +9,7 @@ Makefile.in
|
||||
aclocal.m4
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
config.h.in*
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
@@ -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
|
||||
@@ -40,19 +42,34 @@ unit/test-sms-root
|
||||
unit/test-simutil
|
||||
unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-cell-info
|
||||
unit/test-cell-info-dbus
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-conf
|
||||
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_cell_info
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sailfish_access
|
||||
unit/test-slot-manager
|
||||
unit/test-watch
|
||||
unit/test-sim-info
|
||||
unit/test-sim-info-dbus
|
||||
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,14 @@ 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>
|
||||
Mariem Cherif <mariem.cherif@ardia.com.tn>
|
||||
Bassem Boubaker <bassem.boubaker@actia.fr>
|
||||
Bob Ham <bob.ham@puri.sm>
|
||||
Varun Gargi <varun.gargi@intel.com>
|
||||
Florent Beillonnet <florent.beillonnet@gmail.com>
|
||||
|
||||
@@ -1,3 +1,47 @@
|
||||
ver 1.24:
|
||||
Fix issue with property changed signals and CDMA networks.
|
||||
Fix issue with handling SIM filesystem and SIM removal.
|
||||
Fix issue with handling PIN state and incorrect codes.
|
||||
Fix issue with handling of parsing AID type.
|
||||
Fix issue with SIM detection and QMI devices.
|
||||
Fix issue with PIN handling and QMI devices.
|
||||
Fix issue with USSD handling and QMI devices.
|
||||
Fix issue with handling USSD TERMINATED response.
|
||||
Fix issue with handling USSD reset and STK REFRESH.
|
||||
Add support for detecting Gemalto ALS3 modems.
|
||||
Add support for SIMCom based SIM7100E modems.
|
||||
|
||||
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,17 @@ 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/slot.h include/cell-info.h \
|
||||
include/storage.h include/conf.h include/misc.h \
|
||||
include/mtu-limit.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 +65,7 @@ endif
|
||||
builtin_modules =
|
||||
builtin_sources =
|
||||
builtin_libadd =
|
||||
builtin_cflags =
|
||||
builtin_cflags = -DSAILFISH_OS
|
||||
|
||||
noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
|
||||
|
||||
@@ -120,58 +121,12 @@ builtin_modules += udevng
|
||||
builtin_sources += plugins/udevng.c
|
||||
endif
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
builtin_modules += sailfish_manager
|
||||
builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_manager_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_watch.c
|
||||
if SAILFISH_ACCESS
|
||||
builtin_modules += sailfish_access
|
||||
builtin_sources += plugins/sailfish_access.c
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_forward.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_netmon.c \
|
||||
drivers/ril/ril_netreg.c \
|
||||
drivers/ril/ril_network.c \
|
||||
drivers/ril/ril_oem_raw.c \
|
||||
drivers/ril/ril_phonebook.c \
|
||||
drivers/ril/ril_plugin.c \
|
||||
drivers/ril/ril_radio.c \
|
||||
drivers/ril/ril_radio_caps.c \
|
||||
drivers/ril/ril_radio_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_settings.c \
|
||||
drivers/ril/ril_sms.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
drivers/ril/ril_ussd.c \
|
||||
drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
builtin_modules += rildev
|
||||
@@ -212,7 +167,6 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/infineonmodem/infineon_constants.h \
|
||||
drivers/rilmodem/lte.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if ISIMODEM
|
||||
builtin_modules += isimodem
|
||||
@@ -275,7 +229,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 +246,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 +279,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 +411,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
|
||||
@@ -473,7 +436,7 @@ builtin_sources += drivers/cdmamodem/cdmamodem.h \
|
||||
drivers/cdmamodem/connman.c
|
||||
endif
|
||||
|
||||
if !RILMODEM
|
||||
if EXTRA_MODEMS
|
||||
builtin_modules += g1
|
||||
builtin_sources += plugins/g1.c
|
||||
|
||||
@@ -549,8 +512,8 @@ builtin_sources += plugins/samsung.c
|
||||
builtin_modules += sim900
|
||||
builtin_sources += plugins/sim900.c
|
||||
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
builtin_modules += sim7100
|
||||
builtin_sources += plugins/sim7100.c
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c
|
||||
@@ -561,8 +524,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,10 +657,39 @@ 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 \
|
||||
src/mtu-watch.c \
|
||||
src/main.c src/ofono.h src/log.c src/plugin.c \
|
||||
src/modem.c src/common.h src/common.c \
|
||||
src/manager.c src/dbus.c src/util.h src/util.c \
|
||||
@@ -723,9 +715,16 @@ 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/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/slot-manager.c src/slot-manager-dbus.c \
|
||||
src/cell-info.c src/cell-info-dbus.c \
|
||||
src/sim-info.c src/sim-info-dbus.c \
|
||||
src/conf.c src/mtu-limit.c
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -735,7 +734,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
|
||||
|
||||
BUILT_SOURCES = $(local_headers) src/builtin.h
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
|
||||
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
|
||||
|
||||
plugindir = $(pkglibdir)/plugins
|
||||
|
||||
@@ -774,7 +774,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 +884,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,54 +909,78 @@ 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_cell_info_SOURCES = unit/test-cell-info.c src/cell-info.c src/log.c
|
||||
unit_test_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_cell_info_OBJECTS)
|
||||
unit_tests += unit/test-cell-info
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-Iplugins/sailfish_cell_info
|
||||
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info
|
||||
unit_test_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||
unit/test-cell-info-dbus.c unit/fake_cell_info.c \
|
||||
src/cell-info.c src/cell-info-dbus.c \
|
||||
gdbus/object.c src/dbus-clients.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@DBUS_GLIB_CFLAGS@
|
||||
unit_test_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_cell_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-cell-info-dbus
|
||||
|
||||
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/watch.c src/log.c
|
||||
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
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_sim_info_SOURCES = unit/test-sim-info.c unit/fake_watch.c \
|
||||
src/sim-info.c src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sim_info_OBJECTS)
|
||||
unit_tests += unit/test-sim-info
|
||||
|
||||
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
unit_test_sim_info_dbus_SOURCES = unit/test-sim-info-dbus.c \
|
||||
unit/test-dbus.c unit/fake_watch.c \
|
||||
src/sim-info.c src/sim-info-dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sim_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sim-info-dbus
|
||||
|
||||
unit_test_slot_manager_SOURCES = unit/test-slot-manager.c unit/fake_watch.c \
|
||||
src/slot-manager.c src/cell-info.c src/sim-info.c \
|
||||
src/storage.c src/log.c
|
||||
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_manager
|
||||
unit_test_slot_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_slot_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_slot_manager_OBJECTS)
|
||||
unit_tests += unit/test-slot-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
|
||||
|
||||
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_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_util_OBJECTS)
|
||||
unit_tests += unit/test-ril_util
|
||||
|
||||
else
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-sms \
|
||||
@@ -957,7 +988,13 @@ unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-gprs
|
||||
|
||||
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 +1055,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 +1078,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 +1146,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 +1246,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.24)
|
||||
|
||||
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
|
||||
])
|
||||
|
||||
@@ -177,30 +177,21 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
|
||||
[enable_rilmodem=${enableval}])
|
||||
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||
[enable Sailfish RIL modem]),
|
||||
[enable_sailfish_rilmodem=${enableval}],
|
||||
[enable_sailfish_rilmodem="no"])
|
||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||
AC_ARG_ENABLE(extra-modems,
|
||||
AC_HELP_STRING([--enable-extra-modems],
|
||||
[enable modems not used by Sailfish OS]),
|
||||
[enable_extra_modems=${enableval}])
|
||||
AM_CONDITIONAL(EXTRA_MODEMS, test "${enable_extra_modems}" = "yes")
|
||||
|
||||
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))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||
enable_sailfish_manager=yes
|
||||
need_glibutil=yes
|
||||
fi
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.49, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.49 is required))
|
||||
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||
|
||||
AC_ARG_ENABLE(sailfish-manager,
|
||||
AC_HELP_STRING([--enable-sailfish-manager],
|
||||
[enable Sailfish OS modem manager plugin]),
|
||||
[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]), [
|
||||
@@ -285,6 +276,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 +306,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 +337,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;
|
||||
|
||||
@@ -48,6 +48,51 @@ struct cbs_data {
|
||||
unsigned int vendor;
|
||||
};
|
||||
|
||||
static void at_xmm_etw_sec_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_cbs *cbs = user_data;
|
||||
const char *hexpdu;
|
||||
int pdulen;
|
||||
GAtResultIter iter;
|
||||
unsigned char pdu[88];
|
||||
long hexpdulen;
|
||||
|
||||
DBG("");
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+XETWSECWARN:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &pdulen))
|
||||
return;
|
||||
|
||||
if (pdulen != 88) {
|
||||
ofono_error("Got a CBM message with invalid PDU size!");
|
||||
return;
|
||||
}
|
||||
|
||||
hexpdu = g_at_result_pdu(result);
|
||||
if (hexpdu == NULL) {
|
||||
ofono_error("Got a CBM, but no PDU. Are we in text mode?");
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("Got new Cell Broadcast via XETWSECWARN: %s, %d", hexpdu, pdulen);
|
||||
|
||||
if (decode_hex_own_buf(hexpdu, -1, &hexpdulen, 0, pdu) == NULL) {
|
||||
ofono_error("Unable to hex-decode the PDU");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hexpdulen != pdulen) {
|
||||
ofono_error("hexpdu length not equal to reported pdu length");
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_cbs_notify(cbs, pdu, pdulen);
|
||||
}
|
||||
|
||||
static void at_cbm_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_cbs *cbs = user_data;
|
||||
@@ -124,6 +169,10 @@ static void at_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_XMM:
|
||||
g_at_chat_send(data->chat, "AT+XETWNTFYSTART=2", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -151,6 +200,10 @@ static void at_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->vendor == OFONO_VENDOR_XMM)
|
||||
g_at_chat_send(data->chat, "AT+XETWNTFYSTOP=2", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix,
|
||||
at_cscb_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
@@ -175,6 +228,10 @@ static void at_cbs_register(gboolean ok, GAtResult *result, gpointer user)
|
||||
*/
|
||||
g_at_chat_register(data->chat, "+CBM:", at_cbm_notify, TRUE, cbs, NULL);
|
||||
|
||||
if (data->vendor == OFONO_VENDOR_XMM)
|
||||
g_at_chat_register(data->chat, "+XETWSECWARN:",
|
||||
at_xmm_etw_sec_notify, TRUE, cbs, NULL);
|
||||
|
||||
ofono_cbs_register(cbs);
|
||||
}
|
||||
|
||||
@@ -223,6 +280,13 @@ static int at_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
|
||||
ofono_cbs_set_data(cbs, data);
|
||||
|
||||
if (vendor == OFONO_VENDOR_XMM) {
|
||||
g_at_chat_send(data->chat, "AT+XCMAS=1", cscb_prefix,
|
||||
NULL, NULL, NULL);
|
||||
g_at_chat_send(data->chat, "AT+XETWCFG=1,1,0,0; ", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
g_at_chat_send(data->chat, "AT+CSCB=?", cscb_prefix,
|
||||
at_cscb_support_cb, cbs, NULL);
|
||||
|
||||
|
||||
@@ -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, unsigned int vendor, 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);
|
||||
}
|
||||
@@ -48,6 +48,7 @@ static const char *cops_prefix[] = { "+COPS:", NULL };
|
||||
static const char *csq_prefix[] = { "+CSQ:", NULL };
|
||||
static const char *cind_prefix[] = { "+CIND:", NULL };
|
||||
static const char *cmer_prefix[] = { "+CMER:", NULL };
|
||||
static const char *smoni_prefix[] = { "^SMONI:", NULL };
|
||||
static const char *zpas_prefix[] = { "+ZPAS:", NULL };
|
||||
static const char *option_tech_prefix[] = { "_OCTI:", "_OUWCTI:", NULL };
|
||||
|
||||
@@ -178,6 +179,31 @@ static int option_parse_tech(GAtResult *result)
|
||||
return tech;
|
||||
}
|
||||
|
||||
static int cinterion_parse_tech(GAtResult *result)
|
||||
{
|
||||
int tech = -1;
|
||||
GAtResultIter iter;
|
||||
const char *technology;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^SMONI: "))
|
||||
return tech;
|
||||
|
||||
if (!g_at_result_iter_next_unquoted_string(&iter, &technology))
|
||||
return tech;
|
||||
|
||||
if (strcmp(technology, "2G") == 0) {
|
||||
tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
|
||||
} else if (strcmp(technology, "3G") == 0) {
|
||||
tech = ACCESS_TECHNOLOGY_UTRAN;
|
||||
} else if (strcmp(technology, "4G") == 0) {
|
||||
tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
}
|
||||
|
||||
return tech;
|
||||
}
|
||||
|
||||
static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -205,6 +231,18 @@ static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
cb(&error, status, lac, ci, tech, cbd->data);
|
||||
}
|
||||
|
||||
static void cinterion_query_tech_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct tech_query *tq = user_data;
|
||||
int tech;
|
||||
|
||||
tech = cinterion_parse_tech(result);
|
||||
|
||||
ofono_netreg_status_notify(tq->netreg,
|
||||
tq->status, tq->lac, tq->ci, tech);
|
||||
}
|
||||
|
||||
static void zte_tech_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -1088,6 +1126,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;
|
||||
@@ -1497,6 +1556,12 @@ static void creg_notify(GAtResult *result, gpointer user_data)
|
||||
option_query_tech_cb, tq, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
if (g_at_chat_send(nd->chat, "AT^SMONI",
|
||||
smoni_prefix,
|
||||
cinterion_query_tech_cb, tq, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(tq);
|
||||
@@ -1896,6 +1961,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));
|
||||
|
||||
@@ -1411,12 +1359,12 @@ static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
|
||||
char buf[64];
|
||||
int ret;
|
||||
|
||||
cbd->user = sd;
|
||||
cbd->user = sim;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, 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,
|
||||
};
|
||||
|
||||
@@ -1120,6 +1120,7 @@ static int at_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
|
||||
switch (vd->vendor) {
|
||||
case OFONO_VENDOR_QUALCOMM_MSM:
|
||||
case OFONO_VENDOR_SIMCOM:
|
||||
g_at_chat_send(vd->chat, "AT+COLP=0", NULL, NULL, NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -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);
|
||||
@@ -129,6 +129,7 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
|
||||
/* Telit qmi modems return a "0" string when ESN is not available. */
|
||||
if (!str || strcmp(str, "0") == 0) {
|
||||
qmi_free(str);
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
@@ -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);
|
||||
|
||||
265
ofono/drivers/qmimodem/lte.c
Normal file
265
ofono/drivers/qmimodem/lte.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
*
|
||||
* 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,
|
||||
unsigned int vendor, 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;
|
||||
|
||||
@@ -47,6 +47,13 @@ struct discovery {
|
||||
qmi_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
struct qmi_version {
|
||||
uint8_t type;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct qmi_device {
|
||||
int ref_count;
|
||||
int fd;
|
||||
@@ -73,12 +80,13 @@ 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 {
|
||||
int ref_count;
|
||||
struct qmi_device *device;
|
||||
bool shared;
|
||||
uint8_t type;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
@@ -159,25 +167,25 @@ void qmi_free(void *ptr)
|
||||
|
||||
static struct qmi_request *__request_alloc(uint8_t service,
|
||||
uint8_t client, uint16_t message,
|
||||
uint16_t headroom, const void *data,
|
||||
const void *data,
|
||||
uint16_t length, qmi_message_func_t func,
|
||||
void *user_data, void **head)
|
||||
void *user_data)
|
||||
{
|
||||
struct qmi_request *req;
|
||||
struct qmi_mux_hdr *hdr;
|
||||
struct qmi_message_hdr *msg;
|
||||
uint16_t headroom;
|
||||
|
||||
req = g_try_new0(struct qmi_request, 1);
|
||||
if (!req)
|
||||
return NULL;
|
||||
req = g_new0(struct qmi_request, 1);
|
||||
|
||||
if (service == QMI_SERVICE_CONTROL)
|
||||
headroom = QMI_CONTROL_HDR_SIZE;
|
||||
else
|
||||
headroom = QMI_SERVICE_HDR_SIZE;
|
||||
|
||||
req->len = QMI_MUX_HDR_SIZE + headroom + QMI_MESSAGE_HDR_SIZE + length;
|
||||
|
||||
req->buf = g_try_malloc(req->len);
|
||||
if (!req->buf) {
|
||||
g_free(req);
|
||||
return NULL;
|
||||
}
|
||||
req->buf = g_malloc(req->len);
|
||||
|
||||
req->client = client;
|
||||
|
||||
@@ -201,8 +209,6 @@ static struct qmi_request *__request_alloc(uint8_t service,
|
||||
req->callback = func;
|
||||
req->user_data = user_data;
|
||||
|
||||
*head = req->buf + QMI_MUX_HDR_SIZE;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -254,9 +260,6 @@ static gboolean __service_compare_shared(gpointer key, gpointer value,
|
||||
struct qmi_service *service = value;
|
||||
uint8_t type = GPOINTER_TO_UINT(user_data);
|
||||
|
||||
if (!service->shared)
|
||||
return FALSE;
|
||||
|
||||
if (service->type == type)
|
||||
return TRUE;
|
||||
|
||||
@@ -474,6 +477,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)
|
||||
{
|
||||
@@ -682,14 +696,37 @@ static void wakeup_writer(struct qmi_device *device)
|
||||
can_write_data, device, write_watch_destroy);
|
||||
}
|
||||
|
||||
static void __request_submit(struct qmi_device *device,
|
||||
struct qmi_request *req, uint16_t transaction)
|
||||
static uint16_t __request_submit(struct qmi_device *device,
|
||||
struct qmi_request *req)
|
||||
{
|
||||
req->tid = transaction;
|
||||
struct qmi_mux_hdr *mux;
|
||||
|
||||
mux = req->buf;
|
||||
|
||||
if (mux->service == QMI_SERVICE_CONTROL) {
|
||||
struct qmi_control_hdr *hdr;
|
||||
|
||||
hdr = req->buf + QMI_MUX_HDR_SIZE;
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_control_tid++;
|
||||
if (device->next_control_tid == 0)
|
||||
device->next_control_tid = 1;
|
||||
req->tid = hdr->transaction;
|
||||
} else {
|
||||
struct qmi_service_hdr *hdr;
|
||||
hdr = req->buf + QMI_MUX_HDR_SIZE;
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_service_tid++;
|
||||
if (device->next_service_tid < 256)
|
||||
device->next_service_tid = 256;
|
||||
req->tid = hdr->transaction;
|
||||
}
|
||||
|
||||
g_queue_push_tail(device->req_queue, req);
|
||||
|
||||
wakeup_writer(device);
|
||||
|
||||
return req->tid;
|
||||
}
|
||||
|
||||
static void service_notify(gpointer key, gpointer value, gpointer user_data)
|
||||
@@ -948,6 +985,9 @@ struct qmi_device *qmi_device_new(int fd)
|
||||
device->service_list = g_hash_table_new_full(g_direct_hash,
|
||||
g_direct_equal, NULL, service_destroy);
|
||||
|
||||
device->next_control_tid = 1;
|
||||
device->next_service_tid = 256;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
@@ -1000,7 +1040,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 +1064,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)
|
||||
{
|
||||
@@ -1045,12 +1105,48 @@ static const void *tlv_get(const void *data, uint16_t size,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type,
|
||||
uint16_t *major, uint16_t *minor)
|
||||
{
|
||||
struct qmi_version *info;
|
||||
int i;
|
||||
|
||||
for (i = 0, info = device->version_list;
|
||||
i < device->version_count;
|
||||
i++, info++) {
|
||||
if (info->type == type) {
|
||||
*major = info->major;
|
||||
*minor = info->minor;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qmi_device_has_service(struct qmi_device *device, uint8_t type)
|
||||
{
|
||||
struct qmi_version *info;
|
||||
int i;
|
||||
|
||||
for (i = 0, info = device->version_list;
|
||||
i < device->version_count;
|
||||
i++, info++) {
|
||||
if (info->type == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct discover_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
qmi_discover_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
uint8_t tid;
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
@@ -1111,6 +1207,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 +1226,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,19 +1234,12 @@ 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;
|
||||
|
||||
if (data->func)
|
||||
data->func(count, list, data->user_data);
|
||||
data->func(data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
@@ -1159,14 +1248,37 @@ 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);
|
||||
data->func(data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
__request_free(req, NULL);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1176,7 +1288,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
{
|
||||
struct discover_data *data;
|
||||
struct qmi_request *req;
|
||||
struct qmi_control_hdr *hdr;
|
||||
uint8_t tid;
|
||||
|
||||
if (!device)
|
||||
return false;
|
||||
@@ -1200,20 +1312,12 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
}
|
||||
|
||||
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
|
||||
QMI_CTL_GET_VERSION_INFO, QMI_CONTROL_HDR_SIZE,
|
||||
NULL, 0, discover_callback, data, (void **) &hdr);
|
||||
if (!req) {
|
||||
g_free(data);
|
||||
return false;
|
||||
}
|
||||
QMI_CTL_GET_VERSION_INFO,
|
||||
NULL, 0, discover_callback, data);
|
||||
|
||||
if (device->next_control_tid < 1)
|
||||
device->next_control_tid = 1;
|
||||
tid = __request_submit(device, req);
|
||||
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_control_tid++;
|
||||
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
data->tid = tid;
|
||||
|
||||
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
@@ -1227,24 +1331,13 @@ static void release_client(struct qmi_device *device,
|
||||
{
|
||||
unsigned char release_req[] = { 0x01, 0x02, 0x00, type, client_id };
|
||||
struct qmi_request *req;
|
||||
struct qmi_control_hdr *hdr;
|
||||
|
||||
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
|
||||
QMI_CTL_RELEASE_CLIENT_ID, QMI_CONTROL_HDR_SIZE,
|
||||
QMI_CTL_RELEASE_CLIENT_ID,
|
||||
release_req, sizeof(release_req),
|
||||
func, user_data, (void **) &hdr);
|
||||
if (!req) {
|
||||
func(0x0000, 0x0000, NULL, user_data);
|
||||
return;
|
||||
}
|
||||
func, user_data);
|
||||
|
||||
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);
|
||||
__request_submit(device, req);
|
||||
}
|
||||
|
||||
static void shutdown_destroy(gpointer user_data)
|
||||
@@ -1255,6 +1348,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 +1360,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 +1394,58 @@ 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 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,
|
||||
NULL, 0,
|
||||
qmi_device_sync_callback, func_data);
|
||||
|
||||
__request_submit(device, req);
|
||||
|
||||
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 +1843,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)
|
||||
{
|
||||
@@ -1759,7 +1932,6 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
struct service_create_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
bool shared;
|
||||
uint8_t type;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
@@ -1830,7 +2002,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
||||
|
||||
service->ref_count = 1;
|
||||
service->device = data->device;
|
||||
service->shared = data->shared;
|
||||
|
||||
service->type = data->type;
|
||||
service->major = data->major;
|
||||
@@ -1853,100 +2024,52 @@ done:
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
|
||||
static void service_create_discover(uint8_t count,
|
||||
const struct qmi_version *list, void *user_data)
|
||||
{
|
||||
struct service_create_data *data = user_data;
|
||||
struct qmi_device *device = data->device;
|
||||
struct qmi_request *req;
|
||||
struct qmi_control_hdr *hdr;
|
||||
unsigned char client_req[] = { 0x01, 0x01, 0x00, data->type };
|
||||
unsigned int i;
|
||||
|
||||
__debug_device(device, "service create [type=%d]", data->type);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (list[i].type == data->type) {
|
||||
data->major = list[i].major;
|
||||
data->minor = list[i].minor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
|
||||
QMI_CTL_GET_CLIENT_ID, QMI_CONTROL_HDR_SIZE,
|
||||
client_req, sizeof(client_req),
|
||||
service_create_callback, data, (void **) &hdr);
|
||||
if (!req) {
|
||||
if (data->timeout > 0)
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
data->timeout = g_timeout_add_seconds(0,
|
||||
service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static bool service_create(struct qmi_device *device, bool shared,
|
||||
static bool service_create(struct qmi_device *device,
|
||||
uint8_t type, qmi_create_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy)
|
||||
{
|
||||
struct service_create_data *data;
|
||||
unsigned char client_req[] = { 0x01, 0x01, 0x00, type };
|
||||
struct qmi_request *req;
|
||||
int i;
|
||||
|
||||
data = g_try_new0(struct service_create_data, 1);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (!device->version_list)
|
||||
return false;
|
||||
|
||||
data->super.destroy = service_create_data_free;
|
||||
data->device = device;
|
||||
data->shared = shared;
|
||||
data->type = type;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
if (device->version_list) {
|
||||
service_create_discover(device->version_count,
|
||||
device->version_list, data);
|
||||
goto done;
|
||||
__debug_device(device, "service create [type=%d]", type);
|
||||
|
||||
for (i = 0; i < device->version_count; i++) {
|
||||
if (device->version_list[i].type == data->type) {
|
||||
data->major = device->version_list[i].major;
|
||||
data->minor = device->version_list[i].minor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (qmi_device_discover(device, service_create_discover, data, NULL))
|
||||
goto done;
|
||||
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
|
||||
QMI_CTL_GET_CLIENT_ID,
|
||||
client_req, sizeof(client_req),
|
||||
service_create_callback, data);
|
||||
|
||||
g_free(data);
|
||||
__request_submit(device, req);
|
||||
|
||||
return false;
|
||||
|
||||
done:
|
||||
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_service_create(struct qmi_device *device,
|
||||
uint8_t type, qmi_create_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy)
|
||||
{
|
||||
if (!device || !func)
|
||||
return false;
|
||||
|
||||
if (type == QMI_SERVICE_CONTROL)
|
||||
return false;
|
||||
|
||||
return service_create(device, false, type, func, user_data, destroy);
|
||||
}
|
||||
|
||||
struct service_create_shared_data {
|
||||
struct discovery super;
|
||||
struct qmi_service *service;
|
||||
@@ -2022,7 +2145,15 @@ bool qmi_service_create_shared(struct qmi_device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return service_create(device, true, type, func, user_data, destroy);
|
||||
return service_create(device, type, func, user_data, destroy);
|
||||
}
|
||||
|
||||
bool qmi_service_create(struct qmi_device *device,
|
||||
uint8_t type, qmi_create_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy)
|
||||
{
|
||||
return qmi_service_create_shared(device, type, func,
|
||||
user_data, destroy);
|
||||
}
|
||||
|
||||
static void service_release_callback(uint16_t message, uint16_t length,
|
||||
@@ -2099,8 +2230,6 @@ bool qmi_service_get_version(struct qmi_service *service,
|
||||
}
|
||||
|
||||
struct service_send_data {
|
||||
struct qmi_service *service;
|
||||
struct qmi_param *param;
|
||||
qmi_result_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
@@ -2111,8 +2240,6 @@ static void service_send_free(struct service_send_data *data)
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
qmi_param_free(data->param);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
@@ -2153,7 +2280,7 @@ uint16_t qmi_service_send(struct qmi_service *service,
|
||||
struct qmi_device *device;
|
||||
struct service_send_data *data;
|
||||
struct qmi_request *req;
|
||||
struct qmi_service_hdr *hdr;
|
||||
uint16_t tid;
|
||||
|
||||
if (!service)
|
||||
return 0;
|
||||
@@ -2169,31 +2296,21 @@ uint16_t qmi_service_send(struct qmi_service *service,
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
data->service = service;
|
||||
data->param = param;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
req = __request_alloc(service->type, service->client_id,
|
||||
message, QMI_SERVICE_HDR_SIZE,
|
||||
data->param ? data->param->data : NULL,
|
||||
data->param ? data->param->length : 0,
|
||||
service_send_callback, data, (void **) &hdr);
|
||||
if (!req) {
|
||||
g_free(data);
|
||||
return 0;
|
||||
}
|
||||
message,
|
||||
param ? param->data : NULL,
|
||||
param ? param->length : 0,
|
||||
service_send_callback, data);
|
||||
|
||||
if (device->next_service_tid < 256)
|
||||
device->next_service_tid = 256;
|
||||
qmi_param_free(param);
|
||||
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_service_tid++;
|
||||
tid = __request_submit(device, req);
|
||||
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
|
||||
return hdr->transaction;
|
||||
return tid;
|
||||
}
|
||||
|
||||
bool qmi_service_cancel(struct qmi_service *service, uint16_t id)
|
||||
|
||||
@@ -61,13 +61,6 @@ enum qmi_device_expected_data_format {
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
|
||||
};
|
||||
|
||||
struct qmi_version {
|
||||
uint8_t type;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
void qmi_free(void *ptr);
|
||||
|
||||
typedef void (*qmi_destroy_func_t)(void *user_data);
|
||||
@@ -76,10 +69,9 @@ 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);
|
||||
typedef void (*qmi_discover_func_t)(void *user_data);
|
||||
|
||||
struct qmi_device *qmi_device_new(int fd);
|
||||
|
||||
@@ -96,6 +88,14 @@ 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_has_service(struct qmi_device *device, uint8_t type);
|
||||
bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type,
|
||||
uint16_t *major, uint16_t *minor);
|
||||
|
||||
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 +130,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;
|
||||
@@ -375,8 +493,15 @@ static bool get_card_status(const struct qmi_uim_slot_info *slot,
|
||||
case 0x03: /* PUK1 or PUK for UPIN is required */
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
break;
|
||||
case 0x00: /* Unknown */
|
||||
case 0x01: /* Detected */
|
||||
case 0x04: /* Personalization state must be checked. */
|
||||
/* This is temporary, we could retry and get another result */
|
||||
case 0x05: /* PIN1 blocked */
|
||||
case 0x06: /* Illegal */
|
||||
/*
|
||||
* This could be temporary, we should retry and
|
||||
* expect another result
|
||||
*/
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
need_retry = true;
|
||||
break;
|
||||
@@ -439,7 +564,7 @@ static enum get_card_status_result handle_get_card_status_result(
|
||||
|
||||
index = GUINT16_FROM_LE(status->index_gw_pri);
|
||||
|
||||
if ((index & 0xff) == i && (index >> 8) == n) {
|
||||
if ((index & 0xff) == n && (index >> 8) == i) {
|
||||
if (get_card_status(slot, info1, info2,
|
||||
sim_stat))
|
||||
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
|
||||
@@ -477,20 +602,32 @@ static void query_passwd_state_cb(struct qmi_result *result,
|
||||
struct sim_status sim_stat;
|
||||
enum get_card_status_result res;
|
||||
struct cb_data *retry_cbd;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
sim_stat.retries[i] = -1;
|
||||
|
||||
res = handle_get_card_status_result(result, &sim_stat);
|
||||
switch (res) {
|
||||
case GET_CARD_STATUS_RESULT_OK:
|
||||
DBG("passwd state %d", sim_stat.passwd_state);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
|
||||
if (sim_stat.passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
ofono_sim_inserted_notify(sim, FALSE);
|
||||
} else
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state,
|
||||
cbd->data);
|
||||
break;
|
||||
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
|
||||
data->retry_count++;
|
||||
if (data->retry_count > MAX_RETRY_COUNT) {
|
||||
DBG("Failed after %d attempts", data->retry_count);
|
||||
DBG("Failed after %d attempts. Card state:%d",
|
||||
data->retry_count,
|
||||
sim_stat.card_state);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
ofono_sim_inserted_notify(sim, FALSE);
|
||||
} else {
|
||||
DBG("Retry command");
|
||||
retry_cbd = cb_data_new(cb, cbd->data);
|
||||
@@ -504,6 +641,7 @@ static void query_passwd_state_cb(struct qmi_result *result,
|
||||
DBG("Command failed");
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
ofono_sim_inserted_notify(sim, FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -532,9 +670,13 @@ static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
struct sim_status sim_stat;
|
||||
unsigned int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
sim_stat.retries[i] = -1;
|
||||
|
||||
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||
GET_CARD_STATUS_RESULT_OK) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
@@ -777,6 +919,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);
|
||||
g_free(utf8);
|
||||
|
||||
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(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,283 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* See 3GPP 27.007 7.4 for possible values */
|
||||
#define RIL_MAX_SERVICE_LENGTH 3
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_barring_cbd {
|
||||
struct ril_call_barring *bd;
|
||||
union _ofono_call_barring_cb {
|
||||
ofono_call_barring_query_cb_t query;
|
||||
ofono_call_barring_set_cb_t set;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_barring_cbd_free g_free
|
||||
|
||||
static inline struct ril_call_barring *ril_call_barring_get_data(
|
||||
struct ofono_call_barring *b)
|
||||
{
|
||||
return ofono_call_barring_get_data(b);
|
||||
}
|
||||
|
||||
static struct ril_call_barring_cbd *ril_call_barring_cbd_new(
|
||||
struct ril_call_barring *bd, void *cb, void *data)
|
||||
{
|
||||
struct ril_call_barring_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_call_barring_cbd, 1);
|
||||
cbd->bd = bd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_barring_submit_request(struct ril_call_barring *bd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
{
|
||||
grilio_queue_send_request_full(bd->q, req, code, response,
|
||||
ril_call_barring_cbd_free,
|
||||
ril_call_barring_cbd_new(bd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_call_barring_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_query_cb_t cb = cbd->cb.query;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int bearer_class = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
/*
|
||||
* Services for which the specified barring facility is active.
|
||||
* "0" means "disabled for all, -1 if unknown"
|
||||
*/
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* count */
|
||||
grilio_parser_get_int32(&rilp, &bearer_class);
|
||||
DBG("Active services: %d", bearer_class);
|
||||
cb(ril_error_ok(&error), bearer_class, cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring query error %d", status);
|
||||
cb(ril_error_failure(&error), 0, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
const char *lock, int cls,
|
||||
ofono_call_barring_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("lock: %s, services to query: %d", lock, cls);
|
||||
|
||||
/*
|
||||
* RIL modems do not support 7 as default bearer class. According to
|
||||
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||
* "All tele and bearer services"
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/*
|
||||
* 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) */
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_call_barring_query_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring Set error %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_set(struct ofono_call_barring *b,
|
||||
const char *lock, int enable, const char *passwd, int cls,
|
||||
ofono_call_barring_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("lock: %s, enable: %i, bearer class: %i", lock, enable, cls);
|
||||
|
||||
/*
|
||||
* RIL modem does not support 7 as default bearer class. According to
|
||||
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||
* "All tele and bearer services"
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/* See 3GPP 27.007 7.4 for parameter descriptions */
|
||||
grilio_request_append_int32(req, RIL_SET_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_utf8(req, enable ?
|
||||
RIL_FACILITY_LOCK :
|
||||
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) */
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
ril_call_barring_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring Set PW error %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd(struct ofono_call_barring *b,
|
||||
const char *lock, const char *old_passwd,
|
||||
const char *new_passwd, ofono_call_barring_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("");
|
||||
grilio_request_append_int32(req, RIL_SET_PW_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_utf8(req, old_passwd);
|
||||
grilio_request_append_utf8(req, new_passwd);
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_CHANGE_BARRING_PASSWORD,
|
||||
ril_call_barring_set_passwd_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_barring_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_barring *b = user_data;
|
||||
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||
|
||||
GASSERT(bd->timer_id);
|
||||
bd->timer_id = 0;
|
||||
ofono_call_barring_register(b);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_barring_probe(struct ofono_call_barring *b,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
|
||||
|
||||
DBG("");
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_barring_remove(struct ofono_call_barring *b)
|
||||
{
|
||||
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||
|
||||
DBG("");
|
||||
ofono_call_barring_set_data(b, NULL);
|
||||
|
||||
if (bd->timer_id > 0) {
|
||||
g_source_remove(bd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(bd->q, FALSE);
|
||||
grilio_queue_unref(bd->q);
|
||||
g_free(bd);
|
||||
}
|
||||
|
||||
const struct ofono_call_barring_driver ril_call_barring_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_barring_probe,
|
||||
.remove = ril_call_barring_remove,
|
||||
.query = ril_call_barring_query,
|
||||
.set = ril_call_barring_set,
|
||||
.set_passwd = ril_call_barring_set_passwd
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct ril_call_forward {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
enum ril_call_forward_action {
|
||||
CF_ACTION_DISABLE,
|
||||
CF_ACTION_ENABLE,
|
||||
CF_ACTION_INTERROGATE,
|
||||
CF_ACTION_REGISTRATION,
|
||||
CF_ACTION_ERASURE
|
||||
};
|
||||
|
||||
#define CF_TIME_DEFAULT (0)
|
||||
|
||||
struct ril_call_forward_cbd {
|
||||
struct ril_call_forward *fd;
|
||||
union _ofono_call_forward_cb {
|
||||
ofono_call_forwarding_query_cb_t query;
|
||||
ofono_call_forwarding_set_cb_t set;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static inline struct ril_call_forward *ril_call_forward_get_data(
|
||||
struct ofono_call_forwarding *cf)
|
||||
{
|
||||
return ofono_call_forwarding_get_data(cf);
|
||||
}
|
||||
|
||||
static void ril_call_forward_cbd_free(gpointer cbd)
|
||||
{
|
||||
g_slice_free(struct ril_call_forward_cbd, cbd);
|
||||
}
|
||||
|
||||
static struct ril_call_forward_cbd *ril_call_forward_cbd_new(void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_forward_cbd *cbd;
|
||||
|
||||
cbd = g_slice_new0(struct ril_call_forward_cbd);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
|
||||
int type, int cls, const struct ofono_phone_number *number, int time)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
/*
|
||||
* Modem seems to respond with error to all requests
|
||||
* made with bearer class BEARER_CLASS_DEFAULT.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, action);
|
||||
grilio_request_append_int32(req, type);
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
if (number) {
|
||||
grilio_request_append_int32(req, number->type);
|
||||
grilio_request_append_utf8(req, number->number);
|
||||
} else {
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, NULL); /* No number */
|
||||
}
|
||||
grilio_request_append_int32(req, time);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_forward_cbd *cbd = user_data;
|
||||
ofono_call_forwarding_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("CF setting failed");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_forward_set(struct ofono_call_forwarding *cf,
|
||||
enum ril_call_forward_action cmd, int type, int cls,
|
||||
const struct ofono_phone_number *number, int time,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = ril_call_forward_req(cmd, type, cls, number, time);
|
||||
|
||||
grilio_queue_send_request_full(fd->q, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_call_forward_set_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, const struct ofono_phone_number *number,
|
||||
int time, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf registration");
|
||||
ril_call_forward_set(cf, CF_ACTION_REGISTRATION, type, cls,
|
||||
number, time, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_erasure(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf erasure");
|
||||
ril_call_forward_set(cf, CF_ACTION_ERASURE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_deactivate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf disable");
|
||||
ril_call_forward_set(cf, CF_ACTION_DISABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_activate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf enable");
|
||||
ril_call_forward_set(cf, CF_ACTION_ENABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_forward_cbd *cbd = user_data;
|
||||
ofono_call_forwarding_query_cb_t cb = cbd->cb.query;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ofono_call_forwarding_condition *list = NULL;
|
||||
GRilIoParser rilp;
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, &count);
|
||||
|
||||
list = g_new0(struct ofono_call_forwarding_condition, count);
|
||||
for (i = 0; i < count; i++) {
|
||||
struct ofono_call_forwarding_condition *fw = list + i;
|
||||
char *str;
|
||||
|
||||
grilio_parser_get_int32(&rilp, &fw->status);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &fw->cls);
|
||||
grilio_parser_get_int32(&rilp, &fw->phone_number.type);
|
||||
str = grilio_parser_get_utf8(&rilp);
|
||||
if (str) {
|
||||
strncpy(fw->phone_number.number, str,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
fw->phone_number.number[
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH] = 0;
|
||||
g_free(str);
|
||||
}
|
||||
grilio_parser_get_int32(&rilp, &fw->time);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), count, list, cbd->data);
|
||||
g_free(list);
|
||||
} else {
|
||||
ofono_error("CF query failed");
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_forward_query(struct ofono_call_forwarding *cf, int type,
|
||||
int cls, ofono_call_forwarding_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = ril_call_forward_req(CF_ACTION_INTERROGATE,
|
||||
type, cls, NULL, CF_TIME_DEFAULT);
|
||||
|
||||
ofono_info("cf query");
|
||||
grilio_queue_send_request_full(fd->q, req,
|
||||
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
ril_call_forward_query_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_forward_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_forwarding *cf = user_data;
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
|
||||
fd->timer_id = 0;
|
||||
ofono_call_forwarding_register(cf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_forward_probe(struct ofono_call_forwarding *cf,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_forward *fd = g_try_new0(struct ril_call_forward, 1);
|
||||
|
||||
DBG("");
|
||||
fd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
fd->timer_id = g_idle_add(ril_call_forward_register, cf);
|
||||
ofono_call_forwarding_set_data(cf, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_forward_remove(struct ofono_call_forwarding *cf)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
|
||||
DBG("");
|
||||
ofono_call_forwarding_set_data(cf, NULL);
|
||||
|
||||
if (fd->timer_id) {
|
||||
g_source_remove(fd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(fd->q, FALSE);
|
||||
grilio_queue_unref(fd->q);
|
||||
g_free(fd);
|
||||
}
|
||||
|
||||
const struct ofono_call_forwarding_driver ril_call_forwarding_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_forward_probe,
|
||||
.remove = ril_call_forward_remove,
|
||||
.erasure = ril_call_forward_erasure,
|
||||
.deactivation = ril_call_forward_deactivate,
|
||||
.query = ril_call_forward_query,
|
||||
.registration = ril_call_forward_registration,
|
||||
.activation = ril_call_forward_activate
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct ril_call_settings {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_settings_cbd {
|
||||
union _ofono_call_settings_cb {
|
||||
ofono_call_settings_status_cb_t status;
|
||||
ofono_call_settings_set_cb_t set;
|
||||
ofono_call_settings_clir_cb_t clir;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_settings_cbd_free g_free
|
||||
|
||||
static inline struct ril_call_settings *ril_call_settings_get_data(
|
||||
struct ofono_call_settings *b)
|
||||
{
|
||||
return ofono_call_settings_get_data(b);
|
||||
}
|
||||
|
||||
static struct ril_call_settings_cbd *ril_call_settings_cbd_new(void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_settings_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_call_settings_cbd, 1);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_settings_submit_req(struct ril_call_settings *sd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
{
|
||||
grilio_queue_send_request_full(sd->q, req, code, response,
|
||||
ril_call_settings_cbd_free,
|
||||
ril_call_settings_cbd_new(cb, data));
|
||||
}
|
||||
|
||||
static void ril_call_settings_clip_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int res = 0;
|
||||
|
||||
/* data length of the response */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &res) && res > 0) {
|
||||
grilio_parser_get_int32(&rilp, &res);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), res, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_set(struct ofono_call_settings *cs, int mode,
|
||||
int cls, ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(12);
|
||||
|
||||
grilio_request_append_int32(req, 2); /* Number of params */
|
||||
grilio_request_append_int32(req, mode); /* on/off */
|
||||
|
||||
/* Modem seems to respond with error to all queries
|
||||
* or settings made with bearer class
|
||||
* BEARER_CLASS_DEFAULT. Design decision: If given
|
||||
* class is BEARER_CLASS_DEFAULT let's map it to
|
||||
* SERVICE_CLASS_VOICE effectively making it the
|
||||
* default bearer. This in line with API which is
|
||||
* contains only voice anyways.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CALL_WAITING,
|
||||
ril_call_settings_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int res = 0;
|
||||
int sv = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* first value in int[] is len so let's skip that */
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
|
||||
/* status of call waiting service, disabled is returned only if
|
||||
* service is not active for any service class */
|
||||
grilio_parser_get_int32(&rilp, &res);
|
||||
DBG("CW enabled/disabled: %d", res);
|
||||
|
||||
if (res > 0) {
|
||||
/* services for which call waiting is enabled,
|
||||
27.007 7.12 */
|
||||
grilio_parser_get_int32(&rilp, &sv);
|
||||
DBG("CW enabled for: %d", sv);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), sv, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_query(struct ofono_call_settings *cs, int cls,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
|
||||
/*
|
||||
* RILD expects service class to be 0 as certain carriers can reject
|
||||
* the query with specific service class
|
||||
*/
|
||||
grilio_request_append_int32(req, 0);
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_QUERY_CALL_WAITING,
|
||||
ril_call_settings_cw_query_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clip_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_QUERY_CLIP,
|
||||
ril_call_settings_clip_query_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_clir_cb_t cb = cbd->cb.clir;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int override = -1, network = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
/*first value in int[] is len so let's skip that*/
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
/* Set HideCallerId property from network */
|
||||
grilio_parser_get_int32(&rilp, &override);
|
||||
/* CallingLineRestriction indicates the state of
|
||||
the CLIR supplementary service in the network */
|
||||
grilio_parser_get_int32(&rilp, &network);
|
||||
|
||||
cb(ril_error_ok(&error), override, network, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_clir_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_GET_CLIR,
|
||||
ril_call_settings_clir_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_set(struct ofono_call_settings *cs,
|
||||
int mode, ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, mode); /* for outgoing calls */
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CLIR,
|
||||
ril_call_settings_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_settings_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_settings *cs = user_data;
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
DBG("");
|
||||
GASSERT(sd->timer_id);
|
||||
sd->timer_id = 0;
|
||||
ofono_call_settings_register(cs);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_settings_probe(struct ofono_call_settings *cs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_settings *sd = g_try_new0(struct ril_call_settings, 1);
|
||||
|
||||
DBG("");
|
||||
sd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
sd->timer_id = g_idle_add(ril_call_settings_register, cs);
|
||||
ofono_call_settings_set_data(cs, sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_settings_remove(struct ofono_call_settings *cs)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
DBG("");
|
||||
ofono_call_settings_set_data(cs, NULL);
|
||||
|
||||
if (sd->timer_id > 0) {
|
||||
g_source_remove(sd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_unref(sd->q);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
const struct ofono_call_settings_driver ril_call_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_settings_probe,
|
||||
.remove = ril_call_settings_remove,
|
||||
.clip_query = ril_call_settings_clip_query,
|
||||
.cw_query = ril_call_settings_cw_query,
|
||||
.cw_set = ril_call_settings_cw_set,
|
||||
.clir_query = ril_call_settings_clir_query,
|
||||
.clir_set = ril_call_settings_clir_set
|
||||
|
||||
/*
|
||||
* Not supported in RIL API
|
||||
* .colp_query = ril_call_settings_colp_query,
|
||||
* .colr_query = ril_call_settings_colr_query
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
struct ril_call_volume {
|
||||
struct ofono_call_volume *v;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_volume_req {
|
||||
ofono_call_volume_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static inline struct ril_call_volume *ril_call_volume_get_data(
|
||||
struct ofono_call_volume *v)
|
||||
{
|
||||
return ofono_call_volume_get_data(v);
|
||||
}
|
||||
|
||||
static void ril_call_volume_mute_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_volume_req *cbd = user_data;
|
||||
ofono_call_volume_cb_t cb = cbd->cb;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Could not set the ril mute state");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_volume_mute(struct ofono_call_volume *v, int muted,
|
||||
ofono_call_volume_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||
struct ril_call_volume_req *cbd;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
cbd = g_new(struct ril_call_volume_req, 1);
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
|
||||
DBG("%d", muted);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, muted);
|
||||
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_SET_MUTE,
|
||||
ril_call_volume_mute_cb, g_free, cbd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_volume_query_mute_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_call_volume *vd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int muted = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* Array length */
|
||||
grilio_parser_get_int32(&rilp, &muted);
|
||||
DBG("{%d}", muted);
|
||||
ofono_call_volume_set_muted(vd->v, muted);
|
||||
} else {
|
||||
ofono_error("Could not retrive the ril mute state");
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_call_volume_register(gpointer user_data)
|
||||
{
|
||||
struct ril_call_volume *vd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(vd->timer_id);
|
||||
vd->timer_id = 0;
|
||||
ofono_call_volume_register(vd->v);
|
||||
|
||||
/* Probe the mute state */
|
||||
grilio_queue_send_request_full(vd->q, NULL,
|
||||
RIL_REQUEST_GET_MUTE, ril_call_volume_query_mute_cb, NULL, vd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_volume_probe(struct ofono_call_volume *v,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_volume *vd = g_new0(struct ril_call_volume, 1);
|
||||
|
||||
DBG("");
|
||||
vd->v = v;
|
||||
vd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
vd->timer_id = g_idle_add(ril_call_volume_register, vd);
|
||||
ofono_call_volume_set_data(v, vd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_volume_remove(struct ofono_call_volume *v)
|
||||
{
|
||||
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||
|
||||
DBG("");
|
||||
ofono_call_volume_set_data(v, NULL);
|
||||
|
||||
if (vd->timer_id) {
|
||||
g_source_remove(vd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
const struct ofono_call_volume_driver ril_call_volume_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_volume_probe,
|
||||
.remove = ril_call_volume_remove,
|
||||
.mute = ril_call_volume_mute,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct ril_cbs {
|
||||
struct ofono_cbs *cbs;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
struct ril_cbs_cbd {
|
||||
struct ril_cbs *cd;
|
||||
ofono_cbs_set_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define RIL_CBS_CHECK_RETRY_MS 1000
|
||||
#define RIL_CBS_CHECK_RETRY_COUNT 30
|
||||
|
||||
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
|
||||
|
||||
#define ril_cbs_cbd_free g_free
|
||||
|
||||
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
|
||||
|
||||
cbd->cd = cd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
GRilIoRequest* req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, activate ? 0 :1);
|
||||
|
||||
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||
GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
|
||||
int i, n = gutil_strv_length(list);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *entry = list[i];
|
||||
const char *delim = strchr(entry, '-');
|
||||
int from, to;
|
||||
if (delim) {
|
||||
char **range = g_strsplit(topics, "-", 0);
|
||||
from = atoi(range[0]);
|
||||
to = atoi(range[1]);
|
||||
g_strfreev(range);
|
||||
} else {
|
||||
from = to = atoi(entry);
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, from);
|
||||
grilio_request_append_int32(req, to);
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_append_int32(req, 0xff);
|
||||
grilio_request_append_int32(req, 1);
|
||||
}
|
||||
|
||||
DBG_(cd, "configuring CB");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
g_strfreev(list);
|
||||
}
|
||||
|
||||
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = user_data;
|
||||
|
||||
if (cbd->cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "%s", topics);
|
||||
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
DBG_(cd, "%u bytes", len);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
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]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
cd->cbs = cbs;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
grilio_queue_cancel_all(cd->q, FALSE);
|
||||
grilio_queue_unref(cd->q);
|
||||
g_free(cd->log_prefix);
|
||||
g_free(cd);
|
||||
}
|
||||
|
||||
const struct ofono_cbs_driver ril_cbs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,551 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
|
||||
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;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
guint set_rate_id;
|
||||
};
|
||||
|
||||
enum ril_cell_info_signal {
|
||||
SIGNAL_CELLS_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_CELLS_CHANGED_NAME "ril-cell-info-cells-changed"
|
||||
|
||||
static guint ril_cell_info_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||
#define RIL_CELL_INFO_TYPE (ril_cell_info_get_type())
|
||||
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
|
||||
static inline void ril_cell_free(struct sailfish_cell *cell)
|
||||
{
|
||||
g_slice_free(struct sailfish_cell, cell);
|
||||
}
|
||||
|
||||
static void ril_cell_free1(gpointer cell)
|
||||
{
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
l2 = l2->next;
|
||||
}
|
||||
return !l1 && !l2;
|
||||
}
|
||||
|
||||
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||
{
|
||||
if (!ril_cell_info_list_identical(self->info.cells, l)) {
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
self->info.cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals
|
||||
[SIGNAL_CELLS_CHANGED], 0);
|
||||
} else {
|
||||
g_slist_free_full(l, ril_cell_free1);
|
||||
}
|
||||
}
|
||||
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = INT_MAX;
|
||||
gsm->bsic = INT_MAX;
|
||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||
gsm->timingAdvance = INT_MAX;
|
||||
/* RIL_CellIdentityGsm */
|
||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->lac) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->cid) &&
|
||||
(version < 12 || /* RIL_CellIdentityGsm_v12 part */
|
||||
(grilio_parser_get_int32(rilp, &gsm->arfcn) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bsic))) &&
|
||||
/* RIL_GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
|
||||
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);
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = INT_MAX;
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->cid) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->psc) &&
|
||||
(version < 12 || /* RIL_CellIdentityWcdma_v12 part */
|
||||
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);
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = INT_MAX;
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
grilio_parser_get_int32(rilp, <e->pci) &&
|
||||
grilio_parser_get_int32(rilp, <e->tac) &&
|
||||
(version < 12 || /* RIL_CellIdentityLte_v12 part */
|
||||
grilio_parser_get_int32(rilp, <e->earfcn)) &&
|
||||
grilio_parser_get_int32(rilp, <e->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrp) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrq) &&
|
||||
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);
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
|
||||
struct sailfish_cell **cell_ptr)
|
||||
{
|
||||
int type, reg;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &type) &&
|
||||
grilio_parser_get_int32(rilp, ®) &&
|
||||
/* Skip timestamp */
|
||||
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||
int skip = 0;
|
||||
struct sailfish_cell *cell = NULL;
|
||||
|
||||
/* Normalize the boolean value */
|
||||
reg = (reg != FALSE);
|
||||
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
skip = 10;
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
skip = 6;
|
||||
break;
|
||||
default:
|
||||
skip = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cell) {
|
||||
*cell_ptr = cell;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||
*cell_ptr = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*cell_ptr = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
|
||||
{
|
||||
GSList *l = NULL;
|
||||
GRilIoParser rilp;
|
||||
int i, n;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct sailfish_cell *c;
|
||||
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
|
||||
if (c) {
|
||||
l = g_slist_insert_sorted(l, c,
|
||||
sailfish_cell_compare_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
return l;
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(self->set_rate_id);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
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_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
||||
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
ril_cell_info_set_rate_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
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) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
|
||||
DBG_(self, "%s", ril_radio_state_to_string(radio->state));
|
||||
ril_cell_info_refresh(self);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* sailfish_cell_info interface callbacks */
|
||||
|
||||
struct ril_cell_info_signal_data {
|
||||
sailfish_cell_info_cb_t cb;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static inline struct ril_cell_info *ril_cell_info_cast
|
||||
(struct sailfish_cell_info *info)
|
||||
{
|
||||
return G_CAST(info, struct ril_cell_info, info);
|
||||
}
|
||||
|
||||
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
|
||||
{
|
||||
g_object_ref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
|
||||
{
|
||||
g_object_unref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_cell_info_signal_data *data = user_data;
|
||||
|
||||
data->cb(&self->info, data->arg);
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_disconnect_notify(gpointer data,
|
||||
GClosure *closure)
|
||||
{
|
||||
g_slice_free1(sizeof(struct ril_cell_info_signal_data), data);
|
||||
}
|
||||
|
||||
static gulong ril_cell_info_add_cells_changed_handler_proc
|
||||
(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
if (cb) {
|
||||
struct ril_cell_info_signal_data *data =
|
||||
g_slice_new(struct ril_cell_info_signal_data);
|
||||
|
||||
data->cb = cb;
|
||||
data->arg = arg;
|
||||
return g_signal_connect_data(ril_cell_info_cast(info),
|
||||
SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_CALLBACK(ril_cell_info_cells_changed_cb),
|
||||
data, ril_cell_info_cells_disconnect_notify,
|
||||
G_CONNECT_AFTER);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
|
||||
gulong id)
|
||||
{
|
||||
if (G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, MceDisplay *display,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card)
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
|
||||
self->info.proc = &ril_cell_info_proc;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->display = mce_display_ref(display);
|
||||
self->radio = ril_radio_ref(radio);
|
||||
self->sim_card = ril_sim_card_ref(sim_card);
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
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);
|
||||
self->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
|
||||
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
|
||||
if (self->query_id) {
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = 0;
|
||||
}
|
||||
if (self->set_rate_id) {
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id,
|
||||
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);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
|
||||
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);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,232 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_config.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
{
|
||||
char *val = g_key_file_get_string(file, group, key, NULL);
|
||||
|
||||
if (!val && strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||
/* Check the common section */
|
||||
val = g_key_file_get_string(file, RILCONF_SETTINGS_GROUP, key,
|
||||
NULL);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
const char *key, char delimiter)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
|
||||
if (str) {
|
||||
char **strv, **p;
|
||||
char delimiter_str[2];
|
||||
|
||||
delimiter_str[0] = delimiter;
|
||||
delimiter_str[1] = 0;
|
||||
strv = g_strsplit(str, delimiter_str, -1);
|
||||
|
||||
/* Strip whitespaces */
|
||||
for (p = strv; *p; p++) {
|
||||
*p = g_strstrip(*p);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
return strv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *out_value)
|
||||
{
|
||||
GError *error = NULL;
|
||||
int value = g_key_file_get_integer(file, group, key, &error);
|
||||
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
g_error_free(error);
|
||||
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||
/* Check the common section */
|
||||
error = NULL;
|
||||
value = g_key_file_get_integer(file,
|
||||
RILCONF_SETTINGS_GROUP, key, &error);
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
g_error_free(error);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||
const char *key, gboolean *out_value)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean value = g_key_file_get_boolean(file, group, key, &error);
|
||||
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
g_error_free(error);
|
||||
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||
/* Check the common section */
|
||||
error = NULL;
|
||||
value = g_key_file_get_boolean(file,
|
||||
RILCONF_SETTINGS_GROUP, key, &error);
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
g_error_free(error);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags)
|
||||
{
|
||||
gboolean value;
|
||||
|
||||
if (ril_config_get_boolean(file, group, key, &value)) {
|
||||
if (value) {
|
||||
*flags |= flag;
|
||||
} else {
|
||||
*flags &= ~flag;
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
g_strstrip(str);
|
||||
if (strcasecmp(str, name)) {
|
||||
va_list args;
|
||||
va_start(args, value);
|
||||
while ((name = va_arg(args, char*)) != NULL) {
|
||||
value = va_arg(args, int);
|
||||
if (!strcasecmp(str, name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
ofono_error("Invalid %s config value (%s)", key, str);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
|
||||
if (name) {
|
||||
if (result) {
|
||||
*result = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
while (*ptr) {
|
||||
int val;
|
||||
|
||||
if (ril_parse_int(*ptr++, 0, &val)) {
|
||||
gutil_int_array_append(array, val);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
g_strfreev(values);
|
||||
return gutil_int_array_free_to_ints(array);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
{
|
||||
if (ints) {
|
||||
guint i, n;
|
||||
const int *data = gutil_ints_get_data(ints, &n);
|
||||
GString *buf = g_string_new(NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
if (buf->len > 0) {
|
||||
g_string_append_c(buf, separator);
|
||||
}
|
||||
g_string_append_printf(buf, "%d", data[i]);
|
||||
}
|
||||
return g_string_free(buf, FALSE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_CONFIG_H
|
||||
#define RIL_CONFIG_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
const char *key, char delimiter);
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *value);
|
||||
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||
const char *key, gboolean *value);
|
||||
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, ...);
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||
|
||||
#endif /* RIL_CONFIG_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,599 +0,0 @@
|
||||
/*
|
||||
* RIL constants adopted from AOSP's header:
|
||||
*
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __RIL_CONSTANTS_H
|
||||
#define __RIL_CONSTANTS_H 1
|
||||
|
||||
#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,
|
||||
RADIO_STATE_UNAVAILABLE = 1,
|
||||
RADIO_STATE_SIM_NOT_READY = 2,
|
||||
RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3,
|
||||
RADIO_STATE_SIM_READY = 4,
|
||||
RADIO_STATE_RUIM_NOT_READY = 5,
|
||||
RADIO_STATE_RUIM_READY = 6,
|
||||
RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7,
|
||||
RADIO_STATE_NV_NOT_READY = 8,
|
||||
RADIO_STATE_NV_READY = 9,
|
||||
RADIO_STATE_ON = 10
|
||||
};
|
||||
|
||||
/* Preferred network types */
|
||||
enum ril_pref_net_type {
|
||||
PREF_NET_TYPE_GSM_WCDMA = 0,
|
||||
PREF_NET_TYPE_GSM_ONLY = 1,
|
||||
PREF_NET_TYPE_WCDMA = 2,
|
||||
PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,
|
||||
PREF_NET_TYPE_CDMA_EVDO_AUTO = 4,
|
||||
PREF_NET_TYPE_CDMA_ONLY = 5,
|
||||
PREF_NET_TYPE_EVDO_ONLY = 6,
|
||||
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7,
|
||||
PREF_NET_TYPE_LTE_CDMA_EVDO = 8,
|
||||
PREF_NET_TYPE_LTE_GSM_WCDMA = 9,
|
||||
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10,
|
||||
PREF_NET_TYPE_LTE_ONLY = 11,
|
||||
PREF_NET_TYPE_LTE_WCDMA = 12
|
||||
};
|
||||
|
||||
/* Radio technologies */
|
||||
enum ril_radio_tech {
|
||||
RADIO_TECH_UNKNOWN = 0,
|
||||
RADIO_TECH_GPRS = 1,
|
||||
RADIO_TECH_EDGE = 2,
|
||||
RADIO_TECH_UMTS = 3,
|
||||
RADIO_TECH_IS95A = 4,
|
||||
RADIO_TECH_IS95B = 5,
|
||||
RADIO_TECH_1xRTT = 6,
|
||||
RADIO_TECH_EVDO_0 = 7,
|
||||
RADIO_TECH_EVDO_A = 8,
|
||||
RADIO_TECH_HSDPA = 9,
|
||||
RADIO_TECH_HSUPA = 10,
|
||||
RADIO_TECH_HSPA = 11,
|
||||
RADIO_TECH_EVDO_B = 12,
|
||||
RADIO_TECH_EHRPD = 13,
|
||||
RADIO_TECH_LTE = 14,
|
||||
RADIO_TECH_HSPAP = 15,
|
||||
RADIO_TECH_GSM = 16,
|
||||
RADIO_TECH_TD_SCDMA = 17,
|
||||
RADIO_TECH_IWLAN = 18,
|
||||
RADIO_TECH_LTE_CA = 19
|
||||
};
|
||||
|
||||
/* Radio capabilities */
|
||||
enum ril_radio_access_family {
|
||||
RAF_GPRS = (1 << RADIO_TECH_GPRS),
|
||||
RAF_EDGE = (1 << RADIO_TECH_EDGE),
|
||||
RAF_UMTS = (1 << RADIO_TECH_UMTS),
|
||||
RAF_IS95A = (1 << RADIO_TECH_IS95A),
|
||||
RAF_IS95B = (1 << RADIO_TECH_IS95B),
|
||||
RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
|
||||
RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
|
||||
RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
|
||||
RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
|
||||
RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
|
||||
RAF_HSPA = (1 << RADIO_TECH_HSPA),
|
||||
RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
|
||||
RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
|
||||
RAF_LTE = (1 << RADIO_TECH_LTE),
|
||||
RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
|
||||
RAF_GSM = (1 << RADIO_TECH_GSM),
|
||||
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
|
||||
RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
|
||||
};
|
||||
|
||||
enum ril_radio_capability_phase {
|
||||
RC_PHASE_CONFIGURED = 0,
|
||||
RC_PHASE_START = 1,
|
||||
RC_PHASE_APPLY = 2,
|
||||
RC_PHASE_UNSOL_RSP = 3,
|
||||
RC_PHASE_FINISH = 4
|
||||
};
|
||||
|
||||
enum ril_radio_capability_status {
|
||||
RC_STATUS_NONE = 0,
|
||||
RC_STATUS_SUCCESS = 1,
|
||||
RC_STATUS_FAIL = 2
|
||||
};
|
||||
|
||||
#define RIL_RADIO_CAPABILITY_VERSION 1
|
||||
|
||||
struct ril_radio_capability {
|
||||
int version;
|
||||
int session;
|
||||
enum ril_radio_capability_phase phase;
|
||||
enum ril_radio_access_family rat;
|
||||
char logicalModemUuid[RIL_MAX_UUID_LENGTH];
|
||||
int status;
|
||||
};
|
||||
|
||||
enum ril_uicc_subscription_action {
|
||||
RIL_UICC_SUBSCRIPTION_DEACTIVATE = 0,
|
||||
RIL_UICC_SUBSCRIPTION_ACTIVATE = 1
|
||||
};
|
||||
|
||||
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
|
||||
enum ril_call_fail_cause {
|
||||
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
|
||||
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
|
||||
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
|
||||
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
|
||||
CALL_FAIL_NORMAL = 16,
|
||||
CALL_FAIL_BUSY = 17,
|
||||
CALL_FAIL_NO_USER_RESPONDING = 18,
|
||||
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
|
||||
CALL_FAIL_CALL_REJECTED = 21,
|
||||
CALL_FAIL_NUMBER_CHANGED = 22,
|
||||
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
|
||||
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
|
||||
CALL_FAIL_FACILITY_REJECTED = 29,
|
||||
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
|
||||
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
|
||||
CALL_FAIL_CONGESTION = 34,
|
||||
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
|
||||
CALL_FAIL_TEMPORARY_FAILURE = 41,
|
||||
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
|
||||
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
|
||||
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
|
||||
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
|
||||
CALL_FAIL_QOS_UNAVAILABLE = 49,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
|
||||
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
|
||||
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
|
||||
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
|
||||
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
|
||||
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
|
||||
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
|
||||
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
|
||||
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
|
||||
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
|
||||
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
|
||||
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
|
||||
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
|
||||
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
|
||||
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
|
||||
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
|
||||
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
|
||||
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
|
||||
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
|
||||
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
|
||||
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
|
||||
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
|
||||
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
|
||||
CALL_FAIL_CALL_BARRED = 240,
|
||||
CALL_FAIL_FDN_BLOCKED = 241,
|
||||
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
|
||||
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
|
||||
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
|
||||
|
||||
/* Not defined in ril.h but valid 3GPP specific cause values
|
||||
* for call control. See 3GPP TS 24.008 Annex H. */
|
||||
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
|
||||
CALL_FAIL_PRE_EMPTION = 25
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
|
||||
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
|
||||
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
|
||||
|
||||
/* RIL_REQUEST_SETUP_DATA_CALL */
|
||||
enum ril_data_profile {
|
||||
RIL_DATA_PROFILE_DEFAULT = 0,
|
||||
RIL_DATA_PROFILE_TETHERED = 1,
|
||||
RIL_DATA_PROFILE_IMS = 2,
|
||||
RIL_DATA_PROFILE_FOTA = 3,
|
||||
RIL_DATA_PROFILE_CBS = 4,
|
||||
RIL_DATA_PROFILE_OEM_BASE = 1000,
|
||||
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum ril_auth {
|
||||
RIL_AUTH_NONE = 0,
|
||||
RIL_AUTH_PAP = 1,
|
||||
RIL_AUTH_CHAP = 2,
|
||||
RIL_AUTH_BOTH = 3
|
||||
};
|
||||
|
||||
#define RIL_CARD_MAX_APPS 8
|
||||
|
||||
/* SIM card states */
|
||||
enum ril_card_state {
|
||||
RIL_CARDSTATE_UNKNOWN = -1,
|
||||
RIL_CARDSTATE_ABSENT = 0,
|
||||
RIL_CARDSTATE_PRESENT = 1,
|
||||
RIL_CARDSTATE_ERROR = 2
|
||||
};
|
||||
|
||||
/* SIM personalization substates */
|
||||
enum ril_perso_substate {
|
||||
RIL_PERSOSUBSTATE_UNKNOWN = 0,
|
||||
RIL_PERSOSUBSTATE_IN_PROGRESS = 1,
|
||||
RIL_PERSOSUBSTATE_READY = 2,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK = 3,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE = 5,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM = 7,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_PUK = 8,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM_PUK = 12,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1 = 13,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2 = 14,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD = 15,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE = 16,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM = 18,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD_PUK = 21,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM_PUK = 24
|
||||
};
|
||||
|
||||
/* SIM - App states */
|
||||
enum ril_app_state {
|
||||
RIL_APPSTATE_ILLEGAL = -1,
|
||||
RIL_APPSTATE_UNKNOWN = 0,
|
||||
RIL_APPSTATE_DETECTED = 1,
|
||||
RIL_APPSTATE_PIN = 2,
|
||||
RIL_APPSTATE_PUK = 3,
|
||||
RIL_APPSTATE_SUBSCRIPTION_PERSO = 4,
|
||||
RIL_APPSTATE_READY = 5
|
||||
};
|
||||
|
||||
/* SIM - PIN states */
|
||||
enum ril_pin_state {
|
||||
RIL_PINSTATE_UNKNOWN = 0,
|
||||
RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
|
||||
RIL_PINSTATE_ENABLED_VERIFIED = 2,
|
||||
RIL_PINSTATE_DISABLED = 3,
|
||||
RIL_PINSTATE_ENABLED_BLOCKED = 4,
|
||||
RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
|
||||
};
|
||||
|
||||
/* SIM - App types */
|
||||
enum ril_app_type {
|
||||
RIL_APPTYPE_UNKNOWN = 0,
|
||||
RIL_APPTYPE_SIM = 1,
|
||||
RIL_APPTYPE_USIM = 2,
|
||||
RIL_APPTYPE_RUIM = 3,
|
||||
RIL_APPTYPE_CSIM = 4,
|
||||
RIL_APPTYPE_ISIM = 5
|
||||
};
|
||||
|
||||
/* Cell info */
|
||||
enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_NONE = 0,
|
||||
RIL_CELL_INFO_TYPE_GSM = 1,
|
||||
RIL_CELL_INFO_TYPE_CDMA = 2,
|
||||
RIL_CELL_INFO_TYPE_LTE = 3,
|
||||
RIL_CELL_INFO_TYPE_WCDMA = 4,
|
||||
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
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
/* RIL_FACILITY_LOCK parameters */
|
||||
#define RIL_FACILITY_UNLOCK "0"
|
||||
#define RIL_FACILITY_LOCK "1"
|
||||
|
||||
#endif /*__RIL_CONSTANTS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_DATA_H
|
||||
#define RIL_DATA_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
enum ril_data_call_active {
|
||||
RIL_DATA_CALL_INACTIVE = 0,
|
||||
RIL_DATA_CALL_LINK_DOWN = 1,
|
||||
RIL_DATA_CALL_ACTIVE = 2
|
||||
};
|
||||
|
||||
struct ril_data_call {
|
||||
int cid;
|
||||
enum ril_data_call_fail_cause status;
|
||||
enum ril_data_call_active active;
|
||||
enum ofono_gprs_proto prot;
|
||||
int retry_time;
|
||||
int mtu;
|
||||
char *ifname;
|
||||
char **dnses;
|
||||
char **gateways;
|
||||
char **addresses;
|
||||
};
|
||||
|
||||
struct ril_data_call_list {
|
||||
guint version;
|
||||
guint num;
|
||||
GSList *calls;
|
||||
};
|
||||
|
||||
struct ril_data {
|
||||
GObject object;
|
||||
struct ril_data_priv *priv;
|
||||
struct ril_data_call_list *data_calls;
|
||||
};
|
||||
|
||||
enum ril_data_manager_flags {
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
|
||||
};
|
||||
|
||||
enum ril_data_allow_data_opt {
|
||||
RIL_ALLOW_DATA_AUTO,
|
||||
RIL_ALLOW_DATA_ENABLED,
|
||||
RIL_ALLOW_DATA_DISABLED
|
||||
};
|
||||
|
||||
enum ril_data_call_format {
|
||||
RIL_DATA_CALL_FORMAT_AUTO,
|
||||
RIL_DATA_CALL_FORMAT_6 = 6,
|
||||
RIL_DATA_CALL_FORMAT_9 = 9,
|
||||
RIL_DATA_CALL_FORMAT_11 = 11
|
||||
};
|
||||
|
||||
struct ril_data_options {
|
||||
enum ril_data_allow_data_opt allow_data;
|
||||
enum ril_data_call_format data_call_format;
|
||||
unsigned int data_call_retry_limit;
|
||||
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_assert_data_on(struct ril_data_manager *dm);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
|
||||
int ril_status, const struct ril_data_call *call,
|
||||
void *arg);
|
||||
typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
||||
int ril_status, void *arg);
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config);
|
||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||
void ril_data_unref(struct ril_data *data);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
void ril_data_poll_call_state(struct ril_data *data);
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
gulong ril_data_add_calls_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
void ril_data_remove_handler(struct ril_data *data, gulong id);
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
void ril_data_call_free(struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
int cid);
|
||||
|
||||
/* Constructors of various kinds of RIL requests */
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||
|
||||
#endif /* RIL_DATA_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_idlequeue.h>
|
||||
|
||||
/*
|
||||
* TODO: No public RIL api to query manufacturer or model.
|
||||
* Check where to get, could /system/build.prop be updated to have good values?
|
||||
*/
|
||||
|
||||
enum ril_devinfo_cb_tag {
|
||||
DEVINFO_QUERY_SERIAL = 1,
|
||||
DEVINFO_QUERY_SVN
|
||||
};
|
||||
|
||||
struct ril_devinfo {
|
||||
struct ofono_devinfo *info;
|
||||
GRilIoQueue *q;
|
||||
GUtilIdleQueue *iq;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
};
|
||||
|
||||
struct ril_devinfo_cbd {
|
||||
struct ril_devinfo *di;
|
||||
ofono_devinfo_query_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
#define ril_devinfo_cbd_free g_free
|
||||
|
||||
static inline struct ril_devinfo *ril_devinfo_get_data(
|
||||
struct ofono_devinfo *info)
|
||||
{
|
||||
return ofono_devinfo_get_data(info);
|
||||
}
|
||||
|
||||
struct ril_devinfo_cbd *ril_devinfo_cbd_new(struct ril_devinfo *di,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = g_new0(struct ril_devinfo_cbd, 1);
|
||||
|
||||
cbd->di = di;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_failure(&error), "", data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_revision_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
char *res;
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
res = grilio_parser_get_utf8(&rilp);
|
||||
DBG_(cbd->di, "%s", res);
|
||||
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
|
||||
g_free(res);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
grilio_queue_send_request_full(di->q, NULL,
|
||||
RIL_REQUEST_BASEBAND_VERSION,
|
||||
ril_devinfo_query_revision_cb,
|
||||
ril_devinfo_cbd_free,
|
||||
ril_devinfo_cbd_new(di, cb, data));
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_serial_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
struct ril_devinfo *di = cbd->di;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(di, "%s", di->imei);
|
||||
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_svn_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
struct ril_devinfo *di = cbd->di;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(di, "%s", di->imeisv);
|
||||
if (di->imeisv && di->imeisv[0]) {
|
||||
cbd->cb(ril_error_ok(&error), di->imeisv, cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), "", cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devinfo_query(struct ril_devinfo *di,
|
||||
enum ril_devinfo_cb_tag tag, GUtilIdleFunc fn,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
GVERIFY_FALSE(gutil_idle_queue_cancel_tag(di->iq, tag));
|
||||
gutil_idle_queue_add_tag_full(di->iq, tag, fn,
|
||||
ril_devinfo_cbd_new(di, cb, data),
|
||||
ril_devinfo_cbd_free);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
|
||||
ril_devinfo_query_serial_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_svn(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
ril_devinfo_query(di, DEVINFO_QUERY_SVN,
|
||||
ril_devinfo_query_svn_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_register(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo *di = user_data;
|
||||
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_register(di->info);
|
||||
}
|
||||
|
||||
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
|
||||
|
||||
di->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
DBG_(di, "%s", modem->imei);
|
||||
GASSERT(modem->imei);
|
||||
|
||||
di->q = grilio_queue_new(ril_modem_io(modem));
|
||||
di->info = info;
|
||||
di->imeisv = g_strdup(modem->imeisv);
|
||||
di->imei = g_strdup(modem->imei);
|
||||
di->iq = gutil_idle_queue_new();
|
||||
gutil_idle_queue_add(di->iq, ril_devinfo_register, di);
|
||||
ofono_devinfo_set_data(info, di);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_set_data(info, NULL);
|
||||
gutil_idle_queue_cancel_all(di->iq);
|
||||
gutil_idle_queue_unref(di->iq);
|
||||
grilio_queue_cancel_all(di->q, FALSE);
|
||||
grilio_queue_unref(di->q);
|
||||
g_free(di->log_prefix);
|
||||
g_free(di->imeisv);
|
||||
g_free(di->imei);
|
||||
g_free(di);
|
||||
}
|
||||
|
||||
const struct ofono_devinfo_driver ril_devinfo_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_devinfo_probe,
|
||||
.remove = ril_devinfo_remove,
|
||||
/* query_revision won't be called if query_model is missing */
|
||||
.query_model = ril_devinfo_query_unsupported,
|
||||
.query_revision = ril_devinfo_query_revision,
|
||||
.query_serial = ril_devinfo_query_serial,
|
||||
.query_svn = ril_devinfo_query_svn
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_inotify.h>
|
||||
|
||||
#include <sys/inotify.h>
|
||||
|
||||
typedef GObjectClass RilEccListClass;
|
||||
typedef struct ril_ecclist RilEccList;
|
||||
|
||||
struct ril_ecclist_priv {
|
||||
struct ofono_sim *sim;
|
||||
GUtilInotifyWatchCallback *dir_watch;
|
||||
GUtilInotifyWatchCallback *file_watch;
|
||||
char *dir;
|
||||
char *path;
|
||||
char *name;
|
||||
};
|
||||
|
||||
enum ril_ecclist_signal {
|
||||
SIGNAL_LIST_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_LIST_CHANGED_NAME "ril-ecclist-changed"
|
||||
|
||||
static guint ril_ecclist_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
|
||||
#define RIL_ECCLIST_TYPE (ril_ecclist_get_type())
|
||||
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_ECCLIST_TYPE, RilEccList))
|
||||
|
||||
static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
char **list = NULL;
|
||||
|
||||
if (g_file_test(priv->path, G_FILE_TEST_EXISTS)) {
|
||||
gsize len = 0;
|
||||
gchar *content = NULL;
|
||||
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) {
|
||||
DBG("%s: %s", priv->path, GERRMSG(error));
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
g_free (content);
|
||||
} else {
|
||||
DBG("%s doesn't exist", priv->path);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void ril_ecclist_update(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
char **list = ril_ecclist_read(self);
|
||||
|
||||
if (!gutil_strv_equal(self->list, list)) {
|
||||
DBG("%s changed", priv->name);
|
||||
g_strfreev(self->list);
|
||||
self->list = list;
|
||||
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0);
|
||||
} else {
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
guint cookie, const char *name, void *user_data)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
ril_ecclist_update(self);
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
DBG("file %s is gone", priv->path);
|
||||
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||
priv->file_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
guint cookie, const char *name, void *user_data)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
DBG("0x%04x %s", mask, name);
|
||||
if (!priv->file_watch && !g_strcmp0(name, priv->name)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
DBG("%s is gone", priv->dir);
|
||||
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||
priv->dir_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *self,
|
||||
ril_ecclist_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_LIST_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_ecclist_remove_handler(struct ril_ecclist *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_ecclist *ril_ecclist_new(const char *path)
|
||||
{
|
||||
if (path) {
|
||||
struct ril_ecclist *self = g_object_new(RIL_ECCLIST_TYPE, 0);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", path);
|
||||
priv->path = g_strdup(path);
|
||||
priv->name = g_path_get_basename(path);
|
||||
priv->dir = g_path_get_dirname(path);
|
||||
priv->dir_watch = gutil_inotify_watch_callback_new(priv->dir,
|
||||
IN_MODIFY|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|
|
||||
IN_CREATE|IN_DELETE_SELF|IN_CLOSE_WRITE,
|
||||
ril_ecclist_dir_changed, self);
|
||||
if (priv->dir_watch) {
|
||||
DBG("watching %s", priv->dir);
|
||||
}
|
||||
|
||||
self->list = ril_ecclist_read(self);
|
||||
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);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_ECCLIST(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_ecclist_unref(struct ril_ecclist *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_ECCLIST(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_init(struct ril_ecclist *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_ECCLIST_TYPE,
|
||||
struct ril_ecclist_priv);
|
||||
}
|
||||
|
||||
static void ril_ecclist_dispose(GObject *object)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
if (priv->dir_watch) {
|
||||
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||
priv->dir_watch = NULL;
|
||||
}
|
||||
|
||||
if (priv->file_watch) {
|
||||
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||
priv->file_watch = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(ril_ecclist_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_ecclist_finalize(GObject *object)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
GASSERT(!priv->dir_watch);
|
||||
GASSERT(!priv->file_watch);
|
||||
g_free(priv->dir);
|
||||
g_free(priv->path);
|
||||
g_free(priv->name);
|
||||
g_strfreev(self->list);
|
||||
|
||||
G_OBJECT_CLASS(ril_ecclist_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_ecclist_class_init(RilEccListClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_ecclist_dispose;
|
||||
object_class->finalize = ril_ecclist_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_ecclist_priv));
|
||||
ril_ecclist_signals[SIGNAL_LIST_CHANGED] =
|
||||
g_signal_new(SIGNAL_LIST_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_ECCLIST_H
|
||||
#define RIL_ECCLIST_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_ecclist_priv;
|
||||
|
||||
struct ril_ecclist {
|
||||
GObject object;
|
||||
struct ril_ecclist_priv *priv;
|
||||
char **list;
|
||||
};
|
||||
|
||||
typedef void (*ril_ecclist_cb_t)(struct ril_ecclist *ecc, void *arg);
|
||||
|
||||
struct ril_ecclist *ril_ecclist_new(const char *path);
|
||||
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *ecc);
|
||||
void ril_ecclist_unref(struct ril_ecclist *ecc);
|
||||
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *ecc,
|
||||
ril_ecclist_cb_t cb, void *arg);
|
||||
void ril_ecclist_remove_handler(struct ril_ecclist *ecc, gulong id);
|
||||
|
||||
#endif /* RIL_ECCLIST_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,283 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* This module is the ofono_gprs_driver implementation for rilmodem.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* 1. ofono_gprs_suspend/resume() are not used by this module, as
|
||||
* the concept of suspended GPRS is not exposed by RILD.
|
||||
*
|
||||
* 2. ofono_gprs_bearer_notify() is never called as RILD does not
|
||||
* expose an unsolicited event equivalent to +CPSB ( see 27.007
|
||||
* 7.29 ), and the tech values returned by REQUEST_DATA/VOICE
|
||||
* _REGISTRATION requests do not match the values defined for
|
||||
* <AcT> in the +CPSB definition. Note, the values returned by
|
||||
* the *REGISTRATION commands are aligned with those defined by
|
||||
* +CREG ( see 27.003 7.2 ).
|
||||
*/
|
||||
|
||||
struct ril_gprs {
|
||||
struct ofono_gprs *gprs;
|
||||
struct ril_modem *md;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean attached;
|
||||
int max_cids;
|
||||
enum network_registration_status registration_status;
|
||||
guint register_id;
|
||||
gulong network_event_id;
|
||||
gulong data_event_id;
|
||||
guint set_attached_id;
|
||||
};
|
||||
|
||||
struct ril_gprs_cbd {
|
||||
struct ril_gprs *gd;
|
||||
ofono_gprs_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_gprs_cbd_free g_free
|
||||
|
||||
static struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *ofono)
|
||||
{
|
||||
return ofono ? ofono_gprs_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_cbd *cbd = g_new0(struct ril_gprs_cbd, 1);
|
||||
|
||||
cbd->gd = gd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static enum network_registration_status ril_gprs_fix_registration_status(
|
||||
struct ril_gprs *gd, enum network_registration_status status)
|
||||
{
|
||||
if (!ril_data_allowed(gd->data)) {
|
||||
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
} else {
|
||||
/* TODO: need a way to make sure that SPDI information has
|
||||
* already been read from the SIM (i.e. sim_spdi_read_cb in
|
||||
* network.c has been called) */
|
||||
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gd->md);
|
||||
return ril_netreg_check_if_really_roaming(netreg, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
|
||||
{
|
||||
const enum network_registration_status status =
|
||||
ril_gprs_fix_registration_status(gd, gd->network->data.status);
|
||||
|
||||
if (gd->registration_status != status) {
|
||||
ofono_info("data reg changed %d -> %d (%s), attached %d",
|
||||
gd->registration_status, status,
|
||||
registration_status_to_string(status),
|
||||
gd->attached);
|
||||
gd->registration_status = status;
|
||||
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_check_data_allowed(struct ril_gprs *gd)
|
||||
{
|
||||
DBG("%s %d %d", ril_modem_get_path(gd->md), ril_data_allowed(gd->data),
|
||||
gd->attached);
|
||||
if (!ril_data_allowed(gd->data) && gd->attached) {
|
||||
gd->attached = FALSE;
|
||||
if (gd->gprs) {
|
||||
ofono_gprs_detached_notify(gd->gprs);
|
||||
}
|
||||
}
|
||||
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_set_attached_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_gprs_cbd *cbd = user_data;
|
||||
struct ril_gprs *gd = cbd->gd;
|
||||
|
||||
GASSERT(gd->set_attached_id);
|
||||
gd->set_attached_id = 0;
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
|
||||
if (ril_data_allowed(gd->data) || !attached) {
|
||||
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
gd->attached = attached;
|
||||
gd->set_attached_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_gprs_set_attached_cb,
|
||||
ril_gprs_cbd_new(gd, cb, data),
|
||||
ril_gprs_cbd_free);
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
DBG("%s not allowed to attach", ril_modem_get_path(gd->md));
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_allow_data_changed(struct ril_data *data, void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
|
||||
GASSERT(gd->data == data);
|
||||
DBG("%s %d", ril_modem_get_path(gd->md), ril_data_allowed(data));
|
||||
if (!gd->set_attached_id) {
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_data_registration_state_changed(struct ril_network *net,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
const struct ril_registration_state *data = &net->data;
|
||||
|
||||
GASSERT(gd->network == net);
|
||||
if (data->max_calls > gd->max_cids) {
|
||||
DBG("Setting max cids to %d", data->max_calls);
|
||||
gd->max_cids = data->max_calls;
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
ofono_gprs_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
struct ofono_error error;
|
||||
const enum network_registration_status status = gd->attached ?
|
||||
gd->registration_status :
|
||||
NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
|
||||
|
||||
DBG("%d (%s)", status, registration_status_to_string(status));
|
||||
cb(ril_error_ok(&error), status, data);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_register(gpointer user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
|
||||
gd->register_id = 0;
|
||||
gd->network_event_id = ril_network_add_data_state_changed_handler(
|
||||
gd->network, ril_gprs_data_registration_state_changed, gd);
|
||||
gd->data_event_id = ril_data_add_allow_changed_handler(gd->data,
|
||||
ril_gprs_allow_data_changed, gd);
|
||||
gd->registration_status = ril_gprs_fix_registration_status(gd,
|
||||
gd->network->data.status);
|
||||
|
||||
gd->max_cids = gd->network->data.max_calls;
|
||||
if (gd->max_cids > 0) {
|
||||
DBG("Setting max cids to %d", gd->max_cids);
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
ofono_gprs_register(gd->gprs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_gprs *gd = g_new0(struct ril_gprs, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
gd->md = modem;
|
||||
gd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
gd->q = grilio_queue_new(gd->io);
|
||||
gd->data = ril_data_ref(modem->data);
|
||||
gd->network = ril_network_ref(modem->network);
|
||||
gd->gprs = gprs;
|
||||
ofono_gprs_set_data(gprs, gd);
|
||||
|
||||
/* ofono crashes if we register right away */
|
||||
gd->register_id = g_idle_add(ril_gprs_register, gd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_remove(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
|
||||
DBG("%s", ril_modem_get_path(gd->md));
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
|
||||
if (gd->register_id) {
|
||||
g_source_remove(gd->register_id);
|
||||
}
|
||||
|
||||
ril_network_remove_handler(gd->network, gd->network_event_id);
|
||||
ril_network_unref(gd->network);
|
||||
|
||||
ril_data_remove_handler(gd->data, gd->data_event_id);
|
||||
ril_data_unref(gd->data);
|
||||
|
||||
grilio_channel_unref(gd->io);
|
||||
grilio_queue_cancel_all(gd->q, FALSE);
|
||||
grilio_queue_unref(gd->q);
|
||||
g_free(gd);
|
||||
}
|
||||
|
||||
const struct ofono_gprs_driver ril_gprs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_gprs_probe,
|
||||
.remove = ril_gprs_remove,
|
||||
.set_attached = ril_gprs_set_attached,
|
||||
.attached_status = ril_gprs_registration_status,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,598 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
#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
|
||||
|
||||
struct ril_gprs_context_call {
|
||||
struct ril_data_request *req;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct ril_gprs_context {
|
||||
struct ofono_gprs_context *gc;
|
||||
struct ril_modem *modem;
|
||||
struct ril_network *network;
|
||||
struct ril_data *data;
|
||||
guint active_ctx_cid;
|
||||
gulong calls_changed_id;
|
||||
struct mtu_watch *mtu_watch;
|
||||
struct ril_data_call *active_call;
|
||||
struct ril_gprs_context_call activate;
|
||||
struct ril_gprs_context_call deactivate;
|
||||
};
|
||||
|
||||
static inline struct ril_gprs_context *ril_gprs_context_get_data(
|
||||
struct ofono_gprs_context *gprs)
|
||||
{
|
||||
return ofono_gprs_context_get_data(gprs);
|
||||
}
|
||||
|
||||
static char *ril_gprs_context_netmask(const char *bits)
|
||||
{
|
||||
if (bits) {
|
||||
int nbits = atoi(bits);
|
||||
if (nbits > 0 && nbits < 33) {
|
||||
const char* str;
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||
((1u << nbits)-1) << (32-nbits));
|
||||
str = inet_ntoa(in);
|
||||
if (str) {
|
||||
return g_strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ril_gprs_context_address_family(const char *addr)
|
||||
{
|
||||
if (strchr(addr, ':')) {
|
||||
return AF_INET6;
|
||||
} else if (strchr(addr, '.')) {
|
||||
return AF_INET;
|
||||
} else {
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = NULL;
|
||||
}
|
||||
if (gcd->calls_changed_id) {
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id = 0;
|
||||
}
|
||||
if (gcd->mtu_watch) {
|
||||
mtu_watch_free(gcd->mtu_watch);
|
||||
gcd->mtu_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
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);
|
||||
}
|
||||
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
} else {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
if (gcd->deactivate.req) {
|
||||
struct ril_gprs_context_call deact = gcd->deactivate;
|
||||
|
||||
/*
|
||||
* Complete the deactivate request. We need to
|
||||
* clear gcd->deactivate first because cancelling
|
||||
* the deactivation request will probably result
|
||||
* in ril_gprs_context_deactivate_primary_cb() being
|
||||
* invoked with GRILIO_CANCELLED status. And we don't
|
||||
* want to fail the disconnect request because this
|
||||
* is a success (we wanted to disconnect the data
|
||||
* call and it's gone).
|
||||
*
|
||||
* Additionally, we need to make sure that we don't
|
||||
* complete the same request twice - that would crash
|
||||
* the core.
|
||||
*/
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
ril_data_request_cancel(deact.req);
|
||||
if (deact.cb) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Deactivated data call");
|
||||
deact.cb(ril_error_ok(&error), deact.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gcd->active_ctx_cid != CTX_ID_NONE) {
|
||||
guint id = gcd->active_ctx_cid;
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
DBG("ofono context %u deactivated", id);
|
||||
ofono_gprs_context_deactivated(gcd->gc, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_address(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const char *ip_addr = NULL;
|
||||
char *ip_mask = NULL;
|
||||
const char *ipv6_addr = NULL;
|
||||
unsigned char ipv6_prefix_length = 0;
|
||||
char *tmp_ip_addr = NULL;
|
||||
char *tmp_ipv6_addr = NULL;
|
||||
char * const *list = call->addresses;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n && (!ipv6_addr || !ip_addr); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
tmp_ip_addr = g_strndup(addr, len);
|
||||
ip_addr = tmp_ip_addr;
|
||||
ip_mask = ril_gprs_context_netmask(s+1);
|
||||
} else {
|
||||
ip_addr = addr;
|
||||
}
|
||||
if (!ip_mask) {
|
||||
ip_mask = g_strdup("255.255.255.0");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
const int prefix = atoi(s + 1);
|
||||
tmp_ipv6_addr = g_strndup(addr, len);
|
||||
ipv6_addr = tmp_ipv6_addr;
|
||||
if (prefix >= 0 && prefix <= 128) {
|
||||
ipv6_prefix_length = prefix;
|
||||
}
|
||||
} else {
|
||||
ipv6_addr = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_address(gc, ip_addr, TRUE);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, ip_mask);
|
||||
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr);
|
||||
ofono_gprs_context_set_ipv6_prefix_length(gc, ipv6_prefix_length);
|
||||
|
||||
if (!ip_addr && !ipv6_addr) {
|
||||
ofono_error("GPRS context: No IP address");
|
||||
}
|
||||
|
||||
/* Allocate temporary strings */
|
||||
g_free(ip_mask);
|
||||
g_free(tmp_ip_addr);
|
||||
g_free(tmp_ipv6_addr);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const char *ip_gw = NULL;
|
||||
const char *ipv6_gw = NULL;
|
||||
char * const *list = call->gateways;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
/* Pick 1 gw for each protocol*/
|
||||
for (i = 0; i < n && (!ipv6_gw || !ip_gw); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_gw) ip_gw = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_gw) ipv6_gw = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
char * const *list = call->dnses;
|
||||
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:
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
*ipv6_ptr++ = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
|
||||
|
||||
g_free(ip_dns);
|
||||
g_free(ipv6_dns);
|
||||
}
|
||||
|
||||
/* Only compares the stuff that's important to us */
|
||||
#define DATA_CALL_IFNAME_CHANGED (0x01)
|
||||
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||
#define DATA_CALL_ALL_CHANGED (0x0f)
|
||||
static int ril_gprs_context_data_call_change(
|
||||
const struct ril_data_call *c1,
|
||||
const struct ril_data_call *c2)
|
||||
{
|
||||
if (!c1 && !c2) {
|
||||
return 0;
|
||||
} else if (c1 && c2) {
|
||||
int changes = 0;
|
||||
|
||||
if (g_strcmp0(c1->ifname, c2->ifname)) {
|
||||
changes |= DATA_CALL_IFNAME_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->addresses, c2->addresses)) {
|
||||
changes |= DATA_CALL_ADDRESS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->gateways, c2->gateways)) {
|
||||
changes |= DATA_CALL_GATEWAY_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->dnses, c2->dnses)) {
|
||||
changes |= DATA_CALL_DNS_CHANGED;
|
||||
}
|
||||
|
||||
return changes;
|
||||
} else {
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
{
|
||||
struct ril_gprs_context *gcd = arg;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
|
||||
/*
|
||||
* gcd->active_call can't be NULL here because this callback
|
||||
* is only registered when we have the active call and released
|
||||
* when active call is dropped.
|
||||
*/
|
||||
struct ril_data_call *prev_call = gcd->active_call;
|
||||
const struct ril_data_call *call =
|
||||
ril_data_call_find(data->data_calls, prev_call->cid);
|
||||
int change = 0;
|
||||
|
||||
if (call && call->active != RIL_DATA_CALL_INACTIVE) {
|
||||
/* Compare it against the last known state */
|
||||
change = ril_gprs_context_data_call_change(call, prev_call);
|
||||
} else {
|
||||
ofono_error("Clearing active context");
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
call = NULL;
|
||||
}
|
||||
|
||||
if (!call) {
|
||||
/* We are not interested */
|
||||
return;
|
||||
} else if (!change) {
|
||||
DBG("call %u didn't change", call->cid);
|
||||
return;
|
||||
} else {
|
||||
DBG("call %u changed", call->cid);
|
||||
}
|
||||
|
||||
/*
|
||||
* prev_call points to the previous active call, and it will
|
||||
* be deallocated at the end of the this function. Clear the
|
||||
* gcd->active_call pointer so that we don't deallocate it twice.
|
||||
*/
|
||||
gcd->active_call = NULL;
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
|
||||
if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_info("data call status: %d", call->status);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_IFNAME_CHANGED) {
|
||||
DBG("interface changed");
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_ADDRESS_CHANGED) {
|
||||
DBG("address changed");
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_GATEWAY_CHANGED) {
|
||||
DBG("gateway changed");
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_DNS_CHANGED) {
|
||||
DBG("name server(s) changed");
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
int ril_status, const struct ril_data_call *call,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer cb_data;
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("GPRS context: Reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
} else if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_error("Unexpected data call status %d", call->status);
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
error.error = call->status;
|
||||
} else if (!call->ifname) {
|
||||
/* Must have interface */
|
||||
ofono_error("GPRS context: No interface");
|
||||
} else {
|
||||
ofono_info("setting up data call");
|
||||
|
||||
GASSERT(!gcd->calls_changed_id);
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id =
|
||||
ril_data_add_calls_changed_handler(gcd->data,
|
||||
ril_gprs_context_call_list_changed, gcd);
|
||||
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
ril_error_init_ok(&error);
|
||||
}
|
||||
|
||||
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
}
|
||||
|
||||
cb = gcd->activate.cb;
|
||||
cb_data = gcd->activate.data;
|
||||
GASSERT(gcd->activate.req);
|
||||
memset(&gcd->activate, 0, sizeof(gcd->activate));
|
||||
|
||||
if (cb) {
|
||||
cb(&error, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
|
||||
const int rs = ofono_netreg_get_status(netreg);
|
||||
|
||||
/* Let's make sure that we aren't connecting when roaming not allowed */
|
||||
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
|
||||
if (!__ofono_gprs_get_roaming_allowed(gprs) &&
|
||||
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Can't activate context %u (roaming)",
|
||||
ctx->cid);
|
||||
cb(ril_error_failure(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Activating context: %u", ctx->cid);
|
||||
GASSERT(!gcd->activate.req);
|
||||
GASSERT(ctx->cid != CTX_ID_NONE);
|
||||
|
||||
gcd->active_ctx_cid = ctx->cid;
|
||||
gcd->activate.cb = cb;
|
||||
gcd->activate.data = data;
|
||||
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
|
||||
ril_gprs_context_activate_primary_cb, gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
|
||||
int ril_status, void *user_data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
|
||||
/*
|
||||
* Data call list may change before the completion of the deactivate
|
||||
* request, in that case ril_gprs_context_set_disconnected will be
|
||||
* 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) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(&error, cb_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure we are in the disconnected state */
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
unsigned int id, ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
gcd->deactivate.cb = cb;
|
||||
gcd->deactivate.data = data;
|
||||
gcd->deactivate.req = ril_data_call_deactivate(gcd->data,
|
||||
gcd->active_call->cid,
|
||||
ril_gprs_context_deactivate_primary_cb, gcd);
|
||||
} else if (cb) {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int id)
|
||||
{
|
||||
DBG("%u", id);
|
||||
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||
}
|
||||
|
||||
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_gprs_context *gcd = g_new0(struct ril_gprs_context, 1);
|
||||
|
||||
DBG("");
|
||||
gcd->gc = gc;
|
||||
gcd->modem = modem;
|
||||
gcd->network = ril_network_ref(modem->network);
|
||||
gcd->data = ril_data_ref(modem->data);
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
if (gcd->activate.req) {
|
||||
/*
|
||||
* The core has already completed its pending D-Bus
|
||||
* request, invoking the completion callback will
|
||||
* cause libdbus to panic.
|
||||
*/
|
||||
ril_data_request_detach(gcd->activate.req);
|
||||
ril_data_request_cancel(gcd->activate.req);
|
||||
}
|
||||
|
||||
if (gcd->deactivate.req) {
|
||||
/* Let it complete but we won't be around to be notified. */
|
||||
ril_data_request_detach(gcd->deactivate.req);
|
||||
} else if (gcd->active_call) {
|
||||
ril_data_call_deactivate(gcd->data, gcd->active_call->cid,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
ril_data_unref(gcd->data);
|
||||
ril_network_unref(gcd->network);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
mtu_watch_free(gcd->mtu_watch);
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
const struct ofono_gprs_context_driver ril_gprs_context_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_gprs_context_probe,
|
||||
.remove = ril_gprs_context_remove,
|
||||
.activate_primary = ril_gprs_context_activate_primary,
|
||||
.deactivate_primary = ril_gprs_context_deactivate_primary,
|
||||
.detach_shutdown = ril_gprs_context_detach_shutdown,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,516 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#define MAX_PDP_CONTEXTS (2)
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
enum ril_modem_power_state {
|
||||
POWERED_OFF,
|
||||
POWERED_ON,
|
||||
POWERING_OFF
|
||||
};
|
||||
|
||||
enum ril_modem_online_state {
|
||||
OFFLINE,
|
||||
GOING_ONLINE,
|
||||
ONLINE,
|
||||
GOING_OFFLINE
|
||||
};
|
||||
|
||||
struct ril_modem_online_request {
|
||||
ofono_modem_online_cb_t cb;
|
||||
struct ril_modem_data *md;
|
||||
void *data;
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
struct sailfish_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;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
gulong radio_state_event_id;
|
||||
|
||||
struct ril_modem_online_request set_online;
|
||||
struct ril_modem_online_request set_offline;
|
||||
};
|
||||
|
||||
#define RADIO_POWER_TAG(md) (md)
|
||||
|
||||
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
|
||||
|
||||
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||
{
|
||||
struct ril_modem_data *md = ofono_modem_get_data(o);
|
||||
GASSERT(md->modem.ofono == o);
|
||||
return md;
|
||||
}
|
||||
|
||||
static void *ril_modem_get_atom_data(struct ril_modem *modem,
|
||||
enum ofono_atom_type type)
|
||||
{
|
||||
if (modem && modem->ofono) {
|
||||
struct ofono_atom *atom =
|
||||
__ofono_modem_find_atom(modem->ofono, type);
|
||||
|
||||
if (atom) {
|
||||
return __ofono_atom_get_data(atom);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
|
||||
}
|
||||
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
|
||||
}
|
||||
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
|
||||
}
|
||||
|
||||
static inline struct ofono_radio_settings *ril_modem_radio_settings(
|
||||
struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
|
||||
}
|
||||
|
||||
void ril_modem_delete(struct ril_modem *md)
|
||||
{
|
||||
if (md && md->ofono) {
|
||||
ofono_modem_remove(md->ofono);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (req->cb) {
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *data = req->data;
|
||||
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||
{
|
||||
switch (md->modem.radio->state) {
|
||||
case RADIO_STATE_ON:
|
||||
DBG("online");
|
||||
ril_modem_online_request_ok(&md->set_online);
|
||||
break;
|
||||
|
||||
case RADIO_STATE_OFF:
|
||||
case RADIO_STATE_UNAVAILABLE:
|
||||
DBG("offline");
|
||||
ril_modem_online_request_ok(&md->set_offline);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
|
||||
md->power_state == POWERING_OFF) {
|
||||
md->power_state = POWERED_OFF;
|
||||
if (md->modem.ofono) {
|
||||
ofono_modem_set_powered(md->modem.ofono, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
ril_modem_update_online_state(req->md);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_check(gpointer data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->online_check_id);
|
||||
md->online_check_id = 0;
|
||||
ril_modem_update_online_state(md);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
{
|
||||
if (!md->online_check_id) {
|
||||
md->online_check_id = g_idle_add(ril_modem_online_check, 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) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!ril_modem_radio_settings(m)) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
ofono_radio_settings_create(m->ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
ril_modem_update_radio_settings(md);
|
||||
}
|
||||
|
||||
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) {
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
if (!md->radio_state_event_id) {
|
||||
md->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||
ril_modem_radio_state_cb, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (gprs) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
|
||||
struct ofono_gprs_context *gc =
|
||||
ofono_gprs_context_create(modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
if (gc == NULL)
|
||||
break;
|
||||
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_call_volume_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_settings_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_netmon_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
|
||||
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ril_radio *radio = md->modem.radio;
|
||||
struct ril_modem_online_request *req;
|
||||
|
||||
DBG("%s going %sline", ofono_modem_get_path(modem),
|
||||
online ? "on" : "off");
|
||||
|
||||
ril_radio_set_online(radio, online);
|
||||
if (online) {
|
||||
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_online;
|
||||
} else {
|
||||
ril_radio_power_off(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_offline;
|
||||
}
|
||||
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
}
|
||||
req->timeout_id = g_timeout_add_seconds(ONLINE_TIMEOUT_SECS,
|
||||
ril_modem_online_request_timeout, req);
|
||||
ril_modem_schedule_online_check(md);
|
||||
}
|
||||
|
||||
static int ril_modem_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->power_state = POWERED_ON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ril_modem_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
if (md->set_online.timeout_id || md->set_offline.timeout_id) {
|
||||
md->power_state = POWERING_OFF;
|
||||
return -EINPROGRESS;
|
||||
} else {
|
||||
md->power_state = POWERED_OFF;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_modem_probe(struct ofono_modem *modem)
|
||||
{
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(ofono);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
ofono_modem_set_data(ofono, NULL);
|
||||
|
||||
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||
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);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
}
|
||||
|
||||
if (md->set_online.timeout_id) {
|
||||
g_source_remove(md->set_online.timeout_id);
|
||||
}
|
||||
|
||||
if (md->set_offline.timeout_id) {
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_data_unref(modem->data);
|
||||
sailfish_cell_info_unref(modem->cell_info);
|
||||
grilio_channel_unref(modem->io);
|
||||
grilio_queue_cancel_all(md->q, FALSE);
|
||||
grilio_queue_unref(md->q);
|
||||
g_free(md->ecclist_file);
|
||||
g_free(md->log_prefix);
|
||||
g_free(md->imeisv);
|
||||
g_free(md->imei);
|
||||
g_free(md);
|
||||
}
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
struct ofono_modem *ofono = ofono_modem_create(path + 1,
|
||||
RILMODEM_DRIVER);
|
||||
if (ofono) {
|
||||
int err;
|
||||
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
/*
|
||||
* ril_plugin.c must wait until IMEI becomes known before
|
||||
* creating the modem
|
||||
*/
|
||||
GASSERT(imei);
|
||||
|
||||
/* Copy config */
|
||||
modem->config = *config;
|
||||
modem->imei = md->imei = g_strdup(imei);
|
||||
modem->imeisv = md->imeisv = g_strdup(imeisv);
|
||||
modem->log_prefix = log_prefix; /* No need to strdup */
|
||||
modem->ecclist_file = ecclist_file; /* No need to strdup */
|
||||
md->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
modem->ofono = ofono;
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
modem->sim_settings = ril_sim_settings_ref(settings);
|
||||
modem->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
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->imsi_event_id =
|
||||
sailfish_watch_add_imsi_changed_handler(md->watch,
|
||||
ril_modem_imsi_cb, md);
|
||||
|
||||
md->set_online.md = md;
|
||||
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);
|
||||
|
||||
/*
|
||||
* ofono_modem_reset sets Powered to TRUE without
|
||||
* issuing PropertyChange signal.
|
||||
*/
|
||||
ofono_modem_set_powered(modem->ofono, FALSE);
|
||||
ofono_modem_set_powered(modem->ofono, TRUE);
|
||||
md->power_state = POWERED_ON;
|
||||
|
||||
/*
|
||||
* With some RIL implementations, querying available
|
||||
* band modes causes some magic Android properties to
|
||||
* appear. Otherwise this request is pretty harmless
|
||||
* and useless.
|
||||
*/
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
} else {
|
||||
ofono_error("Error %d registering %s",
|
||||
err, RILMODEM_DRIVER);
|
||||
|
||||
/*
|
||||
* If ofono_modem_register() failed, then
|
||||
* ofono_modem_remove() won't invoke
|
||||
* ril_modem_remove() callback.
|
||||
*/
|
||||
ril_modem_remove(ofono);
|
||||
}
|
||||
|
||||
ofono_modem_remove(ofono);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct ofono_modem_driver ril_modem_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_modem_probe,
|
||||
.remove = ril_modem_remove,
|
||||
.enable = ril_modem_enable,
|
||||
.disable = ril_modem_disable,
|
||||
.pre_sim = ril_modem_pre_sim,
|
||||
.post_sim = ril_modem_post_sim,
|
||||
.post_online = ril_modem_post_online,
|
||||
.set_online = ril_modem_set_online
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
struct ril_netmon {
|
||||
struct ofono_netmon *netmon;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
guint register_id;
|
||||
};
|
||||
|
||||
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
||||
{
|
||||
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
{
|
||||
s_mcc[0] = 0;
|
||||
s_mnc[0] = 0;
|
||||
|
||||
if (mcc >= 0 && mcc <= 999) {
|
||||
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
|
||||
if (mnc >= 0 && mnc <= 999) {
|
||||
const unsigned int mnclen = mnclength(mcc, mnc);
|
||||
const char *format[] = { "%d", "%02d", "%03d" };
|
||||
const char *fmt = (mnclen > 0 &&
|
||||
mnclen <= G_N_ELEMENTS(format)) ?
|
||||
format[mnclen - 1] : format[0];
|
||||
snprintf(s_mnc, OFONO_MAX_MNC_LENGTH + 1, fmt, mnc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||
struct ofono_error error;
|
||||
GSList *l;
|
||||
|
||||
for (l = nm->cell_info->cells; l; l = l->next) {
|
||||
const struct sailfish_cell *cell = l->data;
|
||||
|
||||
if (cell->registered) {
|
||||
switch (cell->type) {
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
ril_netmon_notify_gsm(netmon,
|
||||
&cell->info.gsm);
|
||||
break;
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
ril_netmon_notify_wcdma(netmon,
|
||||
&cell->info.wcdma);
|
||||
break;
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
ril_netmon_notify_lte(netmon,
|
||||
&cell->info.lte);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
static gboolean ril_netmon_register(gpointer user_data)
|
||||
{
|
||||
struct ril_netmon *nm = user_data;
|
||||
|
||||
GASSERT(nm->register_id);
|
||||
nm->register_id = 0;
|
||||
ofono_netmon_register(nm->netmon);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
int ret;
|
||||
|
||||
if (modem->cell_info) {
|
||||
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
|
||||
|
||||
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
|
||||
nm->netmon = netmon;
|
||||
|
||||
ofono_netmon_set_data(netmon, nm);
|
||||
nm->register_id = g_idle_add(ril_netmon_register, nm);
|
||||
ret = 0;
|
||||
} else {
|
||||
DBG("%s no", modem->log_prefix ? modem->log_prefix : "");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
DBG("%s %d", modem->log_prefix ? modem->log_prefix : "", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ril_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
|
||||
if (nm->register_id > 0) {
|
||||
g_source_remove(nm->register_id);
|
||||
}
|
||||
|
||||
sailfish_cell_info_unref(nm->cell_info);
|
||||
g_slice_free(struct ril_netmon, nm);
|
||||
}
|
||||
|
||||
const struct ofono_netmon_driver ril_netmon_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_netmon_probe,
|
||||
.remove = ril_netmon_remove,
|
||||
.request_update = ril_netmon_request_update,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,552 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "simutil.h"
|
||||
|
||||
enum ril_netreg_events {
|
||||
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||
NETREG_RIL_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_netreg_network_events {
|
||||
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
|
||||
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
|
||||
NETREG_NETWORK_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_netreg *netreg;
|
||||
struct ril_network *network;
|
||||
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];
|
||||
};
|
||||
|
||||
struct ril_netreg_cbd {
|
||||
struct ril_netreg *nd;
|
||||
union {
|
||||
ofono_netreg_status_cb_t status;
|
||||
ofono_netreg_operator_cb_t operator;
|
||||
ofono_netreg_operator_list_cb_t operator_list;
|
||||
ofono_netreg_register_cb_t reg;
|
||||
ofono_netreg_strength_cb_t strength;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_netreg_cbd_free g_free
|
||||
|
||||
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
|
||||
{
|
||||
return ofono ? ofono_netreg_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
|
||||
void *cb, void *data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = g_new0(struct ril_netreg_cbd, 1);
|
||||
|
||||
cbd->nd = nd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
|
||||
gint status)
|
||||
{
|
||||
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
/* These functions tolerate NULL argument */
|
||||
const char *net_mcc = ofono_netreg_get_mcc(netreg);
|
||||
const char *net_mnc = ofono_netreg_get_mnc(netreg);
|
||||
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
|
||||
|
||||
if (spdi && net_mcc && net_mnc) {
|
||||
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
|
||||
ofono_info("not roaming based on spdi");
|
||||
return NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ril_netreg_check_status(struct ril_netreg *nd, int status)
|
||||
{
|
||||
return (nd && nd->netreg) ?
|
||||
ril_netreg_check_if_really_roaming(nd->netreg, status) :
|
||||
status;
|
||||
}
|
||||
|
||||
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);
|
||||
GASSERT(nd->notify_id);
|
||||
nd->notify_id = 0;
|
||||
ofono_netreg_status_notify(nd->netreg,
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
/* Coalesce multiple notifications into one */
|
||||
if (nd->notify_id) {
|
||||
DBG("%snotification aready queued", nd->log_prefix);
|
||||
} else {
|
||||
DBG("%squeuing notification", nd->log_prefix);
|
||||
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_registration_status(struct ofono_netreg *netreg,
|
||||
ofono_netreg_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
cb(ril_error_ok(&error),
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech, data);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_current_operator_cb(void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
GASSERT(nd->current_operator_id);
|
||||
nd->current_operator_id = 0;
|
||||
|
||||
cb(ril_error_ok(&error), nd->network->operator, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
ofono_netreg_operator_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
/*
|
||||
* Calling ofono_netreg_status_notify() may result in
|
||||
* ril_netreg_current_operator() being invoked even if one
|
||||
* is already pending. Since ofono core doesn't associate
|
||||
* any context with individual calls, we can safely assume
|
||||
* that such a call essentially cancels the previous one.
|
||||
*/
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
nd->current_operator_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_netreg_current_operator_cb,
|
||||
ril_netreg_cbd_new(nd, cb, data),
|
||||
ril_netreg_cbd_free);
|
||||
}
|
||||
|
||||
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 ofono_network_operator *list;
|
||||
struct ofono_error error;
|
||||
int noperators = 0, i;
|
||||
GRilIoParser rilp;
|
||||
gboolean ok = TRUE;
|
||||
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("Failed to retrive the list of operators: %s",
|
||||
ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* Number of operators at the list (4 strings for every operator) */
|
||||
grilio_parser_get_int32(&rilp, &noperators);
|
||||
GASSERT(!(noperators % 4));
|
||||
noperators /= 4;
|
||||
ofono_info("noperators = %d", noperators);
|
||||
|
||||
list = g_new0(struct ofono_network_operator, noperators);
|
||||
for (i = 0; i < noperators && ok; i++) {
|
||||
struct ofono_network_operator *op = list + i;
|
||||
char *lalpha = grilio_parser_get_utf8(&rilp);
|
||||
char *salpha = grilio_parser_get_utf8(&rilp);
|
||||
char *numeric = grilio_parser_get_utf8(&rilp);
|
||||
char *status = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
/* Try to use long by default */
|
||||
if (lalpha) {
|
||||
strncpy(op->name, lalpha,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else if (salpha) {
|
||||
strncpy(op->name, salpha,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else {
|
||||
op->name[0] = 0;
|
||||
}
|
||||
|
||||
/* Set the proper status */
|
||||
if (!strcmp(status, "available")) {
|
||||
list[i].status = OPERATOR_STATUS_AVAILABLE;
|
||||
} else if (!strcmp(status, "current")) {
|
||||
list[i].status = OPERATOR_STATUS_CURRENT;
|
||||
} else if (!strcmp(status, "forbidden")) {
|
||||
list[i].status = OPERATOR_STATUS_FORBIDDEN;
|
||||
} else {
|
||||
list[i].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;
|
||||
}
|
||||
DBG("[operator=%s, %s, %s, status: %s]", op->name,
|
||||
op->mcc, op->mnc, status);
|
||||
} else {
|
||||
DBG("failed to parse operator list");
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
g_free(status);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
cb(ril_error_ok(&error), noperators, list, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
}
|
||||
|
||||
g_free(list);
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators(struct ofono_netreg *netreg,
|
||||
ofono_netreg_operator_list_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS,
|
||||
ril_netreg_list_operators_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_netreg_register_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;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("registration failed, ril result %d", status);
|
||||
cb(ril_error_failure(&error), 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);
|
||||
|
||||
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,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
const char *mcc, const char *mnc,
|
||||
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 manual: %s%s", mcc, mnc);
|
||||
grilio_request_append_format(req, "%s%s+0", mcc, mnc);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* RIL_SignalStrength_v6 */
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &gw_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &cdma_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &evdo_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* 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 */
|
||||
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
|
||||
evdo_dbm, lte_signal);
|
||||
|
||||
/* Return the first valid one */
|
||||
if (gw_signal != 99 && gw_signal != -1) {
|
||||
return (gw_signal * 100) / 31;
|
||||
}
|
||||
|
||||
if (lte_signal != 99 && lte_signal != -1) {
|
||||
return (lte_signal * 100) / 31;
|
||||
}
|
||||
|
||||
/* In case of dbm, return the value directly */
|
||||
if (cdma_dbm != -1) {
|
||||
return MIN(cdma_dbm, 100);
|
||||
}
|
||||
|
||||
if (evdo_dbm != -1) {
|
||||
return MIN(evdo_dbm, 100);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
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);
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_strength_cb_t cb = cbd->cb.strength;
|
||||
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);
|
||||
} else {
|
||||
ofono_error("Failed to retrive the signal strength: %s",
|
||||
ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength(struct ofono_netreg *netreg,
|
||||
ofono_netreg_strength_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SIGNAL_STRENGTH, ril_netreg_strength_cb,
|
||||
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
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];
|
||||
gchar *nitz;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
g_free(nitz);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_register(gpointer user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
GASSERT(nd->timer_id);
|
||||
nd->timer_id = 0;
|
||||
ofono_netreg_register(nd->netreg);
|
||||
|
||||
/* Register for network state changes */
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_OPERATOR_CHANGED] =
|
||||
ril_network_add_operator_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED] =
|
||||
ril_network_add_voice_state_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
|
||||
/* Register for network time updates */
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_NITZ_TIME_RECEIVED] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_nitz_notify,
|
||||
RIL_UNSOL_NITZ_TIME_RECEIVED, nd);
|
||||
|
||||
/* Register for signal strength changes */
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_SIGNAL_STRENGTH] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_strength_notify,
|
||||
RIL_UNSOL_SIGNAL_STRENGTH, nd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
|
||||
guint slot = ril_modem_slot(modem);
|
||||
|
||||
DBG("[%u] %p", slot, netreg);
|
||||
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
unsigned int i;
|
||||
|
||||
DBG("%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
ofono_netreg_set_data(netreg, NULL);
|
||||
|
||||
if (nd->timer_id > 0) {
|
||||
g_source_remove(nd->timer_id);
|
||||
}
|
||||
|
||||
if (nd->notify_id) {
|
||||
g_source_remove(nd->notify_id);
|
||||
}
|
||||
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
|
||||
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
|
||||
}
|
||||
ril_network_unref(nd->network);
|
||||
|
||||
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
|
||||
G_N_ELEMENTS(nd->ril_event_id));
|
||||
|
||||
grilio_channel_unref(nd->io);
|
||||
grilio_queue_unref(nd->q);
|
||||
g_free(nd->log_prefix);
|
||||
g_free(nd);
|
||||
}
|
||||
|
||||
const struct ofono_netreg_driver ril_netreg_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_netreg_probe,
|
||||
.remove = ril_netreg_remove,
|
||||
.registration_status = ril_netreg_registration_status,
|
||||
.current_operator = ril_netreg_current_operator,
|
||||
.list_operators = ril_netreg_list_operators,
|
||||
.register_auto = ril_netreg_register_auto,
|
||||
.register_manual = ril_netreg_register_manual,
|
||||
.strength = ril_netreg_strength
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,940 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SET_PREF_MODE_HOLDOFF_SEC RIL_RETRY_SECS
|
||||
|
||||
typedef GObjectClass RilNetworkClass;
|
||||
typedef struct ril_network RilNetwork;
|
||||
|
||||
enum ril_network_timer {
|
||||
TIMER_SET_RAT_HOLDOFF,
|
||||
TIMER_FORCE_CHECK_PREF_MODE,
|
||||
TIMER_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_radio_event {
|
||||
RADIO_EVENT_STATE_CHANGED,
|
||||
RADIO_EVENT_ONLINE_CHANGED,
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_unsol_event {
|
||||
UNSOL_EVENT_NETWORK_STATE,
|
||||
UNSOL_EVENT_RADIO_CAPABILITY,
|
||||
UNSOL_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
int rat;
|
||||
char *log_prefix;
|
||||
guint operator_poll_id;
|
||||
guint voice_poll_id;
|
||||
guint data_poll_id;
|
||||
guint timer[TIMER_COUNT];
|
||||
gulong query_rat_id;
|
||||
gulong set_rat_id;
|
||||
gulong unsol_event_id[UNSOL_EVENT_COUNT];
|
||||
gulong settings_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
};
|
||||
|
||||
enum ril_network_signal {
|
||||
SIGNAL_OPERATOR_CHANGED,
|
||||
SIGNAL_VOICE_STATE_CHANGED,
|
||||
SIGNAL_DATA_STATE_CHANGED,
|
||||
SIGNAL_PREF_MODE_CHANGED,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
|
||||
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
|
||||
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
|
||||
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
|
||||
#define SIGNAL_MAX_PREF_MODE_CHANGED_NAME "ril-network-max-pref-mode-changed"
|
||||
|
||||
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilNetwork, ril_network, G_TYPE_OBJECT)
|
||||
#define RIL_NETWORK_TYPE (ril_network_get_type())
|
||||
#define RIL_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,\
|
||||
RIL_NETWORK_TYPE,RilNetwork))
|
||||
|
||||
#define RIL_NETWORK_SIGNAL(klass,name) \
|
||||
ril_network_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
/* Some assumptions: */
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_ANY == 0);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_GSM > OFONO_RADIO_ACCESS_MODE_ANY);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self);
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat);
|
||||
|
||||
static void ril_network_emit(struct ril_network *self,
|
||||
enum ril_network_signal sig)
|
||||
{
|
||||
g_signal_emit(self, ril_network_signals[sig], 0);
|
||||
}
|
||||
|
||||
static void ril_network_stop_timer(struct ril_network *self,
|
||||
enum ril_network_timer tid)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->timer[tid]) {
|
||||
g_source_remove(priv->timer[tid]);
|
||||
priv->timer[tid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_reset_state(struct ril_registration_state *reg)
|
||||
{
|
||||
memset(reg, 0, sizeof(*reg));
|
||||
reg->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
reg->access_tech = -1;
|
||||
reg->ril_tech = -1;
|
||||
reg->lac = -1;
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
const void *data, guint len, struct ril_registration_state *reg)
|
||||
{
|
||||
int nparams, ril_status;
|
||||
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
|
||||
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
ril_network_reset_state(reg);
|
||||
|
||||
/* Size of response string array. The minimum seen in the wild is 3 */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (!grilio_parser_get_int32(&rilp, &nparams) || nparams < 3) {
|
||||
DBG_(self, "broken response");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sstatus = grilio_parser_get_utf8(&rilp); /* response[0] */
|
||||
if (!sstatus) {
|
||||
DBG_(self, "No sstatus value returned!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
slac = grilio_parser_get_utf8(&rilp); /* response[1] */
|
||||
sci = grilio_parser_get_utf8(&rilp); /* response[2] */
|
||||
|
||||
if (nparams > 3) {
|
||||
stech = grilio_parser_get_utf8(&rilp); /* response[3] */
|
||||
}
|
||||
|
||||
ril_status = atoi(sstatus);
|
||||
if (ril_status > 10) {
|
||||
reg->status = ril_status - 10;
|
||||
} else {
|
||||
reg->status = ril_status;
|
||||
}
|
||||
|
||||
/* FIXME: need to review VOICE_REGISTRATION response
|
||||
* as it returns up to 15 parameters ( vs. 6 for DATA ).
|
||||
*
|
||||
* The first four parameters are the same for both
|
||||
* responses ( although status includes values for
|
||||
* emergency calls for VOICE response ).
|
||||
*
|
||||
* Parameters 5 & 6 have different meanings for
|
||||
* voice & data response.
|
||||
*/
|
||||
if (nparams > 4) {
|
||||
/* TODO: different use for CDMA */
|
||||
sreason = grilio_parser_get_utf8(&rilp); /* response[4] */
|
||||
if (nparams > 5) {
|
||||
/* TODO: different use for CDMA */
|
||||
smax = grilio_parser_get_utf8(&rilp); /* response[5] */
|
||||
if (smax) {
|
||||
reg->max_calls = atoi(smax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some older RILs don't provide max calls, in that case let's
|
||||
* supply some reasonable default. We don't need more than 2
|
||||
* simultaneous data calls anyway.
|
||||
*/
|
||||
if (reg->max_calls < 1) {
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(slac, 16, ®->lac)) {
|
||||
reg->lac = -1;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(sci, 16, ®->ci)) {
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
||||
registration_status_to_string(reg->status),
|
||||
slac, sci, reg->ril_tech,
|
||||
registration_tech_to_string(reg->access_tech),
|
||||
sreason, smax);
|
||||
|
||||
g_free(sstatus);
|
||||
g_free(slac);
|
||||
g_free(sci);
|
||||
g_free(stech);
|
||||
g_free(sreason);
|
||||
g_free(smax);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ril_network_op_copy(struct ofono_network_operator *dest,
|
||||
const struct ofono_network_operator *src)
|
||||
{
|
||||
strncpy(dest->mcc, src->mcc, sizeof(dest->mcc));
|
||||
strncpy(dest->mnc, src->mnc, sizeof(dest->mnc));
|
||||
strncpy(dest->name, src->name, sizeof(dest->name));
|
||||
dest->mcc[sizeof(dest->mcc)-1] = 0;
|
||||
dest->mnc[sizeof(dest->mnc)-1] = 0;
|
||||
dest->name[sizeof(dest->name)-1] = 0;
|
||||
dest->status = src->status;
|
||||
dest->tech = src->tech;
|
||||
}
|
||||
|
||||
static gboolean ril_network_op_equal(const struct ofono_network_operator *op1,
|
||||
const struct ofono_network_operator *op2)
|
||||
{
|
||||
if (op1 == op2) {
|
||||
return TRUE;
|
||||
} else if (!op1 || !op2) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return op1->status == op2->status &&
|
||||
op1->tech == op2->tech &&
|
||||
!strncmp(op1->mcc, op2->mcc, sizeof(op2->mcc)) &&
|
||||
!strncmp(op1->mnc, op2->mnc, sizeof(op2->mnc)) &&
|
||||
!strncmp(op1->name, op2->name, sizeof(op2->name));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->operator_poll_id);
|
||||
priv->operator_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ofono_network_operator op;
|
||||
gboolean changed = FALSE;
|
||||
gchar *lalpha;
|
||||
char *salpha;
|
||||
char *numeric;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
lalpha = grilio_parser_get_utf8(&rilp);
|
||||
salpha = grilio_parser_get_utf8(&rilp);
|
||||
numeric = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
op.tech = -1;
|
||||
if (ril_parse_mcc_mnc(numeric, &op)) {
|
||||
if (op.tech < 0) op.tech = self->voice.access_tech;
|
||||
op.status = OPERATOR_STATUS_CURRENT;
|
||||
op.name[0] = 0;
|
||||
if (lalpha) {
|
||||
strncpy(op.name, lalpha, sizeof(op.name));
|
||||
} else if (salpha) {
|
||||
strncpy(op.name, salpha, sizeof(op.name));
|
||||
} else {
|
||||
strncpy(op.name, numeric, sizeof(op.name));
|
||||
}
|
||||
op.name[sizeof(op.name)-1] = 0;
|
||||
if (!self->operator) {
|
||||
self->operator = &priv->operator;
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
} else if (!ril_network_op_equal(&op, &priv->operator)) {
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
}
|
||||
} else if (self->operator) {
|
||||
self->operator = NULL;
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (self->operator) {
|
||||
DBG_(self, "lalpha=%s, salpha=%s, numeric=%s, "
|
||||
"%s, mcc=%s, mnc=%s, %s",
|
||||
lalpha, salpha, numeric,
|
||||
op.name, op.mcc, op.mnc,
|
||||
registration_tech_to_string(op.tech));
|
||||
} else {
|
||||
DBG_(self, "no operator");
|
||||
}
|
||||
ril_network_emit(self, SIGNAL_OPERATOR_CHANGED);
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_voice_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->voice_poll_id);
|
||||
priv->voice_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->voice, sizeof(state))) {
|
||||
DBG_(self, "voice registration changed");
|
||||
self->voice = state;
|
||||
ril_network_emit(self, SIGNAL_VOICE_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->data_poll_id);
|
||||
priv->data_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->data, sizeof(state))) {
|
||||
DBG_(self, "data registration changed");
|
||||
self->data = state;
|
||||
ril_network_emit(self, SIGNAL_DATA_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
|
||||
int code, GRilIoChannelResponseFunc fn)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, id);
|
||||
} else {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
id = grilio_queue_send_request_full(priv->q, req, code, fn,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_network_poll_state(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
||||
ril_network_poll_operator_cb);
|
||||
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||
ril_network_poll_voice_state_cb);
|
||||
priv->data_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_network_poll_data_state_cb);
|
||||
}
|
||||
|
||||
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case PREF_NET_TYPE_LTE_CDMA_EVDO:
|
||||
case PREF_NET_TYPE_LTE_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_LTE_ONLY:
|
||||
case PREF_NET_TYPE_LTE_WCDMA:
|
||||
return OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
case PREF_NET_TYPE_GSM_WCDMA_AUTO:
|
||||
case PREF_NET_TYPE_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA:
|
||||
return OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
default:
|
||||
DBG("unexpected rat mode %d", rat);
|
||||
case PREF_NET_TYPE_GSM_ONLY:
|
||||
return OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
return PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
|
||||
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
}
|
||||
/* no break */
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
return PREF_NET_TYPE_GSM_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_pref_mode_expected(struct ril_network *self)
|
||||
{
|
||||
struct ril_sim_settings *settings = self->settings;
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* On dual-SIM phones such as Jolla C only one slot at a time
|
||||
* is allowed to use LTE. Even if the slot which has been using
|
||||
* LTE gets powered off, we still need to explicitely set its
|
||||
* preferred mode to GSM, to make LTE machinery available to
|
||||
* the other slot. This sort of behaviour might not be necessary
|
||||
* on some hardware and can (should) be made configurable when
|
||||
* it becomes necessary.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
|
||||
/*
|
||||
* OFONO_RADIO_ACCESS_MODE_ANY is zero. If both pref_mode
|
||||
* and max_pref_mode are not ANY, we pick the smallest value.
|
||||
* Otherwise we take any non-zero value if there is one.
|
||||
*/
|
||||
const enum ofono_radio_access_mode pref_mode =
|
||||
(settings->pref_mode && max_pref_mode) ?
|
||||
MIN(settings->pref_mode, max_pref_mode) :
|
||||
settings->pref_mode ? settings->pref_mode :
|
||||
max_pref_mode;
|
||||
return ril_network_mode_to_rat(self, pref_mode);
|
||||
}
|
||||
|
||||
static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
|
||||
}
|
||||
|
||||
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
|
||||
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
|
||||
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
|
||||
|
||||
/*
|
||||
* Don't retry the request if modem is offline or SIM card isn't
|
||||
* ready, to avoid spamming system log with error messages. Radio
|
||||
* and SIM card state change callbacks will schedule a new check
|
||||
* when it's appropriate.
|
||||
*/
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
DBG_(self, "giving up");
|
||||
}
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->set_rat_id);
|
||||
priv->set_rat_id = 0;
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("failed to set rat mode");
|
||||
}
|
||||
|
||||
ril_network_query_pref_mode(self);
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG_(self, "setting rat mode %d", rat);
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, rat);
|
||||
|
||||
grilio_queue_cancel_request(priv->q, priv->set_rat_id, FALSE);
|
||||
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_set_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* Don't do it too often */
|
||||
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
|
||||
ril_network_set_rat_holdoff_cb, self);
|
||||
}
|
||||
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean force)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
force = TRUE;
|
||||
}
|
||||
|
||||
if (priv->rat == rat || force) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_parse_pref_resp(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int pref = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &pref);
|
||||
return pref;
|
||||
}
|
||||
|
||||
static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
|
||||
int status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike ril_network_query_pref_mode_cb, this one always
|
||||
* checks the preferred mode.
|
||||
*/
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
/* This request never fails because in case of error it gets retried */
|
||||
GASSERT(status == RIL_E_SUCCESS);
|
||||
GASSERT(priv->query_rat_id);
|
||||
|
||||
priv->query_rat_id = 0;
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE);
|
||||
priv->query_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_query_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
void ril_network_set_max_pref_mode(struct ril_network *self,
|
||||
enum ofono_radio_access_mode max_mode,
|
||||
gboolean force_check)
|
||||
{
|
||||
if (self && (self->max_pref_mode != max_mode || force_check)) {
|
||||
if (self->max_pref_mode != max_mode) {
|
||||
DBG_(self, "rat mode %d (%s)", max_mode,
|
||||
ofono_radio_access_mode_to_string(max_mode));
|
||||
self->max_pref_mode = max_mode;
|
||||
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
|
||||
}
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
priv->assert_rat = TRUE;
|
||||
ril_network_check_pref_mode(self, immediate);
|
||||
}
|
||||
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_OPERATOR_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_VOICE_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_data_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_DATA_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_network_remove_handler(struct ril_network *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, n);
|
||||
}
|
||||
|
||||
static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
|
||||
guint code, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
|
||||
ril_network_assert_pref_mode(self, FALSE);
|
||||
}
|
||||
|
||||
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_radio_online_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_network_check_pref_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->timer[TIMER_FORCE_CHECK_PREF_MODE]);
|
||||
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] = 0;
|
||||
|
||||
DBG_(self, "checking pref mode");
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_pref_mode_changed_cb(struct ril_sim_settings *settings,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* Postpone ril_network_check_pref_mode because other pref_mode
|
||||
* listeners (namely, ril_data) may want to tweak max_pref_mode
|
||||
*/
|
||||
if (!priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
DBG_(self, "scheduling pref mode check");
|
||||
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] =
|
||||
g_idle_add(ril_network_check_pref_mode_cb, self);
|
||||
} else {
|
||||
DBG_(self, "pref mode check already scheduled");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
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_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
self->settings = ril_sim_settings_ref(settings);
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_state_changed_cb,
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
|
||||
priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_radio_capability_changed_cb,
|
||||
RIL_UNSOL_RADIO_CAPABILITY, self);
|
||||
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
|
||||
ril_radio_add_state_changed_handler(priv->radio,
|
||||
ril_network_radio_state_cb, self);
|
||||
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
|
||||
ril_radio_add_online_changed_handler(priv->radio,
|
||||
ril_network_radio_online_cb, self);
|
||||
priv->settings_event_id =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(settings,
|
||||
ril_network_pref_mode_changed_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
|
||||
/*
|
||||
* Query the initial state. Querying network state before the radio
|
||||
* has been turned on makes RIL unhappy.
|
||||
*/
|
||||
grilio_queue_send_request_full(priv->q, NULL,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_startup_query_pref_mode_cb, NULL, self);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_ref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_NETWORK(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_unref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_NETWORK(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_init(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_NETWORK_TYPE, struct ril_network_priv);
|
||||
|
||||
self->priv = priv;
|
||||
ril_network_reset_state(&self->voice);
|
||||
ril_network_reset_state(&self->data);
|
||||
priv->rat = -1;
|
||||
}
|
||||
|
||||
static void ril_network_finalize(GObject *object)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
enum ril_network_timer tid;
|
||||
|
||||
DBG_(self, "");
|
||||
|
||||
for (tid=0; tid<TIMER_COUNT; tid++) {
|
||||
ril_network_stop_timer(self, tid);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
|
||||
G_N_ELEMENTS(priv->unsol_event_id));
|
||||
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_handler(priv->sim_card,
|
||||
priv->sim_status_event_id);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
ril_sim_settings_remove_handler(self->settings,
|
||||
priv->settings_event_id);
|
||||
ril_sim_settings_unref(self->settings);
|
||||
g_free(priv->log_prefix);
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_network_class_init(RilNetworkClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_network_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_network_priv));
|
||||
RIL_NETWORK_SIGNAL(klass, OPERATOR);
|
||||
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
|
||||
RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_NETWORK_H
|
||||
#define RIL_NETWORK_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
int status; /* enum network_registration_status */
|
||||
int access_tech; /* enum access_technology or -1 if none */
|
||||
int ril_tech;
|
||||
int max_calls;
|
||||
int lac;
|
||||
int ci;
|
||||
};
|
||||
|
||||
struct ril_network {
|
||||
GObject object;
|
||||
struct ril_network_priv *priv;
|
||||
struct ril_registration_state voice;
|
||||
struct ril_registration_state data;
|
||||
const struct ofono_network_operator *operator;
|
||||
enum ofono_radio_access_mode pref_mode;
|
||||
enum ofono_radio_access_mode max_pref_mode;
|
||||
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_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
|
||||
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);
|
||||
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,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
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);
|
||||
|
||||
#endif /* RIL_NETWORK_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "gdbus.h"
|
||||
#include "ofono.h"
|
||||
|
||||
#define RIL_OEM_RAW_INTERFACE "org.ofono.OemRaw"
|
||||
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
|
||||
|
||||
struct ril_oem_raw {
|
||||
GRilIoQueue *q;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
char *log_prefix;
|
||||
};
|
||||
|
||||
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
|
||||
|
||||
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DBusMessage *msg = user_data;
|
||||
DBusMessage *reply;
|
||||
|
||||
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_close_container(&it, &array);
|
||||
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
|
||||
DBG("Timed out");
|
||||
reply = __ofono_error_timed_out(msg);
|
||||
} else {
|
||||
DBG("Error %s", ril_error_to_string(ril_status));
|
||||
reply = __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, reply);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
void *user_data)
|
||||
{
|
||||
DBusMessageIter it;
|
||||
struct ril_oem_raw *oem = user_data;
|
||||
|
||||
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) {
|
||||
char *data;
|
||||
int data_len;
|
||||
DBusMessageIter array;
|
||||
GRilIoRequest *req;
|
||||
|
||||
/* Fetch the data */
|
||||
dbus_message_iter_recurse(&it, &array);
|
||||
dbus_message_iter_get_fixed_array(&array, &data, &data_len);
|
||||
DBG_(oem, "%d bytes", data_len);
|
||||
|
||||
/*
|
||||
* And forward it to rild. Set a timeout because rild may
|
||||
* never respond to invalid requests.
|
||||
*/
|
||||
req = grilio_request_sized_new(data_len);
|
||||
grilio_request_set_timeout(req, RIL_OEM_RAW_TIMEOUT);
|
||||
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));
|
||||
grilio_request_unref(req);
|
||||
return NULL;
|
||||
} else {
|
||||
DBG_(oem, "Unexpected signature");
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_oem_raw_methods[] = {
|
||||
{ GDBUS_ASYNC_METHOD("Send",
|
||||
GDBUS_ARGS({ "request", "ay" }),
|
||||
GDBUS_ARGS({ "response", "ay" }),
|
||||
ril_oem_raw_send) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
const char *log_prefix)
|
||||
{
|
||||
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
oem->path = g_strdup(ril_modem_get_path(modem));
|
||||
oem->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
oem->q = grilio_queue_new(ril_modem_io(modem));
|
||||
oem->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE, ril_oem_raw_methods,
|
||||
NULL, NULL, oem, NULL)) {
|
||||
ofono_modem_add_interface(modem->ofono, RIL_OEM_RAW_INTERFACE);
|
||||
return oem;
|
||||
} else {
|
||||
ofono_error("OemRaw D-Bus register failed");
|
||||
ril_oem_raw_free(oem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_oem_raw_free(struct ril_oem_raw *oem)
|
||||
{
|
||||
if (oem) {
|
||||
DBG("%s", oem->path);
|
||||
g_dbus_unregister_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
dbus_connection_unref(oem->conn);
|
||||
|
||||
grilio_queue_cancel_all(oem->q, TRUE);
|
||||
grilio_queue_unref(oem->q);
|
||||
|
||||
g_free(oem->log_prefix);
|
||||
g_free(oem->path);
|
||||
g_free(oem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_PLUGIN_H
|
||||
#define RIL_PLUGIN_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include "sailfish_manager.h"
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-barring.h>
|
||||
#include <ofono/call-forwarding.h>
|
||||
#include <ofono/call-settings.h>
|
||||
#include <ofono/call-volume.h>
|
||||
#include <ofono/cbs.h>
|
||||
#include <ofono/devinfo.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/phonebook.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/sms.h>
|
||||
#include <ofono/stk.h>
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/voicecall.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#define RILMODEM_DRIVER "ril"
|
||||
|
||||
struct ril_modem {
|
||||
GRilIoChannel *io;
|
||||
const char *imei;
|
||||
const char *imeisv;
|
||||
const char *log_prefix;
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
struct ril_slot_config config;
|
||||
};
|
||||
|
||||
struct ril_oem_raw;
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
const char *log_prefix);
|
||||
void ril_oem_raw_free(struct ril_oem_raw *raw);
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct sailfish_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
|
||||
|
||||
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
|
||||
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
|
||||
#define ril_modem_slot(modem) ((modem)->config.slot)
|
||||
#define ril_modem_io(modem) ((modem)->io)
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *reg, gint status);
|
||||
|
||||
extern const struct ofono_call_barring_driver ril_call_barring_driver;
|
||||
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
|
||||
extern const struct ofono_call_settings_driver ril_call_settings_driver;
|
||||
extern const struct ofono_call_volume_driver ril_call_volume_driver;
|
||||
extern const struct ofono_cbs_driver ril_cbs_driver;
|
||||
extern const struct ofono_devinfo_driver ril_devinfo_driver;
|
||||
extern const struct ofono_gprs_context_driver ril_gprs_context_driver;
|
||||
extern const struct ofono_gprs_driver ril_gprs_driver;
|
||||
extern const struct ofono_modem_driver ril_modem_driver;
|
||||
extern const struct ofono_netreg_driver ril_netreg_driver;
|
||||
extern const struct ofono_phonebook_driver ril_phonebook_driver;
|
||||
extern const struct ofono_radio_settings_driver ril_radio_settings_driver;
|
||||
extern const struct ofono_sim_driver ril_sim_driver;
|
||||
extern const struct ofono_sms_driver ril_sms_driver;
|
||||
extern const struct ofono_stk_driver ril_stk_driver;
|
||||
extern const struct ofono_ussd_driver ril_ussd_driver;
|
||||
extern const struct ofono_voicecall_driver ril_voicecall_driver;
|
||||
extern const struct ofono_netmon_driver ril_netmon_driver;
|
||||
|
||||
#endif /* RIL_PLUGIN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,459 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
typedef GObjectClass RilRadioClass;
|
||||
typedef struct ril_radio RilRadio;
|
||||
|
||||
/*
|
||||
* Object states:
|
||||
*
|
||||
* 1. Idle (!pending && !retry)
|
||||
* 2. Power on/off request pending (pending)
|
||||
* 3. Power on retry has been scheduled (retry)
|
||||
*/
|
||||
struct ril_radio_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gulong state_event_id;
|
||||
char *log_prefix;
|
||||
GHashTable *req_table;
|
||||
guint pending_id;
|
||||
guint retry_id;
|
||||
guint state_changed_while_request_pending;
|
||||
enum ril_radio_state last_known_state;
|
||||
gboolean power_cycle;
|
||||
gboolean next_state_valid;
|
||||
gboolean next_state;
|
||||
};
|
||||
|
||||
enum ril_radio_signal {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_ONLINE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define POWER_RETRY_SECS (1)
|
||||
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
|
||||
#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
|
||||
|
||||
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_radio_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
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))
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
{
|
||||
return radio_state == RADIO_STATE_OFF;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_on(enum ril_radio_state radio_state)
|
||||
{
|
||||
return !ril_radio_state_off(radio_state);
|
||||
}
|
||||
|
||||
static inline void ril_radio_emit_signal(struct ril_radio *self,
|
||||
enum ril_radio_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_radio_signals[id], 0);
|
||||
}
|
||||
|
||||
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);
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self,
|
||||
ril_radio_power_should_be_on(self));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
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);
|
||||
g_source_remove(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_check_state(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
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) {
|
||||
/* All is good, cancel pending retry if there is one */
|
||||
ril_radio_cancel_retry(self);
|
||||
} else if (priv->state_changed_while_request_pending) {
|
||||
/* Hmm... RIL's reaction was inadequate, repeat */
|
||||
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);
|
||||
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
|
||||
ril_radio_power_request_retry_cb, 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),
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
{
|
||||
/*
|
||||
* RIL_REQUEST_RADIO_POWER
|
||||
*
|
||||
* "data" is int *
|
||||
* ((int *)data)[0] is > 0 for "Radio On"
|
||||
* ((int *)data)[0] is == 0 for "Radio Off"
|
||||
*
|
||||
* "response" is NULL
|
||||
**/
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, on);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
priv->next_state_valid = FALSE;
|
||||
priv->next_state = on;
|
||||
priv->state_changed_while_request_pending = 0;
|
||||
ril_radio_cancel_retry(self);
|
||||
|
||||
GASSERT(!priv->pending_id);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||
gboolean allow_repeat)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
const char *on_off = on ? "on" : "off";
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (allow_repeat || priv->next_state != 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);
|
||||
} else {
|
||||
DBG("%s%s (ignored)", priv->log_prefix, on_off);
|
||||
}
|
||||
} else {
|
||||
DBG("%s%s", priv->log_prefix, 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);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_cycle(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(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);
|
||||
GASSERT(!priv->power_cycle);
|
||||
} else if (priv->power_cycle) {
|
||||
DBG("%salready in progress", priv->log_prefix);
|
||||
} else {
|
||||
DBG("%sinitiated", priv->log_prefix);
|
||||
priv->power_cycle = TRUE;
|
||||
if (!priv->pending_id) {
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (g_hash_table_remove(priv->req_table, tag)) {
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
if (!ril_radio_power_should_be_on(self)) {
|
||||
/* The last one turns the lights off */
|
||||
ril_radio_power_request(self, FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_set_online(struct ril_radio *self, gboolean online)
|
||||
{
|
||||
if (G_LIKELY(self) && self->online != online) {
|
||||
gboolean on, was_on = ril_radio_power_should_be_on(self);
|
||||
self->online = online;
|
||||
on = ril_radio_power_should_be_on(self);
|
||||
if (was_on != on) {
|
||||
ril_radio_power_request(self, on, FALSE);
|
||||
}
|
||||
ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_remove_handlers(struct ril_radio *self, gulong *ids, int count)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int radio_state;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &radio_state)) {
|
||||
return radio_state;
|
||||
} else {
|
||||
ofono_error("Error parsing radio state");
|
||||
return RADIO_STATE_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
|
||||
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));
|
||||
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);
|
||||
priv->power_cycle = FALSE;
|
||||
}
|
||||
|
||||
if (priv->pending_id) {
|
||||
priv->state_changed_while_request_pending++;
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io)
|
||||
{
|
||||
struct ril_radio *self = g_object_new(RIL_RADIO_TYPE, NULL);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->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);
|
||||
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_RADIO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_unref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_RADIO(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_init(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_RADIO_TYPE, struct ril_radio_priv);
|
||||
self->priv = priv;
|
||||
priv->req_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static void ril_radio_dispose(GObject *object)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->state_event_id) {
|
||||
grilio_channel_remove_handler(priv->io, priv->state_event_id);
|
||||
priv->state_event_id = 0;
|
||||
}
|
||||
if (priv->pending_id) {
|
||||
grilio_queue_cancel_request(priv->q, priv->pending_id, FALSE);
|
||||
priv->pending_id = 0;
|
||||
}
|
||||
priv->next_state_valid = FALSE;
|
||||
ril_radio_cancel_retry(self);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
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);
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
g_hash_table_unref(priv->req_table);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_radio_class_init(RilRadioClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_radio_dispose;
|
||||
object_class->finalize = ril_radio_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
|
||||
NEW_SIGNAL(klass, STATE);
|
||||
NEW_SIGNAL(klass, ONLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* 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_RADIO_H
|
||||
#define RIL_RADIO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_radio {
|
||||
GObject object;
|
||||
struct ril_radio_priv *priv;
|
||||
enum ril_radio_state state;
|
||||
gboolean online;
|
||||
};
|
||||
|
||||
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io);
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *radio);
|
||||
void ril_radio_unref(struct ril_radio *radio);
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_cycle(struct ril_radio *radio);
|
||||
void ril_radio_confirm_power_on(struct ril_radio *radio);
|
||||
void ril_radio_set_online(struct ril_radio *radio, gboolean online);
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
|
||||
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
|
||||
|
||||
#define ril_radio_remove_all_handlers(r,ids) \
|
||||
ril_radio_remove_handlers(r, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_RADIO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_RADIO_CAPS_H
|
||||
#define RIL_RADIO_CAPS_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_radio_caps;
|
||||
struct ril_radio_caps_manager;
|
||||
struct ril_radio_capability;
|
||||
|
||||
typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
|
||||
void *user_data);
|
||||
/* ril_radio_capability pointer is NULL if functionality is unsupported */
|
||||
typedef void (*ril_radio_caps_check_cb_t)
|
||||
(const struct ril_radio_capability *cap, void *user_data);
|
||||
|
||||
/* The check can be cancelled with grilio_channel_cancel_request */
|
||||
guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb_t cb,
|
||||
void *user_data);
|
||||
|
||||
/* There should be a single ril_radio_caps_manager shared by all all modems */
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_new
|
||||
(struct ril_data_manager *dm);
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
|
||||
(struct ril_radio_caps_manager *mgr);
|
||||
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
|
||||
gulong ril_radio_caps_manager_add_aborted_handler
|
||||
(struct ril_radio_caps_manager *mgr,
|
||||
ril_radio_caps_manager_cb_t cb, void *arg);
|
||||
void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
|
||||
gulong id);
|
||||
|
||||
/* And one ril_radio_caps object per modem */
|
||||
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
const char *log_prefix, GRilIoChannel *io,
|
||||
struct ril_data *data, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim, struct ril_network *net,
|
||||
const struct ril_slot_config *config,
|
||||
const struct ril_radio_capability *cap);
|
||||
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
|
||||
void ril_radio_caps_unref(struct ril_radio_caps *caps);
|
||||
|
||||
#endif /* RIL_RADIO_CAPS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
struct ril_radio_settings {
|
||||
struct ofono_radio_settings *rs;
|
||||
struct ril_sim_settings *settings;
|
||||
const char *log_prefix;
|
||||
char *allocated_log_prefix;
|
||||
guint source_id;
|
||||
};
|
||||
|
||||
struct ril_radio_settings_cbd {
|
||||
struct ril_radio_settings *rsd;
|
||||
union _ofono_radio_settings_cb {
|
||||
ofono_radio_settings_rat_mode_set_cb_t rat_mode_set;
|
||||
ofono_radio_settings_rat_mode_query_cb_t rat_mode_query;
|
||||
ofono_radio_settings_available_rats_query_cb_t available_rats;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define DBG_(rsd,fmt,args...) DBG("%s" fmt, (rsd)->log_prefix, ##args)
|
||||
|
||||
static inline struct ril_radio_settings *ril_radio_settings_get_data(
|
||||
struct ofono_radio_settings *rs)
|
||||
{
|
||||
return ofono_radio_settings_get_data(rs);
|
||||
}
|
||||
|
||||
static void ril_radio_settings_later(struct ril_radio_settings *rsd,
|
||||
GSourceFunc fn, void *cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_radio_settings_cbd, 1);
|
||||
cbd->rsd = rsd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
|
||||
GASSERT(!rsd->source_id);
|
||||
rsd->source_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
fn, cbd, g_free);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_set_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_set(ril_error_ok(&error), cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_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 ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
DBG_(rsd, "%s", ofono_radio_access_mode_to_string(mode));
|
||||
ril_sim_settings_set_pref_mode(rsd->settings, mode);
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_set_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
enum ofono_radio_access_mode mode = rsd->settings->pref_mode;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(rsd, "rat mode %s", ofono_radio_access_mode_to_string(mode));
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_query(ril_error_ok(&error), mode, cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_query_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rsd->settings->techs,
|
||||
cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_available_rats(
|
||||
struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd,
|
||||
ril_radio_settings_query_available_rats_cb, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = user_data;
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
ofono_radio_settings_register(rsd->rs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
|
||||
|
||||
DBG("%s", modem->log_prefix);
|
||||
rsd->rs = rs;
|
||||
rsd->settings = ril_sim_settings_ref(modem->sim_settings);
|
||||
rsd->source_id = g_idle_add(ril_radio_settings_register, rsd);
|
||||
|
||||
if (modem->log_prefix && modem->log_prefix[0]) {
|
||||
rsd->log_prefix = rsd->allocated_log_prefix =
|
||||
g_strconcat(modem->log_prefix, " ", NULL);
|
||||
} else {
|
||||
rsd->log_prefix = "";
|
||||
}
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
if (rsd->source_id) {
|
||||
g_source_remove(rsd->source_id);
|
||||
}
|
||||
ril_sim_settings_unref(rsd->settings);
|
||||
g_free(rsd->allocated_log_prefix);
|
||||
g_free(rsd);
|
||||
}
|
||||
|
||||
const struct ofono_radio_settings_driver ril_radio_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.query_rat_mode = ril_radio_settings_query_rat_mode,
|
||||
.set_rat_mode = ril_radio_settings_set_rat_mode,
|
||||
.query_available_rats = ril_radio_settings_query_available_rats
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user