forked from sailfishos/ofono
Compare commits
1444 Commits
upgrade-2.
...
mer/1.23+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e067fa827 | ||
|
|
2ee5e4c827 | ||
|
|
1366e426be | ||
|
|
586c9b9262 | ||
|
|
83554e071a | ||
|
|
dc41c2d003 | ||
|
|
550d41ae37 | ||
|
|
60e4246d93 | ||
|
|
50619607b0 | ||
|
|
98b357f365 | ||
|
|
56c488d10c | ||
|
|
944cd603e8 | ||
|
|
77be0d5e98 | ||
|
|
d8dd20092c | ||
|
|
c7faa21172 | ||
|
|
98ffc61a03 | ||
|
|
f2b1625872 | ||
|
|
2d5a22284e | ||
|
|
9d742180ab | ||
|
|
f8b0ccc1b4 | ||
|
|
7a54bb8cbe | ||
|
|
56e0923dc3 | ||
|
|
6dfce4b5e9 | ||
|
|
4ec3568d71 | ||
|
|
9b2b7127ef | ||
|
|
1053577376 | ||
|
|
22197b5e04 | ||
|
|
3a358ddc9d | ||
|
|
53929f9f1a | ||
|
|
08bae57a2b | ||
|
|
1915aeda76 | ||
|
|
51bfb17cbc | ||
|
|
a83b553032 | ||
|
|
ec00abd62d | ||
|
|
80924d5787 | ||
|
|
2bdd05aa31 | ||
|
|
544f02e5a2 | ||
|
|
6d4638f9bf | ||
|
|
6584919e9d | ||
|
|
34fb44f4eb | ||
|
|
c98d2f41c5 | ||
|
|
b279be4528 | ||
|
|
a7912fea39 | ||
|
|
f291cea905 | ||
|
|
68f7d30b77 | ||
|
|
890a2697fe | ||
|
|
9568c8449b | ||
|
|
cf91be9742 | ||
|
|
087771dc0f | ||
|
|
645dfe47e5 | ||
|
|
68e8b02d3b | ||
|
|
aa4309e8cb | ||
|
|
cb6b24d950 | ||
|
|
6d1ab13c74 | ||
|
|
45424a3f96 | ||
|
|
4f7398e39d | ||
|
|
cd118ce70b | ||
|
|
99d4ce538e | ||
|
|
9b2c4bcf76 | ||
|
|
0122db04a3 | ||
|
|
021db194cb | ||
|
|
e0a0896205 | ||
|
|
49d0bbbb28 | ||
|
|
9193d06b77 | ||
|
|
b0cd3e4544 | ||
|
|
29cce6969b | ||
|
|
b87f666e4b | ||
|
|
1c1e4fa28b | ||
|
|
f597119845 | ||
|
|
633888932d | ||
|
|
a37f325d4a | ||
|
|
0afceac554 | ||
|
|
109751bcc0 | ||
|
|
30dfbf8fd7 | ||
|
|
c7aab2e790 | ||
|
|
412a2a0e7f | ||
|
|
f1aeedd113 | ||
|
|
639fce8eca | ||
|
|
9cfd0a195e | ||
|
|
cf2d8488cc | ||
|
|
ab0ac10abd | ||
|
|
b2df7de223 | ||
|
|
b56930a87f | ||
|
|
f65e8dd5af | ||
|
|
f2439243b2 | ||
|
|
93ff644856 | ||
|
|
08f8555d51 | ||
|
|
04b2a9b0f9 | ||
|
|
4d513b68d2 | ||
|
|
36f971dc78 | ||
|
|
8ba2d96cff | ||
|
|
a76f50be67 | ||
|
|
43227086c0 | ||
|
|
e40811fbc6 | ||
|
|
8c543b054a | ||
|
|
53233b4dc8 | ||
|
|
4458fbf844 | ||
|
|
542a086d93 | ||
|
|
1176662a81 | ||
|
|
ae29a08a76 | ||
|
|
af1a569430 | ||
|
|
a75558031b | ||
|
|
139fff2e5d | ||
|
|
12614d377a | ||
|
|
463f4f183e | ||
|
|
0ba7505f1e | ||
|
|
c1156320ac | ||
|
|
afe4fc66f0 | ||
|
|
c04b14c49a | ||
|
|
4d6aefcea5 | ||
|
|
c3c4b21c32 | ||
|
|
5ffc3fc426 | ||
|
|
690d62820a | ||
|
|
f1fbd04d66 | ||
|
|
8eaf694b9a | ||
|
|
5087fd9dd7 | ||
|
|
92aebc3ce8 | ||
|
|
c0a5b0fdf3 | ||
|
|
587879b6c2 | ||
|
|
f9ca5c30a6 | ||
|
|
3f9dff449f | ||
|
|
d554061955 | ||
|
|
3ae306ed57 | ||
|
|
6448c0c270 | ||
|
|
e521938d95 | ||
|
|
80158ea5bc | ||
|
|
bfba3e2312 | ||
|
|
e4fc7b9b0c | ||
|
|
f1ec346941 | ||
|
|
9f9bb11a66 | ||
|
|
cf3143bb69 | ||
|
|
56f46a80c0 | ||
|
|
6fb02515f0 | ||
|
|
4efb502fad | ||
|
|
842331f701 | ||
|
|
f743c89bc8 | ||
|
|
20d9835aed | ||
|
|
f4c24f5f83 | ||
|
|
6c07b110c7 | ||
|
|
6205fad90f | ||
|
|
9b7358e5e5 | ||
|
|
502cd55c4e | ||
|
|
103b20bcfd | ||
|
|
8b083e0121 | ||
|
|
8b1fc771ea | ||
|
|
7bb19531cd | ||
|
|
252df1349a | ||
|
|
5a2d64371c | ||
|
|
6995849600 | ||
|
|
69149b3039 | ||
|
|
77eb51bc39 | ||
|
|
d05b1137d5 | ||
|
|
9eae00b28b | ||
|
|
48a6492a68 | ||
|
|
443898d8ef | ||
|
|
23718794cc | ||
|
|
450c5f9b69 | ||
|
|
4f6b8b7243 | ||
|
|
3eec92ec7a | ||
|
|
4216026a7c | ||
|
|
9eb2820397 | ||
|
|
f33550f37f | ||
|
|
020dc3020e | ||
|
|
ad0b9e6303 | ||
|
|
d773d28dad | ||
|
|
4d9fea27ea | ||
|
|
c4a8186f7a | ||
|
|
2c5f1a6626 | ||
|
|
dcb057802f | ||
|
|
fd889b3fac | ||
|
|
fe3f46f29b | ||
|
|
b8eae5f967 | ||
|
|
d818544d92 | ||
|
|
dc1377eb0a | ||
|
|
06599ff36d | ||
|
|
4d2ef8b2da | ||
|
|
cc7f5796bb | ||
|
|
65d2b1306a | ||
|
|
b484003494 | ||
|
|
8a6ec5e645 | ||
|
|
fdc4b27b05 | ||
|
|
9b338c4055 | ||
|
|
fbaf86d862 | ||
|
|
d5c6316a13 | ||
|
|
bf092b518c | ||
|
|
9de95af924 | ||
|
|
5988c88968 | ||
|
|
354793cbe3 | ||
|
|
259c6e2617 | ||
|
|
aa88654d09 | ||
|
|
50499bc69d | ||
|
|
8c64f94743 | ||
|
|
0eabc3ea79 | ||
|
|
8116bd13d1 | ||
|
|
30bbccfd91 | ||
|
|
028a6ab1c7 | ||
|
|
32607771b5 | ||
|
|
d37dfc1ad1 | ||
|
|
e0bfba6fbe | ||
|
|
414791a6f0 | ||
|
|
3fa059a027 | ||
|
|
540b558147 | ||
|
|
6bfb0d07ab | ||
|
|
19a8a137c1 | ||
|
|
11913b2a44 | ||
|
|
2a1e29ab9e | ||
|
|
a64cc4d5b9 | ||
|
|
f464a7c6c1 | ||
|
|
daceb07bb1 | ||
|
|
f9ef31cd5c | ||
|
|
c3c3bab6a2 | ||
|
|
08f0bb08f1 | ||
|
|
ce2b18ede2 | ||
|
|
5f9e43c2da | ||
|
|
2ee038a457 | ||
|
|
3a4f63171f | ||
|
|
64878cced6 | ||
|
|
3f115b2d0d | ||
|
|
c66eec1b1e | ||
|
|
85d1eda7c9 | ||
|
|
08d8d5de73 | ||
|
|
172c97df83 | ||
|
|
1e3e413714 | ||
|
|
15ef3c9c0e | ||
|
|
e9eb113a22 | ||
|
|
abdfb38006 | ||
|
|
79e22d4570 | ||
|
|
aab791f2ad | ||
|
|
90c0ffddea | ||
|
|
a3149c53d9 | ||
|
|
b02a37a9c5 | ||
|
|
eecf9fde2c | ||
|
|
f2bb5d08ba | ||
|
|
d44a1af644 | ||
|
|
50fbd5351b | ||
|
|
9c8700b5c6 | ||
|
|
9221153db9 | ||
|
|
8997e02997 | ||
|
|
7121855966 | ||
|
|
0d013c3f9b | ||
|
|
e2299cbddc | ||
|
|
34cd275117 | ||
|
|
2396ead477 | ||
|
|
32dc1d1806 | ||
|
|
aed679d6da | ||
|
|
baea6fb7e9 | ||
|
|
ba64ce870f | ||
|
|
1e25fbbcbf | ||
|
|
d13339af6c | ||
|
|
890f3235cb | ||
|
|
2603419fa4 | ||
|
|
1abdcc9226 | ||
|
|
928a905cce | ||
|
|
f241580817 | ||
|
|
26826c15c9 | ||
|
|
5b3a045e6c | ||
|
|
c8a08bd815 | ||
|
|
53d1f1ce03 | ||
|
|
1aec6df272 | ||
|
|
b43df906ca | ||
|
|
1d42a2a6a9 | ||
|
|
bab1cb2479 | ||
|
|
a8be51ceef | ||
|
|
a658ec7e77 | ||
|
|
960db7cf2b | ||
|
|
842fe25bcd | ||
|
|
7aa2cbb8cb | ||
|
|
612b295eae | ||
|
|
168919770d | ||
|
|
b603be82ee | ||
|
|
bbeaadd191 | ||
|
|
99d7c4e884 | ||
|
|
9753700d58 | ||
|
|
7772c8971b | ||
|
|
13b39ba633 | ||
|
|
77ac688c5e | ||
|
|
f4bbba9547 | ||
|
|
17f5b9faa5 | ||
|
|
4b266cfbfd | ||
|
|
e56998d640 | ||
|
|
b87fb13b7b | ||
|
|
32753de8a7 | ||
|
|
331c6e98d2 | ||
|
|
69f1b7b36f | ||
|
|
ca6447102f | ||
|
|
9b3dc8143d | ||
|
|
919df873f3 | ||
|
|
7aed70b642 | ||
|
|
0776d5b19b | ||
|
|
ca4c2c4a07 | ||
|
|
eab88cd6cb | ||
|
|
0be2675072 | ||
|
|
d226729730 | ||
|
|
417bbaa963 | ||
|
|
9974013cce | ||
|
|
53e07c0932 | ||
|
|
edce8b06c6 | ||
|
|
8d72007e95 | ||
|
|
ffa0e801a3 | ||
|
|
f6c7117097 | ||
|
|
3d9013eea8 | ||
|
|
b76517559b | ||
|
|
6bdb51dc29 | ||
|
|
4f066a2133 | ||
|
|
61d87e5cf9 | ||
|
|
3d33bea585 | ||
|
|
a741db6087 | ||
|
|
f9a175b1a8 | ||
|
|
04133f8316 | ||
|
|
2e6ae0f001 | ||
|
|
432c05928b | ||
|
|
38054818ed | ||
|
|
f3e4550d67 | ||
|
|
a91c8de5c2 | ||
|
|
9c29518418 | ||
|
|
951e9439d4 | ||
|
|
7cd984aa1a | ||
|
|
06227e5e50 | ||
|
|
bba23c3095 | ||
|
|
a892edaea5 | ||
|
|
2ede8f2464 | ||
|
|
1759502c96 | ||
|
|
134efba989 | ||
|
|
9331cc1ecb | ||
|
|
7c8da34a38 | ||
|
|
a05523974e | ||
|
|
71ef390b4a | ||
|
|
717f6452aa | ||
|
|
0803c21840 | ||
|
|
095060b001 | ||
|
|
c2971da092 | ||
|
|
f07424f0aa | ||
|
|
266a52a40a | ||
|
|
eeea5476d1 | ||
|
|
e38a63d179 | ||
|
|
0ff8608ac3 | ||
|
|
5a330b9852 | ||
|
|
78a9323619 | ||
|
|
8267e206eb | ||
|
|
fac7684958 | ||
|
|
6ba3170ce2 | ||
|
|
b29730b268 | ||
|
|
e095636c97 | ||
|
|
6fef5444fb | ||
|
|
0e62e613e8 | ||
|
|
c08be69130 | ||
|
|
419caedc2c | ||
|
|
ee6a307804 | ||
|
|
412d8c3d4d | ||
|
|
0efebd16d9 | ||
|
|
7a6928c02f | ||
|
|
ec134e68d2 | ||
|
|
a8be769c87 | ||
|
|
a2d87f64c4 | ||
|
|
3ecd55a205 | ||
|
|
d8ea82b2f1 | ||
|
|
c95fe16a9b | ||
|
|
55e923250a | ||
|
|
f5653ae240 | ||
|
|
ecf23c1333 | ||
|
|
e71036f7d7 | ||
|
|
b8e8b930f8 | ||
|
|
65a3f7ee46 | ||
|
|
26c5c4bfa3 | ||
|
|
2d35e5e28d | ||
|
|
ae78d9a946 | ||
|
|
243dd7d17c | ||
|
|
acaafafbb9 | ||
|
|
4f378c806b | ||
|
|
bd33ff471c | ||
|
|
d423608e46 | ||
|
|
3b708effd9 | ||
|
|
f01722cca5 | ||
|
|
f62d53fbd0 | ||
|
|
942aee3f25 | ||
|
|
ecc83568fd | ||
|
|
c911c05fcb | ||
|
|
680979f782 | ||
|
|
250a6abb71 | ||
|
|
6c5d2ab803 | ||
|
|
bf8cb3995c | ||
|
|
8973e52e45 | ||
|
|
0e8dc3605e | ||
|
|
537a39f94a | ||
|
|
c3d93e83d7 | ||
|
|
7cdf3db124 | ||
|
|
398942c78e | ||
|
|
26e39508ad | ||
|
|
a16fcd0d37 | ||
|
|
432e700272 | ||
|
|
aa694b592f | ||
|
|
c5c8b72761 | ||
|
|
2ab7aa0f97 | ||
|
|
549fe2355f | ||
|
|
7493187e47 | ||
|
|
9a3d8d671c | ||
|
|
39eac13743 | ||
|
|
6329bb8639 | ||
|
|
75b07c5c80 | ||
|
|
4f6f964ca4 | ||
|
|
7af95f6db5 | ||
|
|
99f4667eb7 | ||
|
|
c1c3ecab31 | ||
|
|
83dc99658c | ||
|
|
9a7b538087 | ||
|
|
9f7a1ffe3f | ||
|
|
1f81ec7d9d | ||
|
|
6e833401cc | ||
|
|
d9c68c4fb9 | ||
|
|
9e6f7721a0 | ||
|
|
9c529dcdcc | ||
|
|
41814c6e6a | ||
|
|
cf99a5769f | ||
|
|
076e2f0ef1 | ||
|
|
fd76cb72ad | ||
|
|
554e4ab8e5 | ||
|
|
08f3da7577 | ||
|
|
2cbd3b6050 | ||
|
|
78d3d1892d | ||
|
|
1448bd2320 | ||
|
|
ea8dfb48ab | ||
|
|
80921e8b7e | ||
|
|
e4cc912719 | ||
|
|
c5f736d3c3 | ||
|
|
ddf4cec9b8 | ||
|
|
685d0b34d7 | ||
|
|
896f2f7a71 | ||
|
|
e96aacb9e7 | ||
|
|
91560afeec | ||
|
|
09fb8635c9 | ||
|
|
1cb80d7d2f | ||
|
|
7db5552e79 | ||
|
|
d87e40d0ff | ||
|
|
35131ff56b | ||
|
|
c5cc678b2b | ||
|
|
31be9a099b | ||
|
|
ccaf993977 | ||
|
|
74d633c58e | ||
|
|
f870880cf9 | ||
|
|
50c06afc73 | ||
|
|
e4e0ccd51d | ||
|
|
ee052af454 | ||
|
|
296b272274 | ||
|
|
9b9e5159f5 | ||
|
|
fa8002200c | ||
|
|
4cc71c78ec | ||
|
|
27b31e65bb | ||
|
|
e26d365a94 | ||
|
|
63f06cd11c | ||
|
|
96ca3aa907 | ||
|
|
11a84853fe | ||
|
|
a393cf0b11 | ||
|
|
6f263ee8d5 | ||
|
|
92a4760f46 | ||
|
|
c43d41829f | ||
|
|
25638a30c0 | ||
|
|
ed669bf66c | ||
|
|
e01dbd2b21 | ||
|
|
a8f0f26df8 | ||
|
|
56c84395ba | ||
|
|
3bf2b1df5c | ||
|
|
75041ccc37 | ||
|
|
e91ef8a701 | ||
|
|
620a20abdc | ||
|
|
d85fa8a64d | ||
|
|
d33b20889b | ||
|
|
cb8801752c | ||
|
|
a0722f8538 | ||
|
|
e016281b86 | ||
|
|
781a528625 | ||
|
|
5b1ab91b77 | ||
|
|
9604d9ef0a | ||
|
|
598acaa1a8 | ||
|
|
60193032f5 | ||
|
|
9faf27ec28 | ||
|
|
32c26c5a35 | ||
|
|
79fb591342 | ||
|
|
f6e46f78e3 | ||
|
|
7c587772d1 | ||
|
|
0d0728593b | ||
|
|
fd3916b2c7 | ||
|
|
c35557c2ed | ||
|
|
bb07543dd6 | ||
|
|
d346f1289c | ||
|
|
e170b6df4c | ||
|
|
761cd320bb | ||
|
|
60bc47aea2 | ||
|
|
183e4dab4b | ||
|
|
d6cdfc92ad | ||
|
|
b68752640c | ||
|
|
a53fc6ea7e | ||
|
|
63fe971077 | ||
|
|
011f3b74d1 | ||
|
|
4d2e314ad6 | ||
|
|
d846618057 | ||
|
|
38115199f7 | ||
|
|
f88c7ce919 | ||
|
|
9d6b3ec124 | ||
|
|
6dcf5cebc1 | ||
|
|
0e87392c90 | ||
|
|
dab76692db | ||
|
|
21bc90f638 | ||
|
|
d8707d52be | ||
|
|
fa0abf892d | ||
|
|
8a28d4eea8 | ||
|
|
4f0be99683 | ||
|
|
95933beb2d | ||
|
|
018a712e29 | ||
|
|
e6777f1ecc | ||
|
|
a58e1a5e9b | ||
|
|
61be41240f | ||
|
|
dbb40560c6 | ||
|
|
9bf50bb3e3 | ||
|
|
d2353c46a8 | ||
|
|
6701b53737 | ||
|
|
6612bfa1da | ||
|
|
c732d5192d | ||
|
|
6815772b17 | ||
|
|
e4766ef2c4 | ||
|
|
7aa396636b | ||
|
|
096cd04044 | ||
|
|
5eabe96602 | ||
|
|
05dec021c0 | ||
|
|
6f7209b045 | ||
|
|
a766281a02 | ||
|
|
13b4802bec | ||
|
|
e1547fdaf4 | ||
|
|
08c36b2885 | ||
|
|
0180c9febf | ||
|
|
49034cfc69 | ||
|
|
4685e3f0de | ||
|
|
72be5bdff2 | ||
|
|
79c1abfdd3 | ||
|
|
c88cffaa2e | ||
|
|
17e66090ec | ||
|
|
100cf7df1d | ||
|
|
280ed19215 | ||
|
|
ae0f5b0ff6 | ||
|
|
dbfc642eb3 | ||
|
|
e5e5108913 | ||
|
|
9035db3129 | ||
|
|
81391a4101 | ||
|
|
60d449c01d | ||
|
|
b0ccc39866 | ||
|
|
bd2aa28405 | ||
|
|
67e31bb519 | ||
|
|
b848827976 | ||
|
|
ab6764dcc0 | ||
|
|
da42039c80 | ||
|
|
392c00c65e | ||
|
|
7a0fe98d95 | ||
|
|
d508a2f2bb | ||
|
|
8f070cf583 | ||
|
|
d2d8117723 | ||
|
|
6897e57353 | ||
|
|
6a8c2aa9c1 | ||
|
|
076e388d45 | ||
|
|
bcafe0dc3d | ||
|
|
9272075f55 | ||
|
|
526072d7a3 | ||
|
|
0680063527 | ||
|
|
4e08680e5f | ||
|
|
1d85caa7f9 | ||
|
|
db0ef91c81 | ||
|
|
54d8c78a50 | ||
|
|
905c886269 | ||
|
|
f0c7a373ae | ||
|
|
4673da16d5 | ||
|
|
0dc2acee4e | ||
|
|
f749284029 | ||
|
|
778b9f08aa | ||
|
|
40db3f7067 | ||
|
|
e198cf04c0 | ||
|
|
fbd59ba56f | ||
|
|
cff9ded7e6 | ||
|
|
c74386b5e6 | ||
|
|
028f54c26f | ||
|
|
c066f34ea1 | ||
|
|
b1c79d5cae | ||
|
|
0cc61dcfe8 | ||
|
|
5852bebda0 | ||
|
|
768c028a11 | ||
|
|
6b93ea0cc6 | ||
|
|
4a485a7aa0 | ||
|
|
f6fb277cf4 | ||
|
|
03f150838b | ||
|
|
9731ca1a87 | ||
|
|
a09f4c070d | ||
|
|
f018f5a255 | ||
|
|
286396bf91 | ||
|
|
5d6baccced | ||
|
|
514f4cf9cc | ||
|
|
ff8408e6dd | ||
|
|
df1294d77c | ||
|
|
2323ebacb3 | ||
|
|
c780eff0ce | ||
|
|
373248a35b | ||
|
|
fe219b648d | ||
|
|
33f55c569f | ||
|
|
d6cf954354 | ||
|
|
d8e852cb5e | ||
|
|
83e3ec0e98 | ||
|
|
e35f537f72 | ||
|
|
c7daf5aa43 | ||
|
|
490a9c06f4 | ||
|
|
320b3f4605 | ||
|
|
e35dae17d9 | ||
|
|
f4522f4a00 | ||
|
|
ce85c94426 | ||
|
|
4027bdc04e | ||
|
|
c57f99bf01 | ||
|
|
54d610ce6a | ||
|
|
f7f9e32743 | ||
|
|
8c9e370486 | ||
|
|
19b80236f6 | ||
|
|
2ec6fc749d | ||
|
|
0a3bdd20f4 | ||
|
|
284919e76a | ||
|
|
ddcbb89fa1 | ||
|
|
5ec6b8e7ec | ||
|
|
f94681f6f6 | ||
|
|
de8edc84fa | ||
|
|
90faf1b3a5 | ||
|
|
2b139b6974 | ||
|
|
168f193efb | ||
|
|
32d8b5ccfc | ||
|
|
f400ceff80 | ||
|
|
2186c60630 | ||
|
|
d5fb195e2f | ||
|
|
cbb08079d2 | ||
|
|
0583a831fb | ||
|
|
a8a0758e90 | ||
|
|
9e267487f4 | ||
|
|
c8a774dfee | ||
|
|
b88518d0f3 | ||
|
|
b223ccc675 | ||
|
|
947a41a5fc | ||
|
|
e0b4e8694d | ||
|
|
c8db770c99 | ||
|
|
1534143e31 | ||
|
|
d9ad9caf30 | ||
|
|
71de574e87 | ||
|
|
11efbd68e6 | ||
|
|
9981f07797 | ||
|
|
24733f776e | ||
|
|
50ec234239 | ||
|
|
b4991076c6 | ||
|
|
8b02884696 | ||
|
|
8e224a21f6 | ||
|
|
96e191b2d2 | ||
|
|
7ae3aad622 | ||
|
|
3d5d88241e | ||
|
|
31e62567e6 | ||
|
|
8c3127ef21 | ||
|
|
1c1fc4199e | ||
|
|
bfe2f95c4c | ||
|
|
7e4d99236b | ||
|
|
0935a227be | ||
|
|
ffdeb3692c | ||
|
|
627904e382 | ||
|
|
0ab0677765 | ||
|
|
fe6af108ca | ||
|
|
650ff3642f | ||
|
|
41d310aa61 | ||
|
|
27adf83a4b | ||
|
|
55d227ba46 | ||
|
|
dcc1d366f0 | ||
|
|
83cf94824d | ||
|
|
3a0c598805 | ||
|
|
b098314251 | ||
|
|
4ae6c6c0b1 | ||
|
|
d5f0f3b32d | ||
|
|
0209e9847b | ||
|
|
a499ac07ca | ||
|
|
04342bbe69 | ||
|
|
d0d3e4f2f1 | ||
|
|
edcbc5c7e3 | ||
|
|
1df55e3042 | ||
|
|
df93fceb4f | ||
|
|
d21d1a166f | ||
|
|
458f905262 | ||
|
|
9f474ba723 | ||
|
|
a3b4421422 | ||
|
|
28bc1e37ed | ||
|
|
c0b96a4319 | ||
|
|
4296616d00 | ||
|
|
3a43f96fe4 | ||
|
|
b82a1001e2 | ||
|
|
84dc7e2016 | ||
|
|
1482728a61 | ||
|
|
428f62041b | ||
|
|
4b6ec99973 | ||
|
|
0c01da5378 | ||
|
|
8004756c3d | ||
|
|
e01df1a3f1 | ||
|
|
46820a7ba0 | ||
|
|
0493629a9d | ||
|
|
41b3459a5d | ||
|
|
b27373c8a4 | ||
|
|
b450c8fbe3 | ||
|
|
1ac24f32e3 | ||
|
|
977fc5bc15 | ||
|
|
787bddf47b | ||
|
|
c32cd532f2 | ||
|
|
18f2345124 | ||
|
|
00b623e8c4 | ||
|
|
452108d058 | ||
|
|
6b0712dae4 | ||
|
|
9a309f499b | ||
|
|
a204c993e5 | ||
|
|
e881376127 | ||
|
|
66c98d724c | ||
|
|
5c38fe6a84 | ||
|
|
e3bb317504 | ||
|
|
713022a7e8 | ||
|
|
6b79f32715 | ||
|
|
2386e99ad8 | ||
|
|
6ca82960c9 | ||
|
|
93891578fc | ||
|
|
7bcadcd300 | ||
|
|
b3f8dc4a24 | ||
|
|
38e3122217 | ||
|
|
f7de0ab3ef | ||
|
|
defe008062 | ||
|
|
ec930e17c8 | ||
|
|
9f1731cffa | ||
|
|
ed8d55d2d5 | ||
|
|
7b6a461b83 | ||
|
|
3b0ff8fd83 | ||
|
|
00b5886cf9 | ||
|
|
c16fd4e642 | ||
|
|
4b92ac8ba6 | ||
|
|
5b432b8280 | ||
|
|
31aff54463 | ||
|
|
c669ec3c88 | ||
|
|
8c2f54abe0 | ||
|
|
804121cbed | ||
|
|
839e626ee6 | ||
|
|
3a17724136 | ||
|
|
7b0c6610e0 | ||
|
|
0e0b1e98c5 | ||
|
|
b0975c44b1 | ||
|
|
25a6049cf6 | ||
|
|
02fcbdb245 | ||
|
|
a3a8ea4183 | ||
|
|
92d7fb848b | ||
|
|
0b6327a7fc | ||
|
|
84bd588152 | ||
|
|
9e952cf042 | ||
|
|
27a1a05aa7 | ||
|
|
657841e2b0 | ||
|
|
02172f6922 | ||
|
|
0dd225b594 | ||
|
|
452d0d4b5a | ||
|
|
2edae61c0b | ||
|
|
141abd5390 | ||
|
|
22faa0f26a | ||
|
|
4d2453f3a8 | ||
|
|
7a5f52c1f3 | ||
|
|
1ad109f8c7 | ||
|
|
1347755b6f | ||
|
|
62253744a7 | ||
|
|
9a608210cd | ||
|
|
adbfdb23a7 | ||
|
|
ac5d0abe5e | ||
|
|
8dbaaa5efe | ||
|
|
fa1bcc1c19 | ||
|
|
32138ecd04 | ||
|
|
5e999f0b47 | ||
|
|
5c74095f44 | ||
|
|
55befb87cd | ||
|
|
9d7a0f8615 | ||
|
|
974100732c | ||
|
|
35a6a4d8d0 | ||
|
|
f2a64c4d15 | ||
|
|
ed1e90990e | ||
|
|
c8a4727243 | ||
|
|
2ccabbbdef | ||
|
|
7c3638143d | ||
|
|
a0e8b24c70 | ||
|
|
41d432211e | ||
|
|
94f6138e23 | ||
|
|
e82ce81858 | ||
|
|
c18fa5e038 | ||
|
|
c7c53adbb5 | ||
|
|
30a9ef7e7a | ||
|
|
064181f903 | ||
|
|
7d22ed86f8 | ||
|
|
0641a981d1 | ||
|
|
ceb6741a67 | ||
|
|
4797cab10b | ||
|
|
fbf001bbec | ||
|
|
8e90e96509 | ||
|
|
80e9b97036 | ||
|
|
01103f32ae | ||
|
|
4bef0c7b33 | ||
|
|
693d5a77bd | ||
|
|
a2333ead45 | ||
|
|
aa6a436af5 | ||
|
|
ee350d6b4b | ||
|
|
26b85c0606 | ||
|
|
068190a7a5 | ||
|
|
1b292f7cf2 | ||
|
|
cd9a19c090 | ||
|
|
6d357e70a4 | ||
|
|
8f4817106d | ||
|
|
d2ce689008 | ||
|
|
b470166c87 | ||
|
|
158a0da0b2 | ||
|
|
b4bbf0462c | ||
|
|
d80b96790f | ||
|
|
accb571fd6 | ||
|
|
523a4b6a81 | ||
|
|
9d8a6a4978 | ||
|
|
f2fa85aa47 | ||
|
|
a189d13b4a | ||
|
|
3b79a77d78 | ||
|
|
c2ee34e51c | ||
|
|
c3bead1c9b | ||
|
|
a26f1a4b5c | ||
|
|
1eacfdf592 | ||
|
|
ba14ed43e4 | ||
|
|
802b3008be | ||
|
|
3b0191d145 | ||
|
|
282d32f70d | ||
|
|
e0c349a18c | ||
|
|
69d65dc002 | ||
|
|
33e70ddce4 | ||
|
|
d3ada8fcb3 | ||
|
|
4c21ca4e26 | ||
|
|
a3301ec1d2 | ||
|
|
6f11bfc632 | ||
|
|
74262b9ef8 | ||
|
|
199a610607 | ||
|
|
af2d223f0f | ||
|
|
0b6fcf8b71 | ||
|
|
cc05aeccd1 | ||
|
|
5728444ad3 | ||
|
|
4cbb6b5919 | ||
|
|
5699bb4932 | ||
|
|
09fa97c53a | ||
|
|
3eaa8a46bd | ||
|
|
4401319136 | ||
|
|
472ddcf0b1 | ||
|
|
b7e0f276a1 | ||
|
|
5d251aea3a | ||
|
|
cdc0065284 | ||
|
|
6d65dc5bf0 | ||
|
|
5d02c0bba4 | ||
|
|
b99513e080 | ||
|
|
3cf328c781 | ||
|
|
bce68611a1 | ||
|
|
cc497feee7 | ||
|
|
725606af8d | ||
|
|
52db6e5459 | ||
|
|
83441bc203 | ||
|
|
4054f09b60 | ||
|
|
38aa8cff87 | ||
|
|
4959292938 | ||
|
|
c69cea52cf | ||
|
|
4e0b8f7b48 | ||
|
|
9c87063c4a | ||
|
|
dc5a87f4f2 | ||
|
|
ecd35181a3 | ||
|
|
96d6daf67e | ||
|
|
e9702f6ec1 | ||
|
|
0746c615bc | ||
|
|
970020a3b0 | ||
|
|
f3d5e3d5c6 | ||
|
|
bb880ab14a | ||
|
|
922d5e17ee | ||
|
|
7886ce04a1 | ||
|
|
5213398826 | ||
|
|
0bbcc127be | ||
|
|
f7db0a0459 | ||
|
|
2d18086c80 | ||
|
|
0f4560c2eb | ||
|
|
7d80344d6b | ||
|
|
c0c4148099 | ||
|
|
34755f1a79 | ||
|
|
282d560c37 | ||
|
|
e4bca84876 | ||
|
|
aa0ded78b0 | ||
|
|
eb15b12caf | ||
|
|
81b5c716e2 | ||
|
|
33c330988f | ||
|
|
910057a265 | ||
|
|
19f0f8d96e | ||
|
|
f1f3c17c4c | ||
|
|
29d891cbce | ||
|
|
89fa0d5d6a | ||
|
|
c382d9f456 | ||
|
|
b209b6bee6 | ||
|
|
ee3323e98b | ||
|
|
9200e387e1 | ||
|
|
2bc58a7f6f | ||
|
|
35079b11fe | ||
|
|
955d5882b2 | ||
|
|
2583fa99ce | ||
|
|
b8bb15ce9c | ||
|
|
cbf24c7b08 | ||
|
|
a4c4d1526e | ||
|
|
18d1a8834a | ||
|
|
8343d96db5 | ||
|
|
415fce9368 | ||
|
|
33257a139d | ||
|
|
f580867c12 | ||
|
|
edaba80ad1 | ||
|
|
e68314b07d | ||
|
|
d13e48b638 | ||
|
|
e0edfca358 | ||
|
|
7cd2075ada | ||
|
|
3ccacfd5f7 | ||
|
|
5ee13f8e2c | ||
|
|
6ab9dcb553 | ||
|
|
102061107a | ||
|
|
2bb7d629f5 | ||
|
|
5ce01787e8 | ||
|
|
1d57cb0e73 | ||
|
|
3d84c0a120 | ||
|
|
091cf21c0b | ||
|
|
351ac1e9db | ||
|
|
b7481a918f | ||
|
|
e1e4381105 | ||
|
|
cc3ca52e61 | ||
|
|
a71779ea2a | ||
|
|
a9d2849bbb | ||
|
|
ca29c8e538 | ||
|
|
85fe1b7174 | ||
|
|
56e0d9dffa | ||
|
|
6867ba65cb | ||
|
|
6199eaa4d8 | ||
|
|
fabdd6799c | ||
|
|
1219ab6a3f | ||
|
|
85a956d9eb | ||
|
|
c83d992a3b | ||
|
|
b22027017c | ||
|
|
1fa137b36d | ||
|
|
cfd837b1db | ||
|
|
735ad21e89 | ||
|
|
c9078404de | ||
|
|
e375195c92 | ||
|
|
ef5610f741 | ||
|
|
aef9bbd3e0 | ||
|
|
c6eb410f21 | ||
|
|
08b3ea3d0f | ||
|
|
2978862417 | ||
|
|
19228c9e67 | ||
|
|
9be791d531 | ||
|
|
6b9eb7bf8f | ||
|
|
01f8989aee | ||
|
|
2f5efaf591 | ||
|
|
ca1d06c37a | ||
|
|
5f45928a84 | ||
|
|
19f74e6c85 | ||
|
|
41d5cfcab2 | ||
|
|
357c5db580 | ||
|
|
8cea5b9f96 | ||
|
|
5fb35d5fb4 | ||
|
|
e8d57bb928 | ||
|
|
2bfde2418e | ||
|
|
c710ce76c1 | ||
|
|
78acd90464 | ||
|
|
e51b3ca0c8 | ||
|
|
b3c8813bd4 | ||
|
|
e2a3acd9d0 | ||
|
|
2054ca9570 | ||
|
|
48dbb7912a | ||
|
|
d7e7ad671d | ||
|
|
5b5a86dc80 | ||
|
|
c232524e99 | ||
|
|
bfd09a5c14 | ||
|
|
f8adcd2550 | ||
|
|
2a97567147 | ||
|
|
04d84b615e | ||
|
|
6e34792323 | ||
|
|
d6a59f5dc4 | ||
|
|
23e299055f | ||
|
|
a56ef3ba0f | ||
|
|
7294433906 | ||
|
|
d7263cd344 | ||
|
|
2f3b469fbb | ||
|
|
4187e7ee8f | ||
|
|
4d3f89bae0 | ||
|
|
cbd1c5d524 | ||
|
|
7976e44746 | ||
|
|
3d6e220686 | ||
|
|
919526d392 | ||
|
|
b7082146e8 | ||
|
|
094a296a14 | ||
|
|
5c259e751b | ||
|
|
69e5d5b356 | ||
|
|
56e7d0e8ea | ||
|
|
bb2ae6d1a1 | ||
|
|
cf7692db49 | ||
|
|
63f3311cd6 | ||
|
|
c5aae77d41 | ||
|
|
f8e21c8ad4 | ||
|
|
8e6dfe433b | ||
|
|
ae23bb552b | ||
|
|
2becd051d4 | ||
|
|
8cfb1d5ca3 | ||
|
|
50f35458f6 | ||
|
|
51843accf7 | ||
|
|
fb856dc7d6 | ||
|
|
1482748183 | ||
|
|
869ffda61e | ||
|
|
f875cbfda2 | ||
|
|
2a60eaa6e3 | ||
|
|
29b6c41d48 | ||
|
|
2f6491d005 | ||
|
|
1a25047e9d | ||
|
|
899e14bf17 | ||
|
|
2520664c63 | ||
|
|
445bbbd66f | ||
|
|
08fc4b0d03 | ||
|
|
c82e94ffb4 | ||
|
|
fd3712940b | ||
|
|
8410c985c9 | ||
|
|
0878decdc0 | ||
|
|
cb69984722 | ||
|
|
1fe8701f1a | ||
|
|
c5286fee70 | ||
|
|
3c5f6f84e1 | ||
|
|
8b87b55e8d | ||
|
|
bce34cbff3 | ||
|
|
f8351cacf1 | ||
|
|
6b9b8583dc | ||
|
|
1df56480ba | ||
|
|
adc8fce399 | ||
|
|
d24ce4d9de | ||
|
|
f726af3309 | ||
|
|
0ba1fd641b | ||
|
|
41c0b0a2e6 | ||
|
|
322282258a | ||
|
|
f6a7c39bba | ||
|
|
3d3f68c798 | ||
|
|
e8d057c39e | ||
|
|
357e5b69ca | ||
|
|
e77efed603 | ||
|
|
fa252b8d4a | ||
|
|
321c092d6b | ||
|
|
ee912bafe3 | ||
|
|
35eb528a70 | ||
|
|
22a6c4438b | ||
|
|
652bdc15ad | ||
|
|
a71e277850 | ||
|
|
fbee06e8be | ||
|
|
26029566e2 | ||
|
|
0074ff2660 | ||
|
|
82fa5e977a | ||
|
|
823f13a1fa | ||
|
|
7b34498b1e | ||
|
|
37d4e1983b | ||
|
|
e6f26f3bcf | ||
|
|
23e1d2c516 | ||
|
|
1f246cc28c | ||
|
|
ec20f44124 | ||
|
|
8b6139aea8 | ||
|
|
b79c3c3a95 | ||
|
|
c885744273 | ||
|
|
cdd0e4eaff | ||
|
|
402783f877 | ||
|
|
4755990237 | ||
|
|
7a91b4e069 | ||
|
|
35d4ca1e53 | ||
|
|
ea334e9daa | ||
|
|
16964bb8f2 | ||
|
|
0b93ab2d76 | ||
|
|
0bed313ecb | ||
|
|
cfd1d2c30a | ||
|
|
cb7c408beb | ||
|
|
202d8cf162 | ||
|
|
a15a558af6 | ||
|
|
fd8429465f | ||
|
|
8db1008790 | ||
|
|
3e3b4971da | ||
|
|
7c8245e432 | ||
|
|
5a06b04e05 | ||
|
|
1c12df9e99 | ||
|
|
fa3d80cd39 | ||
|
|
18507364ea | ||
|
|
c409ec2940 | ||
|
|
bba910a1d6 | ||
|
|
a7867d24e9 | ||
|
|
8909d4928b | ||
|
|
d9e39a69a5 | ||
|
|
0477eeb75f | ||
|
|
2ff3613e9b | ||
|
|
e5d040f7f9 | ||
|
|
604a3dd22e | ||
|
|
5eb923ad28 | ||
|
|
94fa037b93 | ||
|
|
41135af282 | ||
|
|
47359a3083 | ||
|
|
9c6c354d5a | ||
|
|
8ca5fc24ed | ||
|
|
aecb63423f | ||
|
|
f72f84ec0f | ||
|
|
e593476d81 | ||
|
|
1a4f1b0f9f | ||
|
|
14904ddaeb | ||
|
|
5fc9827e5d | ||
|
|
3539b5c9f9 | ||
|
|
916c1ac904 | ||
|
|
9f659d47b0 | ||
|
|
7d3ec8e9dc | ||
|
|
d5977f9014 | ||
|
|
513b922814 | ||
|
|
7f0cc63b3d | ||
|
|
9fb47a6382 | ||
|
|
ae35e7bff3 | ||
|
|
c7dc8cf262 | ||
|
|
213df4e7c4 | ||
|
|
e78daccea9 | ||
|
|
4f10d24638 | ||
|
|
cfa7ec6dd5 | ||
|
|
d18ba4e9a4 | ||
|
|
8846c58b53 | ||
|
|
4f088c85c7 | ||
|
|
6587a2456a | ||
|
|
edab9dbf2b | ||
|
|
b6cc94bf84 | ||
|
|
4039bed591 | ||
|
|
1f56e8350b | ||
|
|
34b0d68cdd | ||
|
|
ec60fa4eac | ||
|
|
a066917c4d | ||
|
|
da23ddbc15 | ||
|
|
207f67ab62 | ||
|
|
3e3720f416 | ||
|
|
985dbf9795 | ||
|
|
8b56a11936 | ||
|
|
40aa517183 | ||
|
|
6fdf38b74b | ||
|
|
8dc0b46bb3 | ||
|
|
b772df434b | ||
|
|
3726a1a48a | ||
|
|
5e309e5d45 | ||
|
|
ea65572935 | ||
|
|
83f8e1cbe6 | ||
|
|
c97d28cd23 | ||
|
|
9279a008ed | ||
|
|
e9c1603c8b | ||
|
|
5a8eb818ee | ||
|
|
7ab6bffd07 | ||
|
|
86f8a5c1f6 | ||
|
|
f1a87e5f6c | ||
|
|
4dbdf95b12 | ||
|
|
dab3e86325 | ||
|
|
b62f6c1041 | ||
|
|
f41a998695 | ||
|
|
42fa3983ef | ||
|
|
f8a47ae530 | ||
|
|
cf202b1568 | ||
|
|
14ebdfe7b9 | ||
|
|
8732a885a3 | ||
|
|
3f5fa672a5 | ||
|
|
e358485f37 | ||
|
|
e964307ced | ||
|
|
d1d69cf667 | ||
|
|
bf6210bdbb | ||
|
|
bcdd5a95c1 | ||
|
|
fcea7919f9 | ||
|
|
6fd1c1ef33 | ||
|
|
4d960d898d | ||
|
|
a9f47b77ce | ||
|
|
fb81c3571b | ||
|
|
7809498588 | ||
|
|
4d05522b2a | ||
|
|
b6b0306b39 | ||
|
|
5c938a5b64 | ||
|
|
b04d30ff3e | ||
|
|
4bdc8ac62c | ||
|
|
fa20be318d | ||
|
|
3598f4edab | ||
|
|
0524862743 | ||
|
|
d2cfc16201 | ||
|
|
fd874f3a4c | ||
|
|
0a039db7da | ||
|
|
0e6ce9a38e | ||
|
|
3cad68861c | ||
|
|
70d9366499 | ||
|
|
6c17d2b79c | ||
|
|
811b478903 | ||
|
|
6fcc2a1f68 | ||
|
|
792c4674c2 | ||
|
|
e9df792102 | ||
|
|
eb92f42c7d | ||
|
|
bcafdc8d70 | ||
|
|
5aa8f72aaa | ||
|
|
704a3ae354 | ||
|
|
a4f91f2d80 | ||
|
|
e655837ccb | ||
|
|
800ad72129 | ||
|
|
e6cae75c40 | ||
|
|
d655aec432 | ||
|
|
cd2d6a28aa | ||
|
|
8507197fa6 | ||
|
|
ee6b3385db | ||
|
|
24b6aeab5c | ||
|
|
5436c2beea | ||
|
|
87d947fe48 | ||
|
|
af45298bc7 | ||
|
|
cdb32c9139 | ||
|
|
85a9daa5f4 | ||
|
|
17a4fd7b78 | ||
|
|
d42b983dee | ||
|
|
33b14a3326 | ||
|
|
09ac10c3ac | ||
|
|
f47fe40799 | ||
|
|
ef0532222f | ||
|
|
edf7608da8 | ||
|
|
1bd019aec7 | ||
|
|
57ea46e0d7 | ||
|
|
90c4dfe1e5 | ||
|
|
4112433e86 | ||
|
|
97830c757f | ||
|
|
2dcfd64ff4 | ||
|
|
cba91bff8b | ||
|
|
7bf1f707ff | ||
|
|
aa6eed4eeb | ||
|
|
18e6d86edd | ||
|
|
e40d9e80c7 | ||
|
|
4176a82a0b | ||
|
|
447d0af56c | ||
|
|
284c7dfc48 | ||
|
|
a1a6ff7976 | ||
|
|
e2e4b7c868 | ||
|
|
5103af4321 | ||
|
|
b3a10881e7 | ||
|
|
cbc9ce47e0 | ||
|
|
cf059171d7 | ||
|
|
ddabae7a54 | ||
|
|
aabfd23aed | ||
|
|
f7a1089bd6 | ||
|
|
1ba9668f55 | ||
|
|
f6adb2a47e | ||
|
|
1254716006 | ||
|
|
1da578f9af | ||
|
|
863b91f79e | ||
|
|
5c4cd29fc2 | ||
|
|
78ea7d9946 | ||
|
|
e684560e16 | ||
|
|
0af7fd0c2c | ||
|
|
9b20f4c904 | ||
|
|
1c217547fd | ||
|
|
1939a251a0 | ||
|
|
deaee2b27d | ||
|
|
28d59901c2 | ||
|
|
d6ffc2dae7 | ||
|
|
59d80cdaa2 | ||
|
|
e680c7a3dc | ||
|
|
8fb813ab94 | ||
|
|
ca507cbfaf | ||
|
|
d40079d0b5 | ||
|
|
9579ce72a0 | ||
|
|
59880f886c | ||
|
|
3cb3b96104 | ||
|
|
4a384a95a0 | ||
|
|
c69b01677f | ||
|
|
fd358758ce | ||
|
|
b2d55c3bc4 | ||
|
|
d0c9970d15 | ||
|
|
daccbdbeaf | ||
|
|
71c032167d | ||
|
|
82ed6eeba5 | ||
|
|
51cb5c773a | ||
|
|
da3fd754a7 | ||
|
|
7b70463912 | ||
|
|
3107fa0ce4 | ||
|
|
ade915136b | ||
|
|
4ad21b004a | ||
|
|
9ef2e5353c | ||
|
|
1ca3716e8f | ||
|
|
3df6a64280 | ||
|
|
476af72e35 | ||
|
|
b8c7bcc996 | ||
|
|
0418a7db78 | ||
|
|
1ab5d2e278 | ||
|
|
4155f4ad82 | ||
|
|
4b5ebcbefd | ||
|
|
1298be1adb | ||
|
|
52a4e9b5e6 | ||
|
|
23373e6ce7 | ||
|
|
ed23172c8b | ||
|
|
1c3fc7dedc | ||
|
|
8f4101d57e | ||
|
|
2cda8bc793 | ||
|
|
51d004c32c | ||
|
|
74e7e2444f | ||
|
|
5e6a565274 | ||
|
|
f2c7812932 | ||
|
|
8ce00e707b | ||
|
|
6aaae6bc6a | ||
|
|
d34c5fd54d | ||
|
|
8ed185e32d | ||
|
|
d789992c87 | ||
|
|
d3f266372b | ||
|
|
8e036c29fc | ||
|
|
8950228a9f | ||
|
|
54cfafa20d | ||
|
|
17fdc3f451 | ||
|
|
8fe0b753e8 | ||
|
|
06e61e1d8b | ||
|
|
4cbc64e4e9 | ||
|
|
7d90b6e86c | ||
|
|
01fcc3df4b | ||
|
|
52a0680c31 | ||
|
|
809cd31f3f | ||
|
|
c05b8864b0 | ||
|
|
f12701af82 | ||
|
|
f6f27acb04 | ||
|
|
5f45c9487b | ||
|
|
fc286131db | ||
|
|
e037227dc1 | ||
|
|
7cd35aaac3 | ||
|
|
0c52074896 | ||
|
|
c351edd7a5 | ||
|
|
80ead5dedb | ||
|
|
0684eeffc0 | ||
|
|
918706835b | ||
|
|
67b37c9cd5 | ||
|
|
9bcb302884 | ||
|
|
80f7393415 | ||
|
|
58759583fa | ||
|
|
63b3dc2be9 | ||
|
|
57a242851a | ||
|
|
b5f01aa8d2 | ||
|
|
19563292d9 | ||
|
|
6780b25091 | ||
|
|
7c9242398e | ||
|
|
e244554917 | ||
|
|
60782673dc | ||
|
|
8442cc21cd | ||
|
|
1d6082005e | ||
|
|
2a45912752 | ||
|
|
bef4e531b7 | ||
|
|
cc2781ee50 | ||
|
|
340b66025b | ||
|
|
9879fd990c | ||
|
|
74db6eb392 | ||
|
|
771d338001 | ||
|
|
6808dd688e | ||
|
|
2d46bbac4d | ||
|
|
442b427a19 | ||
|
|
bebe9d8d8a | ||
|
|
1b21edb1f5 | ||
|
|
52ee74f0af | ||
|
|
296dd76ff7 | ||
|
|
0e68c13837 | ||
|
|
d332624f5c | ||
|
|
fbee20e850 | ||
|
|
eb52bc247a | ||
|
|
0741acca48 | ||
|
|
70d2d70623 | ||
|
|
baca4c0371 | ||
|
|
aa5e04cbca | ||
|
|
f1cc9990b3 | ||
|
|
6bd0264a22 | ||
|
|
19166a33ef | ||
|
|
eb6128ccb6 | ||
|
|
46e5909e17 | ||
|
|
b5652aaf09 | ||
|
|
aa4b7c2a89 | ||
|
|
1b274a6470 | ||
|
|
cc6a53b191 | ||
|
|
1b5b1b545b | ||
|
|
4389fffb72 | ||
|
|
95ca9ae64d | ||
|
|
71aded607f | ||
|
|
d209f372d4 | ||
|
|
aa16342fc1 | ||
|
|
2a7a6f7f0c | ||
|
|
08a320ad90 | ||
|
|
ff1dffebe4 | ||
|
|
fac809eac9 | ||
|
|
6420640395 | ||
|
|
400cfed044 | ||
|
|
eef25504f9 | ||
|
|
4db63e87f7 | ||
|
|
440da3c009 | ||
|
|
d3e2ce9c9b | ||
|
|
93cd410a7b | ||
|
|
e0fbec976b | ||
|
|
f34d2f9dcf | ||
|
|
361c552898 | ||
|
|
d675c3362f | ||
|
|
9c014fba03 | ||
|
|
89a76af30f | ||
|
|
120f200ba1 | ||
|
|
f2a8ccf079 | ||
|
|
dec2dcd735 | ||
|
|
29a1f8d9ed | ||
|
|
3b7ef48976 | ||
|
|
b9ea2e0924 | ||
|
|
0845da6a2e | ||
|
|
300a11c2e3 | ||
|
|
c5cc1ff7c8 | ||
|
|
cdaa2fedab | ||
|
|
2684fbf24d | ||
|
|
93300ee95e | ||
|
|
8c175ab282 | ||
|
|
24b9943dc1 | ||
|
|
3e711843cb | ||
|
|
ead815513d | ||
|
|
dd78ee5fcb | ||
|
|
e61bfe0f38 | ||
|
|
f22a531051 | ||
|
|
c2a1c60b92 | ||
|
|
82bf1057bb | ||
|
|
1a25661400 | ||
|
|
466a65f2da | ||
|
|
a672583053 | ||
|
|
f47e720628 | ||
|
|
c0433efc12 | ||
|
|
5fc98f5b59 | ||
|
|
e7d60078db | ||
|
|
b6abbc0ece | ||
|
|
a7eb318f01 | ||
|
|
1674126665 | ||
|
|
b1bb48e59f | ||
|
|
abfebddbb9 | ||
|
|
5fb4a13562 | ||
|
|
4ff1488b2e | ||
|
|
2b4db9a52b | ||
|
|
05ca5c155b | ||
|
|
c55ac50f4c | ||
|
|
aa32435945 | ||
|
|
e940b97389 | ||
|
|
24ba9a3cf7 | ||
|
|
f7b8c07a3b | ||
|
|
159083d9c3 | ||
|
|
37d7bc057c | ||
|
|
6d1521313f | ||
|
|
1d926b9415 | ||
|
|
f665278df3 | ||
|
|
0bd5130e02 | ||
|
|
af2c27ea0f | ||
|
|
3370c09c89 | ||
|
|
cd23203094 | ||
|
|
64fcdddaac | ||
|
|
2039b1bd09 | ||
|
|
a52666dc20 |
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>
|
||||
45
ofono/.gitignore
vendored
45
ofono/.gitignore
vendored
@@ -32,6 +32,8 @@ src/ofono.service
|
||||
dundee/dundee
|
||||
dundee/dundee.service
|
||||
|
||||
test-driver
|
||||
test-suite.log
|
||||
unit/test-common
|
||||
unit/test-util
|
||||
unit/test-idmap
|
||||
@@ -42,6 +44,49 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-dbus-access
|
||||
unit/test-dbus-queue
|
||||
unit/test-gprs-filter
|
||||
unit/test-ril_config
|
||||
unit/test-ril_ecclist
|
||||
unit/test-ril_util
|
||||
unit/test-ril_vendor
|
||||
unit/test-ril-transport
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
unit/test-rilmodem-sms
|
||||
unit/test-sailfish_access
|
||||
unit/test-sailfish_cell_info
|
||||
unit/test-sailfish_cell_info_dbus
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sailfish_sim_info_dbus
|
||||
unit/test-config
|
||||
unit/test-watch
|
||||
unit/test-sms-filter
|
||||
unit/test-voicecall-filter
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
unit/test-mbim
|
||||
|
||||
unit/test-grilreply
|
||||
unit/test-grilrequest
|
||||
unit/test-grilunsol
|
||||
unit/test-provision
|
||||
unit/html
|
||||
|
||||
plugins/sailfish_manager/*.gcda
|
||||
plugins/sailfish_manager/*.gcno
|
||||
drivers/*/*.gcda
|
||||
drivers/*/*.gcno
|
||||
drivers/*/*.gcov
|
||||
plugins/*/*.gcda
|
||||
plugins/*/*.gcno
|
||||
plugins/*/*.gcov
|
||||
*/*.gcda
|
||||
*/*.gcno
|
||||
*/*.gcov
|
||||
|
||||
tools/huawei-audio
|
||||
tools/auto-enable
|
||||
|
||||
@@ -104,3 +104,29 @@ Alex J Lennon <ajlennon@dynamicdevices.co.uk>
|
||||
Sergey Alirzaev <zl29ah@gmail.com>
|
||||
Marko Sulejic <marko.sulejic@hale.at>
|
||||
Johannes 'josch' Schauer <josch@mister-muffin.de>
|
||||
Simon Fels <simon.fels@canonical.com>
|
||||
John Ernberg <john.ernberg@actia.se>
|
||||
Dongsu Park <dongsu@endocode.com>
|
||||
Dragos Tatulea <dragos@endocode.com>
|
||||
Samrat Guha Niyogi <samrat.guha.niyogi@intel.com>
|
||||
Anirudh Gargi <anirudh.gargi@intel.com>
|
||||
Nishanth V <nishanth.v@intel.com>
|
||||
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>
|
||||
Vincent Cesson <vincent.cesson@smile.fr>
|
||||
Piotr Haber <gluedig@gmail.com>
|
||||
André Draszik <git@andred.net>
|
||||
Lukasz Nowak <lnowak@tycoint.com>
|
||||
Jonas Bonn <jonas@southpole.se>
|
||||
Matthijs Kooijman <matthijs@stdin.nl>
|
||||
Clayton Craft <clayton@craftyguy.net>
|
||||
Joey Hewitt <joey@joeyhewitt.com>
|
||||
Richard Röjfors <richard.rojfors@gmail.com>
|
||||
Philippe De Swert <philippe.deswert@nomovok.com>
|
||||
Gabriel Lucas <gabriel.lucas@smile.fr>
|
||||
|
||||
@@ -1,3 +1,85 @@
|
||||
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.
|
||||
Fix issue with receiving UTF-16 encoded messages.
|
||||
Fix issue with invalid access in CBS decoding.
|
||||
Fix issue with signal strength on QMI modems.
|
||||
Fix issue with PIN handling with QMI modems.
|
||||
Fix issue with QMI notification message handling.
|
||||
Fix issue with facility lock query on SIM removal.
|
||||
Fix issue with parsing +CLCC and +CCWA fields.
|
||||
Add support for obtaining IMSI via EF reading.
|
||||
Add support for additional netmon info types.
|
||||
Add support for provisioning via configuration files.
|
||||
Add support for Gemalto P-family series of modems.
|
||||
Add support for Telit HE910 and UE910 variants.
|
||||
Add support for Intel SoFIA SIM Toolkit interfaces.
|
||||
Add support for Intel SoFIA LTE features.
|
||||
Add support for U-Blox TOBY-L2 LTE feature.
|
||||
Add support for dedicated LTE atom.
|
||||
|
||||
ver 1.19:
|
||||
Fix issue with DHCP parsing and Huawei modems.
|
||||
Fix issue with detecting Huawei E3372 modem.
|
||||
Fix issue with handling serving cell info.
|
||||
Fix issue with handling SIM SC facility lock.
|
||||
Fix issue with Android RIL PIN retry logic.
|
||||
Fix issue with Android RIL and RAT handling.
|
||||
Add support for Android RIL cell broadcast.
|
||||
Add support for SoFIA 3GR thermal management.
|
||||
|
||||
ver 1.18:
|
||||
Fix issue with cell broadcast and use-after-fee.
|
||||
Fix issue with repeated held call indicator.
|
||||
Fix issue with +CCWA and connection setup.
|
||||
Fix issue with empty operator scan results.
|
||||
Fix issue with persistent RAT mode handling.
|
||||
Fix issue with multiparty call introspection.
|
||||
Fix issue with GRPS context introspection.
|
||||
Fix issue with stale context deactivation.
|
||||
Add support for automatic context activation.
|
||||
Add support for SIM service provider names.
|
||||
Add support for handling allowed APN lists.
|
||||
Add support for network monitoring interface.
|
||||
Add support for U-Blox TOBY-L2 modem series.
|
||||
Add support for Sierra MC73xx QMI modems.
|
||||
Add support for SoFIA 3GR modem series.
|
||||
Add support for upower battery monitoring.
|
||||
Add support for gateway audio card types.
|
||||
Add support for Handsfree audio driver.
|
||||
Add support for Android RIL integration.
|
||||
|
||||
ver 1.17:
|
||||
Fix issue with alphanumeric TP-OA handling.
|
||||
Fix issue with push notification origin port.
|
||||
|
||||
@@ -113,3 +113,5 @@ doc/coding-style.txt.
|
||||
a feature that touches files under 'include/', 'src/' and 'drivers/'
|
||||
directories, split in three separated patches, taking care not to
|
||||
break compilation.
|
||||
|
||||
4) Submit patches using git send-email to ofono@ofono.org
|
||||
|
||||
@@ -21,9 +21,14 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/cdma-connman.h include/gnss.h \
|
||||
include/private-network.h include/cdma-netreg.h \
|
||||
include/cdma-provision.h include/handsfree.h \
|
||||
include/handsfree-audio.h \
|
||||
include/sim-mnclength.h \
|
||||
include/siri.h
|
||||
include/handsfree-audio.h include/siri.h \
|
||||
include/sms-filter.h include/gprs-filter.h \
|
||||
include/voicecall-filter.h include/dbus-access.h \
|
||||
include/ril-constants.h include/ril-transport.h \
|
||||
include/watch.h gdbus/gdbus.h \
|
||||
include/netmon.h include/lte.h include/ims.h \
|
||||
include/storage.h
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
@@ -58,7 +63,7 @@ endif
|
||||
builtin_modules =
|
||||
builtin_sources =
|
||||
builtin_libadd =
|
||||
builtin_cflags =
|
||||
builtin_cflags = -DSAILFISH_OS
|
||||
|
||||
noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
|
||||
|
||||
@@ -97,20 +102,16 @@ gisi_sources = gisi/client.c gisi/client.h gisi/common.h \
|
||||
gisi/server.c gisi/server.h \
|
||||
gisi/socket.c gisi/socket.h
|
||||
|
||||
gril_sources = gril/gril.h gril/gril.c gril/grilio.h \
|
||||
gril/grilio.c gril/grilutil.h \
|
||||
gril/grilutil.c gril/ringbuffer.h \
|
||||
gril/gfunc.h gril/ril.h \
|
||||
gril_sources = gril/gril.h gril/gril.c \
|
||||
gril/grilio.h gril/grilio.c \
|
||||
gril/grilutil.h gril/grilutil.c \
|
||||
gril/gfunc.h gril/gril.h \
|
||||
gril/parcel.c gril/parcel.h \
|
||||
gril/grilreply.c gril/grilreply.h \
|
||||
gril/grilrequest.c gril/grilrequest.h \
|
||||
gril/grilunsol.c gril/grilunsol.h
|
||||
gril/ril_constants.h
|
||||
|
||||
btio_sources = btio/btio.h btio/btio.c
|
||||
|
||||
if UDEV
|
||||
builtin_modules += udev
|
||||
builtin_sources += plugins/udev.c
|
||||
builtin_cflags += @UDEV_CFLAGS@
|
||||
builtin_libadd += @UDEV_LIBS@
|
||||
|
||||
@@ -118,63 +119,96 @@ 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
|
||||
endif
|
||||
|
||||
|
||||
if SAILFISH_ACCESS
|
||||
builtin_modules += sailfish_access
|
||||
builtin_sources += plugins/sailfish_access.c
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if JOLLA_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_cell_info_dbus.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_connman.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
drivers/ril/ril_devmon.c \
|
||||
drivers/ril/ril_devmon_auto.c \
|
||||
drivers/ril/ril_devmon_combine.c \
|
||||
drivers/ril/ril_devmon_ds.c \
|
||||
drivers/ril/ril_devmon_ss.c \
|
||||
drivers/ril/ril_devmon_ur.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
drivers/ril/ril_mce.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_mtu.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_plugin_dbus.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_info.c \
|
||||
drivers/ril/ril_sim_info_dbus.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_vendor.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
# Vendor specific extensions
|
||||
builtin_sources += drivers/ril/ril_vendor_mtk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
builtin_modules += rildev
|
||||
builtin_sources += plugins/rildev.c
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += plugins/ril.c
|
||||
builtin_sources += plugins/ril.c plugins/ril.h
|
||||
|
||||
builtin_modules += infineon
|
||||
builtin_sources += plugins/infineon.c
|
||||
|
||||
builtin_modules += ril_intel
|
||||
builtin_sources += plugins/ril_intel.c
|
||||
|
||||
builtin_modules += rilmodem
|
||||
builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/vendor.h \
|
||||
drivers/rilmodem/rilmodem.c \
|
||||
drivers/rilmodem/devinfo.c \
|
||||
drivers/rilmodem/network-registration.c \
|
||||
drivers/rilmodem/voicecall.c \
|
||||
drivers/rilmodem/voicecall.h \
|
||||
drivers/rilmodem/call-volume.c \
|
||||
drivers/rilmodem/gprs.c \
|
||||
drivers/rilmodem/gprs-context.c \
|
||||
@@ -182,20 +216,16 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/sms.c \
|
||||
drivers/rilmodem/rilutil.c \
|
||||
drivers/rilmodem/rilutil.h \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/phonebook.c \
|
||||
drivers/rilmodem/ussd.c \
|
||||
drivers/rilmodem/call-settings.c \
|
||||
drivers/rilmodem/call-forwarding.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/rilmodem/oemraw-messages.c \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/call-barring.c \
|
||||
drivers/rilmodem/stk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += gril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
drivers/rilmodem/netmon.c \
|
||||
drivers/rilmodem/stk.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/infineonmodem/infineon_constants.h \
|
||||
drivers/rilmodem/lte.c
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -254,11 +284,14 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
|
||||
drivers/qmimodem/ctl.h \
|
||||
drivers/qmimodem/dms.h \
|
||||
drivers/qmimodem/nas.h \
|
||||
drivers/qmimodem/nas.c \
|
||||
drivers/qmimodem/uim.h \
|
||||
drivers/qmimodem/wms.h \
|
||||
drivers/qmimodem/wds.h \
|
||||
drivers/qmimodem/pds.h \
|
||||
drivers/qmimodem/common.h
|
||||
drivers/qmimodem/common.h \
|
||||
drivers/qmimodem/wda.h \
|
||||
drivers/qmimodem/voice.h
|
||||
|
||||
builtin_modules += qmimodem
|
||||
builtin_sources += $(qmi_sources) \
|
||||
@@ -274,8 +307,10 @@ builtin_sources += $(qmi_sources) \
|
||||
drivers/qmimodem/ussd.c \
|
||||
drivers/qmimodem/gprs.c \
|
||||
drivers/qmimodem/gprs-context.c \
|
||||
drivers/qmimodem/lte.c \
|
||||
drivers/qmimodem/radio-settings.c \
|
||||
drivers/qmimodem/location-reporting.c
|
||||
drivers/qmimodem/location-reporting.c \
|
||||
drivers/qmimodem/netmon.c
|
||||
|
||||
builtin_modules += gobi
|
||||
builtin_sources += plugins/gobi.c
|
||||
@@ -283,8 +318,7 @@ endif
|
||||
|
||||
if ATMODEM
|
||||
builtin_modules += atmodem
|
||||
builtin_sources += $(gatchat_sources) \
|
||||
drivers/atmodem/atmodem.h \
|
||||
builtin_sources += drivers/atmodem/atmodem.h \
|
||||
drivers/atmodem/atmodem.c \
|
||||
drivers/atmodem/call-settings.c \
|
||||
drivers/atmodem/sms.c \
|
||||
@@ -306,8 +340,8 @@ builtin_sources += $(gatchat_sources) \
|
||||
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 \
|
||||
@@ -364,7 +398,8 @@ builtin_modules += telitmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/telitmodem/telitmodem.h \
|
||||
drivers/telitmodem/telitmodem.c \
|
||||
drivers/telitmodem/location-reporting.c
|
||||
drivers/telitmodem/location-reporting.c \
|
||||
drivers/telitmodem/gprs-context-ncm.c
|
||||
|
||||
builtin_modules += hsomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
@@ -422,6 +457,28 @@ builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/speedupmodem/speedupmodem.c \
|
||||
drivers/speedupmodem/ussd.c
|
||||
|
||||
builtin_modules += ubloxmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/ubloxmodem/ubloxmodem.h \
|
||||
drivers/ubloxmodem/ubloxmodem.c \
|
||||
drivers/ubloxmodem/gprs-context.c \
|
||||
drivers/ubloxmodem/netmon.c \
|
||||
drivers/ubloxmodem/lte.c
|
||||
|
||||
|
||||
builtin_modules += gemaltomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/gemaltomodem/gemaltomodem.h \
|
||||
drivers/gemaltomodem/gemaltomodem.c \
|
||||
drivers/gemaltomodem/location-reporting.c
|
||||
|
||||
builtin_modules += xmm7modem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/xmm7modem/xmm7modem.h \
|
||||
drivers/xmm7modem/xmm7modem.c \
|
||||
drivers/xmm7modem/radio-settings.c \
|
||||
drivers/xmm7modem/ims.c
|
||||
|
||||
if PHONESIM
|
||||
builtin_modules += phonesim
|
||||
builtin_sources += plugins/phonesim.c
|
||||
@@ -486,6 +543,9 @@ builtin_sources += plugins/caif.c
|
||||
builtin_modules += cinterion
|
||||
builtin_sources += plugins/cinterion.c
|
||||
|
||||
builtin_modules += gemalto
|
||||
builtin_sources += plugins/gemalto.c
|
||||
|
||||
builtin_modules += nokia
|
||||
builtin_sources += plugins/nokia.c
|
||||
|
||||
@@ -513,38 +573,52 @@ builtin_sources += plugins/samsung.c
|
||||
builtin_modules += sim900
|
||||
builtin_sources += plugins/sim900.c
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c
|
||||
|
||||
builtin_modules += quectel
|
||||
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
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
|
||||
if BLUETOOTH
|
||||
if BLUEZ4
|
||||
builtin_modules += bluez4
|
||||
builtin_sources += plugins/bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += sap
|
||||
builtin_sources += plugins/sap.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_bluez4
|
||||
builtin_sources += plugins/hfp_hf_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez4
|
||||
builtin_sources += plugins/hfp_ag_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += dun_gw_bluez4
|
||||
builtin_sources += plugins/dun_gw_bluez4.c plugins/bluez4.h
|
||||
else
|
||||
builtin_modules += hfp_bluez5
|
||||
builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += dun_gw_bluez5
|
||||
builtin_sources += plugins/dun_gw_bluez5.c plugins/bluez5.h
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if BLUETOOTH
|
||||
if BLUEZ4
|
||||
builtin_modules += bluez4
|
||||
builtin_sources += plugins/bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez4
|
||||
builtin_sources += plugins/hfp_ag_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_sources += $(btio_sources)
|
||||
builtin_cflags += @BLUEZ_CFLAGS@
|
||||
@@ -553,16 +627,19 @@ else
|
||||
builtin_modules += bluez5
|
||||
builtin_sources += plugins/bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_bluez5
|
||||
builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez5
|
||||
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += dun_gw_bluez5
|
||||
builtin_sources += plugins/dun_gw_bluez5.c plugins/bluez5.h
|
||||
if SAILFISH_BT
|
||||
builtin_modules += sfos_bt
|
||||
builtin_sources += plugins/sailfish_bt.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if UPOWER
|
||||
builtin_modules += upower
|
||||
builtin_sources += plugins/upower.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if NETTIME
|
||||
@@ -570,17 +647,32 @@ builtin_modules += nettime
|
||||
builtin_sources += plugins/nettime.c
|
||||
endif
|
||||
|
||||
if SAILFISH_DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/sailfish_debuglog.c
|
||||
endif
|
||||
|
||||
if SAILFISH_PROVISION
|
||||
builtin_sources += plugins/sailfish_provision.c
|
||||
PROVISION = 1
|
||||
else
|
||||
if PROVISION
|
||||
builtin_sources += plugins/provision.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if PROVISION
|
||||
builtin_sources += plugins/mbpi.h plugins/mbpi.c
|
||||
|
||||
builtin_modules += provision
|
||||
builtin_sources += plugins/provision.h plugins/provision.c
|
||||
builtin_sources += plugins/provision.h
|
||||
|
||||
builtin_modules += cdma_provision
|
||||
builtin_sources += plugins/cdma-provision.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
builtin_modules += file_provision
|
||||
builtin_sources += plugins/file-provision.c
|
||||
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
@@ -612,24 +704,51 @@ builtin_sources += plugins/smart-messaging.c
|
||||
builtin_modules += push_notification
|
||||
builtin_sources += plugins/push-notification.c
|
||||
|
||||
if PUSHFORWARDER
|
||||
builtin_modules += push_forwarder
|
||||
builtin_sources += plugins/push-forwarder.c
|
||||
builtin_cflags += @WSPCODEC_CFLAGS@
|
||||
builtin_libadd += @WSPCODEC_LIBS@
|
||||
endif
|
||||
|
||||
if DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/debuglog.c
|
||||
if SAILFISH_PUSHFORWARDER
|
||||
builtin_modules += pushforwarder
|
||||
builtin_sources += plugins/sailfish_pushforwarder.c
|
||||
endif
|
||||
|
||||
builtin_modules += sms_history
|
||||
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) src/ofono.ver \
|
||||
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 \
|
||||
@@ -655,7 +774,12 @@ src_ofonod_SOURCES = $(builtin_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/hfp.h src/siri.c
|
||||
src/sms-filter.c src/gprs-filter.c \
|
||||
src/dbus-queue.c src/dbus-access.c src/config.c \
|
||||
src/voicecall-filter.c src/ril-transport.c \
|
||||
src/hfp.h src/siri.c src/watchlist.c \
|
||||
src/netmon.c src/lte.c src/ims.c \
|
||||
src/netmonagent.c src/netmonagent.h
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -665,7 +789,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
|
||||
|
||||
BUILT_SOURCES = $(local_headers) src/builtin.h
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
|
||||
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
|
||||
|
||||
plugindir = $(pkglibdir)/plugins
|
||||
|
||||
@@ -681,7 +806,8 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
|
||||
|
||||
AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \
|
||||
-I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril \
|
||||
-I$(srcdir)/plugins/sailfish_manager
|
||||
|
||||
doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \
|
||||
@@ -701,7 +827,12 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/location-reporting-api.txt \
|
||||
doc/smshistory-api.txt doc/oemraw-api.txt \
|
||||
doc/certification.txt doc/siri-api.txt \
|
||||
doc/telit-modem.txt
|
||||
doc/telit-modem.txt \
|
||||
doc/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt \
|
||||
doc/lte-api.txt \
|
||||
doc/cinterion-hardware-monitor-api.txt \
|
||||
doc/ims-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -735,6 +866,7 @@ test_scripts = test/backtrace \
|
||||
test/receive-sms \
|
||||
test/remove-contexts \
|
||||
test/send-sms \
|
||||
test/cancel-sms \
|
||||
test/set-mic-volume \
|
||||
test/set-speaker-volume \
|
||||
test/test-stk-menu \
|
||||
@@ -799,7 +931,21 @@ test_scripts = test/backtrace \
|
||||
test/set-msisdn \
|
||||
test/test-voicecallagent \
|
||||
test/get-network-time \
|
||||
test/set-ddr
|
||||
test/set-ddr \
|
||||
test/register-auto \
|
||||
test/register-operator \
|
||||
test/set-sms-smsc \
|
||||
test/set-sms-bearer \
|
||||
test/get-serving-cell-info \
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling \
|
||||
test/set-lte-property \
|
||||
test/test-serving-cell-info \
|
||||
test/ims-register \
|
||||
test/ims-unregister \
|
||||
test/list-applications
|
||||
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -811,35 +957,175 @@ EXTRA_DIST = src/genbuiltin plugins/ofono.rules plugins/ofono-speedup.rules \
|
||||
|
||||
dist_man_MANS = doc/ofonod.8
|
||||
|
||||
if TEST_COVERAGE
|
||||
COVERAGE_OPT = --coverage
|
||||
endif
|
||||
|
||||
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-grilrequest \
|
||||
unit/test-grilreply \
|
||||
unit/test-grilunsol \
|
||||
unit/test-sms unit/test-cdmasms \
|
||||
unit/test-provision
|
||||
unit/test-sms unit/test-cdmasms
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info
|
||||
|
||||
unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||
unit/test-sailfish_cell_info_dbus.c \
|
||||
unit/fake_sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@DBUS_GLIB_CFLAGS@
|
||||
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info_dbus
|
||||
|
||||
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
unit/fake_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info
|
||||
|
||||
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
|
||||
unit/test-dbus.c unit/fake_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info_dbus
|
||||
|
||||
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
unit/fake_watch.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/log.c
|
||||
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_manager
|
||||
|
||||
unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \
|
||||
src/log.c src/watchlist.c
|
||||
unit_test_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_watch_OBJECTS)
|
||||
unit_tests += unit/test-watch
|
||||
|
||||
endif
|
||||
|
||||
unit_test_config_SOURCES = unit/test-config.c drivers/ril/ril_util.c \
|
||||
src/config.c src/log.c
|
||||
unit_test_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_config_OBJECTS)
|
||||
unit_tests += unit/test-config
|
||||
|
||||
if SAILFISH_ACCESS
|
||||
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
|
||||
plugins/sailfish_access.c src/dbus-access.c src/log.c
|
||||
unit_test_sailfish_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_sailfish_access_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_access_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_access
|
||||
endif
|
||||
|
||||
unit_test_dbus_access_SOURCES = unit/test-dbus-access.c src/dbus-access.c \
|
||||
src/log.c
|
||||
unit_test_dbus_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_dbus_access_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_access_OBJECTS)
|
||||
unit_tests += unit/test-dbus-access
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_config.c src/log.c
|
||||
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_config_OBJECTS)
|
||||
unit_tests += unit/test-ril_config
|
||||
|
||||
unit_test_ril_ecclist_SOURCES = unit/test-ril_ecclist.c \
|
||||
drivers/ril/ril_ecclist.c src/log.c
|
||||
unit_test_ril_ecclist_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_ecclist_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_ecclist_OBJECTS)
|
||||
unit_tests += unit/test-ril_ecclist
|
||||
|
||||
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_util_OBJECTS)
|
||||
unit_tests += unit/test-ril_util
|
||||
|
||||
unit_test_ril_vendor_SOURCES = unit/test-ril_vendor.c unit/fake_watch.c \
|
||||
drivers/ril/ril_vendor.c drivers/ril/ril_vendor_mtk.c \
|
||||
drivers/ril/ril_util.c src/log.c
|
||||
unit_test_ril_vendor_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_vendor_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_vendor_OBJECTS)
|
||||
unit_tests += unit/test-ril_vendor
|
||||
|
||||
else
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-sms \
|
||||
unit/test-rilmodem-cb \
|
||||
unit/test-rilmodem-gprs
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
if ELL
|
||||
if MBIMMODEM
|
||||
unit_tests += unit/test-mbim
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
noinst_PROGRAMS = $(unit_tests) \
|
||||
unit/test-sms-root unit/test-mux unit/test-caif
|
||||
|
||||
unit_test_common_SOURCES = unit/test-common.c src/common.c src/util.c
|
||||
unit_test_common_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_common_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_common_OBJECTS)
|
||||
|
||||
unit_test_util_SOURCES = unit/test-util.c src/util.c
|
||||
unit_test_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_util_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_utils_OBJECTS)
|
||||
|
||||
unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
|
||||
unit_test_idmap_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_idmap_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_idmap_OBJECTS)
|
||||
|
||||
unit_test_simutil_SOURCES = unit/test-simutil.c src/util.c \
|
||||
src/simutil.c src/smsutil.c src/storage.c
|
||||
unit_test_simutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_simutil_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_simutil_OBJECTS)
|
||||
|
||||
@@ -847,19 +1133,23 @@ unit_test_stkutil_SOURCES = unit/test-stkutil.c unit/stk-test-data.h \
|
||||
src/util.c \
|
||||
src/storage.c src/smsutil.c \
|
||||
src/simutil.c src/stkutil.c
|
||||
unit_test_stkutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_stkutil_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_stkutil_OBJECTS)
|
||||
|
||||
unit_test_sms_SOURCES = unit/test-sms.c src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_OBJECTS)
|
||||
|
||||
unit_test_cdmasms_SOURCES = unit/test-cdmasms.c src/cdma-smsutil.c
|
||||
unit_test_cdmasms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_cdmasms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_cdmasms_OBJECTS)
|
||||
|
||||
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
|
||||
src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_root_CFLAGS = -DSTORAGEDIR='"/tmp/ofono"' $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_root_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_root_OBJECTS)
|
||||
|
||||
@@ -870,30 +1160,98 @@ unit_objects += $(unit_test_mux_OBJECTS)
|
||||
unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
|
||||
drivers/stemodem/caif_socket.h \
|
||||
drivers/stemodem/if_caif.h
|
||||
unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_grilrequest_SOURCES = unit/test-grilrequest.c $(gril_sources) \
|
||||
src/log.c gatchat/ringbuffer.c
|
||||
unit_test_grilrequest_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_grilrequest_OBJECTS)
|
||||
|
||||
unit_test_grilreply_SOURCES = unit/test-grilreply.c $(gril_sources) \
|
||||
src/log.c gatchat/ringbuffer.c
|
||||
unit_test_grilreply_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_grilreply_OBJECTS)
|
||||
|
||||
unit_test_grilunsol_SOURCES = unit/test-grilunsol.c $(gril_sources) \
|
||||
src/log.c gatchat/ringbuffer.c
|
||||
unit_test_grilunsol_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_grilunsol_OBJECTS)
|
||||
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||
src/dbus-queue.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_queue_OBJECTS)
|
||||
unit_tests += unit/test-dbus-queue
|
||||
|
||||
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
plugins/provision.h plugins/provision.c \
|
||||
plugins/mbpi.c src/gprs-provision.c \
|
||||
src/log.c
|
||||
plugins/provision.h plugins/mbpi.c \
|
||||
plugins/sailfish_provision.c \
|
||||
src/gprs-provision.c src/log.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 \
|
||||
unit/rilmodem-test-server.h \
|
||||
unit/rilmodem-test-server.c \
|
||||
unit/rilmodem-test-engine.h \
|
||||
unit/rilmodem-test-engine.c \
|
||||
src/simutil.c \
|
||||
drivers/rilmodem/rilutil.c
|
||||
|
||||
unit_test_rilmodem_cs_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-cs.c \
|
||||
drivers/rilmodem/call-settings.c
|
||||
unit_test_rilmodem_cs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_cs_OBJECTS)
|
||||
|
||||
unit_test_rilmodem_sms_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-sms.c \
|
||||
drivers/rilmodem/sms.c
|
||||
unit_test_rilmodem_sms_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_sms_OBJECTS)
|
||||
|
||||
unit_test_rilmodem_cb_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-cb.c \
|
||||
drivers/rilmodem/call-barring.c
|
||||
unit_test_rilmodem_cb_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_cb_OBJECTS)
|
||||
|
||||
unit_test_rilmodem_gprs_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-gprs.c \
|
||||
drivers/rilmodem/gprs.c
|
||||
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)
|
||||
|
||||
@@ -921,13 +1279,6 @@ tools_lookup_provider_name_LDADD = @GLIB_LIBS@
|
||||
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
||||
tools_tty_redirector_LDADD = @GLIB_LIBS@
|
||||
|
||||
if QMIMODEM
|
||||
noinst_PROGRAMS += tools/qmi
|
||||
|
||||
tools_qmi_SOURCES = $(qmi_sources) tools/qmi.c
|
||||
tools_qmi_LDADD = @GLIB_LIBS@
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
noinst_PROGRAMS += tools/stktest
|
||||
|
||||
@@ -996,6 +1347,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) $< $@
|
||||
|
||||
10
ofono/TODO
10
ofono/TODO
@@ -256,6 +256,16 @@ Voicecall
|
||||
Priority: Medium
|
||||
Complexity: C1
|
||||
|
||||
- DTMF Driver hints
|
||||
|
||||
Currently multiple DTMF tones are sent to the driver in batches of up to 8
|
||||
characters. For those drivers that can only accept a limited set of DTMF
|
||||
characters at a time (e.g. one), add a setting to the core that will change
|
||||
this batch size limit.
|
||||
|
||||
Priority: Medium
|
||||
Complexity: C1
|
||||
|
||||
|
||||
Sim Toolkit
|
||||
===========
|
||||
|
||||
@@ -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.17)
|
||||
AC_INIT(ofono, 1.23)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -33,7 +33,7 @@ AC_PROG_LIBTOOL
|
||||
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
|
||||
[disable code optimization through compiler]), [
|
||||
if (test "${enableval}" = "no"); then
|
||||
CFLAGS="$CFLAGS -O0"
|
||||
CFLAGS="$CFLAGS -O0 -U_FORTIFY_SOURCE"
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -64,11 +64,21 @@ AC_CHECK_FUNC(signalfd, dummy=yes,
|
||||
AC_CHECK_LIB(dl, dlopen, dummy=yes,
|
||||
AC_MSG_ERROR(dynamic linking loader is required))
|
||||
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.28 is required))
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.32 is required))
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(GOBJECT, gobject-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GObject is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GOBJECT_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GOBJECT_LIBS"
|
||||
|
||||
PKG_CHECK_MODULES(GIO, gio-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GIO is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GIO_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GIO_LIBS"
|
||||
|
||||
if (test "${enable_threads}" = "yes"); then
|
||||
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
||||
@@ -167,20 +177,51 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
|
||||
[enable_rilmodem=${enableval}])
|
||||
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(jolla-rilmodem,
|
||||
AC_HELP_STRING([--enable-jolla-rilmodem], [enable Jolla RIL modem]),
|
||||
[enable_jolla_rilmodem=${enableval}], [enable_jolla_rilmodem="no"])
|
||||
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_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")
|
||||
|
||||
if (test "${enable_jolla_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS"
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.35, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.35 is required))
|
||||
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||
|
||||
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.38, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.38 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.6, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.6 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||
enable_sailfish_manager=yes
|
||||
fi
|
||||
|
||||
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]), [
|
||||
if (test "${enableval}" = "no"); then
|
||||
CFLAGS="$CFLAGS -DDISABLE_ADD_REMOVE_CONTEXT"
|
||||
fi
|
||||
])
|
||||
|
||||
AC_ARG_ENABLE(test-coverage,
|
||||
AC_HELP_STRING([--enable-test-coverage], [enable test code coverage]),
|
||||
[enable_test_coverage=${enableval}],
|
||||
[enable_test_coverage="no"])
|
||||
AM_CONDITIONAL(TEST_COVERAGE, test "${enable_test_coverage}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
|
||||
[disable Qualcomm QMI modem support]),
|
||||
[enable_qmimodem=${enableval}])
|
||||
@@ -204,6 +245,16 @@ fi
|
||||
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
|
||||
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-bt, AC_HELP_STRING([--enable-sailfish-bt],
|
||||
[enable Sailfish OS Bluetooth plugin]),
|
||||
[enable_sailfish_bt=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_BT, test "${enable_sailfish_bt}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
|
||||
[enable Sailfish OS provisioning plugin]),
|
||||
[enable_sailfish_provision=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
|
||||
[disable Nettime plugin]),
|
||||
[enable_nettime=${enableval}])
|
||||
@@ -236,27 +287,66 @@ if (test "${enable_provision}" != "no"); then
|
||||
fi
|
||||
AM_CONDITIONAL(PROVISION, test "${enable_provision}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(upower, AC_HELP_STRING([--disable-upower],
|
||||
[disable UPower plugin]),
|
||||
[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}])
|
||||
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
|
||||
[disable Push Forwarder plugin]),
|
||||
[enable_pushforwarder=${enableval}])
|
||||
AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
|
||||
if (test "${enable_pushforwarder}" != "no"); then
|
||||
AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforwarder],
|
||||
[enable Sailfish OS push forwarder plugin]),
|
||||
[enable_sailfish_pushforwarder=${enableval}],
|
||||
[enable_sailfish_pushforwarder="no"])
|
||||
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
|
||||
if (test "${enable_sailfish_pushforwarder}" != "no"); then
|
||||
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
|
||||
AC_MSG_ERROR(WSP decoder is required))
|
||||
AC_SUBST(WSPCODEC_CFLAGS)
|
||||
AC_SUBST(WSPCODEC_LIBS)
|
||||
AC_MSG_ERROR(WSP decoder is required))
|
||||
CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
|
||||
LIBS="$LIBS $WSPCODEC_LIBS"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(debuglog,
|
||||
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
|
||||
[enable_debuglog=${enableval}], [enable_debuglog="no"])
|
||||
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
|
||||
if (test "${enable_debuglog}" = "yes"); then
|
||||
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],
|
||||
[enable Sailfish OS debug log plugin]),
|
||||
[enable_sailfish_debuglog=${enableval}],
|
||||
[enable_sailfish_debuglog="no"])
|
||||
AM_CONDITIONAL(SAILFISH_DEBUGLOG, test "${enable_sailfish_debuglog}" != "no")
|
||||
if (test "${enable_sailfish_debuglog}" = "yes"); then
|
||||
PKG_CHECK_MODULES(DBUSLOG, libdbuslogserver-dbus, dummy=yes,
|
||||
AC_MSG_ERROR(libdbuslogserver-dbus is required))
|
||||
CFLAGS="$CFLAGS $DBUSLOG_CFLAGS"
|
||||
@@ -277,7 +367,7 @@ if (test "$localstatedir" = '${prefix}/var'); then
|
||||
else
|
||||
storagedir="${localstatedir}/lib/ofono"
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_STORAGEDIR, "${storagedir}",
|
||||
[Directory for the storage files])
|
||||
|
||||
if (test "$sysconfdir" = '${prefix}/etc'); then
|
||||
|
||||
17
ofono/doc/allowed-apns-api.txt
Normal file
17
ofono/doc/allowed-apns-api.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Allowed APNs hierarchy
|
||||
=========================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.AllowedAccessPoints
|
||||
Object path [variable prefix]/{modem0,modem1,...}
|
||||
|
||||
Methods array{string} GetAllowedAccessPoints()
|
||||
|
||||
Get the list of allowed access points provided
|
||||
in the SIM card.
|
||||
|
||||
This method returns an array of strings which
|
||||
contains a list of Access Point Names supported
|
||||
by network provider. Returns with an error if
|
||||
SIM reading failed or an empty list if there
|
||||
are no access points listed on the SIM.
|
||||
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
HardwareMonitor hierarchy
|
||||
=========================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.cinterion.HardwareMonitor
|
||||
Object path /{device0,device1,...}
|
||||
|
||||
Methods array{string,variant} GetStatistics
|
||||
|
||||
Returns an array of dict entries representing the
|
||||
current temperature and supply voltage of the modem.
|
||||
|
||||
Units:
|
||||
Temperature: Celsius
|
||||
Voltage: mV
|
||||
@@ -19,7 +19,7 @@ Besides the kernel coding style above, oFono has special flavors for its own.
|
||||
Some of them are mandatory (marked as 'M'), while some others are optional
|
||||
(marked as 'O'), but generally preferred.
|
||||
|
||||
M1: Blank line before and after an if/while/do/for statement
|
||||
M1: Blank line before and after an if/while/do/for/switch statement
|
||||
============================================================
|
||||
There should be a blank line before if statement unless the if is nested and
|
||||
not preceded by an expression or variable declaration.
|
||||
|
||||
@@ -106,7 +106,7 @@ Properties boolean Attached [readonly]
|
||||
GPRS service registration (if known).
|
||||
|
||||
Possible values are:
|
||||
"none", "gsm", "edge", "umts", "hsdpa", "hsupa",
|
||||
"none", "gprs", "edge", "umts", "hsdpa", "hsupa",
|
||||
"hspa" (HSDPA and HSUPA at the same time) and
|
||||
"lte"
|
||||
|
||||
|
||||
@@ -76,6 +76,22 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
fd, byte Acquire()
|
||||
|
||||
Attempts to establish the SCO audio connection
|
||||
returning the filedescriptor of the connection and the
|
||||
codec in use.
|
||||
|
||||
Note: Contrary to Connect this does not call
|
||||
NewConnection so it can be called in a blocking
|
||||
manner.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.Failed
|
||||
[service].Error.NotAvailable
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
Signals PropertyChanged(string name, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
@@ -89,6 +105,10 @@ Properties string RemoteAddress [readonly]
|
||||
|
||||
Bluetooth address of the local adapter.
|
||||
|
||||
string Type [readonly]
|
||||
|
||||
Type of the card. Valid values are "gateway" or
|
||||
"handsfree".
|
||||
|
||||
Handsfree Audio Agent hierarchy [experimental]
|
||||
===============================
|
||||
|
||||
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.
|
||||
35
ofono/doc/lte-api.txt
Normal file
35
ofono/doc/lte-api.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
LongTermEvolution Hierarchy
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.LongTermEvolution
|
||||
Object path [variable prefix]/{modem0,modem1,...}
|
||||
|
||||
|
||||
Methods dict GetProperties()
|
||||
|
||||
Returns all LongTermEvolution configuration properties.
|
||||
|
||||
void SetProperty(string property, variant value)
|
||||
|
||||
Changes the value of the specified property. Only
|
||||
properties that are listed as readwrite are
|
||||
changeable. On success a PropertyChanged signal
|
||||
will be emitted.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.Failed
|
||||
|
||||
Signals PropertyChanged(string property, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
property.
|
||||
|
||||
Properties string DefaultAccessPointName [readwrite]
|
||||
|
||||
On LongTermEvolution, contexts activate automatically.
|
||||
This property allows selection of an APN to be used on
|
||||
next automatic activation.
|
||||
|
||||
Setting this property to an empty string clears the
|
||||
default APN from the modem.
|
||||
@@ -90,6 +90,18 @@ Properties boolean Powered [readwrite]
|
||||
"hfp") this corresponds to the Bluetooth Device
|
||||
Address of the remote device.
|
||||
|
||||
string SoftwareVersionNumber [readonly, optional]
|
||||
|
||||
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
|
||||
@@ -122,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
|
||||
|
||||
150
ofono/doc/networkmonitor-api.txt
Normal file
150
ofono/doc/networkmonitor-api.txt
Normal file
@@ -0,0 +1,150 @@
|
||||
Network Monitor hierarchy
|
||||
=========================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.NetworkMonitor
|
||||
Object path [variable prefix]/{modem0,modem1,...}
|
||||
|
||||
Methods a{sv} GetServingCellInformation()
|
||||
|
||||
Requests the latest serving cell information and basic
|
||||
measurements from oFono. The returned value is a
|
||||
dictionary with the possible key / values documented
|
||||
below. The type of cell is given by the 'Technology'
|
||||
property.
|
||||
|
||||
Based on the type of cell, the dictionary will contain
|
||||
additional key/value pairs. If a given key/value pair
|
||||
is not present, then it is not known or unsupported
|
||||
by the underlying driver.
|
||||
|
||||
Refer to the sections below for which property types
|
||||
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
|
||||
==============================
|
||||
|
||||
string Technology
|
||||
|
||||
Contains the cell type. Possible values are:
|
||||
"gsm", "umts", "lte"
|
||||
|
||||
uint16 LocationAreaCode [optional, gsm, umts]
|
||||
|
||||
Contains the current location area code. Valid range of values is
|
||||
0-65535.
|
||||
|
||||
uint32 CellId [optional, gsm, umts]
|
||||
|
||||
Contains the current network cell id. Valid range of values is
|
||||
0-65535 for gsm and 0-268435455 in umts.
|
||||
|
||||
string MobileNetworkCode [optional, gsm, umts]
|
||||
|
||||
Contains the MNC of the cell.
|
||||
|
||||
string MobileCountryCode [optional, gsm, umts]
|
||||
|
||||
Contains the MCC of the cell.
|
||||
|
||||
uint16 ARFCN [optional, gsm]
|
||||
|
||||
Contains the Absolute Radio Frequency Channel Number. Valid range of
|
||||
values is 0-1023.
|
||||
|
||||
byte ReceivedSignalStrength [optional, gsm]
|
||||
|
||||
Contains the received signal strength level in dBm. Refer to <rxlev>
|
||||
in 27.007, Section 8.69 for more details. Valid range of values is
|
||||
0-63.
|
||||
|
||||
byte BSIC [optional, gsm]
|
||||
|
||||
Contains the Base Station Identity Code. Valid range of values is 0-63.
|
||||
|
||||
byte BitErrorRate [optional, gsm]
|
||||
|
||||
Contains the bit error rate. Refer to <ber> in 27.007, Section 8.69
|
||||
for more details. Valid range of values is 0-7.
|
||||
|
||||
uint16 PrimaryScramblingCode [optional, umts]
|
||||
|
||||
Contains the scrambling code. Valid range of values is 0-512.
|
||||
|
||||
byte TimingAdvance [optional, gsm]
|
||||
|
||||
Contains the Timing Advance. Valid range of values is 0-219.
|
||||
|
||||
byte Strength [optional, gsm, umts, lte]
|
||||
|
||||
Contains the signal strength. Valid values are 0-31. Refer to <rssi>
|
||||
in 27.007, Section 8.5.
|
||||
|
||||
byte ReceivedSignalCodePower [optional, umts]
|
||||
|
||||
Contains the Received Signal Code Power. Valid range of values
|
||||
is 0-96. Refer to <rscp> in 27.007, Section 8.69 for more details.
|
||||
|
||||
byte ReceivedEnergyRatio [optional, umts]
|
||||
|
||||
Contains the Ratio of received energy per PN chip to the total
|
||||
received power spectral density. Valid range of values is 0-49.
|
||||
Refer to <ecno> in 27.007, Section 8.69 for more details.
|
||||
|
||||
byte ReferenceSignalReceivedQuality [optional, lte]
|
||||
|
||||
Contains the Reference Signal Received Quality. Valid range of
|
||||
values is 0-34. Refer to <rsrq> in 27.007, Section 8.69 for more
|
||||
details.
|
||||
|
||||
byte ReferenceSignalReceivedPower [optional, lte]
|
||||
|
||||
Contains the Reference Signal Received Power. Valid range of values
|
||||
is 0-97. Refer to <rsrp> in 27.007, Section 8.69 for more details.
|
||||
|
||||
uint16 EARFCN [optional, lte]
|
||||
|
||||
Contains E-UTRA Absolute Radio Frequency Channel Number. Valid
|
||||
range of values is 0-65535. Refer to Carrier frequency and
|
||||
EARFCN in 36.101, Section 5.7.3 for more details.
|
||||
|
||||
byte EBand [optional, lte]
|
||||
|
||||
Contains E-UTRA operating Band. Valid range of values is 1-43.
|
||||
Refer to Operating bands in 36.101, Section 5.5 for more
|
||||
details.
|
||||
|
||||
byte ChannelQualityIndicator [optional, lte]
|
||||
|
||||
Contains Channel Quality Indicator. Refer to Channel Quality
|
||||
Indicator definition in 36.213, Section 7.2.3 for more details.
|
||||
@@ -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'
|
||||
@@ -17,3 +17,30 @@ GPS:
|
||||
After setting the configuration, a power cycle is required.
|
||||
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
|
||||
can be checked using 'AT+CGMR'.
|
||||
|
||||
LE910 V2
|
||||
========
|
||||
|
||||
Default USB composition of LE910V2 uses PID 0x36 (AT#PORTCFG=0)
|
||||
and consists of 6 serial ports (CDC-ACM standard, /dev/ttyACMx)
|
||||
and 1 network adapter using CDC-NCM standard (wwanx or usbx).
|
||||
|
||||
NCM interface configuration follows Telit documentation
|
||||
(both documents available on Telit Download Zone - registration required)
|
||||
"GE/HE/UE910, UL865, LE910 V2 Linux USB Driver - User Guide r0"
|
||||
(document 1VV0301255 Rev.0 - 2016-01-22)
|
||||
and "Telit LE910-V2 NCM SETUP r3"
|
||||
(document 1VV0301246 Rev.3 - 2016-11-29).
|
||||
|
||||
After context is setup, NCM mode activated and PDP context activated
|
||||
connection configuration can be read using
|
||||
AT+CGPADDR=context_id and AT+CGCONTRDP=context_id commands.
|
||||
This is done automatically and results available via
|
||||
org.ofono.ConnectionContext.GetProperties DBus method.
|
||||
|
||||
Then Linux network interface needs to be configured:
|
||||
ifconfig <Interface> <Address> netmask <Netmask> up
|
||||
route add default gw <Gateway>
|
||||
arp -s <Gateway> 11:22:33:44:55:66
|
||||
|
||||
Only after these steps network interface is usable.
|
||||
|
||||
@@ -59,6 +59,27 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
object DialLast()
|
||||
|
||||
Initiates a new outgoing call to the last dialled number.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.InvalidFormat
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
object DialMemory(string memory position, string hide_callerid)
|
||||
|
||||
Initiates a new outgoing call to the number in the given memory
|
||||
position/favourite. For callerid see the Dial method.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.InvalidFormat
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
void Transfer()
|
||||
|
||||
Joins the currently Active (or Outgoing, depending
|
||||
|
||||
@@ -50,15 +50,14 @@ static int atmodem_init(void)
|
||||
at_call_volume_init();
|
||||
at_gprs_init();
|
||||
at_gprs_context_init();
|
||||
at_sim_auth_init();
|
||||
at_gnss_init();
|
||||
at_lte_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmodem_exit(void)
|
||||
{
|
||||
at_sim_auth_exit();
|
||||
at_stk_exit();
|
||||
at_sim_exit();
|
||||
at_sms_exit();
|
||||
@@ -76,6 +75,7 @@ static void atmodem_exit(void)
|
||||
at_gprs_exit();
|
||||
at_gprs_context_exit();
|
||||
at_gnss_exit();
|
||||
at_lte_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
||||
|
||||
@@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void);
|
||||
|
||||
extern void at_gnss_init(void);
|
||||
extern void at_gnss_exit(void);
|
||||
|
||||
extern void at_lte_init(void);
|
||||
extern void at_lte_exit(void);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gatchat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/log.h>
|
||||
@@ -614,3 +615,42 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req)
|
||||
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||
* of "a.b.c.d.m.m.m.m" for IPv4.
|
||||
* address/netmask must be able to hold
|
||||
* 255.255.255.255 + null = 16 characters
|
||||
*/
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask)
|
||||
{
|
||||
const char *s = addrnetmask;
|
||||
const char *net = NULL;
|
||||
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
/* Count 7 dots for ipv4, less or more means error. */
|
||||
for (i = 0; i < 9; i++, s++) {
|
||||
s = strchr(s, '.');
|
||||
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
if (i == 3) {
|
||||
/* set netmask ptr and break the string */
|
||||
net = s + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 7) {
|
||||
memcpy(address, addrnetmask, net - addrnetmask);
|
||||
address[net - addrnetmask - 1] = '\0';
|
||||
strcpy(netmask, net);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@ struct at_util_sim_state_query *at_util_sim_state_query_new(GAtChat *chat,
|
||||
GDestroyNotify destroy);
|
||||
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
||||
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask);
|
||||
|
||||
struct cb_data {
|
||||
void *cb;
|
||||
void *data;
|
||||
|
||||
@@ -43,10 +43,11 @@
|
||||
#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"
|
||||
|
||||
static const char *cgdata_prefix[] = { "+CGDATA:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
enum state {
|
||||
@@ -67,6 +68,7 @@ struct gprs_context_data {
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data; /* Callback data */
|
||||
unsigned int vendor;
|
||||
gboolean use_atd99;
|
||||
};
|
||||
|
||||
static void ppp_debug(const char *str, void *data)
|
||||
@@ -210,7 +212,7 @@ static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gcd->vendor == OFONO_VENDOR_SIMCOM_SIM900)
|
||||
if (gcd->use_atd99)
|
||||
sprintf(buf, "ATD*99***%u#", gcd->active_context);
|
||||
else
|
||||
sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
|
||||
@@ -247,6 +249,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
/* We only support CHAP and PAP */
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
|
||||
break;
|
||||
@@ -294,6 +298,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
* prefix, this is the least invasive place to set it.
|
||||
*/
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
snprintf(buf + len, sizeof(buf) - len - 3,
|
||||
",\"CHAP:%s\"", ctx->apn);
|
||||
@@ -378,6 +384,43 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
g_at_ppp_shutdown(gcd->ppp);
|
||||
}
|
||||
|
||||
static void at_cgdata_test_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
GAtResultIter iter;
|
||||
const char *data_type;
|
||||
gboolean found = FALSE;
|
||||
|
||||
gcd->use_atd99 = TRUE;
|
||||
|
||||
if (!ok) {
|
||||
DBG("not ok");
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
if (!g_at_result_iter_next(&iter, "+CGDATA:")) {
|
||||
DBG("no +CGDATA line");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!g_at_result_iter_open_list(&iter)) {
|
||||
DBG("no list found");
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (!found && g_at_result_iter_next_string(&iter, &data_type)) {
|
||||
if (g_str_equal(data_type, "PPP")) {
|
||||
found = TRUE;
|
||||
gcd->use_atd99 = FALSE;
|
||||
}
|
||||
}
|
||||
error:
|
||||
DBG("use_atd99:%d", gcd->use_atd99);
|
||||
}
|
||||
|
||||
static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
@@ -387,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;
|
||||
}
|
||||
@@ -405,6 +448,15 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
if (chat == NULL)
|
||||
return 0;
|
||||
|
||||
switch (vendor) {
|
||||
case OFONO_VENDOR_SIMCOM_SIM900:
|
||||
gcd->use_atd99 = FALSE;
|
||||
break;
|
||||
default:
|
||||
g_at_chat_send(chat, "AT+CGDATA=?", cgdata_prefix,
|
||||
at_cgdata_test_cb, gc, NULL);
|
||||
}
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -49,6 +49,9 @@ static const char *none_prefix[] = { NULL };
|
||||
struct gprs_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
unsigned int last_auto_context_id;
|
||||
gboolean telit_try_reattach;
|
||||
int attached;
|
||||
};
|
||||
|
||||
static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
@@ -72,8 +75,10 @@ static void at_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
|
||||
|
||||
if (g_at_chat_send(gd->chat, buf, none_prefix,
|
||||
at_cgatt_cb, cbd, g_free) > 0)
|
||||
at_cgatt_cb, cbd, g_free) > 0) {
|
||||
gd->attached = attached;
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
@@ -141,6 +146,48 @@ static void at_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void at_cgdcont_read_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
int activated_cid = gd->last_auto_context_id;
|
||||
const char *apn = NULL;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
ofono_warn("Can't read CGDCONT contexts.");
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CGDCONT:")) {
|
||||
int read_cid;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &read_cid))
|
||||
break;
|
||||
|
||||
if (read_cid != activated_cid)
|
||||
continue;
|
||||
|
||||
/* ignore protocol */
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
g_at_result_iter_next_string(&iter, &apn);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (apn)
|
||||
ofono_gprs_cid_activated(gprs, activated_cid, apn);
|
||||
else
|
||||
ofono_warn("cid %u: Received activated but no apn present",
|
||||
activated_cid);
|
||||
}
|
||||
|
||||
static void cgreg_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -151,12 +198,35 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
|
||||
NULL, NULL, NULL, gd->vendor) == FALSE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Telit AT modem firmware (tested with UE910-EUR) generates
|
||||
* +CGREG: 0\r\n\r\n+CGEV: NW DETACH
|
||||
* after a context is de-activated and ppp connection closed.
|
||||
* Then, after a random amount of time (observed from a few seconds
|
||||
* to a few hours), an unsolicited +CGREG: 1 arrives.
|
||||
* Attempt to fix the problem, by sending AT+CGATT=1 once.
|
||||
* This does not re-activate the context, but if a network connection
|
||||
* is still correct, will generate an immediate +CGREG: 1.
|
||||
*/
|
||||
if (gd->vendor == OFONO_VENDOR_TELIT) {
|
||||
if (gd->attached && !status && !gd->telit_try_reattach) {
|
||||
DBG("Trying to re-attach gprs network");
|
||||
gd->telit_try_reattach = TRUE;
|
||||
g_at_chat_send(gd->chat, "AT+CGATT=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
gd->telit_try_reattach = FALSE;
|
||||
}
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
|
||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
GAtResultIter iter;
|
||||
const char *event;
|
||||
|
||||
@@ -170,8 +240,18 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
if (g_str_equal(event, "NW DETACH") ||
|
||||
g_str_equal(event, "ME DETACH")) {
|
||||
if (gd->vendor == OFONO_VENDOR_TELIT &&
|
||||
gd->telit_try_reattach)
|
||||
return;
|
||||
|
||||
gd->attached = FALSE;
|
||||
ofono_gprs_detached_notify(gprs);
|
||||
return;
|
||||
} else if (g_str_has_prefix(event, "ME PDN ACT")) {
|
||||
sscanf(event, "%*s %*s %*s %u", &gd->last_auto_context_id);
|
||||
|
||||
g_at_chat_send(gd->chat, "AT+CGDCONT?", cgdcont_prefix,
|
||||
at_cgdcont_read_cb, gprs, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,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;
|
||||
@@ -274,6 +374,9 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||
case 3:
|
||||
bearer = 5; /* HSDPA */
|
||||
break;
|
||||
case 4:
|
||||
bearer = 7; /* LTE */
|
||||
break;
|
||||
default:
|
||||
bearer = 0;
|
||||
break;
|
||||
@@ -303,10 +406,6 @@ static void ublox_ureg_notify(GAtResult *result, gpointer user_data)
|
||||
case 5:
|
||||
bearer = 4;
|
||||
break;
|
||||
case 7:
|
||||
/* XXX: reserved - assume none. */
|
||||
bearer = 0;
|
||||
break;
|
||||
case 8:
|
||||
bearer = 1;
|
||||
break;
|
||||
@@ -353,8 +452,11 @@ 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:
|
||||
g_at_chat_register(gd->chat, "+UREG:", ublox_ureg_notify,
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_send(gd->chat, "AT+UREG=1", none_prefix,
|
||||
@@ -365,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);
|
||||
@@ -476,7 +579,7 @@ static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
|
||||
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
|
||||
continue;
|
||||
|
||||
if (!g_at_result_iter_close_list(&iter))
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
continue;
|
||||
|
||||
if (g_at_result_iter_open_list(&iter))
|
||||
|
||||
142
ofono/drivers/atmodem/lte.c
Normal file
142
ofono/drivers/atmodem/lte.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
struct lte_driver_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("LTE config with APN: %s", info->apn);
|
||||
|
||||
if (strlen(info->apn) > 0)
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"",
|
||||
info->apn);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\"");
|
||||
|
||||
/* We can't do much in case of failure so don't check response. */
|
||||
if (g_at_chat_send(ldd->chat, buf, NULL,
|
||||
at_lte_set_default_attach_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static gboolean lte_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
|
||||
ofono_lte_register(lte);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct lte_driver_data *ldd;
|
||||
|
||||
DBG("at lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_driver_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ldd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
g_idle_add(lte_delayed_register, lte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("at lte remove");
|
||||
|
||||
g_at_chat_unref(ldd->chat);
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "atmodem",
|
||||
.probe = at_lte_probe,
|
||||
.remove = at_lte_remove,
|
||||
.set_default_attach_info = at_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void at_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void at_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -1088,6 +1088,27 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
GAtResultIter iter;
|
||||
const char *mode;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!strcmp("LTE", mode))
|
||||
nd->tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
|
||||
/* for other technologies, notification ^MODE is used */
|
||||
}
|
||||
|
||||
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
@@ -1580,17 +1601,28 @@ static inline ofono_bool_t append_cmer_element(char *buf, int *len, int cap,
|
||||
static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
struct netreg_data *nd)
|
||||
{
|
||||
const char *mode;
|
||||
const char *ind;
|
||||
int len = sprintf(buf, "AT+CMER=");
|
||||
const char *mode;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (nd->vendor) {
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
/* UBX-13002752 R33: TOBY L2 doesn't support mode 2 and 3 */
|
||||
mode = "1";
|
||||
break;
|
||||
default:
|
||||
mode = "3";
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward unsolicited result codes directly to the TE;
|
||||
* TA‑TE link specific inband technique used to embed result codes and
|
||||
* data when TA is in on‑line data mode
|
||||
*/
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], "3", FALSE))
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], mode, FALSE))
|
||||
return FALSE;
|
||||
|
||||
/* No keypad event reporting */
|
||||
@@ -1607,14 +1639,14 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
* Telit does not support mode 1.
|
||||
* All indicator events shall be directed from TA to TE.
|
||||
*/
|
||||
mode = "2";
|
||||
ind = "2";
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Only those indicator events, which are not caused by +CIND
|
||||
* shall be indicated by the TA to the TE.
|
||||
*/
|
||||
mode = "1";
|
||||
ind = "1";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1623,7 +1655,7 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
* <ind> indicates the indicator order number (as specified for +CIND)
|
||||
* and <value> is the new value of indicator.
|
||||
*/
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[3], mode, TRUE))
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[3], ind, TRUE))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
@@ -1885,6 +1917,10 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for 4G system mode reports */
|
||||
g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for network time reports */
|
||||
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/sim-auth.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
#include "simutil.h"
|
||||
#include "vendor.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
struct sim_auth_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
};
|
||||
|
||||
static const char *cuad_prefix[] = { "+CUAD:", NULL };
|
||||
|
||||
static void at_discover_apps_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
GAtResultIter iter;
|
||||
ofono_sim_list_apps_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
const unsigned char *dataobj;
|
||||
gint linelen;
|
||||
unsigned char *buffer;
|
||||
int len;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, NULL, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
len = 0;
|
||||
while (g_at_result_iter_next(&iter, "+CUAD:")) {
|
||||
if (!g_at_result_iter_next_hexstring(&iter, NULL, &linelen))
|
||||
goto error;
|
||||
|
||||
len += linelen;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
buffer = g_malloc(len);
|
||||
len = 0;
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CUAD:")) {
|
||||
g_at_result_iter_next_hexstring(&iter, &dataobj, &linelen);
|
||||
memcpy(buffer + len, dataobj, linelen);
|
||||
len += linelen;
|
||||
}
|
||||
|
||||
cb(&error, buffer, len, cbd->data);
|
||||
|
||||
g_free(buffer);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
||||
}
|
||||
|
||||
static void at_discover_apps(struct ofono_sim_auth *sa,
|
||||
ofono_sim_list_apps_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct sim_auth_data *sad = ofono_sim_auth_get_data(sa);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(sad->chat, "AT+CUAD", cuad_prefix,
|
||||
at_discover_apps_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
||||
}
|
||||
|
||||
static gboolean at_sim_auth_register(gpointer user)
|
||||
{
|
||||
struct ofono_sim_auth *sa = user;
|
||||
|
||||
ofono_sim_auth_register(sa);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_sim_auth_probe(struct ofono_sim_auth *sa, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct sim_auth_data *sad;
|
||||
|
||||
sad = g_new0(struct sim_auth_data, 1);
|
||||
sad->chat = g_at_chat_clone(chat);
|
||||
sad->vendor = vendor;
|
||||
|
||||
ofono_sim_auth_set_data(sa, sad);
|
||||
g_idle_add(at_sim_auth_register, sa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at_sim_auth_remove(struct ofono_sim_auth *sa)
|
||||
{
|
||||
struct sim_auth_data *sad = ofono_sim_auth_get_data(sa);
|
||||
|
||||
g_idle_remove_by_data(sa);
|
||||
ofono_sim_auth_set_data(sa, NULL);
|
||||
|
||||
g_at_chat_unref(sad->chat);
|
||||
g_free(sad);
|
||||
}
|
||||
|
||||
static struct ofono_sim_auth_driver driver = {
|
||||
.name = "atmodem",
|
||||
.probe = at_sim_auth_probe,
|
||||
.remove = at_sim_auth_remove,
|
||||
.list_apps = at_discover_apps,
|
||||
};
|
||||
|
||||
void at_sim_auth_init(void)
|
||||
{
|
||||
ofono_sim_auth_driver_register(&driver);
|
||||
}
|
||||
|
||||
void at_sim_auth_exit(void)
|
||||
{
|
||||
ofono_sim_auth_driver_unregister(&driver);
|
||||
}
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "gatresult.h"
|
||||
#include "simutil.h"
|
||||
#include "vendor.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
@@ -50,7 +51,7 @@
|
||||
struct sim_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
guint ready_id;
|
||||
guint passwd_type_mask;
|
||||
struct at_util_sim_state_query *sim_state_query;
|
||||
};
|
||||
|
||||
@@ -64,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;
|
||||
@@ -93,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);
|
||||
@@ -134,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,
|
||||
@@ -175,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)
|
||||
@@ -257,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)
|
||||
@@ -287,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;
|
||||
@@ -836,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;
|
||||
@@ -1053,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)
|
||||
@@ -1100,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:
|
||||
@@ -1120,10 +1173,16 @@ static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
|
||||
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)
|
||||
@@ -1214,99 +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;
|
||||
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, cbd->data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->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;
|
||||
|
||||
@@ -1316,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:
|
||||
@@ -1363,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,
|
||||
@@ -1382,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));
|
||||
|
||||
@@ -1457,9 +1408,8 @@ static void at_pin_enable(struct ofono_sim *sim,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
int ret;
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
||||
@@ -1488,10 +1438,8 @@ static void at_change_passwd(struct ofono_sim *sim,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
int ret;
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len ||
|
||||
at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
||||
@@ -1548,9 +1496,8 @@ static void at_query_clck(struct ofono_sim *sim,
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
||||
@@ -1566,13 +1513,363 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static gboolean at_sim_register(gpointer user)
|
||||
static void at_clck_query_cb(gboolean ok, GAtResult *result, gpointer user)
|
||||
{
|
||||
struct ofono_sim *sim = user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
GAtResultIter iter;
|
||||
const char *fac;
|
||||
|
||||
if (!ok)
|
||||
goto done;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
/* e.g. +CLCK: ("SC","FD","PN","PU","PP","PC","PF") */
|
||||
if (!g_at_result_iter_next(&iter, "+CLCK:") ||
|
||||
!g_at_result_iter_open_list(&iter))
|
||||
goto done;
|
||||
|
||||
/* Clear the default mask */
|
||||
sd->passwd_type_mask = 0;
|
||||
|
||||
/* Set the bits for <fac>s that are actually supported */
|
||||
while (g_at_result_iter_next_string(&iter, &fac)) {
|
||||
unsigned int i;
|
||||
|
||||
/* Find it in the list of known <fac>s */
|
||||
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++) {
|
||||
if (!g_strcmp0(at_clck_cpwd_fac[i], fac)) {
|
||||
sd->passwd_type_mask |= (1 << i);
|
||||
DBG("found %s", fac);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ofono_sim_register(sim);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
static 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,
|
||||
@@ -1580,18 +1877,22 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct sim_data *sd;
|
||||
unsigned int i;
|
||||
|
||||
sd = g_new0(struct sim_data, 1);
|
||||
sd->chat = g_at_chat_clone(chat);
|
||||
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);
|
||||
g_idle_add(at_sim_register, sim);
|
||||
|
||||
return 0;
|
||||
/* <fac>s supported by default */
|
||||
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++)
|
||||
if (at_clck_cpwd_fac[i])
|
||||
sd->passwd_type_mask |= (1 << i);
|
||||
|
||||
/* Query supported <fac>s */
|
||||
return g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
|
||||
at_clck_query_cb, sim, NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
static void at_sim_remove(struct ofono_sim *sim)
|
||||
@@ -1627,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 = {
|
||||
|
||||
@@ -319,26 +319,6 @@ static void at_cnma_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
"Further SMS reception is not guaranteed");
|
||||
}
|
||||
|
||||
static gboolean at_parse_cmt(GAtResult *result, const char **pdu, int *pdulen)
|
||||
{
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, pdulen))
|
||||
return FALSE;
|
||||
|
||||
*pdu = g_at_result_pdu(result);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||
{
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
@@ -347,11 +327,21 @@ static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||
DBG("");
|
||||
|
||||
/* We must acknowledge the PDU using CNMA */
|
||||
if (data->cnma_ack_pdu)
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
||||
data->cnma_ack_pdu_len, data->cnma_ack_pdu);
|
||||
else /* Should be a safe fallback */
|
||||
if (data->cnma_ack_pdu) {
|
||||
switch (data->vendor) {
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1");
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
||||
data->cnma_ack_pdu_len,
|
||||
data->cnma_ack_pdu);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Should be a safe fallback */
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=0");
|
||||
}
|
||||
|
||||
g_at_chat_send(data->chat, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
||||
}
|
||||
@@ -409,16 +399,34 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_sms *sms = user_data;
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
GAtResultIter iter;
|
||||
const char *hexpdu;
|
||||
unsigned char pdu[176];
|
||||
long pdu_len;
|
||||
int tpdu_len;
|
||||
unsigned char pdu[176];
|
||||
|
||||
if (!at_parse_cmt(result, &hexpdu, &tpdu_len)) {
|
||||
ofono_error("Unable to parse CMT notification");
|
||||
return;
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
||||
goto err;
|
||||
|
||||
switch (data->vendor) {
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||
goto err;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
hexpdu = g_at_result_pdu(result);
|
||||
|
||||
if (strlen(hexpdu) > sizeof(pdu) * 2) {
|
||||
ofono_error("Bad PDU length in CMT notification");
|
||||
return;
|
||||
@@ -431,6 +439,9 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
if (data->vendor != OFONO_VENDOR_SIMCOM)
|
||||
at_ack_delivery(sms);
|
||||
|
||||
err:
|
||||
ofono_error("Unable to parse CMT notification");
|
||||
}
|
||||
|
||||
static void at_cmgr_notify(GAtResult *result, gpointer user_data)
|
||||
@@ -742,7 +753,7 @@ static void at_sms_initialized(struct ofono_sms *sms)
|
||||
|
||||
static void at_sms_not_supported(struct ofono_sms *sms)
|
||||
{
|
||||
ofono_error("SMS not supported by this modem. If this is in error"
|
||||
ofono_error("SMS not supported by this modem. If this is an error"
|
||||
" please submit patches to support this hardware");
|
||||
|
||||
ofono_sms_remove(sms);
|
||||
|
||||
@@ -45,5 +45,7 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_ALCATEL,
|
||||
OFONO_VENDOR_QUECTEL,
|
||||
OFONO_VENDOR_UBLOX,
|
||||
OFONO_VENDOR_UBLOX_TOBY_L2,
|
||||
OFONO_VENDOR_CINTERION,
|
||||
OFONO_VENDOR_XMM,
|
||||
};
|
||||
|
||||
@@ -253,8 +253,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
|
||||
@@ -1147,8 +1146,7 @@ static void at_voicecall_remove(struct ofono_voicecall *vc)
|
||||
if (vd->vts_source)
|
||||
g_source_remove(vd->vts_source);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* RIL library with GLib integration
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012-2013 Canonical Ltd.
|
||||
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,38 +19,31 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GRILREPLY_H
|
||||
#define __GRILREPLY_H
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <gatchat.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/types.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "gemaltomodem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
static int gemaltomodem_init(void)
|
||||
{
|
||||
gemalto_location_reporting_init();
|
||||
|
||||
struct reply_setup_data_call {
|
||||
guint version;
|
||||
guint status;
|
||||
gint cid;
|
||||
guint retry_time;
|
||||
guint active;
|
||||
guint protocol;
|
||||
gchar *ifname;
|
||||
gchar **dns_addresses;
|
||||
gchar **gateways;
|
||||
gchar **ip_addrs;
|
||||
};
|
||||
|
||||
void g_ril_reply_free_setup_data_call(struct reply_setup_data_call *reply);
|
||||
|
||||
struct reply_setup_data_call *g_ril_reply_parse_data_call(GRil *gril,
|
||||
struct ril_msg *message,
|
||||
struct ofono_error *error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GRILREPLY_H */
|
||||
static void gemaltomodem_exit(void)
|
||||
{
|
||||
gemalto_location_reporting_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
gemaltomodem_init, gemaltomodem_exit)
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -19,11 +19,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
extern void gemalto_location_reporting_init();
|
||||
extern void gemalto_location_reporting_exit();
|
||||
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
#include "gattty.h"
|
||||
|
||||
#include "gemaltomodem.h"
|
||||
|
||||
static const char *sgpsc_prefix[] = { "^SGPSC:", NULL };
|
||||
|
||||
struct gps_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void gemalto_gps_disable_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_location_reporting *lr = cbd->user;
|
||||
ofono_location_reporting_disable_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("lr=%p, ok=%d", lr, ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_disable(
|
||||
struct ofono_location_reporting *lr,
|
||||
ofono_location_reporting_disable_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("lr=%p", lr);
|
||||
|
||||
cbd->user = lr;
|
||||
|
||||
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",0", sgpsc_prefix,
|
||||
gemalto_gps_disable_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static int enable_data_stream(struct ofono_location_reporting *lr)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
const char *gps_dev;
|
||||
GHashTable *options;
|
||||
GIOChannel *channel;
|
||||
int fd;
|
||||
|
||||
modem = ofono_location_reporting_get_modem(lr);
|
||||
gps_dev = ofono_modem_get_string(modem, "GPS");
|
||||
|
||||
options = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
if (options == NULL)
|
||||
return -1;
|
||||
|
||||
g_hash_table_insert(options, "Baud", "115200");
|
||||
|
||||
channel = g_at_tty_open(gps_dev, options);
|
||||
|
||||
g_hash_table_destroy(options);
|
||||
|
||||
if (channel == NULL)
|
||||
return -1;
|
||||
|
||||
fd = g_io_channel_unix_get_fd(channel);
|
||||
|
||||
g_io_channel_set_close_on_unref(channel, FALSE);
|
||||
g_io_channel_unref(channel);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void gemalto_sgpsc_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_location_reporting_enable_cb_t cb = cbd->cb;
|
||||
struct ofono_location_reporting *lr = cbd->user;
|
||||
struct ofono_error error;
|
||||
int fd;
|
||||
|
||||
DBG("lr=%p ok=%d", lr, ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fd = enable_data_stream(lr);
|
||||
|
||||
if (fd < 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cb(&error, fd, cbd->data);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_enable(struct ofono_location_reporting *lr,
|
||||
ofono_location_reporting_enable_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("lr=%p", lr);
|
||||
|
||||
cbd->user = lr;
|
||||
|
||||
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",2", sgpsc_prefix,
|
||||
gemalto_sgpsc_cb, cbd, NULL) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_support_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_location_reporting *lr = user_data;
|
||||
|
||||
if (!ok) {
|
||||
ofono_location_reporting_remove(lr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_location_reporting_register(lr);
|
||||
}
|
||||
|
||||
static int gemalto_location_reporting_probe(struct ofono_location_reporting *lr,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct gps_data *gd;
|
||||
|
||||
gd = g_try_new0(struct gps_data, 1);
|
||||
if (gd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_location_reporting_set_data(lr, gd);
|
||||
|
||||
g_at_chat_send(gd->chat, "AT^SGPSC=?", sgpsc_prefix,
|
||||
gemalto_location_reporting_support_cb,
|
||||
lr, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_remove(struct ofono_location_reporting *lr)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
|
||||
ofono_location_reporting_set_data(lr, NULL);
|
||||
|
||||
g_at_chat_unref(gd->chat);
|
||||
g_free(gd);
|
||||
}
|
||||
|
||||
static struct ofono_location_reporting_driver driver = {
|
||||
.name = "gemaltomodem",
|
||||
.type = OFONO_LOCATION_REPORTING_TYPE_NMEA,
|
||||
.probe = gemalto_location_reporting_probe,
|
||||
.remove = gemalto_location_reporting_remove,
|
||||
.enable = gemalto_location_reporting_enable,
|
||||
.disable = gemalto_location_reporting_disable,
|
||||
};
|
||||
|
||||
void gemalto_location_reporting_init()
|
||||
{
|
||||
ofono_location_reporting_driver_register(&driver);
|
||||
}
|
||||
|
||||
void gemalto_location_reporting_exit()
|
||||
{
|
||||
ofono_location_reporting_driver_unregister(&driver);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -286,8 +287,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
|
||||
@@ -405,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)
|
||||
@@ -709,6 +748,15 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
|
||||
int num_type, validity;
|
||||
struct ofono_call *call;
|
||||
|
||||
/* Waiting call notification makes no sense, when there are
|
||||
* no calls at all. This can happen when a phone already has
|
||||
* waiting and active calls and is being connected over HFP
|
||||
* but it first sends +CCWA before we manage to synchronize
|
||||
* calls with AT+CLCC.
|
||||
*/
|
||||
if (!vd->calls)
|
||||
return;
|
||||
|
||||
/* CCWA can repeat, ignore if we already have an waiting call */
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_WAITING),
|
||||
@@ -1110,6 +1158,17 @@ static void ciev_callheld_notify(struct ofono_voicecall *vc,
|
||||
*/
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
||||
poll_clcc, vc);
|
||||
} else {
|
||||
if (vd->clcc_source)
|
||||
g_source_remove(vd->clcc_source);
|
||||
|
||||
/*
|
||||
* We got a notification that there is a held call
|
||||
* and no active call but we already are in such state.
|
||||
* Let's schedule a poll to see what happened.
|
||||
*/
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
||||
poll_clcc, vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,8 +1295,7 @@ static void hfp_voicecall_remove(struct ofono_voicecall *vc)
|
||||
if (vd->expect_release_source)
|
||||
g_source_remove(vd->expect_release_source);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
|
||||
@@ -1250,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,
|
||||
|
||||
@@ -80,7 +80,7 @@ static gboolean get_next_addr(GAtResultIter *iter, char **addr)
|
||||
if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
|
||||
return FALSE;
|
||||
|
||||
val = strtol(str, NULL, 16);
|
||||
val = strtoul(str, NULL, 16);
|
||||
|
||||
if (addr)
|
||||
*addr = g_strdup_printf("%u.%u.%u.%u",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1009,8 +1009,7 @@ static void ifx_voicecall_remove(struct ofono_voicecall *vc)
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
g_strfreev(vd->en_list);
|
||||
|
||||
|
||||
77
ofono/drivers/infineonmodem/infineon_constants.h
Normal file
77
ofono/drivers/infineonmodem/infineon_constants.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
*
|
||||
* RIL constants for infineon modem
|
||||
*
|
||||
* Copyright (C) 2014 Canonical 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INFINEON_CONSTANTS_H
|
||||
#define INFINEON_CONSTANTS_H
|
||||
|
||||
/* Messages encapsulated in RIL_REQUEST_OEM_HOOK_RAW requests */
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_SELECT_BAND 1
|
||||
#define INF_RIL_REQUEST_OEM_SET_SELECT_BAND 2
|
||||
#define INF_RIL_REQUEST_OEM_SET_CIRCUIT_SWITCHING_PAGING 3
|
||||
#define INF_RIL_REQUEST_OEM_GET_LAST_FAILURE_REPORT_FOR_CS_REGISTRATION 4
|
||||
#define INF_RIL_REQUEST_OEM_GET_SELECT_BEARER_SERVICE_TYPE 5
|
||||
#define INF_RIL_REQUEST_OEM_GET_XPROGRESS_STATUS 6
|
||||
#define INF_RIL_REQUEST_OEM_SET_SS_NOTIFY 7
|
||||
#define INF_RIL_REQUEST_OEM_GET_SS_NOTIFY 8
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTHENTICATION_TYPE 9
|
||||
#define INF_RIL_REQUEST_OEM_SWITCH_OFF_MS 10
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_TIMEZONE_UPDATE 11
|
||||
#define INF_RIL_REQUEST_OEM_SET_TIMEZONE_RESPORTING 12
|
||||
#define INF_RIL_REQUEST_OEM_SET_DISPLAY_SIM_AND_PB_STATUS 13
|
||||
#define INF_RIL_REQUEST_OEM_GET_REMAIN_SIM_PIN_ATTEMPTS 14
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_REDIAL 15
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_CALL_STATUS_REPORTING 16
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_ANSWER 17
|
||||
#define INF_RIL_REQUEST_OEM_SET_LINE 18
|
||||
#define INF_RIL_REQUEST_OEM_PDP_ACTIVATE_OR_DEACTIVATE 19
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_GPRS_MS_CLASS 20
|
||||
#define INF_RIL_REQUEST_OEM_SET_TRACE_AND_AT_INTERFACES 21
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_TRACE_AND_AT_INTERFACES_CONFIGURE 22
|
||||
#define INF_RIL_REQUEST_OEM_SWITCH_TRACE_ON_OR_OFF 23
|
||||
#define INF_RIL_REQUEST_OEM_READ_EXCEPTION_LOG 24
|
||||
#define INF_RIL_REQUEST_OEM_GET_PHONE_ACTIVITY_STATUS 25
|
||||
#define INF_RIL_REQUEST_OEM_INITIATE_RESEND_SMS_IF_GPRS_FAILS 26
|
||||
#define INF_RIL_REQUEST_OEM_GET_DEVICE_NUMBER 27
|
||||
#define INF_RIL_REQUEST_OEM_ENABLE_STK 28
|
||||
#define INF_RIL_REQUEST_OEM_GET_SUBSCRIBER_NUMBER 29
|
||||
#define INF_RIL_REQUEST_OEM_SELECT_PHONE_BOOK 30
|
||||
#define INF_RIL_REQUEST_OEM_READ_PHONE_BOOK 31
|
||||
#define INF_RIL_REQUEST_OEM_INSERT_RECORD_TO_PHONE_BOOK 32
|
||||
#define INF_RIL_REQUEST_OEM_DELECT_RECORD_IN_PHONE_BOOK 33
|
||||
#define INF_RIL_REQUEST_OEM_GET_RECORD_FIELDS_MAX_LEN 34
|
||||
#define INF_RIL_REQUEST_OEM_SET_SERIAL_PORT 35
|
||||
#define INF_RIL_REQUEST_OEM_SET_DATA_PREFERED 36
|
||||
#define INF_RIL_REQUEST_OEM_SET_MODEM_ROUTING 37
|
||||
#define INF_RIL_REQUEST_OEM_CLEAR_MISS_NUMBER 38
|
||||
#define INF_RIL_REQUEST_OEM_ATH 39
|
||||
#define INF_RIL_REQUEST_OEM_NOSIG_MODE_TEST 40
|
||||
#define INF_RIL_REQUEST_OEM_SELECT_3G_BAND 41
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_3G_BAND 42
|
||||
#define INF_RIL_REQUEST_OEM_HW_RESET_MODEM 43
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_DIRECT 44
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_QUERY 45
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_SET 46
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_DELTE 47
|
||||
#define INF_RIL_REQUEST_OEM_SET_USB_LOG 48
|
||||
#define INF_RIL_REQUEST_OEM_UPDATE_CSQ 49
|
||||
#define INF_RIL_REQUEST_OEM_DUMP_CELL_ENV 50
|
||||
|
||||
#endif /* INFINEON_CONSTANTS_H */
|
||||
@@ -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,
|
||||
|
||||
@@ -1715,7 +1715,7 @@ static void isi_release_specific(struct ofono_voicecall *ovc, int id,
|
||||
|
||||
if ((status->mode_info & CALL_MODE_ORIGINATOR))
|
||||
cause = CALL_CAUSE_BUSY_USER_REQUEST;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
isi_call_release_req(ovc, id, CALL_CAUSE_TYPE_CLIENT, cause, cb, data);
|
||||
|
||||
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);
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/devinfo.h>
|
||||
@@ -125,7 +127,8 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
|
||||
}
|
||||
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
|
||||
if (!str) {
|
||||
/* Telit qmi modems return a "0" string when ESN is not available. */
|
||||
if (!str || strcmp(str, "0") == 0) {
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
@@ -24,18 +24,22 @@
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "wda.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_context_data {
|
||||
struct qmi_service *wds;
|
||||
struct qmi_service *wda;
|
||||
struct qmi_device *dev;
|
||||
unsigned int active_context;
|
||||
uint32_t pkt_handle;
|
||||
};
|
||||
@@ -61,8 +65,12 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
|
||||
|
||||
switch (status->status) {
|
||||
case QMI_WDS_CONN_STATUS_DISCONNECTED:
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
data->active_context = 0;
|
||||
if (data->pkt_handle) {
|
||||
/* The context has been disconnected by the network */
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
data->pkt_handle = 0;
|
||||
data->active_context = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -75,18 +83,68 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
|
||||
struct ofono_modem *modem;
|
||||
const char *interface;
|
||||
uint8_t pdp_type, ip_family;
|
||||
uint32_t ip_addr;
|
||||
struct in_addr addr;
|
||||
char* straddr;
|
||||
char* apn;
|
||||
const char *dns[3] = { NULL, NULL, NULL };
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
|
||||
apn = qmi_result_get_string(result, QMI_WDS_RESULT_APN);
|
||||
if (apn) {
|
||||
DBG("APN: %s", apn);
|
||||
g_free(apn);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_PDP_TYPE, &pdp_type))
|
||||
DBG("PDP type %d", pdp_type);
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
|
||||
DBG("IP family %d", ip_family);
|
||||
|
||||
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_IP_ADDRESS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("IP addr: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_address(gc, straddr, 1);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_GATEWAY, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("Gateway: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, straddr);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_GATEWAY_NETMASK, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("Gateway netmask: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, straddr);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_PRIMARY_DNS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
dns[0] = inet_ntoa(addr);
|
||||
DBG("Primary DNS: %s", dns[0]);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_SECONDARY_DNS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
dns[1] = inet_ntoa(addr);
|
||||
DBG("Secondary DNS: %s", dns[1]);
|
||||
}
|
||||
|
||||
if (dns[0])
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
done:
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
@@ -94,8 +152,6 @@ done:
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
@@ -120,8 +176,12 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
data->pkt_handle = handle;
|
||||
|
||||
/* Duplicate cbd, the old one will be freed when this method returns */
|
||||
cbd = cb_data_new(cb, cbd->data);
|
||||
cbd->user = gc;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_GET_SETTINGS, NULL,
|
||||
get_settings_cb, cbd, NULL) > 0)
|
||||
get_settings_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
@@ -131,12 +191,39 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
data->active_context = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gets called for "automatic" contexts, those which are
|
||||
* not activated via activate_primary. For these, we will still need
|
||||
* to call start_net in order to get the packet handle for the context.
|
||||
* The process for automatic contexts is essentially identical to that
|
||||
* for others.
|
||||
*/
|
||||
static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("cid %u", cid);
|
||||
|
||||
data->active_context = cid;
|
||||
|
||||
cbd->user = gc;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_START_NET, NULL,
|
||||
start_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
data->active_context = 0;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
@@ -151,6 +238,7 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct qmi_param *param;
|
||||
uint8_t ip_family;
|
||||
uint8_t auth;
|
||||
|
||||
DBG("cid %u", ctx->cid);
|
||||
|
||||
@@ -178,8 +266,31 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
|
||||
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = QMI_WDS_AUTHENTICATION_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = QMI_WDS_AUTHENTICATION_PAP;
|
||||
break;
|
||||
default:
|
||||
auth = QMI_WDS_AUTHENTICATION_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
qmi_param_append_uint8(param, QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE,
|
||||
auth);
|
||||
|
||||
if (ctx->username[0] != '\0')
|
||||
qmi_param_append(param, QMI_WDS_PARAM_USERNAME,
|
||||
strlen(ctx->username), ctx->username);
|
||||
|
||||
if (ctx->password[0] != '\0')
|
||||
qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
|
||||
strlen(ctx->password), ctx->password);
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_START_NET, param,
|
||||
start_net_cb, cbd, NULL) > 0)
|
||||
start_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
@@ -202,17 +313,19 @@ static void stop_net_cb(struct qmi_result *result, void *user_data)
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
data->active_context = 0;
|
||||
|
||||
data->pkt_handle = 0;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
|
||||
g_free(cbd);
|
||||
data->active_context = 0;
|
||||
}
|
||||
|
||||
static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
@@ -233,17 +346,26 @@ static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_STOP_NET, param,
|
||||
stop_net_cb, cbd, NULL) > 0)
|
||||
stop_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
qmi_deactivate_primary(gc, cid, NULL, NULL);
|
||||
}
|
||||
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
@@ -263,6 +385,69 @@ static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
pkt_status_notify, gc, NULL);
|
||||
}
|
||||
|
||||
static void get_data_format_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
uint32_t llproto;
|
||||
enum qmi_device_expected_data_format expected_llproto;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
|
||||
if (!qmi_result_get_uint32(result, QMI_WDA_LL_PROTOCOL, &llproto))
|
||||
goto done;
|
||||
|
||||
expected_llproto = qmi_device_get_expected_data_format(data->dev);
|
||||
|
||||
if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_802_3) &&
|
||||
(expected_llproto ==
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP)) {
|
||||
if (!qmi_device_set_expected_data_format(data->dev,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3))
|
||||
DBG("Fail to set expected data to 802.3");
|
||||
else
|
||||
DBG("expected data set to 802.3");
|
||||
} else if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP) &&
|
||||
(expected_llproto ==
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3)) {
|
||||
if (!qmi_device_set_expected_data_format(data->dev,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP))
|
||||
DBG("Fail to set expected data to raw-ip");
|
||||
else
|
||||
DBG("expected data set to raw-ip");
|
||||
}
|
||||
|
||||
done:
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void create_wda_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
DBG("Failed to request WDA service, continue initialization");
|
||||
goto error;
|
||||
}
|
||||
|
||||
data->wda = qmi_service_ref(service);
|
||||
|
||||
if (qmi_service_send(data->wda, QMI_WDA_GET_DATA_FORMAT, NULL,
|
||||
get_data_format_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
@@ -274,8 +459,9 @@ static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
data = g_new0(struct gprs_context_data, 1);
|
||||
|
||||
ofono_gprs_context_set_data(gc, data);
|
||||
data->dev = device;
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_WDS, create_wds_cb, gc, NULL);
|
||||
qmi_service_create(device, QMI_SERVICE_WDA, create_wda_cb, gc, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -288,9 +474,15 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->wds);
|
||||
if (data->wds) {
|
||||
qmi_service_unregister_all(data->wds);
|
||||
qmi_service_unref(data->wds);
|
||||
}
|
||||
|
||||
qmi_service_unref(data->wds);
|
||||
if (data->wda) {
|
||||
qmi_service_unregister_all(data->wda);
|
||||
qmi_service_unref(data->wda);
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
@@ -301,6 +493,8 @@ static struct ofono_gprs_context_driver driver = {
|
||||
.remove = qmi_gprs_context_remove,
|
||||
.activate_primary = qmi_activate_primary,
|
||||
.deactivate_primary = qmi_deactivate_primary,
|
||||
.read_settings = qmi_gprs_read_settings,
|
||||
.detach_shutdown = qmi_gprs_context_detach_shutdown,
|
||||
};
|
||||
|
||||
void qmi_gprs_context_init(void)
|
||||
|
||||
@@ -29,17 +29,23 @@
|
||||
|
||||
#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)
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
{
|
||||
const struct qmi_nas_serving_system *ss;
|
||||
uint16_t len;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
@@ -47,14 +53,165 @@ static bool extract_ss_info(struct qmi_result *result, int *status)
|
||||
if (!ss)
|
||||
return false;
|
||||
|
||||
if (ss->ps_state == QMI_NAS_ATTACH_STATUS_ATTACHED)
|
||||
*status = 0x01;
|
||||
if (ss->ps_state == QMI_NAS_ATTACH_STATE_ATTACHED)
|
||||
*status = NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
else
|
||||
*status = 0x00;
|
||||
*status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
|
||||
*tech = -1;
|
||||
for (i = 0; i < ss->radio_if_count; i++) {
|
||||
DBG("radio in use %d", ss->radio_if[i]);
|
||||
|
||||
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static 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;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!extract_ss_info(result, &status, &tech))
|
||||
return -1;
|
||||
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED) {
|
||||
if (tech == ACCESS_TECHNOLOGY_EUTRAN) {
|
||||
/* On LTE we are effectively always attached; and
|
||||
* the default bearer is established as soon as the
|
||||
* network is joined. We just need to query the
|
||||
* parameters in effect on the default bearer and
|
||||
* let the ofono core know about the activated
|
||||
* context.
|
||||
*/
|
||||
get_lte_attach_params(gprs);
|
||||
}
|
||||
} else {
|
||||
data->last_auto_context_id = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -62,10 +219,10 @@ static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!extract_ss_info(result, &status))
|
||||
return;
|
||||
status = handle_ss_info(result, gprs);
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
if (status >= 0)
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
|
||||
static void attach_detach_cb(struct qmi_result *result, void *user_data)
|
||||
@@ -124,22 +281,26 @@ error:
|
||||
static void get_ss_info_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_gprs *gprs = cbd->user;
|
||||
ofono_gprs_status_cb_t cb = cbd->cb;
|
||||
int status;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto error;
|
||||
|
||||
if (!extract_ss_info(result, &status)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
status = handle_ss_info(result, gprs);
|
||||
|
||||
if (status < 0)
|
||||
goto error;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
@@ -150,6 +311,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = gprs;
|
||||
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||
get_ss_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
@@ -159,6 +321,36 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_gprs_remove(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
data->wds = qmi_service_ref(service);
|
||||
|
||||
/*
|
||||
* First get the SS info - the modem may already be connected,
|
||||
* and the state-change notification may never arrive
|
||||
*/
|
||||
qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||
ss_info_notify, gprs, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, gprs, NULL);
|
||||
|
||||
ofono_gprs_set_cid_range(gprs, 1, 1);
|
||||
|
||||
ofono_gprs_register(gprs);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -174,12 +366,8 @@ 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_SS_INFO_IND,
|
||||
ss_info_notify, gprs, NULL);
|
||||
|
||||
ofono_gprs_set_cid_range(gprs, 1, 1);
|
||||
|
||||
ofono_gprs_register(gprs);
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS,
|
||||
create_wds_cb, gprs, NULL);
|
||||
}
|
||||
|
||||
static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
@@ -194,7 +382,10 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
|
||||
ofono_gprs_set_data(gprs, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, gprs, NULL);
|
||||
data->dev = device;
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, gprs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -207,6 +398,9 @@ static void qmi_gprs_remove(struct ofono_gprs *gprs)
|
||||
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->wds);
|
||||
qmi_service_unref(data->wds);
|
||||
|
||||
qmi_service_unregister_all(data->nas);
|
||||
|
||||
qmi_service_unref(data->nas);
|
||||
|
||||
264
ofono/drivers/qmimodem/lte.c
Normal file
264
ofono/drivers/qmimodem/lte.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jonas Bonn. All rights reserved.
|
||||
* Copyright (C) 2018 Norrbonn AB. All rights reserved.
|
||||
* Copyright (C) 2018 Data Respons ASA. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct lte_data {
|
||||
struct qmi_service *wds;
|
||||
uint8_t default_profile;
|
||||
};
|
||||
|
||||
static void modify_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
DBG("Failed to modify profile: %d", error);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmimodem_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data)
|
||||
{
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct qmi_param* param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
p.index = ldd->default_profile;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* WDS APN Name */
|
||||
qmi_param_append(param, QMI_WDS_PARAM_APN,
|
||||
strlen(info->apn), info->apn);
|
||||
|
||||
/* Modify profile */
|
||||
if (qmi_service_send(ldd->wds, 0x28, param,
|
||||
modify_profile_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void reset_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error))
|
||||
ofono_error("Reset profile error: %hd", error);
|
||||
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
uint16_t error;
|
||||
uint8_t index;
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Get default profile error: %hd", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Profile index */
|
||||
if (!qmi_result_get_uint8(result, 0x01, &index)) {
|
||||
ofono_error("Failed query default profile");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG("Default profile index: %hhd", index);
|
||||
|
||||
ldd->default_profile = index;
|
||||
|
||||
p.index = index;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* Reset profile */
|
||||
if (qmi_service_send(ldd->wds, 0x4b, param,
|
||||
reset_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to reset profile %hhd", index);
|
||||
ofono_lte_remove(lte);
|
||||
}
|
||||
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t family;
|
||||
} __attribute((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
.family = 0, /* embedded */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_lte_remove(lte);
|
||||
return;
|
||||
}
|
||||
|
||||
ldd->wds = qmi_service_ref(service);
|
||||
|
||||
/* Query the default profile */
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile type */
|
||||
qmi_param_append(param, 0x1, sizeof(p), &p);
|
||||
|
||||
/* Get default profile */
|
||||
if (qmi_service_send(ldd->wds, 0x49, param,
|
||||
get_default_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to query default profile");
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static int qmimodem_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
struct qmi_device *device = data;
|
||||
struct lte_data *ldd;
|
||||
|
||||
DBG("qmimodem lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_WDS,
|
||||
create_wds_cb, lte, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmimodem_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
qmi_service_unregister_all(ldd->wds);
|
||||
|
||||
qmi_service_unref(ldd->wds);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmimodem_lte_probe,
|
||||
.remove = qmimodem_lte_remove,
|
||||
.set_default_attach_info = qmimodem_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void qmi_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void qmi_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* RIL chat library with GLib integration
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012 Canonical Ltd.
|
||||
* 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
|
||||
@@ -20,27 +19,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GRIL_RESPONSE_H
|
||||
#define __GRIL_RESPONSE_H
|
||||
#include "nas.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "src/common.h"
|
||||
|
||||
struct _GRilResponse {
|
||||
GSList *lines;
|
||||
char *final_or_pdu;
|
||||
};
|
||||
int qmi_nas_rat_to_tech(uint8_t rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
}
|
||||
|
||||
typedef struct _GRilResponse GRilResponse;
|
||||
|
||||
#define G_RIL_RESPONSE_LINE_LENGTH_MAX 2048
|
||||
|
||||
const char *g_ril_final_response(GRilResponse *response);
|
||||
const char *g_ril_response_pdu(GRilResponse *response);
|
||||
|
||||
#ifdef __cplusplus
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GRIL_RESPONSE_H */
|
||||
@@ -19,6 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define QMI_NAS_RESET 0 /* Reset NAS service state variables */
|
||||
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
|
||||
#define QMI_NAS_EVENT 2 /* Connection state report indication */
|
||||
@@ -33,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
|
||||
@@ -63,7 +67,7 @@ struct qmi_nas_rf_info {
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Get the signal strength */
|
||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x10
|
||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x01
|
||||
|
||||
/* Scan for visible network */
|
||||
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
|
||||
@@ -95,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
|
||||
@@ -140,9 +145,29 @@ struct qmi_nas_current_plmn {
|
||||
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
|
||||
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
|
||||
|
||||
#define QMI_NAS_ATTACH_STATUS_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATUS_ATTACHED 0x01
|
||||
#define QMI_NAS_ATTACH_STATUS_DETACHED 0x02
|
||||
/* qmi_nas_serving_system.status */
|
||||
#define QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED 0x00
|
||||
#define QMI_NAS_REGISTRATION_STATE_REGISTERED 0x01
|
||||
#define QMI_NAS_REGISTRATION_STATE_SEARCHING 0x02
|
||||
#define QMI_NAS_REGISTRATION_STATE_DENIED 0x03
|
||||
#define QMI_NAS_REGISTRATION_STATE_UNKNOWN 0x04
|
||||
|
||||
#define QMI_NAS_RESULT_3GGP_DST 0x1b
|
||||
#define QMI_NAS_RESULT_3GPP_TIME 0x1c
|
||||
struct qmi_nas_3gpp_time {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t timezone;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* cs_state/ps_state */
|
||||
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
|
||||
#define QMI_NAS_ATTACH_STATE_DETACHED 0x02
|
||||
|
||||
/* Get info about home network */
|
||||
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
|
||||
@@ -152,3 +177,14 @@ struct qmi_nas_home_network {
|
||||
uint8_t desc_len;
|
||||
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,18 +44,36 @@ struct netreg_data {
|
||||
uint8_t current_rat;
|
||||
};
|
||||
|
||||
static int rat_to_tech(uint8_t rat)
|
||||
static bool extract_ss_info_time(
|
||||
struct qmi_result *result,
|
||||
struct ofono_network_time *time)
|
||||
{
|
||||
switch (rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
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;
|
||||
}
|
||||
|
||||
return -1;
|
||||
/* TODO: 3gpp2 */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
@@ -64,7 +83,7 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
const struct qmi_nas_serving_system *ss;
|
||||
const struct qmi_nas_current_plmn *plmn;
|
||||
uint8_t i, roaming;
|
||||
uint16_t value16, len;
|
||||
uint16_t value16, len, opname_len;
|
||||
uint32_t value32;
|
||||
|
||||
DBG("");
|
||||
@@ -82,13 +101,13 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
for (i = 0; i < ss->radio_if_count; i++) {
|
||||
DBG("radio in use %d", ss->radio_if[i]);
|
||||
|
||||
*tech = rat_to_tech(ss->radio_if[i]);
|
||||
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_NAS_RESULT_ROAMING_STATUS,
|
||||
&roaming)) {
|
||||
if (ss->status == 1 && roaming == 0)
|
||||
*status = 5;
|
||||
*status = NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||
}
|
||||
|
||||
if (!operator)
|
||||
@@ -100,8 +119,21 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
GUINT16_FROM_LE(plmn->mcc));
|
||||
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
|
||||
GUINT16_FROM_LE(plmn->mnc));
|
||||
strncpy(operator->name, plmn->desc, plmn->desc_len);
|
||||
operator->name[plmn->desc_len] = '\0';
|
||||
opname_len = plmn->desc_len;
|
||||
if (opname_len > OFONO_MAX_OPERATOR_NAME_LENGTH)
|
||||
opname_len = OFONO_MAX_OPERATOR_NAME_LENGTH;
|
||||
|
||||
/*
|
||||
* Telit QMI modems can return non-utf-8 characters in
|
||||
* plmn-desc. When that happens, libdbus will abort ofono.
|
||||
* If non-utf-8 characters are detected, use mccmnc string.
|
||||
*/
|
||||
if (g_utf8_validate(plmn->desc, opname_len, NULL)) {
|
||||
strncpy(operator->name, plmn->desc, opname_len);
|
||||
operator->name[opname_len] = '\0';
|
||||
} else
|
||||
snprintf(operator->name, OFONO_MAX_OPERATOR_NAME_LENGTH,
|
||||
"%s%s", operator->mcc, operator->mnc);
|
||||
|
||||
DBG("%s (%s:%s)", operator->name, operator->mcc, operator->mnc);
|
||||
}
|
||||
@@ -125,11 +157,15 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
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;
|
||||
@@ -265,7 +301,7 @@ static void scan_nets_cb(struct qmi_result *result, void *user_data)
|
||||
DBG("%03d:%02d %d", netrat->info[i].mcc, netrat->info[i].mnc,
|
||||
netrat->info[i].rat);
|
||||
|
||||
list[i].tech = rat_to_tech(netrat->info[i].rat);
|
||||
list[i].tech = qmi_nas_rat_to_tech(netrat->info[i].rat);
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -296,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("");
|
||||
|
||||
@@ -305,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;
|
||||
}
|
||||
|
||||
@@ -357,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);
|
||||
@@ -451,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);
|
||||
}
|
||||
|
||||
@@ -474,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)
|
||||
@@ -499,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;
|
||||
@@ -543,7 +583,7 @@ static int qmi_netreg_probe(struct ofono_netreg *netreg,
|
||||
|
||||
ofono_netreg_set_data(netreg, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS,
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, netreg, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
@@ -33,12 +35,18 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "ctl.h"
|
||||
|
||||
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data);
|
||||
|
||||
struct discovery {
|
||||
qmi_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
struct qmi_device {
|
||||
int ref_count;
|
||||
int fd;
|
||||
@@ -49,6 +57,7 @@ struct qmi_device {
|
||||
GQueue *req_queue;
|
||||
GQueue *control_queue;
|
||||
GQueue *service_queue;
|
||||
GQueue *discovery_queue;
|
||||
uint8_t next_control_tid;
|
||||
uint16_t next_service_tid;
|
||||
qmi_debug_func_t debug_func;
|
||||
@@ -60,6 +69,12 @@ struct qmi_device {
|
||||
uint8_t version_count;
|
||||
GHashTable *service_list;
|
||||
unsigned int release_users;
|
||||
qmi_shutdown_func_t shutdown_func;
|
||||
void *shutdown_user_data;
|
||||
qmi_destroy_func_t shutdown_destroy;
|
||||
guint shutdown_source;
|
||||
bool shutting_down : 1;
|
||||
bool destroyed : 1;
|
||||
};
|
||||
|
||||
struct qmi_service {
|
||||
@@ -209,6 +224,14 @@ static gint __request_compare(gconstpointer a, gconstpointer b)
|
||||
return req->tid - tid;
|
||||
}
|
||||
|
||||
static void __discovery_free(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct discovery *d = data;
|
||||
qmi_destroy_func_t destroy = d->destroy;
|
||||
|
||||
destroy(d);
|
||||
}
|
||||
|
||||
static void __notify_free(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct qmi_notify *notify = data;
|
||||
@@ -313,8 +336,12 @@ static const char *__service_type_to_string(uint8_t type)
|
||||
return "UIM";
|
||||
case QMI_SERVICE_PBM:
|
||||
return "PBM";
|
||||
case QMI_SERVICE_QCHAT:
|
||||
return "QCHAT";
|
||||
case QMI_SERVICE_RMTFS:
|
||||
return "RMTFS";
|
||||
case QMI_SERVICE_TEST:
|
||||
return "TEST";
|
||||
case QMI_SERVICE_LOC:
|
||||
return "LOC";
|
||||
case QMI_SERVICE_SAR:
|
||||
@@ -326,9 +353,21 @@ static const char *__service_type_to_string(uint8_t type)
|
||||
case QMI_SERVICE_TS:
|
||||
return "TS";
|
||||
case QMI_SERVICE_TMD:
|
||||
return "TMS";
|
||||
return "TMD";
|
||||
case QMI_SERVICE_WDA:
|
||||
return "WDA";
|
||||
case QMI_SERVICE_CSVT:
|
||||
return "CSVT";
|
||||
case QMI_SERVICE_COEX:
|
||||
return "COEX";
|
||||
case QMI_SERVICE_PDC:
|
||||
return "PDC";
|
||||
case QMI_SERVICE_RFRPE:
|
||||
return "RFRPE";
|
||||
case QMI_SERVICE_DSD:
|
||||
return "DSD";
|
||||
case QMI_SERVICE_SSCTL:
|
||||
return "SSCTL";
|
||||
case QMI_SERVICE_CAT_OLD:
|
||||
return "CAT";
|
||||
case QMI_SERVICE_RMS:
|
||||
@@ -437,6 +476,17 @@ static const char *__error_to_string(uint16_t error)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int qmi_error_to_ofono_cme(int qmi_error) {
|
||||
switch (qmi_error) {
|
||||
case 0x0019:
|
||||
return 4; /* Not Supported */
|
||||
case 0x0052:
|
||||
return 32; /* Access Denied */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void __debug_msg(const char dir, const void *buf, size_t len,
|
||||
qmi_debug_func_t function, void *user_data)
|
||||
{
|
||||
@@ -758,7 +808,7 @@ static void handle_packet(struct qmi_device *device,
|
||||
|
||||
tid = GUINT16_FROM_LE(service->transaction);
|
||||
|
||||
if (service->type == 0x04 && tid == 0x0000) {
|
||||
if (service->type == 0x04) {
|
||||
handle_indication(device, hdr->service, hdr->client,
|
||||
message, length, data);
|
||||
return;
|
||||
@@ -838,6 +888,21 @@ static void read_watch_destroy(gpointer user_data)
|
||||
device->read_watch = 0;
|
||||
}
|
||||
|
||||
static void __qmi_device_discovery_started(struct qmi_device *device,
|
||||
struct discovery *d)
|
||||
{
|
||||
g_queue_push_tail(device->discovery_queue, d);
|
||||
}
|
||||
|
||||
static void __qmi_device_discovery_complete(struct qmi_device *device,
|
||||
struct discovery *d)
|
||||
{
|
||||
if (g_queue_remove(device->discovery_queue, d) != TRUE)
|
||||
return;
|
||||
|
||||
__discovery_free(d, NULL);
|
||||
}
|
||||
|
||||
static void service_destroy(gpointer data)
|
||||
{
|
||||
struct qmi_service *service = data;
|
||||
@@ -891,6 +956,7 @@ struct qmi_device *qmi_device_new(int fd)
|
||||
device->req_queue = g_queue_new();
|
||||
device->control_queue = g_queue_new();
|
||||
device->service_queue = g_queue_new();
|
||||
device->discovery_queue = g_queue_new();
|
||||
|
||||
device->service_list = g_hash_table_new_full(g_direct_hash,
|
||||
g_direct_equal, NULL, service_destroy);
|
||||
@@ -927,6 +993,9 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
g_queue_foreach(device->req_queue, __request_free, NULL);
|
||||
g_queue_free(device->req_queue);
|
||||
|
||||
g_queue_foreach(device->discovery_queue, __discovery_free, NULL);
|
||||
g_queue_free(device->discovery_queue);
|
||||
|
||||
if (device->write_watch > 0)
|
||||
g_source_remove(device->write_watch);
|
||||
|
||||
@@ -936,12 +1005,18 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
if (device->close_on_unref)
|
||||
close(device->fd);
|
||||
|
||||
if (device->shutdown_source)
|
||||
g_source_remove(device->shutdown_source);
|
||||
|
||||
g_hash_table_destroy(device->service_list);
|
||||
|
||||
g_free(device->version_str);
|
||||
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,
|
||||
@@ -962,6 +1037,23 @@ void qmi_device_set_close_on_unref(struct qmi_device *device, bool do_close)
|
||||
device->close_on_unref = do_close;
|
||||
}
|
||||
|
||||
void qmi_result_print_tlvs(struct qmi_result *result)
|
||||
{
|
||||
const void *ptr = result->data;
|
||||
uint16_t len = result->length;
|
||||
|
||||
while (len > QMI_TLV_HDR_SIZE) {
|
||||
const struct qmi_tlv_hdr *tlv = ptr;
|
||||
uint16_t tlv_length = GUINT16_FROM_LE(tlv->length);
|
||||
|
||||
DBG("tlv: 0x%02x len 0x%04x", tlv->type, tlv->length);
|
||||
|
||||
ptr += QMI_TLV_HDR_SIZE + tlv_length;
|
||||
len -= QMI_TLV_HDR_SIZE + tlv_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const void *tlv_get(const void *data, uint16_t size,
|
||||
uint8_t type, uint16_t *length)
|
||||
{
|
||||
@@ -987,13 +1079,30 @@ static const void *tlv_get(const void *data, uint16_t size,
|
||||
}
|
||||
|
||||
struct discover_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
qmi_discover_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
uint8_t tid;
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static void discover_data_free(gpointer user_data)
|
||||
{
|
||||
struct discover_data *data = user_data;
|
||||
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void discover_callback(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data)
|
||||
{
|
||||
@@ -1007,8 +1116,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
uint8_t count;
|
||||
unsigned int i;
|
||||
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
count = 0;
|
||||
list = NULL;
|
||||
|
||||
@@ -1038,6 +1145,13 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
uint8_t type = service_list->services[i].type;
|
||||
const char *name = __service_type_to_string(type);
|
||||
|
||||
if (name)
|
||||
__debug_device(device, "found service [%s %d.%d]",
|
||||
name, major, minor);
|
||||
else
|
||||
__debug_device(device, "found service [%d %d.%d]",
|
||||
type, major, minor);
|
||||
|
||||
if (type == QMI_SERVICE_CONTROL) {
|
||||
device->control_major = major;
|
||||
device->control_minor = minor;
|
||||
@@ -1050,13 +1164,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
list[count].name = name;
|
||||
|
||||
count++;
|
||||
|
||||
if (name)
|
||||
__debug_device(device, "found service [%s %d.%d]",
|
||||
name, major, minor);
|
||||
else
|
||||
__debug_device(device, "found service [%d %d.%d]",
|
||||
type, major, minor);
|
||||
}
|
||||
|
||||
ptr = tlv_get(buffer, length, 0x10, &len);
|
||||
@@ -1065,13 +1172,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
|
||||
device->version_str = strndup(ptr + 1, *((uint8_t *) ptr));
|
||||
|
||||
service_list = ptr + *((uint8_t *) ptr) + 1;
|
||||
|
||||
for (i = 0; i < service_list->count; i++) {
|
||||
if (service_list->services[i].type == QMI_SERVICE_CONTROL)
|
||||
continue;
|
||||
}
|
||||
|
||||
done:
|
||||
device->version_list = list;
|
||||
device->version_count = count;
|
||||
@@ -1079,27 +1179,45 @@ done:
|
||||
if (data->func)
|
||||
data->func(count, list, data->user_data);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
|
||||
static gboolean discover_reply(gpointer user_data)
|
||||
{
|
||||
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);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
__request_free(req, NULL);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1120,13 +1238,15 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = discover_data_free;
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
if (device->version_list) {
|
||||
g_timeout_add_seconds(0, discover_reply, data);
|
||||
data->timeout = g_timeout_add_seconds(0, discover_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1143,10 +1263,12 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_control_tid++;
|
||||
data->tid = hdr->transaction;
|
||||
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
|
||||
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1177,63 +1299,315 @@ static void release_client(struct qmi_device *device,
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
}
|
||||
|
||||
struct shutdown_data {
|
||||
struct qmi_device *device;
|
||||
qmi_shutdown_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
static gboolean shutdown_reply(gpointer user_data)
|
||||
static void shutdown_destroy(gpointer user_data)
|
||||
{
|
||||
struct shutdown_data *data = user_data;
|
||||
struct qmi_device *device = user_data;
|
||||
|
||||
if (data->func)
|
||||
data->func(data->user_data);
|
||||
if (device->shutdown_destroy)
|
||||
device->shutdown_destroy(device->shutdown_user_data);
|
||||
|
||||
g_free(data);
|
||||
device->shutdown_source = 0;
|
||||
|
||||
return FALSE;
|
||||
if (device->destroyed)
|
||||
g_free(device);
|
||||
}
|
||||
|
||||
static gboolean shutdown_timeout(gpointer user_data)
|
||||
static gboolean shutdown_callback(gpointer user_data)
|
||||
{
|
||||
struct shutdown_data *data = user_data;
|
||||
struct qmi_device *device = data->device;
|
||||
struct qmi_device *device = user_data;
|
||||
|
||||
if (device->release_users > 0)
|
||||
return TRUE;
|
||||
|
||||
return shutdown_reply(data);
|
||||
device->shutting_down = true;
|
||||
|
||||
if (device->shutdown_func)
|
||||
device->shutdown_func(device->shutdown_user_data);
|
||||
|
||||
device->shutting_down = true;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy)
|
||||
{
|
||||
struct shutdown_data *data;
|
||||
|
||||
if (!device)
|
||||
return false;
|
||||
|
||||
if (device->shutdown_source > 0)
|
||||
return false;
|
||||
|
||||
__debug_device(device, "device %p shutdown", device);
|
||||
|
||||
data = g_try_new0(struct shutdown_data, 1);
|
||||
if (!data)
|
||||
device->shutdown_source = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
|
||||
0, shutdown_callback, device,
|
||||
shutdown_destroy);
|
||||
if (device->shutdown_source == 0)
|
||||
return false;
|
||||
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
if (device->release_users > 0)
|
||||
g_timeout_add_seconds(0, shutdown_timeout, data);
|
||||
else
|
||||
g_timeout_add_seconds(0, shutdown_reply, data);
|
||||
device->shutdown_func = func;
|
||||
device->shutdown_user_data = user_data;
|
||||
device->shutdown_destroy = destroy;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sync_data {
|
||||
qmi_sync_func_t func;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void qmi_device_sync_callback(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data)
|
||||
{
|
||||
struct sync_data *data = user_data;
|
||||
|
||||
if (data->func)
|
||||
data->func(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
/* sync will release all previous clients */
|
||||
bool qmi_device_sync(struct qmi_device *device,
|
||||
qmi_sync_func_t func, void *user_data)
|
||||
{
|
||||
struct qmi_request *req;
|
||||
struct qmi_control_hdr *hdr;
|
||||
struct sync_data *func_data;
|
||||
|
||||
if (!device)
|
||||
return false;
|
||||
|
||||
__debug_device(device, "Sending sync to reset QMI");
|
||||
|
||||
func_data = g_new0(struct sync_data, 1);
|
||||
func_data->func = func;
|
||||
func_data->user_data = user_data;
|
||||
|
||||
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
|
||||
QMI_CTL_SYNC, QMI_CONTROL_HDR_SIZE,
|
||||
NULL, 0,
|
||||
qmi_device_sync_callback, func_data, (void **) &hdr);
|
||||
|
||||
if (device->next_control_tid < 1)
|
||||
device->next_control_tid = 1;
|
||||
|
||||
hdr->type = 0x00;
|
||||
hdr->transaction = device->next_control_tid++;
|
||||
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if the device support the QMI call SYNC over the CTL interface */
|
||||
bool qmi_device_is_sync_supported(struct qmi_device *device)
|
||||
{
|
||||
if (device == NULL)
|
||||
return false;
|
||||
|
||||
return (device->control_major > 1 ||
|
||||
(device->control_major == 1 && device->control_minor >= 5));
|
||||
}
|
||||
|
||||
static bool get_device_file_name(struct qmi_device *device,
|
||||
char *file_name, int size)
|
||||
{
|
||||
pid_t pid;
|
||||
char temp[100];
|
||||
ssize_t result;
|
||||
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
pid = getpid();
|
||||
|
||||
snprintf(temp, 100, "/proc/%d/fd/%d", (int) pid, device->fd);
|
||||
temp[99] = 0;
|
||||
|
||||
result = readlink(temp, file_name, size - 1);
|
||||
|
||||
if (result == -1 || result >= size - 1) {
|
||||
DBG("Error %d in readlink", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
file_name[result] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *get_first_dir_in_directory(char *dir_path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dir_entry;
|
||||
char *dir_name = NULL;
|
||||
|
||||
dir = opendir(dir_path);
|
||||
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
dir_entry = readdir(dir);
|
||||
|
||||
while ((dir_entry != NULL)) {
|
||||
if (dir_entry->d_type == DT_DIR &&
|
||||
strcmp(dir_entry->d_name, ".") != 0 &&
|
||||
strcmp(dir_entry->d_name, "..") != 0) {
|
||||
dir_name = g_strdup(dir_entry->d_name);
|
||||
break;
|
||||
}
|
||||
|
||||
dir_entry = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return dir_name;
|
||||
}
|
||||
|
||||
static char *get_device_interface(struct qmi_device *device)
|
||||
{
|
||||
char * const driver_names[] = { "usbmisc", "usb" };
|
||||
unsigned int i;
|
||||
char file_path[PATH_MAX];
|
||||
char *file_name;
|
||||
char *interface = NULL;
|
||||
|
||||
if (!get_device_file_name(device, file_path, sizeof(file_path)))
|
||||
return NULL;
|
||||
|
||||
file_name = basename(file_path);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(driver_names) && !interface; i++) {
|
||||
gchar *sysfs_path;
|
||||
|
||||
sysfs_path = g_strdup_printf("/sys/class/%s/%s/device/net/",
|
||||
driver_names[i], file_name);
|
||||
interface = get_first_dir_in_directory(sysfs_path);
|
||||
g_free(sysfs_path);
|
||||
}
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
|
||||
struct qmi_device *device)
|
||||
{
|
||||
char *sysfs_path = NULL;
|
||||
char *interface = NULL;
|
||||
int fd = -1;
|
||||
char value;
|
||||
enum qmi_device_expected_data_format expected =
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
|
||||
|
||||
if (!device)
|
||||
goto done;
|
||||
|
||||
interface = get_device_interface(device);
|
||||
|
||||
if (!interface) {
|
||||
DBG("Error while getting interface name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Build sysfs file path and open it */
|
||||
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||
|
||||
fd = open(sysfs_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
/* maybe not supported by kernel */
|
||||
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (read(fd, &value, 1) != 1) {
|
||||
DBG("Error %d in read(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (value == 'Y')
|
||||
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP;
|
||||
else if (value == 'N')
|
||||
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3;
|
||||
else
|
||||
DBG("Unexpected sysfs file contents");
|
||||
|
||||
done:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (sysfs_path)
|
||||
g_free(sysfs_path);
|
||||
|
||||
if (interface)
|
||||
g_free(interface);
|
||||
|
||||
return expected;
|
||||
}
|
||||
|
||||
bool qmi_device_set_expected_data_format(struct qmi_device *device,
|
||||
enum qmi_device_expected_data_format format)
|
||||
{
|
||||
bool res = false;
|
||||
char *sysfs_path = NULL;
|
||||
char *interface = NULL;
|
||||
int fd = -1;
|
||||
char value;
|
||||
|
||||
if (!device)
|
||||
goto done;
|
||||
|
||||
switch (format) {
|
||||
case QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3:
|
||||
value = 'N';
|
||||
break;
|
||||
case QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP:
|
||||
value = 'Y';
|
||||
break;
|
||||
default:
|
||||
DBG("Unhandled format: %d", (int) format);
|
||||
goto done;
|
||||
}
|
||||
|
||||
interface = get_device_interface(device);
|
||||
|
||||
if (!interface) {
|
||||
DBG("Error while getting interface name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Build sysfs file path and open it */
|
||||
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||
|
||||
fd = open(sysfs_path, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
/* maybe not supported by kernel */
|
||||
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (write(fd, &value, 1) != 1) {
|
||||
DBG("Error %d in write(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
res = true;
|
||||
|
||||
done:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (sysfs_path)
|
||||
g_free(sysfs_path);
|
||||
|
||||
if (interface)
|
||||
g_free(interface);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct qmi_param *qmi_param_new(void)
|
||||
{
|
||||
struct qmi_param *param;
|
||||
@@ -1435,6 +1809,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
uint16_t len, tmp;
|
||||
|
||||
if (!result || !type)
|
||||
return false;
|
||||
|
||||
ptr = tlv_get(result->data, result->length, type, &len);
|
||||
if (!ptr)
|
||||
return false;
|
||||
|
||||
memcpy(&tmp, ptr, 2);
|
||||
|
||||
if (value)
|
||||
*value = GINT16_FROM_LE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value)
|
||||
{
|
||||
@@ -1501,6 +1896,7 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
}
|
||||
|
||||
struct service_create_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
bool shared;
|
||||
uint8_t type;
|
||||
@@ -1512,16 +1908,29 @@ struct service_create_data {
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static gboolean service_create_reply(gpointer user_data)
|
||||
static void service_create_data_free(gpointer user_data)
|
||||
{
|
||||
struct service_create_data *data = user_data;
|
||||
|
||||
data->func(NULL, data->user_data);
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static gboolean service_create_reply(gpointer user_data)
|
||||
{
|
||||
struct service_create_data *data = user_data;
|
||||
|
||||
data->timeout = 0;
|
||||
data->func(NULL, data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1537,8 +1946,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
||||
uint16_t len;
|
||||
unsigned int hash_id;
|
||||
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
result_code = tlv_get(buffer, length, 0x02, &len);
|
||||
if (!result_code)
|
||||
goto done;
|
||||
@@ -1580,13 +1987,9 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
||||
|
||||
done:
|
||||
data->func(service, data->user_data);
|
||||
|
||||
qmi_service_unref(service);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
|
||||
static void service_create_discover(uint8_t count,
|
||||
@@ -1617,7 +2020,9 @@ static void service_create_discover(uint8_t count,
|
||||
if (data->timeout > 0)
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
g_timeout_add_seconds(0, service_create_reply, data);
|
||||
data->timeout = g_timeout_add_seconds(0,
|
||||
service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1640,6 +2045,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = service_create_data_free;
|
||||
data->device = device;
|
||||
data->shared = shared;
|
||||
data->type = type;
|
||||
@@ -1662,6 +2068,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
||||
|
||||
done:
|
||||
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1680,17 +2087,23 @@ bool qmi_service_create(struct qmi_device *device,
|
||||
}
|
||||
|
||||
struct service_create_shared_data {
|
||||
struct discovery super;
|
||||
struct qmi_service *service;
|
||||
struct qmi_device *device;
|
||||
qmi_create_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static gboolean service_create_shared_reply(gpointer user_data)
|
||||
static void service_create_shared_data_free(gpointer user_data)
|
||||
{
|
||||
struct service_create_shared_data *data = user_data;
|
||||
|
||||
data->func(data->service, data->user_data);
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
qmi_service_unref(data->service);
|
||||
|
||||
@@ -1698,6 +2111,16 @@ static gboolean service_create_shared_reply(gpointer user_data)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static gboolean service_create_shared_reply(gpointer user_data)
|
||||
{
|
||||
struct service_create_shared_data *data = user_data;
|
||||
|
||||
data->timeout = 0;
|
||||
data->func(data->service, data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1724,13 +2147,16 @@ bool qmi_service_create_shared(struct qmi_device *device,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = service_create_shared_data_free;
|
||||
data->service = qmi_service_ref(service);
|
||||
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
g_timeout_add(0, service_create_shared_reply, data);
|
||||
data->timeout = g_timeout_add(0,
|
||||
service_create_shared_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,18 +35,32 @@
|
||||
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
|
||||
#define QMI_SERVICE_UIM 11 /* UIM service */
|
||||
#define QMI_SERVICE_PBM 12 /* Phonebook service */
|
||||
#define QMI_SERVICE_QCHAT 13
|
||||
#define QMI_SERVICE_RMTFS 14 /* Remote file system service */
|
||||
#define QMI_SERVICE_TEST 15
|
||||
#define QMI_SERVICE_LOC 16 /* Location service */
|
||||
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
|
||||
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
|
||||
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
|
||||
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
|
||||
#define QMI_SERVICE_TMD 24 /* Thermal mitigation device service */
|
||||
#define QMI_SERVICE_WDA 26 /* Wireless data administrative service */
|
||||
#define QMI_SERVICE_CSVT 29
|
||||
#define QMI_SERVICE_COEX 34
|
||||
#define QMI_SERVICE_PDC 36 /* Persistent device configuration service */
|
||||
#define QMI_SERVICE_RFRPE 41
|
||||
#define QMI_SERVICE_DSD 42
|
||||
#define QMI_SERVICE_SSCTL 43
|
||||
#define QMI_SERVICE_CAT_OLD 224 /* Card application toolkit service */
|
||||
#define QMI_SERVICE_RMS 225 /* Remote management service */
|
||||
#define QMI_SERVICE_OMA 226 /* OMA device management service */
|
||||
|
||||
enum qmi_device_expected_data_format {
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
|
||||
};
|
||||
|
||||
struct qmi_version {
|
||||
uint8_t type;
|
||||
uint16_t major;
|
||||
@@ -62,7 +76,7 @@ typedef void (*qmi_destroy_func_t)(void *user_data);
|
||||
struct qmi_device;
|
||||
|
||||
typedef void (*qmi_debug_func_t)(const char *str, void *user_data);
|
||||
|
||||
typedef void (*qmi_sync_func_t)(void *user_data);
|
||||
typedef void (*qmi_shutdown_func_t)(void *user_data);
|
||||
typedef void (*qmi_discover_func_t)(uint8_t count,
|
||||
const struct qmi_version *list, void *user_data);
|
||||
@@ -82,6 +96,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_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,
|
||||
enum qmi_device_expected_data_format format);
|
||||
|
||||
struct qmi_param;
|
||||
|
||||
@@ -112,13 +134,17 @@ const void *qmi_result_get(struct qmi_result *result, uint8_t type,
|
||||
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
|
||||
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
uint8_t *value);
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value);
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value);
|
||||
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
||||
uint32_t *value);
|
||||
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
uint64_t *value);
|
||||
void qmi_result_print_tlvs(struct qmi_result *result);
|
||||
|
||||
int qmi_error_to_ofono_cme(int qmi_error);
|
||||
|
||||
struct qmi_service;
|
||||
|
||||
|
||||
@@ -39,16 +39,20 @@ static int qmimodem_init(void)
|
||||
qmi_ussd_init();
|
||||
qmi_gprs_init();
|
||||
qmi_gprs_context_init();
|
||||
qmi_lte_init();
|
||||
qmi_radio_settings_init();
|
||||
qmi_location_reporting_init();
|
||||
qmi_netmon_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmimodem_exit(void)
|
||||
{
|
||||
qmi_netmon_exit();
|
||||
qmi_location_reporting_exit();
|
||||
qmi_radio_settings_exit();
|
||||
qmi_lte_exit();
|
||||
qmi_gprs_context_exit();
|
||||
qmi_gprs_exit();
|
||||
qmi_ussd_exit();
|
||||
|
||||
@@ -48,8 +48,14 @@ extern void qmi_gprs_exit(void);
|
||||
extern void qmi_gprs_context_init(void);
|
||||
extern void qmi_gprs_context_exit(void);
|
||||
|
||||
extern void qmi_lte_init(void);
|
||||
extern void qmi_lte_exit(void);
|
||||
|
||||
extern void qmi_radio_settings_init(void);
|
||||
extern void qmi_radio_settings_exit(void);
|
||||
|
||||
extern void qmi_location_reporting_init(void);
|
||||
extern void qmi_location_reporting_exit(void);
|
||||
|
||||
extern void qmi_netmon_init(void);
|
||||
extern void qmi_netmon_exit(void);
|
||||
|
||||
@@ -29,15 +29,202 @@
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
#include "dms.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct settings_data {
|
||||
struct qmi_service *nas;
|
||||
struct qmi_service *dms;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
static void get_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
uint16_t pref;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_result_get_uint16(result,
|
||||
QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref);
|
||||
|
||||
switch (pref) {
|
||||
case QMI_NAS_RAT_MODE_PREF_GSM:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_UMTS:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_LTE:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL,
|
||||
get_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void set_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_GSM;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_UMTS;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param) {
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE,
|
||||
pref);
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_SET_SYSTEM_SELECTION_PREF, param,
|
||||
set_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void get_caps_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
|
||||
const struct qmi_dms_device_caps *caps;
|
||||
unsigned int available_rats;
|
||||
uint16_t len;
|
||||
uint8_t i;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto error;
|
||||
|
||||
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
|
||||
if (!caps)
|
||||
goto error;
|
||||
|
||||
available_rats = 0;
|
||||
for (i = 0; i < caps->radio_if_count; i++) {
|
||||
switch (caps->radio_if[i]) {
|
||||
case QMI_DMS_RADIO_IF_GSM:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_UMTS:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_LTE:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_available_rats(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (!rsd->dms)
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL,
|
||||
get_caps_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service)
|
||||
return;
|
||||
|
||||
data->dms = qmi_service_ref(service);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
@@ -74,10 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, rs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_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)
|
||||
@@ -88,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);
|
||||
@@ -99,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)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "dms.h"
|
||||
#include "uim.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
@@ -38,15 +39,36 @@
|
||||
#define EF_STATUS_INVALIDATED 0
|
||||
#define EF_STATUS_VALID 1
|
||||
|
||||
struct sim_data {
|
||||
struct qmi_service *uim;
|
||||
uint32_t event_mask;
|
||||
/* max number of retry of commands that can temporary fail */
|
||||
#define MAX_RETRY_COUNT 100
|
||||
|
||||
enum get_card_status_result {
|
||||
GET_CARD_STATUS_RESULT_OK, /* No error */
|
||||
GET_CARD_STATUS_RESULT_ERROR, /* Definitive error */
|
||||
GET_CARD_STATUS_RESULT_TEMP_ERROR, /* error, a retry could work */
|
||||
};
|
||||
|
||||
/* information from QMI_UIM_GET_CARD_STATUS command */
|
||||
struct sim_status {
|
||||
uint8_t card_state;
|
||||
uint8_t app_type;
|
||||
uint8_t passwd_state;
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
};
|
||||
|
||||
struct sim_data {
|
||||
struct qmi_device *qmi_dev;
|
||||
struct qmi_service *dms;
|
||||
struct qmi_service *uim;
|
||||
uint32_t event_mask;
|
||||
uint8_t app_type;
|
||||
uint32_t retry_count;
|
||||
guint poll_source;
|
||||
};
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data);
|
||||
|
||||
static int create_fileid_data(uint8_t app_type, int fileid,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
@@ -146,7 +168,7 @@ static void qmi_read_attributes(struct ofono_sim *sim, int fileid,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
struct qmi_param *param;
|
||||
@@ -211,7 +233,7 @@ static void qmi_read_transparent(struct ofono_sim *sim,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char read_data[4];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
@@ -257,7 +279,7 @@ static void qmi_read_record(struct ofono_sim *sim,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char read_data[4];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
@@ -295,76 +317,214 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
||||
static void write_generic_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_write_cb_t cb = cbd->cb;
|
||||
uint16_t len;
|
||||
const uint8_t *card_result;
|
||||
uint8_t sw1, sw2;
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
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;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_data);
|
||||
}
|
||||
sw1 = card_result[0];
|
||||
sw2 = card_result[1];
|
||||
|
||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
DBG("%02x, %02x", sw1, sw2);
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
||||
(sw1 == 0x90 && sw2 != 0x00)) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
||||
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, data->retries, user_data);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void card_setup(const struct qmi_uim_slot_info *slot,
|
||||
static void write_generic(struct ofono_sim *sim,
|
||||
uint16_t qmi_message, int fileid,
|
||||
int start_or_recordnum,
|
||||
int length, const unsigned char *value,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char write_data[4 + length];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("file id 0x%04x path len %d", fileid, path_len);
|
||||
|
||||
fileid_len = create_fileid_data(data->app_type, fileid,
|
||||
path, path_len, fileid_data);
|
||||
|
||||
if (fileid_len < 0)
|
||||
goto error;
|
||||
|
||||
write_data[0] = start_or_recordnum & 0xff;
|
||||
write_data[1] = (start_or_recordnum & 0xff00) >> 8;
|
||||
write_data[2] = length & 0xff;
|
||||
write_data[3] = (length & 0xff00) >> 8;
|
||||
memcpy(&write_data[4], value, length);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
|
||||
qmi_param_append(param, 0x02, fileid_len, fileid_data);
|
||||
qmi_param_append(param, 0x03, 4 + length, write_data);
|
||||
|
||||
if (qmi_service_send(data->uim, qmi_message, param,
|
||||
write_generic_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_write_transparent(struct ofono_sim *sim,
|
||||
int fileid, int start, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_TRANSPARENT, fileid, start,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_linear(struct ofono_sim *sim,
|
||||
int fileid, int record, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, record,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_cyclic(struct ofono_sim *sim,
|
||||
int fileid, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, 0,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void get_imsi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_imsi_cb_t cb = cbd->cb;
|
||||
char *str;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMSI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
|
||||
|
||||
qmi_free(str);
|
||||
}
|
||||
|
||||
static void qmi_read_imsi(struct ofono_sim *sim,
|
||||
ofono_sim_imsi_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->dms, QMI_DMS_GET_IMSI, NULL,
|
||||
get_imsi_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
/* Return true if a retry could give another (better) result */
|
||||
static bool get_card_status(const struct qmi_uim_slot_info *slot,
|
||||
const struct qmi_uim_app_info1 *info1,
|
||||
const struct qmi_uim_app_info2 *info2,
|
||||
struct sim_data *data)
|
||||
struct sim_status *sim_stat)
|
||||
{
|
||||
data->card_state = slot->card_state;
|
||||
data->app_type = info1->app_type;
|
||||
bool need_retry = false;
|
||||
sim_stat->card_state = slot->card_state;
|
||||
sim_stat->app_type = info1->app_type;
|
||||
|
||||
switch (info1->app_state) {
|
||||
case 0x02: /* PIN1 or UPIN is required */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
||||
break;
|
||||
case 0x03: /* PUK1 or PUK for UPIN is required */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
break;
|
||||
case 0x04: /* Personalization state must be checked. */
|
||||
/* This is temporary, we could retry and get another result */
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
need_retry = true;
|
||||
break;
|
||||
case 0x07: /* Ready */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||
break;
|
||||
default:
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
DBG("info1->app_state:0x%x: OFONO_SIM_PASSWORD_INVALID",
|
||||
info1->app_state);
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
||||
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
||||
|
||||
return need_retry;
|
||||
}
|
||||
|
||||
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
static enum get_card_status_result handle_get_card_status_result(
|
||||
struct qmi_result *result, struct sim_status *sim_stat)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
const void *ptr;
|
||||
const struct qmi_uim_card_status *status;
|
||||
uint16_t len, offset;
|
||||
uint8_t i;
|
||||
|
||||
DBG("");
|
||||
enum get_card_status_result res = GET_CARD_STATUS_RESULT_ERROR;
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
@@ -397,15 +557,211 @@ static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
index = GUINT16_FROM_LE(status->index_gw_pri);
|
||||
|
||||
if ((index & 0xff) == i && (index >> 8) == n)
|
||||
card_setup(slot, info1, info2, data);
|
||||
if ((index & 0xff) == i && (index >> 8) == n) {
|
||||
if (get_card_status(slot, info1, info2,
|
||||
sim_stat))
|
||||
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
|
||||
else
|
||||
res = GET_CARD_STATUS_RESULT_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean query_passwd_state_retry(gpointer userdata)
|
||||
{
|
||||
struct cb_data *cbd = userdata;
|
||||
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
|
||||
data->poll_source = 0;
|
||||
|
||||
qmi_query_passwd_state(sim, cb, cbd->data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void query_passwd_state_cb(struct qmi_result *result,
|
||||
void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct sim_status sim_stat;
|
||||
enum get_card_status_result res;
|
||||
struct cb_data *retry_cbd;
|
||||
|
||||
res = handle_get_card_status_result(result, &sim_stat);
|
||||
switch (res) {
|
||||
case GET_CARD_STATUS_RESULT_OK:
|
||||
DBG("passwd state %d", sim_stat.passwd_state);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
|
||||
break;
|
||||
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
|
||||
data->retry_count++;
|
||||
if (data->retry_count > MAX_RETRY_COUNT) {
|
||||
DBG("Failed after %d attempts", data->retry_count);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
} else {
|
||||
DBG("Retry command");
|
||||
retry_cbd = cb_data_new(cb, cbd->data);
|
||||
retry_cbd->user = sim;
|
||||
data->poll_source = g_timeout_add(20,
|
||||
query_passwd_state_retry,
|
||||
retry_cbd);
|
||||
}
|
||||
break;
|
||||
case GET_CARD_STATUS_RESULT_ERROR:
|
||||
DBG("Command failed");
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = sim;
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||
query_passwd_state_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
struct sim_status sim_stat;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||
GET_CARD_STATUS_RESULT_OK) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.retries, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||
query_pin_retries_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void pin_send_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
int passwd_len;
|
||||
struct qmi_param *param;
|
||||
struct qmi_uim_param_message_info *info_data;
|
||||
unsigned char session_info_data[2];
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!passwd)
|
||||
goto error;
|
||||
|
||||
passwd_len = strlen(passwd);
|
||||
|
||||
if (passwd_len <= 0 || passwd_len > 0xFF)
|
||||
goto error;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* param info */
|
||||
info_data = alloca(2 + passwd_len);
|
||||
info_data->pin_id = 0x01; /* PIN 1 */
|
||||
info_data->length = (uint8_t) passwd_len;
|
||||
memcpy(info_data->pin_value, passwd, passwd_len);
|
||||
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_INFO, 2 + passwd_len,
|
||||
info_data);
|
||||
/* param Session Information */
|
||||
session_info_data[0] = 0x6;
|
||||
session_info_data[1] = 0x0;
|
||||
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_SESSION_INFO, 2,
|
||||
session_info_data);
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_VERIFY_PIN, param,
|
||||
pin_send_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct sim_status sim_stat;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||
GET_CARD_STATUS_RESULT_OK) {
|
||||
data->app_type = 0; /* Unknown */
|
||||
sim_stat.card_state = 0x00; /* Absent */
|
||||
} else {
|
||||
data->app_type = sim_stat.app_type;
|
||||
}
|
||||
|
||||
ofono_sim_register(sim);
|
||||
|
||||
switch (data->card_state) {
|
||||
switch (sim_stat.card_state) {
|
||||
case 0x00: /* Absent */
|
||||
case 0x02: /* Error */
|
||||
break;
|
||||
@@ -465,30 +821,44 @@ static void create_uim_cb(struct qmi_service *service, void *user_data)
|
||||
return;
|
||||
|
||||
error:
|
||||
qmi_service_unref(data->uim);
|
||||
|
||||
ofono_sim_remove(sim);
|
||||
}
|
||||
|
||||
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request DMS service");
|
||||
ofono_sim_remove(sim);
|
||||
return;
|
||||
}
|
||||
|
||||
data->dms = qmi_service_ref(service);
|
||||
|
||||
qmi_service_create(data->qmi_dev, QMI_SERVICE_UIM, create_uim_cb, sim,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int qmi_sim_probe(struct ofono_sim *sim,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
struct qmi_device *device = user_data;
|
||||
struct sim_data *data;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
data = g_new0(struct sim_data, 1);
|
||||
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
data->retries[i] = -1;
|
||||
data->qmi_dev = device;
|
||||
|
||||
ofono_sim_set_data(sim, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_UIM, create_uim_cb, sim, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||
create_dms_cb, sim, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -501,9 +871,18 @@ static void qmi_sim_remove(struct ofono_sim *sim)
|
||||
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->uim);
|
||||
if (data->poll_source > 0)
|
||||
g_source_remove(data->poll_source);
|
||||
|
||||
qmi_service_unref(data->uim);
|
||||
if (data->uim) {
|
||||
qmi_service_unregister_all(data->uim);
|
||||
qmi_service_unref(data->uim);
|
||||
data->uim = NULL;
|
||||
}
|
||||
if (data->dms) {
|
||||
qmi_service_unregister_all(data->dms);
|
||||
qmi_service_unref(data->dms);
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
@@ -516,8 +895,13 @@ 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,
|
||||
.send_passwd = qmi_pin_send,
|
||||
};
|
||||
|
||||
void qmi_sim_init(void)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
|
||||
#define QMI_UIM_GET_FILE_ATTRIBUTES 36 /* Get file attributes */
|
||||
|
||||
#define QMI_UIM_VERIFY_PIN 38 /* Verify PIN */
|
||||
|
||||
#define QMI_UIM_EVENT_REGISTRATION 46 /* Register for indications */
|
||||
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
|
||||
|
||||
@@ -91,3 +93,12 @@ struct qmi_uim_file_attributes {
|
||||
uint16_t raw_len;
|
||||
uint8_t raw_value[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Verify PIN parameter */
|
||||
#define QMI_UIM_PARAM_MESSAGE_SESSION_INFO 0x01
|
||||
#define QMI_UIM_PARAM_MESSAGE_INFO 0x02
|
||||
struct qmi_uim_param_message_info {
|
||||
uint8_t pin_id;
|
||||
uint8_t length;
|
||||
uint8_t pin_value[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2011-2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -23,20 +24,103 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/ussd.h>
|
||||
|
||||
#include <smsutil.h>
|
||||
#include "qmi.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
#include "voice.h"
|
||||
|
||||
struct ussd_data {
|
||||
struct qmi_service *voice;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
static int validate_ussd_data(const struct qmi_ussd_data *data, uint16_t size)
|
||||
{
|
||||
if (data == NULL)
|
||||
return 1;
|
||||
|
||||
if (size < sizeof(*data))
|
||||
return 1;
|
||||
|
||||
if (size < sizeof(*data) + data->length)
|
||||
return 1;
|
||||
|
||||
if (data->dcs < QMI_USSD_DCS_ASCII || data->dcs > QMI_USSD_DCS_UCS2)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int convert_qmi_dcs_gsm_dcs(int qmi_dcs, int *gsm_dcs)
|
||||
{
|
||||
switch (qmi_dcs) {
|
||||
case QMI_USSD_DCS_ASCII:
|
||||
*gsm_dcs = USSD_DCS_8BIT;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void async_orig_ind(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_ussd *ussd = user_data;
|
||||
const struct qmi_ussd_data *qmi_ussd;
|
||||
uint16_t error = 0;
|
||||
uint16_t len;
|
||||
int gsm_dcs;
|
||||
|
||||
DBG("");
|
||||
|
||||
qmi_result_get_uint16(result, QMI_VOICE_PARAM_ASYNC_USSD_ERROR, &error);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
/* no error */
|
||||
break;
|
||||
case 92:
|
||||
qmi_result_get_uint16(result,
|
||||
QMI_VOICE_PARAM_ASYNC_USSD_FAILURE_CASE,
|
||||
&error);
|
||||
DBG("Failure Cause: 0x%04x", error);
|
||||
goto error;
|
||||
default:
|
||||
DBG("USSD Error 0x%04x", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
qmi_ussd = qmi_result_get(result, QMI_VOICE_PARAM_ASYNC_USSD_DATA,
|
||||
&len);
|
||||
if (qmi_ussd == NULL)
|
||||
return;
|
||||
|
||||
if (validate_ussd_data(qmi_ussd, len))
|
||||
goto error;
|
||||
|
||||
if (convert_qmi_dcs_gsm_dcs(qmi_ussd->dcs, &gsm_dcs))
|
||||
goto error;
|
||||
|
||||
ofono_ussd_notify(ussd, OFONO_USSD_STATUS_NOTIFY, gsm_dcs,
|
||||
qmi_ussd->data, qmi_ussd->length);
|
||||
return;
|
||||
|
||||
error:
|
||||
ofono_ussd_notify(ussd, OFONO_USSD_STATUS_TERMINATED, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static void create_voice_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_ussd *ussd = user_data;
|
||||
@@ -44,7 +128,7 @@ static void create_voice_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
if (service == NULL) {
|
||||
ofono_error("Failed to request Voice service");
|
||||
ofono_ussd_remove(ussd);
|
||||
return;
|
||||
@@ -58,6 +142,9 @@ static void create_voice_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
data->voice = qmi_service_ref(service);
|
||||
|
||||
qmi_service_register(data->voice, QMI_VOICE_ASYNC_ORIG_USSD,
|
||||
async_orig_ind, ussd, NULL);
|
||||
|
||||
ofono_ussd_register(ussd);
|
||||
}
|
||||
|
||||
@@ -77,7 +164,6 @@ static int qmi_ussd_probe(struct ofono_ussd *ussd,
|
||||
create_voice_cb, ussd, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void qmi_ussd_remove(struct ofono_ussd *ussd)
|
||||
@@ -93,10 +179,103 @@ static void qmi_ussd_remove(struct ofono_ussd *ussd)
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void qmi_ussd_cancel(struct ofono_ussd *ussd,
|
||||
ofono_ussd_cb_t cb, void *user_data)
|
||||
{
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(ud->voice, QMI_VOICE_CANCEL_USSD, NULL,
|
||||
NULL, NULL, NULL) > 0)
|
||||
CALLBACK_WITH_SUCCESS(cb, user_data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* The cb is called when the request (on modem layer) reports success or
|
||||
* failure. It doesn't contain a network result. We get the network answer
|
||||
* via VOICE_IND.
|
||||
*/
|
||||
static void qmi_ussd_request_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_ussd_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
qmi_result_print_tlvs(result);
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
const unsigned char *pdu, int len,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct qmi_ussd_data *qmi_ussd;
|
||||
struct qmi_param *param;
|
||||
char *utf8 = NULL;
|
||||
long utf8_len = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (dcs) {
|
||||
case 0xf: /* 7bit GSM unspecific */
|
||||
utf8 = ussd_decode(dcs, len, pdu);
|
||||
if (!utf8)
|
||||
goto error;
|
||||
|
||||
utf8_len = strlen(utf8);
|
||||
break;
|
||||
default:
|
||||
DBG("Unsupported USSD Data Coding Scheme 0x%x", dcs);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* So far only DCS_ASCII works.
|
||||
* DCS_8BIT and DCS_UCS2 is broken, because the modem firmware
|
||||
* (least on a EC20) encodes those in-correctly onto the air interface,
|
||||
* resulting in wrong decoded USSD data.
|
||||
*/
|
||||
qmi_ussd = alloca(sizeof(struct qmi_ussd_data) + utf8_len);
|
||||
qmi_ussd->dcs = QMI_USSD_DCS_ASCII;
|
||||
qmi_ussd->length = len;
|
||||
memcpy(qmi_ussd->data, utf8, utf8_len);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (param == NULL)
|
||||
goto error;
|
||||
|
||||
qmi_param_append(param, QMI_VOICE_PARAM_USS_DATA,
|
||||
sizeof(struct qmi_ussd_data) + utf8_len, qmi_ussd);
|
||||
|
||||
if (qmi_service_send(ud->voice, QMI_VOICE_ASYNC_ORIG_USSD, param,
|
||||
qmi_ussd_request_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
error:
|
||||
g_free(utf8);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static struct ofono_ussd_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_ussd_probe,
|
||||
.remove = qmi_ussd_remove,
|
||||
.request = qmi_ussd_request,
|
||||
.cancel = qmi_ussd_cancel
|
||||
};
|
||||
|
||||
void qmi_ussd_init(void)
|
||||
|
||||
@@ -39,6 +39,15 @@ static inline struct cb_data *cb_data_new(void *cb, void *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CALLBACK_WITH_CME_ERROR(cb, err, args...) \
|
||||
do { \
|
||||
struct ofono_error cb_e; \
|
||||
cb_e.type = OFONO_ERROR_TYPE_CME; \
|
||||
cb_e.error = err; \
|
||||
\
|
||||
cb(&cb_e, ##args); \
|
||||
} while (0) \
|
||||
|
||||
#define CALLBACK_WITH_FAILURE(cb, args...) \
|
||||
do { \
|
||||
struct ofono_error cb_e; \
|
||||
|
||||
62
ofono/drivers/qmimodem/voice.h
Normal file
62
ofono/drivers/qmimodem/voice.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define QMI_VOICE_PARAM_USS_DATA 0x01
|
||||
|
||||
#define QMI_VOICE_PARAM_ASYNC_USSD_ERROR 0x10
|
||||
#define QMI_VOICE_PARAM_ASYNC_USSD_FAILURE_CASE 0x11
|
||||
#define QMI_VOICE_PARAM_ASYNC_USSD_DATA 0x12
|
||||
|
||||
#define QMI_VOICE_PARAM_USSD_IND_USER_ACTION 0x01
|
||||
#define QMI_VOICE_PARAM_USSD_IND_DATA 0x10
|
||||
#define QMI_VOICE_PARAM_USSD_IND_UCS2 0x11
|
||||
|
||||
/* according to GSM TS 23.038 section 5
|
||||
* coding group 1111, No message class, 8 bit data
|
||||
*/
|
||||
#define USSD_DCS_8BIT 0xf4
|
||||
/* coding group 01xx, Class 0, UCS2 (16 bit) */
|
||||
#define USSD_DCS_UCS2 0x48
|
||||
/* default alphabet Language unspecific */
|
||||
#define USSD_DCS_UNSPECIFIC 0x0f
|
||||
|
||||
/* based on qmi ussd definition */
|
||||
enum qmi_ussd_dcs {
|
||||
QMI_USSD_DCS_ASCII = 0x1,
|
||||
QMI_USSD_DCS_8BIT,
|
||||
QMI_USSD_DCS_UCS2,
|
||||
};
|
||||
|
||||
enum qmi_ussd_user_required {
|
||||
QMI_USSD_NO_USER_ACTION_REQUIRED = 0x1,
|
||||
QMI_USSD_USER_ACTION_REQUIRED,
|
||||
};
|
||||
|
||||
/* QMI service voice. Using an enum to prevent doublicated entries */
|
||||
enum voice_commands {
|
||||
QMI_VOICE_CANCEL_USSD = 0x3c,
|
||||
QMI_VOICE_USSD_RELEASE_IND = 0x3d,
|
||||
QMI_VOICE_USSD_IND = 0x3e,
|
||||
QMI_VOICE_SUPS_IND = 0x42,
|
||||
QMI_VOICE_ASYNC_ORIG_USSD = 0x43,
|
||||
};
|
||||
|
||||
struct qmi_ussd_data {
|
||||
uint8_t dcs;
|
||||
uint8_t length;
|
||||
uint8_t data[0];
|
||||
} __attribute__((__packed__));
|
||||
25
ofono/drivers/qmimodem/wda.h
Normal file
25
ofono/drivers/qmimodem/wda.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Kerlink SA. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define QMI_WDA_SET_DATA_FORMAT 32 /* Set data format */
|
||||
#define QMI_WDA_GET_DATA_FORMAT 33 /* Get data format */
|
||||
|
||||
/* Get and set data format interface */
|
||||
#define QMI_WDA_LL_PROTOCOL 0x11 /* uint32_t */
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_UNKNOWN 0
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_802_3 1
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP 2
|
||||
@@ -30,6 +30,13 @@
|
||||
/* Start WDS network interface */
|
||||
#define QMI_WDS_PARAM_APN 0x14 /* string */
|
||||
#define QMI_WDS_PARAM_IP_FAMILY 0x19 /* uint8 */
|
||||
#define QMI_WDS_PARAM_USERNAME 0x17 /* string */
|
||||
#define QMI_WDS_PARAM_PASSWORD 0x18 /* string */
|
||||
#define QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE 0x16 /* uint8 */
|
||||
|
||||
#define QMI_WDS_AUTHENTICATION_NONE 0x0
|
||||
#define QMI_WDS_AUTHENTICATION_PAP 0x1
|
||||
#define QMI_WDS_AUTHENTICATION_CHAP 0x2
|
||||
|
||||
#define QMI_WDS_RESULT_PKT_HANDLE 0x01 /* uint32 */
|
||||
|
||||
@@ -51,10 +58,12 @@ struct qmi_wds_notify_conn_status {
|
||||
|
||||
/* Get the runtime data session settings */
|
||||
#define QMI_WDS_RESULT_PDP_TYPE 0x11 /* uint8 */
|
||||
#define QMI_WDS_RESULT_APN 0x14 /* string */
|
||||
#define QMI_WDS_RESULT_PRIMARY_DNS 0x15 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_GATEWAY 0x20 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_GATEWAY_NETMASK 0x21 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_IP_FAMILY 0x2b /* uint8 */
|
||||
|
||||
#define QMI_WDS_PDP_TYPE_IPV4 0x00
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#define QMI_WMS_RAW_SEND 32 /* Send a raw message */
|
||||
|
||||
#define QMI_WMS_RAW_READ 34 /* Read raw message from storage*/
|
||||
|
||||
#define QMI_WMS_GET_MSG_LIST 49 /* Get list of messages from the device */
|
||||
#define QMI_WMS_SET_ROUTES 50 /* Set routes for message memory storage */
|
||||
#define QMI_WMS_GET_ROUTES 51 /* Get routes for message memory storage */
|
||||
@@ -62,9 +64,17 @@ struct qmi_wms_param_message {
|
||||
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
||||
#define QMI_WMS_STORAGE_TYPE_NV 1
|
||||
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
||||
#define QMI_WMS_STORAGE_TYPE_NONE 255
|
||||
|
||||
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
||||
|
||||
struct qmi_wms_raw_message {
|
||||
uint8_t msg_tag;
|
||||
uint8_t msg_format;
|
||||
uint16_t msg_length;
|
||||
uint8_t msg_data[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Get routes for message memory storage */
|
||||
#define QMI_WMS_RESULT_ROUTE_LIST 0x01
|
||||
#define QMI_WMS_PARAM_ROUTE_LIST 0x01
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,9 +14,9 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
* ril.h does not state that string count must be given, but that is
|
||||
* still expected by the modem
|
||||
*/
|
||||
#define RIL_QUERY_STRING_COUNT 4
|
||||
#define RIL_SET_STRING_COUNT 5
|
||||
#define RIL_SET_PW_STRING_COUNT 3
|
||||
|
||||
struct ril_call_barring {
|
||||
struct ril_sim_card *card;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
@@ -107,7 +107,7 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
GRilIoRequest *req;
|
||||
|
||||
DBG("lock: %s, services to query: %d", lock, cls);
|
||||
|
||||
@@ -124,15 +124,9 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
|
||||
/*
|
||||
* See 3GPP 27.007 7.4 for parameter descriptions.
|
||||
* According to ril.h password should be empty string "" when not
|
||||
* needed, but in reality we only need to give string length as 0
|
||||
*/
|
||||
grilio_request_append_int32(req, RIL_QUERY_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_int32(req, 0); /* Password length */
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
|
||||
req = grilio_request_array_utf8_new(4, lock, "", cls_textual,
|
||||
ril_sim_card_app_aid(bd->card));
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_call_barring_query_cb, cb, data);
|
||||
@@ -183,7 +177,7 @@ static void ril_call_barring_set(struct ofono_call_barring *b,
|
||||
RIL_FACILITY_UNLOCK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
grilio_request_append_utf8(req, ril_sim_card_app_aid(bd->card));
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
@@ -244,6 +238,7 @@ static int ril_call_barring_probe(struct ofono_call_barring *b,
|
||||
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
|
||||
|
||||
DBG("");
|
||||
bd->card = ril_sim_card_ref(modem->sim_card);
|
||||
bd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
bd->timer_id = g_idle_add(ril_call_barring_register, b);
|
||||
ofono_call_barring_set_data(b, bd);
|
||||
@@ -261,6 +256,7 @@ static void ril_call_barring_remove(struct ofono_call_barring *b)
|
||||
g_source_remove(bd->timer_id);
|
||||
}
|
||||
|
||||
ril_sim_card_unref(bd->card);
|
||||
grilio_queue_cancel_all(bd->q, FALSE);
|
||||
grilio_queue_unref(bd->q);
|
||||
g_free(bd);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ril_call_volume {
|
||||
struct ofono_call_volume *v;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,27 +16,141 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct ril_cbs {
|
||||
struct ofono_cbs *cbs;
|
||||
GRilIoChannel *io;
|
||||
guint timer_id;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
guint register_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
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 ofono_error error;
|
||||
cb(ril_error_ok(&error), 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_clear_topics(struct ofono_cbs *cbs,
|
||||
static gboolean ril_cbs_retry(GRilIoRequest *request, int ril_status,
|
||||
const void *resp_data, guint resp_len, void *user_data)
|
||||
{
|
||||
return ril_status == RIL_E_INVALID_STATE;
|
||||
}
|
||||
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
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_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
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_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
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 ofono_error error;
|
||||
cb(ril_error_ok(&error), 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,
|
||||
@@ -44,32 +158,40 @@ static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char* pdu;
|
||||
guint32 pdu_len;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
pdu = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", pdu);
|
||||
if (pdu) {
|
||||
ofono_cbs_notify(cd->cbs, (const guchar *)pdu, strlen(pdu));
|
||||
g_free(pdu);
|
||||
if (grilio_parser_get_uint32(&rilp, &pdu_len)) {
|
||||
const void* pdu = grilio_parser_get_bytes(&rilp, pdu_len);
|
||||
|
||||
/*
|
||||
* By default assume that it's a length followed by the
|
||||
* binary PDU data.
|
||||
*/
|
||||
if (pdu && grilio_parser_bytes_remaining(&rilp) < 4) {
|
||||
DBG_(cd, "%u bytes", pdu_len);
|
||||
ofono_cbs_notify(cd->cbs, pdu, pdu_len);
|
||||
} else {
|
||||
/*
|
||||
* But I've seen cell broadcasts arriving without
|
||||
* the length, simply as a blob.
|
||||
*/
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_register(gpointer user_data)
|
||||
static gboolean ril_cbs_register(void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(cd->timer_id);
|
||||
cd->timer_id = 0;
|
||||
ofono_cbs_register(cd->cbs);
|
||||
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->register_id = 0;
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
ofono_cbs_register(cd->cbs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
@@ -78,11 +200,15 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
|
||||
DBG("");
|
||||
cd->cbs = cbs;
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->timer_id = g_idle_add(ril_cbs_register, cd);
|
||||
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);
|
||||
cd->register_id = g_idle_add(ril_cbs_register, cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -90,15 +216,16 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG("");
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
|
||||
if (cd->timer_id > 0) {
|
||||
g_source_remove(cd->timer_id);
|
||||
DBG_(cd, "");
|
||||
if (cd->register_id) {
|
||||
g_source_remove(cd->register_id);
|
||||
}
|
||||
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
grilio_queue_cancel_all(cd->q, FALSE);
|
||||
grilio_queue_unref(cd->q);
|
||||
g_free(cd->log_prefix);
|
||||
g_free(cd);
|
||||
}
|
||||
|
||||
@@ -106,8 +233,8 @@ const struct ofono_cbs_driver ril_cbs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_set_topics,
|
||||
.clear_topics = ril_clear_topics
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,28 +18,31 @@
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_mce.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||
#include <gutil_idlepool.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define DEFAULT_UPDATE_RATE_MS (10000) /* 10 sec */
|
||||
#define MAX_RETRIES (5)
|
||||
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
|
||||
struct ril_cell_info_priv {
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct sailfish_cell_info info;
|
||||
GRilIoChannel *io;
|
||||
struct ril_mce *mce;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
gulong display_state_event_id;
|
||||
gulong radio_state_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gboolean sim_card_ready;
|
||||
int update_rate_ms;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
@@ -59,63 +63,36 @@ G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
static inline void ril_cell_free(struct sailfish_cell *cell)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
if (c1->type != c2->type) {
|
||||
return c1->type - c2->type;
|
||||
} else if (c1->type == RIL_CELL_INFO_TYPE_GSM) {
|
||||
const struct ril_cell_info_gsm *g1 = &c1->info.gsm;
|
||||
const struct ril_cell_info_gsm *g2 = &c2->info.gsm;
|
||||
|
||||
if (g1->lac != g2->lac) {
|
||||
return g1->lac - g2->lac;
|
||||
} else {
|
||||
return g1->cid - g2->cid;
|
||||
}
|
||||
} else if (c2->type == RIL_CELL_INFO_TYPE_WCDMA) {
|
||||
const struct ril_cell_info_wcdma *w1 = &c1->info.wcdma;
|
||||
const struct ril_cell_info_wcdma *w2 = &c2->info.wcdma;
|
||||
|
||||
if (w1->lac != w2->lac) {
|
||||
return w1->lac - w2->lac;
|
||||
} else {
|
||||
return w1->cid - w2->cid;
|
||||
}
|
||||
} else {
|
||||
const struct ril_cell_info_lte *l1 = &c1->info.lte;
|
||||
const struct ril_cell_info_lte *l2 = &c2->info.lte;
|
||||
|
||||
GASSERT(c1->type == RIL_CELL_INFO_TYPE_LTE);
|
||||
if (l1->ci != l2->ci) {
|
||||
return l1->ci - l2->ci;
|
||||
} else if (l1->pci != l2->pci) {
|
||||
return l1->pci - l2->pci;
|
||||
} else {
|
||||
return l1->tac - l2->tac;
|
||||
}
|
||||
}
|
||||
} else if (c1) {
|
||||
return 1;
|
||||
} else if (c2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
g_slice_free(struct sailfish_cell, cell);
|
||||
}
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
static void ril_cell_free1(gpointer cell)
|
||||
{
|
||||
return ril_cell_compare_location(v1, v2);
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static const char *ril_cell_info_int_format(int value, const char *format)
|
||||
{
|
||||
if (value == SAILFISH_CELL_INVALID_VALUE) {
|
||||
return "";
|
||||
} else {
|
||||
static GUtilIdlePool *ril_cell_info_pool = NULL;
|
||||
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
|
||||
char *str = g_strdup_printf(format, value);
|
||||
|
||||
gutil_idle_pool_add(pool, str, g_free);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
@@ -126,121 +103,166 @@ static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
|
||||
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||
{
|
||||
if (!ril_cell_info_list_identical(self->cells, l)) {
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
self->cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals[
|
||||
SIGNAL_CELLS_CHANGED], 0);
|
||||
if (!ril_cell_info_list_identical(self->info.cells, l)) {
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
self->info.cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals
|
||||
[SIGNAL_CELLS_CHANGED], 0);
|
||||
} else {
|
||||
g_slist_free_full(l, g_free);
|
||||
g_slist_free_full(l, ril_cell_free1);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
|
||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
|
||||
/* 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)) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,"
|
||||
"strength=%d,err=%d", registered, gsm->mcc, gsm->mnc,
|
||||
gsm->lac, gsm->cid, gsm->signalStrength,
|
||||
gsm->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_GSM;
|
||||
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%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
|
||||
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
|
||||
ril_cell_info_int_format(gsm->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
|
||||
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
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 = RIL_CELL_INFO_TYPE_WCDMA;
|
||||
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
|
||||
ril_cell_info_int_format(wcdma->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(wcdma->bitErrorRate,
|
||||
",err=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_lte *lte = &cell->info.lte;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = SAILFISH_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
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=0x%x,rssnr=0x%x,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 = RIL_CELL_INFO_TYPE_LTE;
|
||||
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(lte->ci, ",ci=%d"),
|
||||
ril_cell_info_int_format(lte->pci, ",pci=%d"),
|
||||
ril_cell_info_int_format(lte->tac, ",tac=%d"),
|
||||
ril_cell_info_int_format(lte->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
|
||||
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
|
||||
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
|
||||
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
|
||||
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
struct ril_cell **cell_ptr)
|
||||
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 ril_cell *cell = NULL;
|
||||
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, reg);
|
||||
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, reg);
|
||||
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, reg);
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
skip = 10;
|
||||
@@ -255,20 +277,20 @@ static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
|
||||
if (cell) {
|
||||
*cell_ptr = cell;
|
||||
return type;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||
*cell_ptr = NULL;
|
||||
return type;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*cell_ptr = NULL;
|
||||
return RIL_CELL_INFO_TYPE_NONE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
|
||||
{
|
||||
GSList *l = NULL;
|
||||
GRilIoParser rilp;
|
||||
@@ -276,17 +298,18 @@ static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct ril_cell *c;
|
||||
struct sailfish_cell *c;
|
||||
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, &c); i++) {
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
|
||||
if (c) {
|
||||
l = g_slist_insert_sorted(l, c,
|
||||
ril_cell_compare_func);
|
||||
sailfish_cell_compare_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -296,85 +319,75 @@ static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
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);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
|
||||
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->set_rate_id);
|
||||
priv->set_rate_id = 0;
|
||||
GASSERT(self->set_rate_id);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_retry(GRilIoRequest* request, int ril_status,
|
||||
const void* response_data, guint response_len, void* user_data)
|
||||
{
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = grilio_channel_send_request_full(priv->io, req,
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1,
|
||||
(self->update_rate_ms > 0) ? self->update_rate_ms : INT_MAX);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id, FALSE);
|
||||
priv->set_rate_id = grilio_channel_send_request_full(priv->io, req,
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
||||
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
ril_cell_info_set_rate_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
ril_cell_info_set_rate(self,
|
||||
(priv->mce->display_state == RIL_MCE_DISPLAY_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
}
|
||||
|
||||
static void ril_cell_info_display_state_cb(struct ril_mce *mce, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
|
||||
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
@@ -392,126 +405,161 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
const gboolean sim_card_was_ready = priv->sim_card_ready;
|
||||
|
||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (priv->sim_card_ready != sim_card_was_ready) {
|
||||
ril_cell_info_refresh(self);
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
/* sailfish_cell_info interface callbacks */
|
||||
|
||||
struct ril_cell_info_closure {
|
||||
GCClosure cclosure;
|
||||
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,
|
||||
struct ril_cell_info_closure *closure)
|
||||
{
|
||||
closure->cb(&self->info, closure->arg);
|
||||
}
|
||||
|
||||
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_closure *closure =
|
||||
(struct ril_cell_info_closure *) g_closure_new_simple
|
||||
(sizeof(struct ril_cell_info_closure), NULL);
|
||||
GCClosure* cc = &closure->cclosure;
|
||||
|
||||
cc->closure.data = closure;
|
||||
cc->callback = G_CALLBACK(ril_cell_info_cells_changed_cb);
|
||||
closure->cb = cb;
|
||||
closure->arg = arg;
|
||||
return g_signal_connect_closure_by_id(ril_cell_info_cast(info),
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED], 0,
|
||||
&cc->closure, FALSE);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_update_interval_proc
|
||||
(struct sailfish_cell_info *info, int ms)
|
||||
{
|
||||
struct ril_cell_info *self = ril_cell_info_cast(info);
|
||||
|
||||
if (self->update_rate_ms != ms) {
|
||||
self->update_rate_ms = ms;
|
||||
DBG_(self, "%d ms", ms);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
|
||||
ril_cell_info_cb_t cb, void *arg)
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
|
||||
ril_cell_info_ref_proc,
|
||||
ril_cell_info_unref_proc,
|
||||
ril_cell_info_add_cells_changed_handler_proc,
|
||||
ril_cell_info_remove_handler_proc,
|
||||
ril_cell_info_set_update_interval_proc
|
||||
};
|
||||
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_mce *mce,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card)
|
||||
{
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->mce = ril_mce_ref(mce);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
self->info.proc = &ril_cell_info_proc;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->radio = ril_radio_ref(radio);
|
||||
self->sim_card = ril_sim_card_ref(sim_card);
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
priv->display_state_event_id =
|
||||
ril_mce_add_display_state_changed_handler(mce,
|
||||
ril_cell_info_display_state_cb, self);
|
||||
priv->radio_state_event_id =
|
||||
self->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(radio,
|
||||
ril_cell_info_radio_state_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
self->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_CELL_INFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_unref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_CELL_INFO(self));
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_CELL_INFO_TYPE,
|
||||
struct ril_cell_info_priv);
|
||||
self->update_rate_ms = DEFAULT_UPDATE_RATE_MS;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, &priv->event_id, 1);
|
||||
if (priv->query_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = 0;
|
||||
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
|
||||
if (self->query_id) {
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = 0;
|
||||
}
|
||||
if (priv->set_rate_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
|
||||
if (self->set_rate_id) {
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id,
|
||||
FALSE);
|
||||
priv->set_rate_id = 0;
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
if (priv->display_state_event_id) {
|
||||
ril_mce_remove_handler(priv->mce, priv->display_state_event_id);
|
||||
priv->display_state_event_id = 0;
|
||||
}
|
||||
ril_radio_remove_handlers(priv->radio, &priv->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(priv->sim_card,
|
||||
&priv->sim_status_event_id, 1);
|
||||
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(self->sim_card,
|
||||
&self->sim_status_event_id, 1);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
ril_mce_unref(priv->mce);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
g_free(self->log_prefix);
|
||||
grilio_channel_unref(self->io);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -521,7 +569,6 @@ static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_cell_info_priv));
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,39 +18,11 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_cell {
|
||||
enum ril_cell_info_type type;
|
||||
gboolean registered;
|
||||
union {
|
||||
struct ril_cell_info_gsm gsm;
|
||||
struct ril_cell_info_wcdma wcdma;
|
||||
struct ril_cell_info_lte lte;
|
||||
} info;
|
||||
};
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
struct ril_cell_info_priv;
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct ril_cell_info_priv *priv;
|
||||
GSList *cells;
|
||||
};
|
||||
|
||||
typedef void (*ril_cell_info_cb_t)(struct ril_cell_info *info, void *arg);
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2);
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2);
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_mce *mce,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card);
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *info);
|
||||
void ril_cell_info_unref(struct ril_cell_info *info);
|
||||
struct ril_cell *ril_cell_find_cell(struct ril_cell_info *info,
|
||||
const struct ril_cell *cell);
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *info,
|
||||
ril_cell_info_cb_t cb, void *arg);
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *info, gulong id);
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card);
|
||||
|
||||
#endif /* RIL_CELL_INFO_H */
|
||||
|
||||
|
||||
@@ -1,586 +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_plugin.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
struct ril_cell_entry {
|
||||
guint cell_id;
|
||||
char *path;
|
||||
struct ril_cell cell;
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus {
|
||||
struct ril_modem *md;
|
||||
struct ril_cell_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
};
|
||||
|
||||
#define RIL_CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
|
||||
#define RIL_CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define RIL_CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
#define RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
|
||||
#define RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define RIL_CELL_DBUS_REMOVED_SIGNAL "Removed"
|
||||
|
||||
struct ril_cell_property {
|
||||
const char *name;
|
||||
glong off;
|
||||
int flag;
|
||||
};
|
||||
|
||||
#define RIL_CELL_GSM_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_gsm,name), value }
|
||||
#define RIL_CELL_WCDMA_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_wcdma,name), value }
|
||||
#define RIL_CELL_LTE_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_lte,name), value }
|
||||
|
||||
static const struct ril_cell_property ril_cell_gsm_properties [] = {
|
||||
RIL_CELL_GSM_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_GSM_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_GSM_PROPERTY(0x04,lac),
|
||||
RIL_CELL_GSM_PROPERTY(0x08,cid),
|
||||
RIL_CELL_GSM_PROPERTY(0x10,signalStrength),
|
||||
RIL_CELL_GSM_PROPERTY(0x20,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_wcdma_properties [] = {
|
||||
RIL_CELL_WCDMA_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x04,lac),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x08,cid),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x10,psc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x20,signalStrength),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x40,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_lte_properties [] = {
|
||||
RIL_CELL_LTE_PROPERTY(0x001,mcc),
|
||||
RIL_CELL_LTE_PROPERTY(0x002,mnc),
|
||||
RIL_CELL_LTE_PROPERTY(0x004,ci),
|
||||
RIL_CELL_LTE_PROPERTY(0x008,pci),
|
||||
RIL_CELL_LTE_PROPERTY(0x010,tac),
|
||||
RIL_CELL_LTE_PROPERTY(0x020,signalStrength),
|
||||
RIL_CELL_LTE_PROPERTY(0x040,rsrp),
|
||||
RIL_CELL_LTE_PROPERTY(0x080,rsrq),
|
||||
RIL_CELL_LTE_PROPERTY(0x100,rssnr),
|
||||
RIL_CELL_LTE_PROPERTY(0x200,cqi),
|
||||
RIL_CELL_LTE_PROPERTY(0x400,timingAdvance)
|
||||
};
|
||||
|
||||
#define RIL_CELL_PROPERTY_REGISTERED 0x1000
|
||||
|
||||
typedef void (*ril_cell_info_dbus_append_fn)(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry);
|
||||
|
||||
static const char *ril_cell_info_dbus_cell_type_str(enum ril_cell_info_type t)
|
||||
{
|
||||
switch (t) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
return "gsm";
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
return "cdma";
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
return "lte";
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
return "wcdma";
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
return "tdscdma";
|
||||
case RIL_CELL_INFO_TYPE_NONE:
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ril_cell_property *ril_cell_info_dbus_cell_properties(
|
||||
enum ril_cell_info_type type, int *count)
|
||||
{
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
*count = G_N_ELEMENTS(ril_cell_gsm_properties);
|
||||
return ril_cell_gsm_properties;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
*count = G_N_ELEMENTS(ril_cell_wcdma_properties);
|
||||
return ril_cell_wcdma_properties;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
*count = G_N_ELEMENTS(ril_cell_lte_properties);
|
||||
return ril_cell_lte_properties;
|
||||
default:
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static void ril_cell_info_destroy_entry(struct ril_cell_entry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
g_free(entry->path);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_reply(DBusMessage *msg,
|
||||
const struct ril_cell_entry *entry,
|
||||
ril_cell_info_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
append(&it, entry);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_version(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_int32_t version = RIL_CELL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
const char *type = ril_cell_info_dbus_cell_type_str(entry->cell.type);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
int i, n;
|
||||
DBusMessageIter dict;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
||||
for (i = 0; i < n; i++) {
|
||||
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
|
||||
if (value != INT_MAX) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_close_container(it, &dict);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_all(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
ril_cell_info_dbus_append_version(it, entry);
|
||||
ril_cell_info_dbus_append_type(it, entry);
|
||||
ril_cell_info_dbus_append_registered(it, entry);
|
||||
ril_cell_info_dbus_append_properties(it, entry);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_type(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_type);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_registered(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_registered);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_properties(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_properties);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_cell_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll", NULL,
|
||||
GDBUS_ARGS({ "version", "i" },
|
||||
{ "type", "s" },
|
||||
{ "registered", "b" },
|
||||
{ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
|
||||
GDBUS_ARGS({ "version", "i" }),
|
||||
ril_cell_info_dbus_cell_get_version) },
|
||||
{ GDBUS_METHOD("GetType", NULL,
|
||||
GDBUS_ARGS({ "type", "s" }),
|
||||
ril_cell_info_dbus_cell_get_type) },
|
||||
{ GDBUS_METHOD("GetRegistered", NULL,
|
||||
GDBUS_ARGS({ "registered", "b" }),
|
||||
ril_cell_info_dbus_cell_get_registered) },
|
||||
{ GDBUS_METHOD("GetProperties", NULL,
|
||||
GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_properties) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_cell_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "registered", "b" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_id(
|
||||
struct ril_cell_info_dbus *dbus, guint id)
|
||||
{
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (entry->cell_id == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint ril_cell_info_dbus_next_cell_id(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
while (ril_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
|
||||
dbus->next_cell_id++;
|
||||
}
|
||||
return dbus->next_cell_id++;
|
||||
}
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_cell(
|
||||
struct ril_cell_info_dbus *dbus, const struct ril_cell *cell)
|
||||
{
|
||||
if (cell) {
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!ril_cell_compare_location(&entry->cell, cell)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_emit_path_list(struct ril_cell_info_dbus *dbus,
|
||||
const char *name, GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static int ril_cell_info_dbus_compare(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
{
|
||||
if (c1->type == c2->type) {
|
||||
int i, n, mask = 0;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(c1->type, &n);
|
||||
|
||||
if (c1->registered != c2->registered) {
|
||||
mask |= RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const glong offset = prop[i].off;
|
||||
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
|
||||
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
|
||||
if (v1 != v2) {
|
||||
mask |= prop[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_property_changed(struct ril_cell_info_dbus *dbus,
|
||||
const struct ril_cell_entry *entry, int mask)
|
||||
{
|
||||
int i, n;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & RIL_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
mask &= ~RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, RIL_CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_update_entries(struct ril_cell_info_dbus *dbus,
|
||||
gboolean emit_signals)
|
||||
{
|
||||
GSList *l;
|
||||
GPtrArray* added = NULL;
|
||||
GPtrArray* removed = NULL;
|
||||
|
||||
/* Remove non-existent cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
|
||||
ril_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
if (emit_signals) {
|
||||
if (!removed) {
|
||||
removed =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_free);
|
||||
}
|
||||
/* Steal the path */
|
||||
g_ptr_array_add(removed, entry->path);
|
||||
entry->path = NULL;
|
||||
}
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
|
||||
/* Add new cells */
|
||||
for (l = dbus->info->cells; l; l = l->next) {
|
||||
const struct ril_cell *cell = l->data;
|
||||
struct ril_cell_entry *entry =
|
||||
ril_cell_info_dbus_find_cell(dbus, cell);
|
||||
|
||||
if (entry) {
|
||||
if (emit_signals) {
|
||||
int diff = ril_cell_info_dbus_compare(cell,
|
||||
&entry->cell);
|
||||
entry->cell = *cell;
|
||||
ril_cell_info_dbus_property_changed(dbus,
|
||||
entry, diff);
|
||||
} else {
|
||||
entry->cell = *cell;
|
||||
}
|
||||
} else {
|
||||
entry = g_new0(struct ril_cell_entry, 1);
|
||||
entry->cell = *cell;
|
||||
entry->cell_id = ril_cell_info_dbus_next_cell_id(dbus);
|
||||
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
|
||||
entry->cell_id);
|
||||
dbus->entries = g_slist_append(dbus->entries, entry);
|
||||
DBG("%s added", entry->path);
|
||||
g_dbus_register_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
ril_cell_info_dbus_cell_methods,
|
||||
ril_cell_info_dbus_cell_signals, NULL,
|
||||
entry, NULL);
|
||||
if (emit_signals) {
|
||||
if (!added) {
|
||||
added = g_ptr_array_new();
|
||||
}
|
||||
g_ptr_array_add(added, entry->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
|
||||
g_ptr_array_free(removed, TRUE);
|
||||
}
|
||||
|
||||
if (added) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
|
||||
g_ptr_array_free(added, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_cells_changed_cb(struct ril_cell_info *info,
|
||||
void *arg)
|
||||
{
|
||||
DBG("");
|
||||
ril_cell_info_dbus_update_entries((struct ril_cell_info_dbus *)arg,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct ril_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
ril_cell_info_dbus_get_cells) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = g_new0(struct ril_cell_info_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->md = md;
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->info = ril_cell_info_ref(info);
|
||||
dbus->handler_id = ril_cell_info_add_cells_changed_handler(info,
|
||||
ril_cell_info_dbus_cells_changed_cb, dbus);
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, ril_cell_info_dbus_methods,
|
||||
ril_cell_info_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ril_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_cell_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
/* Unregister cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
l = l->next;
|
||||
}
|
||||
g_slist_free(dbus->entries);
|
||||
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
ril_cell_info_remove_handler(dbus->info, dbus->handler_id);
|
||||
ril_cell_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,10 +15,20 @@
|
||||
*/
|
||||
|
||||
#include "ril_config.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
{
|
||||
char *val = g_key_file_get_string(file, group, key, NULL);
|
||||
|
||||
@@ -29,6 +40,31 @@ char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
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)
|
||||
{
|
||||
@@ -106,6 +142,168 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (result) {
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
char **values, **ptr;
|
||||
|
||||
if (comment) *comment = 0;
|
||||
values = g_strsplit(str, "+", -1);
|
||||
|
||||
for (ok = TRUE, ptr = values; *ptr && ok; ptr++) {
|
||||
const char* found_str = NULL;
|
||||
const char* s = g_strstrip(*ptr);
|
||||
|
||||
if (!strcasecmp(s, name)) {
|
||||
found_str = name;
|
||||
if (result) {
|
||||
*result |= value;
|
||||
}
|
||||
} else {
|
||||
va_list args;
|
||||
const char* known;
|
||||
|
||||
va_start(args, value);
|
||||
while ((known = va_arg(args, char*)) != NULL) {
|
||||
const int bit = va_arg(args, int);
|
||||
|
||||
if (!strcasecmp(s, known)) {
|
||||
found_str = known;
|
||||
if (result) {
|
||||
*result |= bit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!found_str) {
|
||||
ofono_error("Unknown bit '%s' in %s", s, key);
|
||||
ok = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(values);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
if (!ok && result) {
|
||||
*result = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key)
|
||||
{
|
||||
char *value = ril_config_get_string(file, group, key);
|
||||
|
||||
if (value) {
|
||||
GUtilIntArray *array = gutil_int_array_new();
|
||||
char **values, **ptr;
|
||||
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(value, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
values = g_strsplit(value, ",", -1);
|
||||
ptr = values;
|
||||
|
||||
while (*ptr) {
|
||||
int val;
|
||||
|
||||
if (gutil_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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -22,13 +23,27 @@
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
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, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||
|
||||
#endif /* RIL_CONFIG_H */
|
||||
|
||||
|
||||
622
ofono/drivers/ril/ril_connman.c
Normal file
622
ofono/drivers/ril/ril_connman.c
Normal file
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_connman.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define CONNMAN_BUS DBUS_BUS_SYSTEM
|
||||
#define CONNMAN_SERVICE "net.connman"
|
||||
#define CONNMAN_PATH "/"
|
||||
|
||||
#define CONNMAN_GET_PROPERTIES "GetProperties"
|
||||
#define CONNMAN_GET_TECHNOLOGIES "GetTechnologies"
|
||||
#define CONNMAN_PROPERTY_CHANGED "PropertyChanged"
|
||||
#define CONNMAN_TECH_CONNECTED "Connected"
|
||||
#define CONNMAN_TECH_TETHERING "Tethering"
|
||||
|
||||
#define CONNMAN_INTERFACE_(name) "net.connman." name
|
||||
#define CONNMAN_MANAGER_INTERFACE CONNMAN_INTERFACE_("Manager")
|
||||
#define CONNMAN_TECH_INTERFACE CONNMAN_INTERFACE_("Technology")
|
||||
|
||||
#define CONNMAN_TECH_PATH_(name) "/net/connman/technology/" name
|
||||
#define CONNMAN_TECH_PATH_WIFI CONNMAN_TECH_PATH_("wifi")
|
||||
|
||||
#define CONNMAN_TECH_CONNECTED_BIT (0x01)
|
||||
#define CONNMAN_TECH_TETHERING_BIT (0x02)
|
||||
#define CONNMAN_TECH_ALL_PROPERTY_BITS (\
|
||||
CONNMAN_TECH_CONNECTED_BIT | \
|
||||
CONNMAN_TECH_TETHERING_BIT)
|
||||
|
||||
typedef GObjectClass ConnManObjectClass;
|
||||
|
||||
typedef struct connman_tech ConnManTech;
|
||||
|
||||
typedef struct connman_object {
|
||||
GObject object;
|
||||
struct ril_connman pub;
|
||||
guint32 pending_signals;
|
||||
DBusConnection *connection;
|
||||
DBusPendingCall *call;
|
||||
guint service_watch;
|
||||
guint signal_watch;
|
||||
GHashTable *techs;
|
||||
ConnManTech *wifi;
|
||||
} ConnManObject;
|
||||
|
||||
G_DEFINE_TYPE(ConnManObject, connman_object, G_TYPE_OBJECT)
|
||||
#define CONNMAN_OBJECT_TYPE (connman_object_get_type())
|
||||
#define CONNMAN_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
CONNMAN_OBJECT_TYPE, ConnManObject))
|
||||
|
||||
struct connman_tech {
|
||||
ConnManObject *obj;
|
||||
const char *path;
|
||||
gboolean connected;
|
||||
gboolean tethering;
|
||||
};
|
||||
|
||||
typedef struct connman_closure {
|
||||
GCClosure cclosure;
|
||||
ril_connman_property_cb_t callback;
|
||||
gpointer user_data;
|
||||
} ConnManClosure;
|
||||
|
||||
#define connman_closure_new() ((ConnManClosure *) \
|
||||
g_closure_new_simple(sizeof(ConnManClosure), NULL))
|
||||
|
||||
#define SIGNAL_PROPERTY_CHANGED_NAME "ril-connman-property-changed"
|
||||
#define SIGNAL_PROPERTY_DETAIL "%x"
|
||||
#define SIGNAL_PROPERTY_DETAIL_MAX_LEN (8)
|
||||
|
||||
#define SIGNAL_BIT(property) (1 << (property - 1))
|
||||
#define SIGNAL_BIT_(name) SIGNAL_BIT(RIL_CONNMAN_PROPERTY_##name)
|
||||
|
||||
enum connman_object_signal {
|
||||
SIGNAL_PROPERTY_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
static guint connman_object_signals[SIGNAL_COUNT];
|
||||
static GQuark connman_object_property_quarks[RIL_CONNMAN_PROPERTY_COUNT - 1];
|
||||
|
||||
static inline ConnManObject *connman_object_cast(struct ril_connman *connman)
|
||||
{
|
||||
return G_LIKELY(connman) ?
|
||||
CONNMAN_OBJECT(G_CAST(connman, ConnManObject, pub)) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
static inline const char *connman_iter_get_string(DBusMessageIter *it)
|
||||
{
|
||||
const char *str = NULL;
|
||||
|
||||
dbus_message_iter_get_basic(it, &str);
|
||||
return str;
|
||||
}
|
||||
|
||||
static GQuark connman_object_property_quark(enum ril_connman_property p)
|
||||
{
|
||||
/* For ANY property this function is expected to return zero */
|
||||
if (p > RIL_CONNMAN_PROPERTY_ANY && p < RIL_CONNMAN_PROPERTY_COUNT) {
|
||||
const int i = p - 1;
|
||||
|
||||
if (G_UNLIKELY(!connman_object_property_quarks[i])) {
|
||||
char buf[SIGNAL_PROPERTY_DETAIL_MAX_LEN + 1];
|
||||
|
||||
snprintf(buf, sizeof(buf), SIGNAL_PROPERTY_DETAIL, p);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
connman_object_property_quarks[i] =
|
||||
g_quark_from_string(buf);
|
||||
}
|
||||
return connman_object_property_quarks[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connman_object_property_changed(ConnManObject *self,
|
||||
enum ril_connman_property property, ConnManClosure *closure)
|
||||
{
|
||||
closure->callback(&self->pub, property, closure->user_data);
|
||||
}
|
||||
|
||||
static void connman_object_emit_property_change(ConnManObject *self,
|
||||
enum ril_connman_property p)
|
||||
{
|
||||
self->pending_signals &= ~SIGNAL_BIT(p);
|
||||
g_signal_emit(self, connman_object_signals[SIGNAL_PROPERTY_CHANGED],
|
||||
connman_object_property_quark(p), p);
|
||||
}
|
||||
|
||||
static void connman_object_emit_pending_signals(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
gboolean valid_changed, present_changed;
|
||||
enum ril_connman_property p;
|
||||
|
||||
/* Handlers could drop their references to us */
|
||||
g_object_ref(self);
|
||||
|
||||
/*
|
||||
* PRESENT and VALID are the last signals to be emitted if the object
|
||||
* BECOMES present and/or valid.
|
||||
*/
|
||||
if ((self->pending_signals & SIGNAL_BIT_(VALID)) &&
|
||||
connman->valid) {
|
||||
self->pending_signals &= ~SIGNAL_BIT_(VALID);
|
||||
valid_changed = TRUE;
|
||||
} else {
|
||||
valid_changed = FALSE;
|
||||
}
|
||||
if ((self->pending_signals & SIGNAL_BIT_(PRESENT)) &&
|
||||
connman->present) {
|
||||
self->pending_signals &= ~SIGNAL_BIT_(PRESENT);
|
||||
present_changed = TRUE;
|
||||
} else {
|
||||
present_changed = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit the signals. Not that in case if valid has become FALSE,
|
||||
* then VALID is emitted first, otherwise it's emitted last.
|
||||
* Same thing with PRESENT.
|
||||
*/
|
||||
for (p = RIL_CONNMAN_PROPERTY_ANY + 1;
|
||||
p < RIL_CONNMAN_PROPERTY_COUNT && self->pending_signals;
|
||||
p++) {
|
||||
if (self->pending_signals & SIGNAL_BIT(p)) {
|
||||
connman_object_emit_property_change(self, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Then emit PRESENT and VALID if necessary */
|
||||
if (present_changed) {
|
||||
connman_object_emit_property_change(self,
|
||||
RIL_CONNMAN_PROPERTY_PRESENT);
|
||||
}
|
||||
if (valid_changed) {
|
||||
connman_object_emit_property_change(self,
|
||||
RIL_CONNMAN_PROPERTY_VALID);
|
||||
}
|
||||
|
||||
/* And release the temporary reference */
|
||||
g_object_unref(self);
|
||||
}
|
||||
|
||||
static void connman_cancel_call(ConnManObject *self)
|
||||
{
|
||||
if (self->call) {
|
||||
dbus_pending_call_cancel(self->call);
|
||||
dbus_pending_call_unref(self->call);
|
||||
self->call = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static ConnManTech *connman_tech_new(ConnManObject *self, const char *path)
|
||||
{
|
||||
ConnManTech *tech = g_new0(ConnManTech, 1);
|
||||
char *key = g_strdup(path);
|
||||
|
||||
tech->obj = self;
|
||||
tech->path = key;
|
||||
g_hash_table_replace(self->techs, key, tech);
|
||||
return tech;
|
||||
}
|
||||
|
||||
static void connman_invalidate(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (connman->valid) {
|
||||
connman->valid = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_update_valid(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
const gboolean valid = (connman->present && !self->call);
|
||||
|
||||
if (connman->valid != valid) {
|
||||
connman->valid = valid;
|
||||
self->pending_signals |= SIGNAL_BIT_(VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean connman_update_tethering(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
gboolean tethering = FALSE;
|
||||
GHashTableIter it;
|
||||
gpointer value;
|
||||
|
||||
g_hash_table_iter_init(&it, self->techs);
|
||||
while (g_hash_table_iter_next(&it, NULL, &value)) {
|
||||
const ConnManTech *tech = value;
|
||||
|
||||
if (tech->tethering) {
|
||||
tethering = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (connman->tethering != tethering) {
|
||||
connman->tethering = tethering;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_set_tech_tethering(ConnManTech *tech, gboolean tethering)
|
||||
{
|
||||
if (tech->tethering != tethering) {
|
||||
ConnManObject *self = tech->obj;
|
||||
|
||||
tech->tethering = tethering;
|
||||
DBG(CONNMAN_TECH_TETHERING " %s for %s",
|
||||
tethering ? "on" : "off", tech->path);
|
||||
if (tethering) {
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (G_LIKELY(!connman->tethering)) {
|
||||
/* Definitely tethering now */
|
||||
connman->tethering = TRUE;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
DBG("Tethering on");
|
||||
}
|
||||
} else if (connman_update_tethering(self)) {
|
||||
/* Not tethering anymore */
|
||||
DBG("Tethering off");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_set_tech_connected(ConnManTech *tech, gboolean connected)
|
||||
{
|
||||
if (tech->connected != connected) {
|
||||
ConnManObject *self = tech->obj;
|
||||
|
||||
tech->connected = connected;
|
||||
DBG(CONNMAN_TECH_CONNECTED " %s for %s",
|
||||
connected ? "on" : "off", tech->path);
|
||||
if (tech == self->wifi) {
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
connman->wifi_connected = connected;
|
||||
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
|
||||
DBG("WiFi %sconnected", connected ? "" : "dis");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int connman_tech_set_property(ConnManTech *tech, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter var;
|
||||
DBusBasicValue value;
|
||||
const char *key = connman_iter_get_string(it);
|
||||
|
||||
dbus_message_iter_next(it);
|
||||
dbus_message_iter_recurse(it, &var);
|
||||
dbus_message_iter_get_basic(&var, &value);
|
||||
if (!g_ascii_strcasecmp(key, CONNMAN_TECH_CONNECTED)) {
|
||||
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
|
||||
connman_set_tech_connected(tech, value.bool_val);
|
||||
return CONNMAN_TECH_CONNECTED_BIT;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(key, CONNMAN_TECH_TETHERING)) {
|
||||
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
|
||||
connman_set_tech_tethering(tech, value.bool_val);
|
||||
return CONNMAN_TECH_TETHERING_BIT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connman_tech_set_properties(ConnManTech *tech, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter dict;
|
||||
int handled = 0;
|
||||
|
||||
dbus_message_iter_recurse(it, &dict);
|
||||
while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
|
||||
DBusMessageIter entry;
|
||||
|
||||
dbus_message_iter_recurse(&dict, &entry);
|
||||
handled |= connman_tech_set_property(tech, &entry);
|
||||
if (handled == CONNMAN_TECH_ALL_PROPERTY_BITS) {
|
||||
/* Ignore the rest */
|
||||
break;
|
||||
}
|
||||
dbus_message_iter_next(&dict);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean connman_tech_property_changed(DBusConnection *conn,
|
||||
DBusMessage *msg, void *user_data)
|
||||
{
|
||||
const char *path = dbus_message_get_path(msg);
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
ConnManTech *tech = g_hash_table_lookup(self->techs, path);
|
||||
DBusMessageIter it;
|
||||
|
||||
if (tech && dbus_message_has_signature(msg, "sv") &&
|
||||
dbus_message_iter_init(msg, &it)) {
|
||||
const char* name = connman_iter_get_string(&it);
|
||||
|
||||
if (!connman_tech_set_property(tech, &it)) {
|
||||
DBG("%s changed for %s", name, path);
|
||||
}
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void connman_set_techs(ConnManObject *self, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter list;
|
||||
|
||||
dbus_message_iter_recurse(it, &list);
|
||||
while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
|
||||
DBusMessageIter entry;
|
||||
const char *path;
|
||||
ConnManTech *tech;
|
||||
|
||||
dbus_message_iter_recurse(&list, &entry);
|
||||
path = connman_iter_get_string(&entry);
|
||||
tech = connman_tech_new(self, path);
|
||||
|
||||
DBG("%s", path);
|
||||
if (!g_strcmp0(path, CONNMAN_TECH_PATH_WIFI)) {
|
||||
/* WiFi is a special case */
|
||||
self->wifi = tech;
|
||||
}
|
||||
|
||||
dbus_message_iter_next(&entry);
|
||||
connman_tech_set_properties(tech, &entry);
|
||||
dbus_message_iter_next(&list);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_techs_reply(DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusError error;
|
||||
DBusMessageIter array;
|
||||
|
||||
dbus_error_init(&error);
|
||||
if (dbus_set_error_from_message(&error, reply)) {
|
||||
DBG("Failed to get technologies: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
} else if (dbus_message_has_signature(reply, "a(oa{sv})") &&
|
||||
dbus_message_iter_init(reply, &array)) {
|
||||
connman_set_techs(self, &array);
|
||||
}
|
||||
|
||||
dbus_message_unref(reply);
|
||||
dbus_pending_call_unref(self->call);
|
||||
self->call = NULL;
|
||||
connman_update_valid(self);
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
|
||||
static void connman_get_techs(ConnManObject *self)
|
||||
{
|
||||
DBusMessage *msg = dbus_message_new_method_call(CONNMAN_SERVICE,
|
||||
CONNMAN_PATH, CONNMAN_MANAGER_INTERFACE,
|
||||
CONNMAN_GET_TECHNOLOGIES);
|
||||
|
||||
connman_cancel_call(self);
|
||||
if (g_dbus_send_message_with_reply(self->connection, msg,
|
||||
&self->call, DBUS_TIMEOUT_INFINITE)) {
|
||||
/* Not valid while any request is pending */
|
||||
connman_invalidate(self);
|
||||
dbus_pending_call_set_notify(self->call, connman_techs_reply,
|
||||
self, NULL);
|
||||
}
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void connman_appeared(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (!connman->present) {
|
||||
DBG("connman is there");
|
||||
connman->present = TRUE;
|
||||
self->pending_signals |= SIGNAL_BIT_(PRESENT);
|
||||
connman_get_techs(self);
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_vanished(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (connman->present) {
|
||||
|
||||
DBG("connman has disappeared");
|
||||
g_hash_table_remove_all(self->techs);
|
||||
self->wifi = NULL;
|
||||
connman->present = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(PRESENT);
|
||||
if (connman->wifi_connected) {
|
||||
connman->wifi_connected = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
|
||||
}
|
||||
if (connman->tethering) {
|
||||
connman->tethering = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
}
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_init(ConnManObject *self, DBusConnection *connection)
|
||||
{
|
||||
self->connection = dbus_connection_ref(connection);
|
||||
self->service_watch = g_dbus_add_service_watch(self->connection,
|
||||
CONNMAN_SERVICE, connman_appeared, connman_vanished,
|
||||
self, NULL);
|
||||
self->signal_watch = g_dbus_add_signal_watch(self->connection,
|
||||
CONNMAN_SERVICE, NULL, CONNMAN_TECH_INTERFACE,
|
||||
CONNMAN_PROPERTY_CHANGED, connman_tech_property_changed,
|
||||
self, NULL);
|
||||
}
|
||||
|
||||
struct ril_connman *ril_connman_new()
|
||||
{
|
||||
static ConnManObject *instance = NULL;
|
||||
|
||||
if (instance) {
|
||||
g_object_ref(instance);
|
||||
return &instance->pub;
|
||||
} else {
|
||||
DBusError error;
|
||||
DBusConnection *connection;
|
||||
|
||||
dbus_error_init(&error);
|
||||
connection = dbus_bus_get(CONNMAN_BUS, NULL);
|
||||
|
||||
if (connection) {
|
||||
instance = g_object_new(CONNMAN_OBJECT_TYPE, NULL);
|
||||
connman_init(instance, connection);
|
||||
dbus_connection_unref(connection);
|
||||
g_object_add_weak_pointer(G_OBJECT(instance),
|
||||
(gpointer*)(&instance));
|
||||
return &instance->pub;
|
||||
} else {
|
||||
ofono_error("Unable to attach to connman bus: %s",
|
||||
error.message);
|
||||
dbus_error_free(&error);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_connman *ril_connman_ref(struct ril_connman *connman)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(self);
|
||||
return connman;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_connman_unref(struct ril_connman *connman)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(self);
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
|
||||
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self) && G_LIKELY(cb)) {
|
||||
/*
|
||||
* We can't directly connect the provided callback because
|
||||
* it expects the first parameter to point to public part
|
||||
* of the object but glib will call it with ConnManObject
|
||||
* as the first parameter. connman_object_property_changed()
|
||||
* will do the conversion.
|
||||
*/
|
||||
ConnManClosure *closure = connman_closure_new();
|
||||
GCClosure *cc = &closure->cclosure;
|
||||
|
||||
cc->closure.data = closure;
|
||||
cc->callback = G_CALLBACK(connman_object_property_changed);
|
||||
closure->callback = cb;
|
||||
closure->user_data = arg;
|
||||
|
||||
return g_signal_connect_closure_by_id(self,
|
||||
connman_object_signals[SIGNAL_PROPERTY_CHANGED],
|
||||
connman_object_property_quark(p), &cc->closure, FALSE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ril_connman_remove_handler(struct ril_connman *connman, gulong id)
|
||||
{
|
||||
if (G_LIKELY(id)) {
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
|
||||
int n)
|
||||
{
|
||||
gutil_disconnect_handlers(connman_object_cast(connman), ids, n);
|
||||
}
|
||||
|
||||
static void connman_object_init(ConnManObject *self)
|
||||
{
|
||||
self->techs = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
}
|
||||
|
||||
static void connman_object_finalize(GObject *object)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(object);
|
||||
|
||||
connman_cancel_call(self);
|
||||
g_hash_table_destroy(self->techs);
|
||||
g_dbus_remove_watch(self->connection, self->service_watch);
|
||||
g_dbus_remove_watch(self->connection, self->signal_watch);
|
||||
dbus_connection_unref(self->connection);
|
||||
G_OBJECT_CLASS(connman_object_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void connman_object_class_init(ConnManObjectClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = connman_object_finalize;
|
||||
connman_object_signals[SIGNAL_PROPERTY_CHANGED] =
|
||||
g_signal_new(SIGNAL_PROPERTY_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass),
|
||||
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
61
ofono/drivers/ril/ril_connman.h
Normal file
61
ofono/drivers/ril/ril_connman.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_CONNMAN_H
|
||||
#define RIL_CONNMAN_H
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
struct ril_connman {
|
||||
gboolean valid; /* TRUE if other fields are valid */
|
||||
gboolean present; /* ConnMan is present on D-Bus */
|
||||
gboolean tethering; /* At least one technology is tethering */
|
||||
gboolean wifi_connected; /* WiFi network is connected */
|
||||
};
|
||||
|
||||
enum ril_connman_property {
|
||||
RIL_CONNMAN_PROPERTY_ANY,
|
||||
RIL_CONNMAN_PROPERTY_VALID,
|
||||
RIL_CONNMAN_PROPERTY_PRESENT,
|
||||
RIL_CONNMAN_PROPERTY_TETHERING,
|
||||
RIL_CONNMAN_PROPERTY_WIFI_CONNECTED,
|
||||
RIL_CONNMAN_PROPERTY_COUNT
|
||||
};
|
||||
|
||||
typedef void (*ril_connman_property_cb_t)(struct ril_connman *connman,
|
||||
enum ril_connman_property property, void *arg);
|
||||
|
||||
struct ril_connman *ril_connman_new(void);
|
||||
struct ril_connman *ril_connman_ref(struct ril_connman *connman);
|
||||
void ril_connman_unref(struct ril_connman *connman);
|
||||
|
||||
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
|
||||
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg);
|
||||
void ril_connman_remove_handler(struct ril_connman *connman, gulong id);
|
||||
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
|
||||
int n);
|
||||
|
||||
#define ril_connman_remove_all_handlers(connman, ids) \
|
||||
ril_connman_remove_handlers(connman, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_CONNMAN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user