forked from sailfishos/ofono
Compare commits
1681 Commits
mer/1.14+g
...
upgrade-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
153eb3a4f3 | ||
|
|
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 | ||
|
|
3b4ce1f47b | ||
|
|
d8aefd40c4 | ||
|
|
e79055354c | ||
|
|
5e75f650c3 | ||
|
|
ae782ca6f2 | ||
|
|
b929a8e8c8 | ||
|
|
530c3bc812 | ||
|
|
0e1a58781f | ||
|
|
77a26177e5 | ||
|
|
f6ea7e4c36 | ||
|
|
babea14604 | ||
|
|
e13ae6d5b3 | ||
|
|
40ce8f7185 | ||
|
|
f68585a784 | ||
|
|
16105b8ace | ||
|
|
91245de799 | ||
|
|
c52471132a | ||
|
|
a8e7b86733 | ||
|
|
8829682fad | ||
|
|
246e30d1a5 | ||
|
|
83267e1fa5 | ||
|
|
e1ab11ad25 | ||
|
|
a9193282d5 | ||
|
|
f80bb5c5bb | ||
|
|
66eb87777f | ||
|
|
e5291006fd | ||
|
|
c609d7cc07 | ||
|
|
0de562b019 | ||
|
|
60b11f712c | ||
|
|
80d347b964 | ||
|
|
97abd10984 | ||
|
|
5201fc0183 | ||
|
|
14e4ef8e07 | ||
|
|
22bc6d526e | ||
|
|
baa4fe30e5 | ||
|
|
d0d0793ccb | ||
|
|
55dd461ce7 | ||
|
|
4da1a30290 | ||
|
|
303f527d79 | ||
|
|
27e8621c0b | ||
|
|
200237372a | ||
|
|
9cae262c80 | ||
|
|
5e23459b67 | ||
|
|
a88d7af6c8 | ||
|
|
290c3d2388 | ||
|
|
ee880398ad | ||
|
|
d65bbc3236 | ||
|
|
655544be45 | ||
|
|
50a544a191 | ||
|
|
9e7a4a4d72 | ||
|
|
c5b5e3109d | ||
|
|
deb106343a | ||
|
|
771e8becf2 | ||
|
|
a0b69f974a | ||
|
|
b3a4aaea95 | ||
|
|
137e504e10 | ||
|
|
2de3e445f0 | ||
|
|
1cd0d60768 | ||
|
|
d1f1f16355 | ||
|
|
4df72c9376 | ||
|
|
a35ca2bbd9 | ||
|
|
8376174c76 | ||
|
|
b6f5befcac | ||
|
|
403f29320c | ||
|
|
54209b39bd | ||
|
|
3ca442ad15 | ||
|
|
3a579dd7be | ||
|
|
a7266fc9c8 | ||
|
|
04dbd344b3 | ||
|
|
296534c2a8 | ||
|
|
6114482e2a | ||
|
|
8281885ba5 | ||
|
|
9cd3b84421 | ||
|
|
8d65aaefed | ||
|
|
ce15cfe48d | ||
|
|
3a1e37b498 | ||
|
|
ecef97dd83 | ||
|
|
a68f1e9c4d | ||
|
|
42808ed0f7 | ||
|
|
d896ebcb37 | ||
|
|
93c57284bd | ||
|
|
91436f9643 | ||
|
|
d0d2587b2a | ||
|
|
3e10878348 | ||
|
|
6de8c4aa85 | ||
|
|
a9da50f890 | ||
|
|
3ca5161a78 | ||
|
|
03b3ca7776 | ||
|
|
6e5316aba9 | ||
|
|
49b752f0ad | ||
|
|
268684eebf | ||
|
|
24db1db2b1 | ||
|
|
55977c1dac | ||
|
|
1025a6c6ed | ||
|
|
98a143233d | ||
|
|
88013ff63e | ||
|
|
efbe8b12c9 | ||
|
|
ba9cc0eb4a | ||
|
|
46b5f22464 | ||
|
|
a31332ebae | ||
|
|
b30141c3d3 | ||
|
|
e8ae8bba1c | ||
|
|
3ea25fb81f | ||
|
|
197df7141d | ||
|
|
eef6993391 | ||
|
|
f1a5941b35 | ||
|
|
5f6a258d0a | ||
|
|
9fa18f967b | ||
|
|
4d17a2e3b9 | ||
|
|
c34b3c39b2 | ||
|
|
df1824b2e2 | ||
|
|
b3a18326e1 | ||
|
|
93e564d5e5 | ||
|
|
42847e03b5 | ||
|
|
f0d6b69972 | ||
|
|
2100a8d975 | ||
|
|
c393e63e4e | ||
|
|
b24bc9761b | ||
|
|
06daa7cf21 | ||
|
|
49215d60b2 | ||
|
|
f3f3b73d6f | ||
|
|
113d9424b5 | ||
|
|
2a8489c4d9 | ||
|
|
c4f968b87a | ||
|
|
537c7ae8b4 | ||
|
|
b320fc7f59 | ||
|
|
edf49e6e99 | ||
|
|
b7985a1d67 | ||
|
|
bbb2c68a72 | ||
|
|
bd3f7f35eb | ||
|
|
65bf1a24fa | ||
|
|
0c37015145 | ||
|
|
a8551cdce7 | ||
|
|
5bd2b96240 | ||
|
|
3bf309b887 | ||
|
|
c14b9bbf93 | ||
|
|
568bd615cd | ||
|
|
4d55f94015 | ||
|
|
95d06963cd | ||
|
|
479458138a | ||
|
|
c221d677d1 | ||
|
|
a32da19192 | ||
|
|
a20da10621 | ||
|
|
64c754c3b9 | ||
|
|
d64fd7dca7 | ||
|
|
f608c0821a | ||
|
|
7d29ef130a | ||
|
|
141eadee1d | ||
|
|
e84602d79c | ||
|
|
b63b6355d5 | ||
|
|
f7f007a122 | ||
|
|
5769656848 | ||
|
|
bbc276b4c7 | ||
|
|
4b79de53fe | ||
|
|
12ffd8acf9 | ||
|
|
df9b35b440 | ||
|
|
76e991d3da | ||
|
|
90803904be | ||
|
|
84e547c2ed | ||
|
|
652798d592 | ||
|
|
979a3bcef3 | ||
|
|
69178c8ecb | ||
|
|
1ac1c9268d | ||
|
|
5483a8ecc0 | ||
|
|
95dacebb0c | ||
|
|
b92b1ce13f | ||
|
|
70ab2175a0 | ||
|
|
9810a258a1 | ||
|
|
760c17052f | ||
|
|
e77b62a91e | ||
|
|
7103c81a77 | ||
|
|
2bc610353d | ||
|
|
dd04ac248d | ||
|
|
c5b3357000 | ||
|
|
ddbdf9f649 | ||
|
|
7b5be51527 | ||
|
|
5aef6a8356 | ||
|
|
b99cd4f8ca | ||
|
|
47ee85e955 | ||
|
|
b500f4fa65 | ||
|
|
c2c048dc05 | ||
|
|
df923b481f | ||
|
|
ed0c1f94f6 | ||
|
|
6d2852cdaf | ||
|
|
72a1ecf5d0 | ||
|
|
2fa10fb265 | ||
|
|
f907c3a85d | ||
|
|
4a7b325191 | ||
|
|
a8103a39fa | ||
|
|
4076502017 | ||
|
|
7ed41beadd | ||
|
|
e45389cf84 | ||
|
|
4bae61c83e | ||
|
|
11d6e76f0a | ||
|
|
4cfa5cdf36 | ||
|
|
135923532c | ||
|
|
d112c042e3 | ||
|
|
b9407ff65f | ||
|
|
5a92625c9f | ||
|
|
c684033671 | ||
|
|
59cb9c39b9 | ||
|
|
0831fd803a | ||
|
|
1b6c20759c | ||
|
|
3681eb63b1 | ||
|
|
5303f766a9 | ||
|
|
2f68eeea6c | ||
|
|
7a7744781a | ||
|
|
fc1491c634 | ||
|
|
c631a48c41 | ||
|
|
21e90e5abd | ||
|
|
bfcf8b726b | ||
|
|
3b69c9843b | ||
|
|
f24252e2c6 | ||
|
|
4be4cb4f57 | ||
|
|
9d4f682b14 | ||
|
|
bd736f7aa6 | ||
|
|
ff328c2a73 | ||
|
|
10e908fa96 | ||
|
|
4aa59c7274 | ||
|
|
d61be44bb4 | ||
|
|
0ed1ef1e4c | ||
|
|
2fa193ad5b | ||
|
|
e686240eeb | ||
|
|
18bc7a3ad8 | ||
|
|
6624066917 | ||
|
|
6015490d41 | ||
|
|
a135d0ea52 | ||
|
|
f86159c180 | ||
|
|
de2b622f3b | ||
|
|
077f3f2e1e | ||
|
|
acbd40f9ad | ||
|
|
26398c769f | ||
|
|
60c53428f0 | ||
|
|
90824a8906 | ||
|
|
b85b8f0019 | ||
|
|
29069fd152 | ||
|
|
8e4e88e4fc | ||
|
|
40f148c134 | ||
|
|
730d5ff9b5 | ||
|
|
c6000fd909 | ||
|
|
f2edab4ed8 | ||
|
|
9915ccb3ba | ||
|
|
b5be8420ab | ||
|
|
5498e22839 | ||
|
|
802d351ab0 | ||
|
|
3d62d57d20 | ||
|
|
3b1b272967 | ||
|
|
5e2a7afabd | ||
|
|
f7fa1c81f3 | ||
|
|
62a0b3518b | ||
|
|
d7cbedc0e9 | ||
|
|
1e75448127 | ||
|
|
7ab4da0c91 | ||
|
|
f13991d04e | ||
|
|
c451110c39 | ||
|
|
cb9183f3ff | ||
|
|
c1a9d7a578 | ||
|
|
9aee7ccadd | ||
|
|
0777b2853a | ||
|
|
b7bd9ca425 | ||
|
|
8929d131a3 | ||
|
|
97e34cc851 | ||
|
|
e558d48b6f | ||
|
|
51fc828c5e | ||
|
|
ac14de37ca | ||
|
|
665c053803 | ||
|
|
aca873a5c4 | ||
|
|
a12e10e36f | ||
|
|
7cd3fb74d4 | ||
|
|
84289d83fd | ||
|
|
f826abdbc7 | ||
|
|
4e9cbcdb89 | ||
|
|
f6ac328110 | ||
|
|
8d46ababee | ||
|
|
9ec8d03c7c | ||
|
|
3e6bbc676f | ||
|
|
8be0245664 | ||
|
|
ca105f7040 | ||
|
|
dbb3ec13e5 | ||
|
|
1b3302322a | ||
|
|
cd76f913f0 | ||
|
|
8dc220bc11 | ||
|
|
b04fabcda3 | ||
|
|
71df8bb15e | ||
|
|
35ebbf4c97 | ||
|
|
a2acb227fd | ||
|
|
def77f7653 | ||
|
|
c3af639874 | ||
|
|
b2b67fa74e | ||
|
|
96754c0dfc | ||
|
|
f2c474c55a | ||
|
|
07144c2dd5 | ||
|
|
58076d9a00 | ||
|
|
4a937b96aa | ||
|
|
fceb5a41c2 | ||
|
|
0073dc7bfc | ||
|
|
297bdaba0f | ||
|
|
f14db3b2a6 | ||
|
|
4a0182616d | ||
|
|
bbdfc8f46d | ||
|
|
fbd59a8dc9 | ||
|
|
48da783732 | ||
|
|
eebe2f3ac2 | ||
|
|
7eb6d5559a | ||
|
|
9a47510eb5 | ||
|
|
8fc7ae836f | ||
|
|
4677729502 | ||
|
|
8c0f4f27eb | ||
|
|
b932bed519 | ||
|
|
db83ac369b | ||
|
|
e26df8a645 | ||
|
|
5144f3fa14 | ||
|
|
0d6459b9b0 | ||
|
|
10328e626d | ||
|
|
5b407d654a | ||
|
|
d88af05dc3 | ||
|
|
99cae6876f | ||
|
|
89e6593f9c | ||
|
|
93ccb84761 | ||
|
|
e70afdd9dc | ||
|
|
1edb6eec9b | ||
|
|
946b568f43 | ||
|
|
f3f3dabfac | ||
|
|
4c0f783f5c | ||
|
|
444611c086 | ||
|
|
8e9085f5ab | ||
|
|
c33a48ea0c | ||
|
|
f8d9485dc2 | ||
|
|
23c45abd57 | ||
|
|
a371f46735 | ||
|
|
ce0529fcf6 | ||
|
|
fc3f937a67 | ||
|
|
7d4a19b114 | ||
|
|
4242f6ee72 | ||
|
|
b31a3c2390 | ||
|
|
8d47f97106 | ||
|
|
fdba39b8ed | ||
|
|
288364295c | ||
|
|
bce5d9579c | ||
|
|
1c2987670d | ||
|
|
44585697c3 | ||
|
|
3860230644 | ||
|
|
07da2f3fa7 | ||
|
|
7d0d72a4a9 | ||
|
|
f9ee2ae9b8 | ||
|
|
063234a433 | ||
|
|
c006d822f1 | ||
|
|
a5b040b781 | ||
|
|
97abe1751d | ||
|
|
2f75b13ecd | ||
|
|
73e517bcca | ||
|
|
dae225a0d6 | ||
|
|
97ac3f7c76 | ||
|
|
26a00f2f31 | ||
|
|
cede3700f7 | ||
|
|
318d313fc9 | ||
|
|
8e6ebab83b | ||
|
|
7331c88b41 | ||
|
|
063eefbac1 | ||
|
|
12b510b4e7 | ||
|
|
c04f5df8ec | ||
|
|
011bc0741a | ||
|
|
773834c5a3 | ||
|
|
14acafc581 | ||
|
|
b4df40608b | ||
|
|
26f750fe4f | ||
|
|
51f6837545 | ||
|
|
6919c43ff6 | ||
|
|
621614e518 | ||
|
|
8e820dfdd3 | ||
|
|
04cc2e9fd2 | ||
|
|
ae5c8e6e3a | ||
|
|
1509cb811a | ||
|
|
5682df6d82 | ||
|
|
3e38512e2f | ||
|
|
dc5157c5d0 | ||
|
|
59449f74a1 | ||
|
|
ff63e9b057 | ||
|
|
d8edd49535 | ||
|
|
7b73f569eb | ||
|
|
8660527b11 | ||
|
|
5672f7248d | ||
|
|
d6bc91ebfc | ||
|
|
3d592d7d46 | ||
|
|
2ed0073bd1 | ||
|
|
f6ade48648 | ||
|
|
73ba48c9fb | ||
|
|
f3611cef21 | ||
|
|
15d682e62a | ||
|
|
e2398b4dfa | ||
|
|
42deee76a1 | ||
|
|
2af3c733b7 | ||
|
|
604fa223f4 | ||
|
|
04218d3a86 | ||
|
|
41fadd3787 | ||
|
|
d539ed19f3 | ||
|
|
25f926c733 | ||
|
|
151b837428 | ||
|
|
0c23ed90b7 | ||
|
|
54854c44a2 | ||
|
|
da297d5722 | ||
|
|
aba76cec73 | ||
|
|
3cdc8f775d | ||
|
|
bee03f8b56 | ||
|
|
7f4da6d59f | ||
|
|
5754fff800 | ||
|
|
fff6952703 | ||
|
|
96ff96ab1a | ||
|
|
986ac50b9e | ||
|
|
8600d8d293 | ||
|
|
369af1b401 | ||
|
|
500b5234b2 | ||
|
|
93eb292b75 | ||
|
|
3cc42fb087 | ||
|
|
c9e426ecd7 | ||
|
|
10f173981c | ||
|
|
782f2327fd | ||
|
|
8bda4032ca | ||
|
|
b2f4bd7603 | ||
|
|
33bb6d829c | ||
|
|
bb71141d79 | ||
|
|
4e466f6fec | ||
|
|
a89f8cd56d | ||
|
|
95482cb84a | ||
|
|
fce95b767a | ||
|
|
44049f064a | ||
|
|
b899f4aca2 | ||
|
|
e1cbc5c5ea | ||
|
|
5210b85c22 | ||
|
|
e6048f1dc1 | ||
|
|
1bea99ac56 | ||
|
|
6bdc109ec0 | ||
|
|
aab24b3f24 | ||
|
|
65eea56efe | ||
|
|
8ac7e502b7 | ||
|
|
9e8bdf0d64 | ||
|
|
70e99152a3 | ||
|
|
a90fc92665 | ||
|
|
7dca0a7315 | ||
|
|
1d23793eb0 | ||
|
|
804bef98ad | ||
|
|
1fdde8fecb | ||
|
|
1c484a6d04 | ||
|
|
19519b2132 | ||
|
|
64e888ef04 | ||
|
|
b33e0061d0 | ||
|
|
2babf82823 | ||
|
|
87a35d5d83 | ||
|
|
3d264276de | ||
|
|
d6bd24add3 | ||
|
|
9624eb9ace | ||
|
|
14672319d2 | ||
|
|
0d8b576ab6 | ||
|
|
c16121469b | ||
|
|
812f552ace | ||
|
|
42ebb69384 | ||
|
|
45478b17cf | ||
|
|
88f46a9b01 | ||
|
|
2abcb85809 | ||
|
|
331700a697 | ||
|
|
a753d6c012 | ||
|
|
d39007c948 | ||
|
|
fe52d1dc53 | ||
|
|
8be724836e | ||
|
|
8c96a7e091 | ||
|
|
f9bd555dc0 | ||
|
|
6c4ac05fbc | ||
|
|
934ea9a9fe | ||
|
|
cf90f1505d | ||
|
|
f9d5ee5fa9 | ||
|
|
e2785b1865 | ||
|
|
fb1b213e22 | ||
|
|
d3560b3784 | ||
|
|
017c1161d4 | ||
|
|
de02f68a2e | ||
|
|
0f28d9206d | ||
|
|
eef67018b6 | ||
|
|
299ffc9620 | ||
|
|
39f08a5e1c | ||
|
|
6c0f90fc1b | ||
|
|
33537adb9f | ||
|
|
e176a9019f | ||
|
|
7166aebd51 | ||
|
|
debb0d2d3e | ||
|
|
ab5b6d1217 | ||
|
|
7e3a6628fa | ||
|
|
fa105c4ba6 | ||
|
|
99c03292ad | ||
|
|
66cf2a30fa | ||
|
|
a4fa356b16 | ||
|
|
43e83852dc | ||
|
|
36a21da227 | ||
|
|
bef4d610a3 | ||
|
|
2d158167c2 | ||
|
|
02c5b73f6e | ||
|
|
0727da1d5b | ||
|
|
d292e0e0ed | ||
|
|
881207ce18 | ||
|
|
0f0733c348 | ||
|
|
71fd5c148a | ||
|
|
476e440f47 | ||
|
|
35440277d1 | ||
|
|
4f67e6743e | ||
|
|
c9ba23ae3d | ||
|
|
dcdddee5c5 | ||
|
|
195c2c6a1e | ||
|
|
51cf33c206 | ||
|
|
08ddddc8d2 | ||
|
|
dc5eed9c24 | ||
|
|
72e656e1fb | ||
|
|
8ebb17977b | ||
|
|
af1717977d | ||
|
|
cb48cfa9c3 | ||
|
|
759c0bbde4 | ||
|
|
300695d069 | ||
|
|
f88c1c3ab2 | ||
|
|
7415ef7418 | ||
|
|
887d9cf5d1 | ||
|
|
6231d5cc1c | ||
|
|
5b1f978a5c | ||
|
|
1d1b9df844 | ||
|
|
7fb4899970 | ||
|
|
1e0c41889f | ||
|
|
08e673050a | ||
|
|
1b1b1861ab | ||
|
|
8a4c29ca74 | ||
|
|
9aeea028ed | ||
|
|
0adfefa0c4 | ||
|
|
7c8db19341 | ||
|
|
37ec5f9221 | ||
|
|
d2d6f57b5f | ||
|
|
6a272bf700 | ||
|
|
e1c8e2e2dc | ||
|
|
5fb138dc13 | ||
|
|
e2790ae176 | ||
|
|
516700c84c | ||
|
|
e23e6aceae | ||
|
|
0532e2a6ea | ||
|
|
ce2f0f3642 | ||
|
|
0400b250c9 | ||
|
|
bfcad4f346 | ||
|
|
9d49e2cee1 | ||
|
|
c99e70f97a | ||
|
|
edc0035d18 | ||
|
|
121f308cdb | ||
|
|
2fcf1aee03 | ||
|
|
a14ebf50e0 | ||
|
|
1b0d419355 | ||
|
|
43f444db00 | ||
|
|
1eb6243bc9 | ||
|
|
22e892a22e | ||
|
|
361eed7b9a | ||
|
|
864efe1add | ||
|
|
0d8a06af30 | ||
|
|
293c701e25 | ||
|
|
cca3e085b3 | ||
|
|
7f29608feb | ||
|
|
1f3e30f1ba | ||
|
|
7ab4034bf4 | ||
|
|
bb1984cabb | ||
|
|
6df64cd1a9 | ||
|
|
4a0831bc80 | ||
|
|
b2bfdd69d2 | ||
|
|
1588e7c082 | ||
|
|
5cffd8af95 | ||
|
|
d2f6ffc18d | ||
|
|
6369cc902c | ||
|
|
d05b718cc0 | ||
|
|
c144fadca6 | ||
|
|
532e8020e5 | ||
|
|
310915429b | ||
|
|
9285ec0d89 | ||
|
|
8cbe061c3b | ||
|
|
3e13676766 | ||
|
|
73831c3d76 | ||
|
|
7011dcdf2f | ||
|
|
f6341502c8 | ||
|
|
8edaaaf210 | ||
|
|
a88662d23c | ||
|
|
1dd8580930 | ||
|
|
65be2b344c | ||
|
|
62c34467a2 | ||
|
|
d9f252fb61 | ||
|
|
815d62888f | ||
|
|
35feae07e5 |
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>
|
|
||||||
42
ofono/.gitignore
vendored
42
ofono/.gitignore
vendored
@@ -32,6 +32,8 @@ src/ofono.service
|
|||||||
dundee/dundee
|
dundee/dundee
|
||||||
dundee/dundee.service
|
dundee/dundee.service
|
||||||
|
|
||||||
|
test-driver
|
||||||
|
test-suite.log
|
||||||
unit/test-common
|
unit/test-common
|
||||||
unit/test-util
|
unit/test-util
|
||||||
unit/test-idmap
|
unit/test-idmap
|
||||||
@@ -42,6 +44,46 @@ unit/test-mux
|
|||||||
unit/test-caif
|
unit/test-caif
|
||||||
unit/test-stkutil
|
unit/test-stkutil
|
||||||
unit/test-cdmasms
|
unit/test-cdmasms
|
||||||
|
unit/test-dbus-access
|
||||||
|
unit/test-dbus-queue
|
||||||
|
unit/test-gprs-filter
|
||||||
|
unit/test-ril_config
|
||||||
|
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-watch
|
||||||
|
unit/test-sms-filter
|
||||||
|
unit/test-voicecall-filter
|
||||||
|
unit/test-*.log
|
||||||
|
unit/test-*.trs
|
||||||
|
|
||||||
|
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/huawei-audio
|
||||||
tools/auto-enable
|
tools/auto-enable
|
||||||
|
|||||||
@@ -96,3 +96,33 @@ Tony Espy <espy@canonical.com>
|
|||||||
Martin Pitt <martin.pitt@ubuntu.com>
|
Martin Pitt <martin.pitt@ubuntu.com>
|
||||||
Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
|
Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
|
||||||
Jussi Pakkanen <jussi.pakkanen@canonical.com>
|
Jussi Pakkanen <jussi.pakkanen@canonical.com>
|
||||||
|
Sergio Checa Blanco <sergio.checa@bmw-carit.de>
|
||||||
|
Philip Paeps <philip@paeps.cx>
|
||||||
|
Kuba Pawlak <kubax.t.pawlak@intel.com>
|
||||||
|
Tommi Kenakkala <tommi.kenakkala@tieto.com>
|
||||||
|
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>
|
||||||
|
Antoine Aubert <a.aubert@overkiz.com>
|
||||||
|
Djalal Harouni <djalal@endocode.com>
|
||||||
|
Christophe Ronco <c.ronco@kerlink.fr>
|
||||||
|
Vincent Cesson <vincent.cesson@smile.fr>
|
||||||
|
Piotr Haber <gluedig@gmail.com>
|
||||||
|
André Draszik <git@andred.net>
|
||||||
|
Lukasz Nowak <lnowak@tycoint.com>
|
||||||
|
Jonas Bonn <jonas@southpole.se>
|
||||||
|
Matthijs Kooijman <matthijs@stdin.nl>
|
||||||
|
Clayton Craft <clayton@craftyguy.net>
|
||||||
|
Joey Hewitt <joey@joeyhewitt.com>
|
||||||
|
|||||||
@@ -1,3 +1,97 @@
|
|||||||
|
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.
|
||||||
|
Fix issue with reading of EF_MWIS records.
|
||||||
|
Fix issue with handling AT+CPINR results.
|
||||||
|
Fix issue with SIM state polling for Sierra modems.
|
||||||
|
Fix issue with HFP handling and AT command prefixes.
|
||||||
|
Fix issue with HFP and extra CCWA event handling.
|
||||||
|
Fix issue with HFP call state and +CHUP errors.
|
||||||
|
|
||||||
|
ver 1.16:
|
||||||
|
Fix issue with PIN retry handling.
|
||||||
|
Fix issue with HFP and multiple calls.
|
||||||
|
Add support for Distracted Driving Reduction.
|
||||||
|
Add support for available technologies property.
|
||||||
|
Add support for Telit location reporting driver.
|
||||||
|
Add support for u-blox SARA-U270 modems.
|
||||||
|
Add support for Quectel UC15 modems.
|
||||||
|
|
||||||
|
ver 1.15:
|
||||||
|
Fix issue with EF_PNN access affecting PLMN display.
|
||||||
|
Fix issue with SIM detection and Telit HE910 modems.
|
||||||
|
Fix issue with Mobile Provider Database provisioning.
|
||||||
|
Fix issue with bit-shifting and ID mapping allocations.
|
||||||
|
Fix issue with Handsfree and unsolicited notifications.
|
||||||
|
Fix issue with Handsfree and three way calling feature.
|
||||||
|
Add support for Handsfree subscriber number feature.
|
||||||
|
Add support for Handsfree multiple DTMF characters.
|
||||||
|
Add support for PAP authentication.
|
||||||
|
|
||||||
ver 1.14:
|
ver 1.14:
|
||||||
Add support for Apple Siri specific Handsfree commands.
|
Add support for Apple Siri specific Handsfree commands.
|
||||||
Add support for provisioning of MMSC and Message Proxy.
|
Add support for provisioning of MMSC and Message Proxy.
|
||||||
|
|||||||
@@ -113,3 +113,5 @@ doc/coding-style.txt.
|
|||||||
a feature that touches files under 'include/', 'src/' and 'drivers/'
|
a feature that touches files under 'include/', 'src/' and 'drivers/'
|
||||||
directories, split in three separated patches, taking care not to
|
directories, split in three separated patches, taking care not to
|
||||||
break compilation.
|
break compilation.
|
||||||
|
|
||||||
|
4) Submit patches using git send-email to ofono@ofono.org
|
||||||
|
|||||||
@@ -21,11 +21,22 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
|||||||
include/cdma-connman.h include/gnss.h \
|
include/cdma-connman.h include/gnss.h \
|
||||||
include/private-network.h include/cdma-netreg.h \
|
include/private-network.h include/cdma-netreg.h \
|
||||||
include/cdma-provision.h include/handsfree.h \
|
include/cdma-provision.h include/handsfree.h \
|
||||||
include/handsfree-audio.h include/sim-mnclength.h \
|
include/sim-mnclength.h \
|
||||||
include/oemraw.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/netmon.h include/lte.h \
|
||||||
|
include/storage.h include/watch.h \
|
||||||
|
gdbus/gdbus.h
|
||||||
|
|
||||||
nodist_pkginclude_HEADERS = include/version.h
|
nodist_pkginclude_HEADERS = include/version.h
|
||||||
|
|
||||||
|
if SAILFISH_MANAGER
|
||||||
|
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
|
||||||
|
include/sailfish_manager.h
|
||||||
|
endif
|
||||||
|
|
||||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
||||||
$(nodist_pkginclude_HEADERS), \
|
$(nodist_pkginclude_HEADERS), \
|
||||||
include/ofono/$(notdir $(file)))
|
include/ofono/$(notdir $(file)))
|
||||||
@@ -96,20 +107,16 @@ gisi_sources = gisi/client.c gisi/client.h gisi/common.h \
|
|||||||
gisi/server.c gisi/server.h \
|
gisi/server.c gisi/server.h \
|
||||||
gisi/socket.c gisi/socket.h
|
gisi/socket.c gisi/socket.h
|
||||||
|
|
||||||
gril_sources = gril/gril.h gril/gril.c gril/grilio.h \
|
gril_sources = gril/gril.h gril/gril.c \
|
||||||
gril/grilio.c gril/grilutil.h \
|
gril/grilio.h gril/grilio.c \
|
||||||
gril/grilutil.c gril/ringbuffer.h \
|
gril/grilutil.h gril/grilutil.c \
|
||||||
gril/gfunc.h gril/ril.h \
|
gril/gfunc.h gril/gril.h \
|
||||||
gril/parcel.c gril/parcel.h \
|
gril/parcel.c gril/parcel.h \
|
||||||
gril/grilreply.c gril/grilreply.h \
|
gril/ril_constants.h
|
||||||
gril/grilrequest.c gril/grilrequest.h \
|
|
||||||
gril/grilunsol.c gril/grilunsol.h
|
|
||||||
|
|
||||||
btio_sources = btio/btio.h btio/btio.c
|
btio_sources = btio/btio.h btio/btio.c
|
||||||
|
|
||||||
if UDEV
|
if UDEV
|
||||||
builtin_modules += udev
|
|
||||||
builtin_sources += plugins/udev.c
|
|
||||||
builtin_cflags += @UDEV_CFLAGS@
|
builtin_cflags += @UDEV_CFLAGS@
|
||||||
builtin_libadd += @UDEV_LIBS@
|
builtin_libadd += @UDEV_LIBS@
|
||||||
|
|
||||||
@@ -117,18 +124,89 @@ builtin_modules += udevng
|
|||||||
builtin_sources += plugins/udevng.c
|
builtin_sources += plugins/udevng.c
|
||||||
endif
|
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 RILMODEM
|
||||||
builtin_sources += $(gril_sources)
|
if SAILFISH_RILMODEM
|
||||||
|
|
||||||
builtin_modules += ril
|
builtin_modules += ril
|
||||||
builtin_sources += plugins/ril.c
|
builtin_sources += drivers/ril/ril_call_barring.c \
|
||||||
|
drivers/ril/ril_call_forward.c \
|
||||||
|
drivers/ril/ril_call_settings.c \
|
||||||
|
drivers/ril/ril_call_volume.c \
|
||||||
|
drivers/ril/ril_cell_info.c \
|
||||||
|
drivers/ril/ril_config.c \
|
||||||
|
drivers/ril/ril_cbs.c \
|
||||||
|
drivers/ril/ril_data.c \
|
||||||
|
drivers/ril/ril_devinfo.c \
|
||||||
|
drivers/ril/ril_ecclist.c \
|
||||||
|
drivers/ril/ril_gprs.c \
|
||||||
|
drivers/ril/ril_gprs_context.c \
|
||||||
|
drivers/ril/ril_modem.c \
|
||||||
|
drivers/ril/ril_netmon.c \
|
||||||
|
drivers/ril/ril_netreg.c \
|
||||||
|
drivers/ril/ril_network.c \
|
||||||
|
drivers/ril/ril_oem_raw.c \
|
||||||
|
drivers/ril/ril_phonebook.c \
|
||||||
|
drivers/ril/ril_plugin.c \
|
||||||
|
drivers/ril/ril_radio.c \
|
||||||
|
drivers/ril/ril_radio_caps.c \
|
||||||
|
drivers/ril/ril_radio_settings.c \
|
||||||
|
drivers/ril/ril_sim.c \
|
||||||
|
drivers/ril/ril_sim_card.c \
|
||||||
|
drivers/ril/ril_sim_settings.c \
|
||||||
|
drivers/ril/ril_sms.c \
|
||||||
|
drivers/ril/ril_stk.c \
|
||||||
|
drivers/ril/ril_ussd.c \
|
||||||
|
drivers/ril/ril_util.c \
|
||||||
|
drivers/ril/ril_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 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_modules += rilmodem
|
||||||
builtin_sources += drivers/rilmodem/rilmodem.h \
|
builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||||
|
drivers/rilmodem/vendor.h \
|
||||||
drivers/rilmodem/rilmodem.c \
|
drivers/rilmodem/rilmodem.c \
|
||||||
drivers/rilmodem/devinfo.c \
|
drivers/rilmodem/devinfo.c \
|
||||||
drivers/rilmodem/network-registration.c \
|
drivers/rilmodem/network-registration.c \
|
||||||
drivers/rilmodem/voicecall.c \
|
drivers/rilmodem/voicecall.c \
|
||||||
|
drivers/rilmodem/voicecall.h \
|
||||||
drivers/rilmodem/call-volume.c \
|
drivers/rilmodem/call-volume.c \
|
||||||
drivers/rilmodem/gprs.c \
|
drivers/rilmodem/gprs.c \
|
||||||
drivers/rilmodem/gprs-context.c \
|
drivers/rilmodem/gprs-context.c \
|
||||||
@@ -136,16 +214,17 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
|||||||
drivers/rilmodem/sms.c \
|
drivers/rilmodem/sms.c \
|
||||||
drivers/rilmodem/rilutil.c \
|
drivers/rilmodem/rilutil.c \
|
||||||
drivers/rilmodem/rilutil.h \
|
drivers/rilmodem/rilutil.h \
|
||||||
drivers/rilmodem/radio-settings.c \
|
|
||||||
drivers/rilmodem/phonebook.c \
|
|
||||||
drivers/rilmodem/ussd.c \
|
drivers/rilmodem/ussd.c \
|
||||||
drivers/rilmodem/call-settings.c \
|
drivers/rilmodem/call-settings.c \
|
||||||
drivers/rilmodem/call-forwarding.c \
|
drivers/rilmodem/call-forwarding.c \
|
||||||
drivers/rilmodem/cbs.c \
|
drivers/rilmodem/radio-settings.c \
|
||||||
drivers/rilmodem/oemraw-messages.c \
|
|
||||||
drivers/rilmodem/call-barring.c \
|
drivers/rilmodem/call-barring.c \
|
||||||
drivers/rilmodem/stk.c
|
drivers/rilmodem/netmon.c \
|
||||||
|
drivers/rilmodem/stk.c \
|
||||||
|
drivers/rilmodem/cbs.c \
|
||||||
|
drivers/infineonmodem/infineon_constants.h \
|
||||||
|
drivers/rilmodem/lte.c
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ISIMODEM
|
if ISIMODEM
|
||||||
@@ -203,11 +282,13 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
|
|||||||
drivers/qmimodem/ctl.h \
|
drivers/qmimodem/ctl.h \
|
||||||
drivers/qmimodem/dms.h \
|
drivers/qmimodem/dms.h \
|
||||||
drivers/qmimodem/nas.h \
|
drivers/qmimodem/nas.h \
|
||||||
|
drivers/qmimodem/nas.c \
|
||||||
drivers/qmimodem/uim.h \
|
drivers/qmimodem/uim.h \
|
||||||
drivers/qmimodem/wms.h \
|
drivers/qmimodem/wms.h \
|
||||||
drivers/qmimodem/wds.h \
|
drivers/qmimodem/wds.h \
|
||||||
drivers/qmimodem/pds.h \
|
drivers/qmimodem/pds.h \
|
||||||
drivers/qmimodem/common.h
|
drivers/qmimodem/common.h \
|
||||||
|
drivers/qmimodem/wda.h
|
||||||
|
|
||||||
builtin_modules += qmimodem
|
builtin_modules += qmimodem
|
||||||
builtin_sources += $(qmi_sources) \
|
builtin_sources += $(qmi_sources) \
|
||||||
@@ -224,7 +305,8 @@ builtin_sources += $(qmi_sources) \
|
|||||||
drivers/qmimodem/gprs.c \
|
drivers/qmimodem/gprs.c \
|
||||||
drivers/qmimodem/gprs-context.c \
|
drivers/qmimodem/gprs-context.c \
|
||||||
drivers/qmimodem/radio-settings.c \
|
drivers/qmimodem/radio-settings.c \
|
||||||
drivers/qmimodem/location-reporting.c
|
drivers/qmimodem/location-reporting.c \
|
||||||
|
drivers/qmimodem/netmon.c
|
||||||
|
|
||||||
builtin_modules += gobi
|
builtin_modules += gobi
|
||||||
builtin_sources += plugins/gobi.c
|
builtin_sources += plugins/gobi.c
|
||||||
@@ -232,8 +314,7 @@ endif
|
|||||||
|
|
||||||
if ATMODEM
|
if ATMODEM
|
||||||
builtin_modules += atmodem
|
builtin_modules += atmodem
|
||||||
builtin_sources += $(gatchat_sources) \
|
builtin_sources += drivers/atmodem/atmodem.h \
|
||||||
drivers/atmodem/atmodem.h \
|
|
||||||
drivers/atmodem/atmodem.c \
|
drivers/atmodem/atmodem.c \
|
||||||
drivers/atmodem/call-settings.c \
|
drivers/atmodem/call-settings.c \
|
||||||
drivers/atmodem/sms.c \
|
drivers/atmodem/sms.c \
|
||||||
@@ -256,7 +337,8 @@ builtin_sources += $(gatchat_sources) \
|
|||||||
drivers/atmodem/gprs.c \
|
drivers/atmodem/gprs.c \
|
||||||
drivers/atmodem/gprs-context.c \
|
drivers/atmodem/gprs-context.c \
|
||||||
drivers/atmodem/sim-auth.c \
|
drivers/atmodem/sim-auth.c \
|
||||||
drivers/atmodem/gnss.c
|
drivers/atmodem/gnss.c \
|
||||||
|
drivers/atmodem/lte.c
|
||||||
|
|
||||||
builtin_modules += nwmodem
|
builtin_modules += nwmodem
|
||||||
builtin_sources += drivers/atmodem/atutil.h \
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
@@ -309,6 +391,13 @@ builtin_sources += drivers/atmodem/atutil.h \
|
|||||||
drivers/mbmmodem/stk.c \
|
drivers/mbmmodem/stk.c \
|
||||||
drivers/mbmmodem/location-reporting.c
|
drivers/mbmmodem/location-reporting.c
|
||||||
|
|
||||||
|
builtin_modules += telitmodem
|
||||||
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
|
drivers/telitmodem/telitmodem.h \
|
||||||
|
drivers/telitmodem/telitmodem.c \
|
||||||
|
drivers/telitmodem/location-reporting.c \
|
||||||
|
drivers/telitmodem/gprs-context-ncm.c
|
||||||
|
|
||||||
builtin_modules += hsomodem
|
builtin_modules += hsomodem
|
||||||
builtin_sources += drivers/atmodem/atutil.h \
|
builtin_sources += drivers/atmodem/atutil.h \
|
||||||
drivers/hsomodem/hsomodem.h \
|
drivers/hsomodem/hsomodem.h \
|
||||||
@@ -365,15 +454,33 @@ builtin_sources += drivers/atmodem/atutil.h \
|
|||||||
drivers/speedupmodem/speedupmodem.c \
|
drivers/speedupmodem/speedupmodem.c \
|
||||||
drivers/speedupmodem/ussd.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
|
||||||
|
|
||||||
if PHONESIM
|
if PHONESIM
|
||||||
builtin_modules += phonesim
|
builtin_modules += phonesim
|
||||||
builtin_sources += plugins/phonesim.c
|
builtin_sources += plugins/phonesim.c
|
||||||
|
|
||||||
if DATAFILES
|
if DATAFILES
|
||||||
dist_conf_DATA += plugins/phonesim.conf
|
dist_conf_DATA += plugins/phonesim.conf
|
||||||
if RILMODEM
|
|
||||||
dist_conf_DATA += gril/ril_subscription.conf
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -429,8 +536,11 @@ builtin_sources += plugins/stemgr.c
|
|||||||
builtin_modules += caif
|
builtin_modules += caif
|
||||||
builtin_sources += plugins/caif.c
|
builtin_sources += plugins/caif.c
|
||||||
|
|
||||||
builtin_modules += tc65
|
builtin_modules += cinterion
|
||||||
builtin_sources += plugins/tc65.c
|
builtin_sources += plugins/cinterion.c
|
||||||
|
|
||||||
|
builtin_modules += gemalto
|
||||||
|
builtin_sources += plugins/gemalto.c
|
||||||
|
|
||||||
builtin_modules += nokia
|
builtin_modules += nokia
|
||||||
builtin_sources += plugins/nokia.c
|
builtin_sources += plugins/nokia.c
|
||||||
@@ -458,33 +568,56 @@ builtin_sources += plugins/samsung.c
|
|||||||
|
|
||||||
builtin_modules += sim900
|
builtin_modules += sim900
|
||||||
builtin_sources += plugins/sim900.c
|
builtin_sources += plugins/sim900.c
|
||||||
|
|
||||||
|
builtin_modules += connman
|
||||||
|
builtin_sources += plugins/connman.c
|
||||||
|
|
||||||
|
builtin_modules += telit
|
||||||
|
builtin_sources += plugins/telit.c
|
||||||
|
|
||||||
|
builtin_modules += quectel
|
||||||
|
builtin_sources += plugins/quectel.c
|
||||||
|
|
||||||
|
builtin_modules += ublox
|
||||||
|
builtin_sources += plugins/ublox.c
|
||||||
|
|
||||||
|
builtin_modules += xmm7xxx
|
||||||
|
builtin_sources += plugins/xmm7xxx.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
builtin_modules += connman
|
builtin_modules += connman
|
||||||
builtin_sources += plugins/connman.c
|
builtin_sources += plugins/connman.c
|
||||||
|
|
||||||
builtin_modules += he910
|
builtin_modules += mnclength
|
||||||
builtin_sources += plugins/he910.c
|
builtin_sources += plugins/mnclength.c
|
||||||
|
|
||||||
if BLUETOOTH
|
if BLUETOOTH
|
||||||
if BLUEZ4
|
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_modules += sap
|
||||||
builtin_sources += plugins/sap.c plugins/bluez4.h
|
builtin_sources += plugins/sap.c plugins/bluez4.h
|
||||||
|
|
||||||
builtin_modules += hfp_bluez4
|
builtin_modules += hfp_bluez4
|
||||||
builtin_sources += plugins/hfp_hf_bluez4.c plugins/bluez4.h
|
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_modules += dun_gw_bluez4
|
||||||
builtin_sources += plugins/dun_gw_bluez4.c plugins/bluez4.h
|
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_sources += $(btio_sources)
|
||||||
builtin_cflags += @BLUEZ_CFLAGS@
|
builtin_cflags += @BLUEZ_CFLAGS@
|
||||||
@@ -493,16 +626,19 @@ else
|
|||||||
builtin_modules += bluez5
|
builtin_modules += bluez5
|
||||||
builtin_sources += plugins/bluez5.c plugins/bluez5.h
|
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_modules += hfp_ag_bluez5
|
||||||
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
|
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
|
||||||
|
|
||||||
builtin_modules += dun_gw_bluez5
|
if SAILFISH_BT
|
||||||
builtin_sources += plugins/dun_gw_bluez5.c plugins/bluez5.h
|
builtin_modules += sfos_bt
|
||||||
|
builtin_sources += plugins/sailfish_bt.c
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if UPOWER
|
||||||
|
builtin_modules += upower
|
||||||
|
builtin_sources += plugins/upower.c
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if NETTIME
|
if NETTIME
|
||||||
@@ -510,17 +646,32 @@ builtin_modules += nettime
|
|||||||
builtin_sources += plugins/nettime.c
|
builtin_sources += plugins/nettime.c
|
||||||
endif
|
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
|
if PROVISION
|
||||||
builtin_sources += plugins/mbpi.h plugins/mbpi.c
|
builtin_sources += plugins/mbpi.h plugins/mbpi.c
|
||||||
|
|
||||||
builtin_modules += provision
|
builtin_modules += provision
|
||||||
builtin_sources += plugins/provision.h plugins/provision.c
|
builtin_sources += plugins/provision.h
|
||||||
|
|
||||||
builtin_modules += cdma_provision
|
builtin_modules += cdma_provision
|
||||||
builtin_sources += plugins/cdma-provision.c
|
builtin_sources += plugins/cdma-provision.c
|
||||||
|
|
||||||
builtin_modules += mnclength
|
builtin_modules += file_provision
|
||||||
builtin_sources += plugins/mnclength.c
|
builtin_sources += plugins/file-provision.c
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if MAINTAINER_MODE
|
if MAINTAINER_MODE
|
||||||
@@ -541,6 +692,9 @@ builtin_sources += examples/private-network.c
|
|||||||
|
|
||||||
builtin_modules += stktest
|
builtin_modules += stktest
|
||||||
builtin_sources += plugins/stktest.c
|
builtin_sources += plugins/stktest.c
|
||||||
|
|
||||||
|
builtin_modules += emulator_fuzz
|
||||||
|
builtin_sources += plugins/emulator_fuzz.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
builtin_modules += smart_messaging
|
builtin_modules += smart_messaging
|
||||||
@@ -549,19 +703,21 @@ builtin_sources += plugins/smart-messaging.c
|
|||||||
builtin_modules += push_notification
|
builtin_modules += push_notification
|
||||||
builtin_sources += plugins/push-notification.c
|
builtin_sources += plugins/push-notification.c
|
||||||
|
|
||||||
if PUSHFORWARDER
|
if SAILFISH_PUSHFORWARDER
|
||||||
builtin_modules += push_forwarder
|
builtin_modules += pushforwarder
|
||||||
builtin_sources += plugins/push-forwarder.c
|
builtin_sources += plugins/sailfish_pushforwarder.c
|
||||||
builtin_cflags += @WSPCODEC_CFLAGS@
|
|
||||||
builtin_libadd += @WSPCODEC_LIBS@
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
builtin_modules += sms_history
|
builtin_modules += sms_history
|
||||||
builtin_sources += plugins/smshistory.c
|
builtin_sources += plugins/smshistory.c
|
||||||
|
|
||||||
|
builtin_modules += allowed_apns
|
||||||
|
builtin_sources += plugins/allowed-apns.c
|
||||||
|
|
||||||
sbin_PROGRAMS = src/ofonod
|
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/main.c src/ofono.h src/log.c src/plugin.c \
|
||||||
src/modem.c src/common.h src/common.c \
|
src/modem.c src/common.h src/common.c \
|
||||||
src/manager.c src/dbus.c src/util.h src/util.c \
|
src/manager.c src/dbus.c src/util.h src/util.c \
|
||||||
@@ -586,8 +742,13 @@ src_ofonod_SOURCES = $(builtin_sources) src/ofono.ver \
|
|||||||
src/cdma-sms.c src/private-network.c src/cdma-netreg.c \
|
src/cdma-sms.c src/private-network.c src/cdma-netreg.c \
|
||||||
src/cdma-provision.c src/handsfree.c \
|
src/cdma-provision.c src/handsfree.c \
|
||||||
src/handsfree-audio.c src/bluetooth.h \
|
src/handsfree-audio.c src/bluetooth.h \
|
||||||
src/hfp.h src/sim-mnclength.c src/oemraw.c \
|
src/sim-mnclength.c src/voicecallagent.c \
|
||||||
src/siri.c src/voicecallagent.c
|
src/sms-filter.c src/gprs-filter.c \
|
||||||
|
src/dbus-queue.c src/dbus-access.c \
|
||||||
|
src/voicecall-filter.c src/ril-transport.c \
|
||||||
|
src/hfp.h src/siri.c src/watchlist.c \
|
||||||
|
src/netmon.c src/lte.c \
|
||||||
|
src/netmonagent.c src/netmonagent.h
|
||||||
|
|
||||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||||
@@ -597,7 +758,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
|
|||||||
|
|
||||||
BUILT_SOURCES = $(local_headers) src/builtin.h
|
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
|
plugindir = $(pkglibdir)/plugins
|
||||||
|
|
||||||
@@ -630,9 +792,14 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
|||||||
doc/sim-api.txt doc/stk-api.txt \
|
doc/sim-api.txt doc/stk-api.txt \
|
||||||
doc/audio-settings-api.txt doc/text-telephony-api.txt \
|
doc/audio-settings-api.txt doc/text-telephony-api.txt \
|
||||||
doc/calypso-modem.txt doc/message-api.txt \
|
doc/calypso-modem.txt doc/message-api.txt \
|
||||||
doc/location-reporting-api.txt doc/smshistory-api.txt \
|
doc/location-reporting-api.txt \
|
||||||
doc/oemraw-api.txt \
|
doc/smshistory-api.txt doc/oemraw-api.txt \
|
||||||
doc/certification.txt doc/siri-api.txt
|
doc/certification.txt doc/siri-api.txt \
|
||||||
|
doc/telit-modem.txt \
|
||||||
|
doc/networkmonitor-api.txt \
|
||||||
|
doc/allowed-apns-api.txt \
|
||||||
|
doc/lte-api.txt \
|
||||||
|
doc/cinterion-hardware-monitor-api.txt
|
||||||
|
|
||||||
|
|
||||||
test_scripts = test/backtrace \
|
test_scripts = test/backtrace \
|
||||||
@@ -666,6 +833,7 @@ test_scripts = test/backtrace \
|
|||||||
test/receive-sms \
|
test/receive-sms \
|
||||||
test/remove-contexts \
|
test/remove-contexts \
|
||||||
test/send-sms \
|
test/send-sms \
|
||||||
|
test/cancel-sms \
|
||||||
test/set-mic-volume \
|
test/set-mic-volume \
|
||||||
test/set-speaker-volume \
|
test/set-speaker-volume \
|
||||||
test/test-stk-menu \
|
test/test-stk-menu \
|
||||||
@@ -729,7 +897,19 @@ test_scripts = test/backtrace \
|
|||||||
test/display-icon \
|
test/display-icon \
|
||||||
test/set-msisdn \
|
test/set-msisdn \
|
||||||
test/test-voicecallagent \
|
test/test-voicecallagent \
|
||||||
test/get-network-time
|
test/get-network-time \
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
if TEST
|
if TEST
|
||||||
testdir = $(pkglibdir)/test
|
testdir = $(pkglibdir)/test
|
||||||
@@ -741,35 +921,156 @@ EXTRA_DIST = src/genbuiltin plugins/ofono.rules plugins/ofono-speedup.rules \
|
|||||||
|
|
||||||
dist_man_MANS = doc/ofonod.8
|
dist_man_MANS = doc/ofonod.8
|
||||||
|
|
||||||
|
if TEST_COVERAGE
|
||||||
|
COVERAGE_OPT = --coverage
|
||||||
|
endif
|
||||||
|
|
||||||
unit_objects =
|
unit_objects =
|
||||||
|
|
||||||
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
||||||
unit/test-simutil unit/test-stkutil \
|
unit/test-simutil unit/test-stkutil \
|
||||||
unit/test-sms unit/test-cdmasms \
|
unit/test-sms unit/test-cdmasms
|
||||||
unit/test-grilrequest \
|
|
||||||
unit/test-grilreply \
|
if SAILFISH_MANAGER
|
||||||
unit/test-grilunsol \
|
|
||||||
unit/test-sms unit/test-cdmasms \
|
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||||
unit/test-provision
|
plugins/sailfish_manager/sailfish_cell_info.c
|
||||||
|
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||||
|
-Iplugins/sailfish_manager
|
||||||
|
unit_test_sailfish_cell_info_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@ -Iplugins/sailfish_manager
|
||||||
|
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
|
||||||
|
unit_tests += unit/test-sailfish_cell_info_dbus
|
||||||
|
|
||||||
|
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||||
|
unit/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"' -Iplugins/sailfish_manager
|
||||||
|
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||||
|
unit_tests += unit/test-sailfish_sim_info
|
||||||
|
|
||||||
|
unit_test_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"' \
|
||||||
|
-Iplugins/sailfish_manager
|
||||||
|
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
|
||||||
|
unit_tests += unit/test-sailfish_sim_info_dbus
|
||||||
|
|
||||||
|
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||||
|
unit/fake_watch.c \
|
||||||
|
plugins/sailfish_manager/sailfish_manager.c \
|
||||||
|
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||||
|
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||||
|
src/storage.c src/log.c
|
||||||
|
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||||
|
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||||
|
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"' -Iplugins/sailfish_manager
|
||||||
|
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||||
|
unit_objects += $(unit_test_watch_OBJECTS)
|
||||||
|
unit_tests += unit/test-watch
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
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_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
|
||||||
|
|
||||||
noinst_PROGRAMS = $(unit_tests) \
|
noinst_PROGRAMS = $(unit_tests) \
|
||||||
unit/test-sms-root unit/test-mux unit/test-caif
|
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_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_test_common_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_common_OBJECTS)
|
unit_objects += $(unit_test_common_OBJECTS)
|
||||||
|
|
||||||
unit_test_util_SOURCES = unit/test-util.c src/util.c
|
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_test_util_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_utils_OBJECTS)
|
unit_objects += $(unit_test_utils_OBJECTS)
|
||||||
|
|
||||||
unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
|
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_test_idmap_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_idmap_OBJECTS)
|
unit_objects += $(unit_test_idmap_OBJECTS)
|
||||||
|
|
||||||
unit_test_simutil_SOURCES = unit/test-simutil.c src/util.c \
|
unit_test_simutil_SOURCES = unit/test-simutil.c src/util.c \
|
||||||
src/simutil.c src/smsutil.c src/storage.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_test_simutil_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_simutil_OBJECTS)
|
unit_objects += $(unit_test_simutil_OBJECTS)
|
||||||
|
|
||||||
@@ -777,19 +1078,23 @@ unit_test_stkutil_SOURCES = unit/test-stkutil.c unit/stk-test-data.h \
|
|||||||
src/util.c \
|
src/util.c \
|
||||||
src/storage.c src/smsutil.c \
|
src/storage.c src/smsutil.c \
|
||||||
src/simutil.c src/stkutil.c
|
src/simutil.c src/stkutil.c
|
||||||
|
unit_test_stkutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
unit_test_stkutil_LDADD = @GLIB_LIBS@
|
unit_test_stkutil_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_stkutil_OBJECTS)
|
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_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_test_sms_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_sms_OBJECTS)
|
unit_objects += $(unit_test_sms_OBJECTS)
|
||||||
|
|
||||||
unit_test_cdmasms_SOURCES = unit/test-cdmasms.c src/cdma-smsutil.c
|
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_test_cdmasms_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_cdmasms_OBJECTS)
|
unit_objects += $(unit_test_cdmasms_OBJECTS)
|
||||||
|
|
||||||
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
|
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
|
||||||
src/util.c src/smsutil.c src/storage.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_test_sms_root_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_sms_root_OBJECTS)
|
unit_objects += $(unit_test_sms_root_OBJECTS)
|
||||||
|
|
||||||
@@ -800,30 +1105,92 @@ unit_objects += $(unit_test_mux_OBJECTS)
|
|||||||
unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
|
unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
|
||||||
drivers/stemodem/caif_socket.h \
|
drivers/stemodem/caif_socket.h \
|
||||||
drivers/stemodem/if_caif.h
|
drivers/stemodem/if_caif.h
|
||||||
|
unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||||
unit_objects += $(unit_test_caif_OBJECTS)
|
unit_objects += $(unit_test_caif_OBJECTS)
|
||||||
|
|
||||||
unit_test_grilrequest_SOURCES = unit/test-grilrequest.c $(gril_sources) \
|
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||||
src/log.c gatchat/ringbuffer.c
|
src/dbus-queue.c gdbus/object.c \
|
||||||
unit_test_grilrequest_LDADD = @GLIB_LIBS@ -ldl
|
src/dbus.c src/log.c
|
||||||
unit_objects += $(unit_test_grilrequest_OBJECTS)
|
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
|
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||||
unit_test_grilreply_SOURCES = unit/test-grilreply.c $(gril_sources) \
|
unit_objects += $(unit_test_dbus_queue_OBJECTS)
|
||||||
src/log.c gatchat/ringbuffer.c
|
unit_tests += unit/test-dbus-queue
|
||||||
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_provision_SOURCES = unit/test-provision.c \
|
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||||
plugins/provision.h plugins/provision.c \
|
plugins/provision.h plugins/mbpi.c \
|
||||||
plugins/mbpi.c src/gprs-provision.c \
|
plugins/sailfish_provision.c \
|
||||||
src/log.c
|
src/gprs-provision.c src/log.c
|
||||||
|
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||||
unit_objects += $(unit_test_provision_OBJECTS)
|
unit_objects += $(unit_test_provision_OBJECTS)
|
||||||
|
unit_tests += unit/test-provision
|
||||||
|
|
||||||
|
unit_test_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)
|
||||||
|
|
||||||
TESTS = $(unit_tests)
|
TESTS = $(unit_tests)
|
||||||
|
|
||||||
@@ -851,13 +1218,6 @@ tools_lookup_provider_name_LDADD = @GLIB_LIBS@
|
|||||||
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
||||||
tools_tty_redirector_LDADD = @GLIB_LIBS@
|
tools_tty_redirector_LDADD = @GLIB_LIBS@
|
||||||
|
|
||||||
if QMIMODEM
|
|
||||||
noinst_PROGRAMS += tools/qmi
|
|
||||||
|
|
||||||
tools_qmi_SOURCES = $(qmi_sources) tools/qmi.c
|
|
||||||
tools_qmi_LDADD = @GLIB_LIBS@
|
|
||||||
endif
|
|
||||||
|
|
||||||
if MAINTAINER_MODE
|
if MAINTAINER_MODE
|
||||||
noinst_PROGRAMS += tools/stktest
|
noinst_PROGRAMS += tools/stktest
|
||||||
|
|
||||||
@@ -926,6 +1286,10 @@ include/ofono/version.h: include/version.h
|
|||||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||||
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
|
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
|
||||||
|
|
||||||
|
include/ofono/gdbus.h: $(abs_top_srcdir)/gdbus/gdbus.h
|
||||||
|
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||||
|
$(AM_V_GEN)$(LN_S) $< $@
|
||||||
|
|
||||||
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
|
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
|
||||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||||
$(AM_V_GEN)$(LN_S) $< $@
|
$(AM_V_GEN)$(LN_S) $< $@
|
||||||
|
|||||||
10
ofono/TODO
10
ofono/TODO
@@ -256,6 +256,16 @@ Voicecall
|
|||||||
Priority: Medium
|
Priority: Medium
|
||||||
Complexity: C1
|
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
|
Sim Toolkit
|
||||||
===========
|
===========
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ AC_DEFUN([AC_PROG_CC_PIE], [
|
|||||||
|
|
||||||
AC_DEFUN([COMPILER_FLAGS], [
|
AC_DEFUN([COMPILER_FLAGS], [
|
||||||
if (test "${CFLAGS}" = ""); then
|
if (test "${CFLAGS}" = ""); then
|
||||||
CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2"
|
CFLAGS="-Wall -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2"
|
||||||
fi
|
fi
|
||||||
if (test "$USE_MAINTAINER_MODE" = "yes"); then
|
if (test "$USE_MAINTAINER_MODE" = "yes"); then
|
||||||
CFLAGS="$CFLAGS -Werror -Wextra"
|
CFLAGS="$CFLAGS -Werror -Wextra"
|
||||||
@@ -22,6 +22,7 @@ AC_DEFUN([COMPILER_FLAGS], [
|
|||||||
CFLAGS="$CFLAGS -Wmissing-declarations"
|
CFLAGS="$CFLAGS -Wmissing-declarations"
|
||||||
CFLAGS="$CFLAGS -Wredundant-decls"
|
CFLAGS="$CFLAGS -Wredundant-decls"
|
||||||
CFLAGS="$CFLAGS -Wcast-align"
|
CFLAGS="$CFLAGS -Wcast-align"
|
||||||
|
CFLAGS="$CFLAGS -Wno-format-truncation"
|
||||||
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
|
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.60)
|
AC_PREREQ(2.60)
|
||||||
AC_INIT(ofono, 1.14)
|
AC_INIT(ofono, 1.21)
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
@@ -33,7 +33,7 @@ AC_PROG_LIBTOOL
|
|||||||
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
|
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
|
||||||
[disable code optimization through compiler]), [
|
[disable code optimization through compiler]), [
|
||||||
if (test "${enableval}" = "no"); then
|
if (test "${enableval}" = "no"); then
|
||||||
CFLAGS="$CFLAGS -O0"
|
CFLAGS="$CFLAGS -O0 -U_FORTIFY_SOURCE"
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
|
|||||||
if (test "${enableval}" = "yes" &&
|
if (test "${enableval}" = "yes" &&
|
||||||
test "${ac_cv_prog_cc_g}" = "yes"); then
|
test "${ac_cv_prog_cc_g}" = "yes"); then
|
||||||
CFLAGS="$CFLAGS -g"
|
CFLAGS="$CFLAGS -g"
|
||||||
|
CPPFLAGS="$CPPFLAGS -DDEBUG"
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -63,11 +64,21 @@ AC_CHECK_FUNC(signalfd, dummy=yes,
|
|||||||
AC_CHECK_LIB(dl, dlopen, dummy=yes,
|
AC_CHECK_LIB(dl, dlopen, dummy=yes,
|
||||||
AC_MSG_ERROR(dynamic linking loader is required))
|
AC_MSG_ERROR(dynamic linking loader is required))
|
||||||
|
|
||||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
|
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
|
||||||
AC_MSG_ERROR(GLib >= 2.28 is required))
|
AC_MSG_ERROR(GLib >= 2.32 is required))
|
||||||
AC_SUBST(GLIB_CFLAGS)
|
AC_SUBST(GLIB_CFLAGS)
|
||||||
AC_SUBST(GLIB_LIBS)
|
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
|
if (test "${enable_threads}" = "yes"); then
|
||||||
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
|
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
|
||||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
||||||
@@ -166,6 +177,51 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
|
|||||||
[enable_rilmodem=${enableval}])
|
[enable_rilmodem=${enableval}])
|
||||||
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||||
|
[enable Sailfish RIL modem]),
|
||||||
|
[enable_sailfish_rilmodem=${enableval}],
|
||||||
|
[enable_sailfish_rilmodem="no"])
|
||||||
|
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||||
|
|
||||||
|
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||||
|
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.25, dummy=yes,
|
||||||
|
AC_MSG_ERROR(libgrilio >= 1.0.25 is required))
|
||||||
|
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.30, dummy=yes,
|
||||||
|
AC_MSG_ERROR(libglibutil >= 1.0.30 is required))
|
||||||
|
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||||
|
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
|
||||||
|
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||||
|
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||||
|
enable_sailfish_manager=yes
|
||||||
|
need_glibutil=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
if (test "${enable_sailfish_manager}" = "yes"); then
|
||||||
|
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
|
||||||
|
AC_MSG_ERROR(dbus-glib is required by unit tests))
|
||||||
|
AC_SUBST(DBUS_GLIB_CFLAGS)
|
||||||
|
AC_SUBST(DBUS_GLIB_LIBS)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
|
||||||
|
[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],
|
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
|
||||||
[disable Qualcomm QMI modem support]),
|
[disable Qualcomm QMI modem support]),
|
||||||
[enable_qmimodem=${enableval}])
|
[enable_qmimodem=${enableval}])
|
||||||
@@ -189,6 +245,16 @@ fi
|
|||||||
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
|
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
|
||||||
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
|
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],
|
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
|
||||||
[disable Nettime plugin]),
|
[disable Nettime plugin]),
|
||||||
[enable_nettime=${enableval}])
|
[enable_nettime=${enableval}])
|
||||||
@@ -201,7 +267,7 @@ AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE],
|
|||||||
[location of provision database]), [path_provisiondb=${withval}])
|
[location of provision database]), [path_provisiondb=${withval}])
|
||||||
|
|
||||||
AC_ARG_ENABLE(provision, AC_HELP_STRING([--disable-provision],
|
AC_ARG_ENABLE(provision, AC_HELP_STRING([--disable-provision],
|
||||||
[disable provisioning suport]),
|
[disable provisioning support]),
|
||||||
[enable_provision=${enableval}])
|
[enable_provision=${enableval}])
|
||||||
if (test "${enable_provision}" != "no"); then
|
if (test "${enable_provision}" != "no"); then
|
||||||
if (test -n "${path_provisiondb}"); then
|
if (test -n "${path_provisiondb}"); then
|
||||||
@@ -221,20 +287,59 @@ if (test "${enable_provision}" != "no"); then
|
|||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(PROVISION, test "${enable_provision}" != "no")
|
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(datafiles, AC_HELP_STRING([--disable-datafiles],
|
AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
|
||||||
[do not install configuration and data files]),
|
[do not install configuration and data files]),
|
||||||
[enable_datafiles=${enableval}])
|
[enable_datafiles=${enableval}])
|
||||||
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
|
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
|
||||||
|
|
||||||
AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
|
AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforwarder],
|
||||||
[disable Push Forwarder plugin]),
|
[enable Sailfish OS push forwarder plugin]),
|
||||||
[enable_pushforwarder=${enableval}])
|
[enable_sailfish_pushforwarder=${enableval}],
|
||||||
AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
|
[enable_sailfish_pushforwarder="no"])
|
||||||
if (test "${enable_pushforwarder}" != "no"); then
|
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
|
||||||
|
if (test "${enable_sailfish_pushforwarder}" != "no"); then
|
||||||
|
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.15, dummy=yes,
|
||||||
|
AC_MSG_ERROR(libglibutil >= 1.0.15 is required))
|
||||||
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
|
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
|
||||||
AC_MSG_ERROR(WSP decoder is required))
|
AC_MSG_ERROR(WSP decoder is required))
|
||||||
AC_SUBST(WSPCODEC_CFLAGS)
|
CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
|
||||||
AC_SUBST(WSPCODEC_LIBS)
|
LIBS="$LIBS $WSPCODEC_LIBS"
|
||||||
|
need_glibutil=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(sailfish-access, AC_HELP_STRING([--enable-sailfish-access],
|
||||||
|
[enable Sailfish OS access plugin]),
|
||||||
|
[enable_sailfish_access=${enableval}],
|
||||||
|
[enable_sailfish_access="no"])
|
||||||
|
|
||||||
|
AM_CONDITIONAL(SAILFISH_ACCESS, test "${enable_sailfish_access}" != "no")
|
||||||
|
if (test "${enable_sailfish_access}" == "yes"); then
|
||||||
|
PKG_CHECK_MODULES(DBUSACCESS, libdbusaccess, dummy=yes,
|
||||||
|
AC_MSG_ERROR(libdbusaccess is required))
|
||||||
|
CFLAGS="$CFLAGS $DBUSACCESS_CFLAGS"
|
||||||
|
LIBS="$LIBS $DBUSACCESS_LIBS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(sailfish-debuglog, AC_HELP_STRING([--enable-sailfish-debuglog],
|
||||||
|
[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"
|
||||||
|
LIBS="$LIBS $DBUSLOG_LIBS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (test "${need_glibutil}" = "yes"); then
|
||||||
|
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||||
|
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if (test "${prefix}" = "NONE"); then
|
if (test "${prefix}" = "NONE"); then
|
||||||
@@ -251,7 +356,7 @@ if (test "$localstatedir" = '${prefix}/var'); then
|
|||||||
else
|
else
|
||||||
storagedir="${localstatedir}/lib/ofono"
|
storagedir="${localstatedir}/lib/ofono"
|
||||||
fi
|
fi
|
||||||
AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
|
AC_DEFINE_UNQUOTED(DEFAULT_STORAGEDIR, "${storagedir}",
|
||||||
[Directory for the storage files])
|
[Directory for the storage files])
|
||||||
|
|
||||||
if (test "$sysconfdir" = '${prefix}/etc'); then
|
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
|
Some of them are mandatory (marked as 'M'), while some others are optional
|
||||||
(marked as 'O'), but generally preferred.
|
(marked as 'O'), but generally preferred.
|
||||||
|
|
||||||
M1: Blank line before and after an if/while/do/for statement
|
M1: Blank line before and after an if/while/do/for/switch statement
|
||||||
============================================================
|
============================================================
|
||||||
There should be a blank line before if statement unless the if is nested and
|
There should be a blank line before if statement unless the if is nested and
|
||||||
not preceded by an expression or variable declaration.
|
not preceded by an expression or variable declaration.
|
||||||
@@ -306,6 +306,13 @@ Example:
|
|||||||
2)
|
2)
|
||||||
0x1 << y // Wrong
|
0x1 << y // Wrong
|
||||||
|
|
||||||
|
M17: Avoid forward-declaration of static functions
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
Functions that are static should not be forward-declared. The only exception
|
||||||
|
to this rule is if a circular dependency condition exists, and the forward
|
||||||
|
declaration cannot be avoided.
|
||||||
|
|
||||||
O1: Shorten the name
|
O1: Shorten the name
|
||||||
====================
|
====================
|
||||||
Better to use abbreviation, rather than full name, to name a variable,
|
Better to use abbreviation, rather than full name, to name a variable,
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ Methods dict GetProperties()
|
|||||||
[service].Error.NotFound
|
[service].Error.NotFound
|
||||||
[service].Error.Failed
|
[service].Error.Failed
|
||||||
|
|
||||||
|
void ResetContexts()
|
||||||
|
|
||||||
|
Removes all contexts and re-provisions from the APN
|
||||||
|
database. Contexts must all be deactivated for this
|
||||||
|
method to work, and the atom must not be powered.
|
||||||
|
|
||||||
|
Possible Errors: [service].Error.InProgress
|
||||||
|
[service].Error.InvalidArguments
|
||||||
|
[service].Error.NotAllowed
|
||||||
|
|
||||||
Signals PropertyChanged(string property, variant value)
|
Signals PropertyChanged(string property, variant value)
|
||||||
|
|
||||||
This signal indicates a changed value of the given
|
This signal indicates a changed value of the given
|
||||||
@@ -96,7 +106,7 @@ Properties boolean Attached [readonly]
|
|||||||
GPRS service registration (if known).
|
GPRS service registration (if known).
|
||||||
|
|
||||||
Possible values are:
|
Possible values are:
|
||||||
"none", "gsm", "edge", "umts", "hsdpa", "hsupa",
|
"none", "gprs", "edge", "umts", "hsdpa", "hsupa",
|
||||||
"hspa" (HSDPA and HSUPA at the same time) and
|
"hspa" (HSDPA and HSUPA at the same time) and
|
||||||
"lte"
|
"lte"
|
||||||
|
|
||||||
@@ -155,6 +165,15 @@ Methods dict GetProperties()
|
|||||||
[service].Error.AttachInProgress
|
[service].Error.AttachInProgress
|
||||||
[service].Error.NotImplemented
|
[service].Error.NotImplemented
|
||||||
|
|
||||||
|
Methods void ProvisionContext()
|
||||||
|
Resets all properties back to default. Fails to make
|
||||||
|
any changes to the context if it is active or in the
|
||||||
|
process of being activated or deactivated.
|
||||||
|
|
||||||
|
Possible Errors: [service].Error.Failed
|
||||||
|
[service].Error.InProgress
|
||||||
|
[service].Error.NotAvailable
|
||||||
|
|
||||||
Signals PropertyChanged(string property, variant value)
|
Signals PropertyChanged(string property, variant value)
|
||||||
|
|
||||||
This signal indicates a changed value of the given
|
This signal indicates a changed value of the given
|
||||||
@@ -180,6 +199,10 @@ Properties boolean Active [readwrite]
|
|||||||
"wap" - Used by WAP related services
|
"wap" - Used by WAP related services
|
||||||
"ims" - Used by IMS related services
|
"ims" - Used by IMS related services
|
||||||
|
|
||||||
|
string AuthenticationMethod [readwrite]
|
||||||
|
Holds the PPP authentication method to use. Valid
|
||||||
|
values are "pap" and "chap". Defaults to "chap".
|
||||||
|
|
||||||
string Username [readwrite]
|
string Username [readwrite]
|
||||||
|
|
||||||
Holds the username to be used for authentication
|
Holds the username to be used for authentication
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ Methods dict GetProperties()
|
|||||||
|
|
||||||
Possible Errors: [service].Error.InProgress
|
Possible Errors: [service].Error.InProgress
|
||||||
[service].Error.InvalidArguments
|
[service].Error.InvalidArguments
|
||||||
|
[service].Error.NotImplemented
|
||||||
|
[service].Error.NotSupported
|
||||||
|
|
||||||
string RequestPhoneNumber()
|
string RequestPhoneNumber()
|
||||||
|
|
||||||
@@ -51,6 +53,7 @@ Properties array{string} Features [readonly]
|
|||||||
"private-chat"
|
"private-chat"
|
||||||
"create-multiparty"
|
"create-multiparty"
|
||||||
"transfer"
|
"transfer"
|
||||||
|
"hf-indicators"
|
||||||
|
|
||||||
boolean InbandRinging [readonly]
|
boolean InbandRinging [readonly]
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ Properties array{string} Features [readonly]
|
|||||||
to activate or deactivate the function from the HF, or
|
to activate or deactivate the function from the HF, or
|
||||||
the AG could autonomously initiate it.
|
the AG could autonomously initiate it.
|
||||||
|
|
||||||
boolean EchoCancelingNoiseReduction [readwrite]
|
boolean EchoCancelingNoiseReduction [readwrite, optional]
|
||||||
|
|
||||||
Non-persistent Boolean property representing whether
|
Non-persistent Boolean property representing whether
|
||||||
echo canceling and noise reduction is enabled in the
|
echo canceling and noise reduction is enabled in the
|
||||||
@@ -80,3 +83,10 @@ Properties array{string} Features [readonly]
|
|||||||
array{string} SubscriberNumbers [readonly]
|
array{string} SubscriberNumbers [readonly]
|
||||||
|
|
||||||
List of subscriber numbers provided by the AG.
|
List of subscriber numbers provided by the AG.
|
||||||
|
|
||||||
|
boolean DistractedDrivingReduction [readwrite, optional]
|
||||||
|
|
||||||
|
Non-persistent property representing whether
|
||||||
|
distracted driving reduction mode should be enabled in
|
||||||
|
the AG. Support for this feature is optional on the
|
||||||
|
AG.
|
||||||
|
|||||||
@@ -76,6 +76,22 @@ Methods dict GetProperties()
|
|||||||
[service].Error.NotImplemented
|
[service].Error.NotImplemented
|
||||||
[service].Error.NotAllowed
|
[service].Error.NotAllowed
|
||||||
|
|
||||||
|
fd, byte Acquire()
|
||||||
|
|
||||||
|
Attempts to establish the SCO audio connection
|
||||||
|
returning the filedescriptor of the connection and the
|
||||||
|
codec in use.
|
||||||
|
|
||||||
|
Note: Contrary to Connect this does not call
|
||||||
|
NewConnection so it can be called in a blocking
|
||||||
|
manner.
|
||||||
|
|
||||||
|
Possible Errors: [service].Error.InProgress
|
||||||
|
[service].Error.Failed
|
||||||
|
[service].Error.NotAvailable
|
||||||
|
[service].Error.NotImplemented
|
||||||
|
[service].Error.NotAllowed
|
||||||
|
|
||||||
Signals PropertyChanged(string name, variant value)
|
Signals PropertyChanged(string name, variant value)
|
||||||
|
|
||||||
This signal indicates a changed value of the given
|
This signal indicates a changed value of the given
|
||||||
@@ -89,6 +105,10 @@ Properties string RemoteAddress [readonly]
|
|||||||
|
|
||||||
Bluetooth address of the local adapter.
|
Bluetooth address of the local adapter.
|
||||||
|
|
||||||
|
string Type [readonly]
|
||||||
|
|
||||||
|
Type of the card. Valid values are "gateway" or
|
||||||
|
"handsfree".
|
||||||
|
|
||||||
Handsfree Audio Agent hierarchy [experimental]
|
Handsfree Audio Agent hierarchy [experimental]
|
||||||
===============================
|
===============================
|
||||||
|
|||||||
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,11 @@ Properties boolean Powered [readwrite]
|
|||||||
"hfp") this corresponds to the Bluetooth Device
|
"hfp") this corresponds to the Bluetooth Device
|
||||||
Address of the remote device.
|
Address of the remote device.
|
||||||
|
|
||||||
|
string SoftwareVersionNumber [readonly, optional]
|
||||||
|
|
||||||
|
String representing the software version number of the
|
||||||
|
modem device.
|
||||||
|
|
||||||
array{string} Features [readonly]
|
array{string} Features [readonly]
|
||||||
|
|
||||||
List of currently enabled features. It uses simple
|
List of currently enabled features. It uses simple
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ Signals PropertyChanged(string property, variant value)
|
|||||||
This signal indicates a changed value of the given
|
This signal indicates a changed value of the given
|
||||||
property.
|
property.
|
||||||
|
|
||||||
|
OperatorsChanged(array{object,dict})
|
||||||
|
|
||||||
|
Signal that gets emitted when operator list has
|
||||||
|
changed. It contains the current list of operators.
|
||||||
|
|
||||||
Properties string Mode [readonly]
|
Properties string Mode [readonly]
|
||||||
|
|
||||||
The current registration mode. The default of this
|
The current registration mode. The default of this
|
||||||
|
|||||||
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.
|
||||||
@@ -45,6 +45,11 @@ Properties string TechnologyPreference [readwrite]
|
|||||||
"umts" Only UMTS used for radio access.
|
"umts" Only UMTS used for radio access.
|
||||||
"lte" Only LTE used for radio access.
|
"lte" Only LTE used for radio access.
|
||||||
|
|
||||||
|
array{string} AvailableTechnologies [readonly, optional]
|
||||||
|
|
||||||
|
List of values for TechnologyPreference property
|
||||||
|
supported by the modem.
|
||||||
|
|
||||||
string GsmBand [readwrite, optional]
|
string GsmBand [readwrite, optional]
|
||||||
|
|
||||||
Frequency band in which the modem is allowed to
|
Frequency band in which the modem is allowed to
|
||||||
|
|||||||
@@ -93,6 +93,11 @@ Properties boolean Present [readonly]
|
|||||||
|
|
||||||
Contains the IMSI of the SIM, if available.
|
Contains the IMSI of the SIM, if available.
|
||||||
|
|
||||||
|
string ServiceProviderName [readonly, optional]
|
||||||
|
|
||||||
|
Contains the service provider name fetched from the
|
||||||
|
SIM card, if available.
|
||||||
|
|
||||||
string MobileCountryCode [readonly, optional]
|
string MobileCountryCode [readonly, optional]
|
||||||
|
|
||||||
Contains the Mobile Country Code (MCC) of the home
|
Contains the Mobile Country Code (MCC) of the home
|
||||||
|
|||||||
46
ofono/doc/telit-modem.txt
Normal file
46
ofono/doc/telit-modem.txt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
oFono - Open Source Telephony
|
||||||
|
*****************************
|
||||||
|
|
||||||
|
Purpose
|
||||||
|
=======
|
||||||
|
The purpose of this document is to identify issues and configuration
|
||||||
|
requirements with Telit's modems.
|
||||||
|
|
||||||
|
HE910
|
||||||
|
=====
|
||||||
|
|
||||||
|
GPS:
|
||||||
|
To enable location reporting on the Telit HE910 the modem needs to be
|
||||||
|
switched to Port Configuration #8. Please refer to Telit's
|
||||||
|
'HE910 UE910 Family Ports Arrangements' section 4.1.3 for rationale and
|
||||||
|
'AT Commands Reference Guide' section 3.5.7.1.96 for specific AT command.
|
||||||
|
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.
|
||||||
@@ -52,6 +52,7 @@ static int atmodem_init(void)
|
|||||||
at_gprs_context_init();
|
at_gprs_context_init();
|
||||||
at_sim_auth_init();
|
at_sim_auth_init();
|
||||||
at_gnss_init();
|
at_gnss_init();
|
||||||
|
at_lte_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -76,6 +77,7 @@ static void atmodem_exit(void)
|
|||||||
at_gprs_exit();
|
at_gprs_exit();
|
||||||
at_gprs_context_exit();
|
at_gprs_context_exit();
|
||||||
at_gnss_exit();
|
at_gnss_exit();
|
||||||
|
at_lte_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
||||||
|
|||||||
@@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void);
|
|||||||
|
|
||||||
extern void at_gnss_init(void);
|
extern void at_gnss_init(void);
|
||||||
extern void at_gnss_exit(void);
|
extern void at_gnss_exit(void);
|
||||||
|
|
||||||
|
extern void at_lte_init(void);
|
||||||
|
extern void at_lte_exit(void);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <gatchat.h>
|
#include <gatchat.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||||
#include <ofono/log.h>
|
#include <ofono/log.h>
|
||||||
@@ -614,3 +615,42 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req)
|
|||||||
|
|
||||||
g_free(req);
|
g_free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||||
|
* of "a.b.c.d.m.m.m.m" for IPv4.
|
||||||
|
* address/netmask must be able to hold
|
||||||
|
* 255.255.255.255 + null = 16 characters
|
||||||
|
*/
|
||||||
|
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||||
|
char *address, char *netmask)
|
||||||
|
{
|
||||||
|
const char *s = addrnetmask;
|
||||||
|
const char *net = NULL;
|
||||||
|
|
||||||
|
int ret = -EINVAL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Count 7 dots for ipv4, less or more means error. */
|
||||||
|
for (i = 0; i < 9; i++, s++) {
|
||||||
|
s = strchr(s, '.');
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == 3) {
|
||||||
|
/* set netmask ptr and break the string */
|
||||||
|
net = s + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 7) {
|
||||||
|
memcpy(address, addrnetmask, net - addrnetmask);
|
||||||
|
address[net - addrnetmask - 1] = '\0';
|
||||||
|
strcpy(netmask, net);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ struct at_util_sim_state_query *at_util_sim_state_query_new(GAtChat *chat,
|
|||||||
GDestroyNotify destroy);
|
GDestroyNotify destroy);
|
||||||
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
||||||
|
|
||||||
|
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||||
|
char *address, char *netmask);
|
||||||
|
|
||||||
struct cb_data {
|
struct cb_data {
|
||||||
void *cb;
|
void *cb;
|
||||||
void *data;
|
void *data;
|
||||||
|
|||||||
@@ -43,10 +43,11 @@
|
|||||||
#include "atmodem.h"
|
#include "atmodem.h"
|
||||||
#include "vendor.h"
|
#include "vendor.h"
|
||||||
|
|
||||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
#define TUN_DEV "/dev/net/tun"
|
||||||
|
|
||||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||||
|
|
||||||
|
static const char *cgdata_prefix[] = { "+CGDATA:", NULL };
|
||||||
static const char *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
|
|
||||||
enum state {
|
enum state {
|
||||||
@@ -59,6 +60,7 @@ enum state {
|
|||||||
struct gprs_context_data {
|
struct gprs_context_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
unsigned int active_context;
|
unsigned int active_context;
|
||||||
|
GAtPPPAuthMethod auth_method;
|
||||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||||
GAtPPP *ppp;
|
GAtPPP *ppp;
|
||||||
@@ -66,6 +68,7 @@ struct gprs_context_data {
|
|||||||
ofono_gprs_context_cb_t cb;
|
ofono_gprs_context_cb_t cb;
|
||||||
void *cb_data; /* Callback data */
|
void *cb_data; /* Callback data */
|
||||||
unsigned int vendor;
|
unsigned int vendor;
|
||||||
|
gboolean use_atd99;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ppp_debug(const char *str, void *data)
|
static void ppp_debug(const char *str, void *data)
|
||||||
@@ -154,6 +157,7 @@ static gboolean setup_ppp(struct ofono_gprs_context *gc)
|
|||||||
if (getenv("OFONO_PPP_DEBUG"))
|
if (getenv("OFONO_PPP_DEBUG"))
|
||||||
g_at_ppp_set_debug(gcd->ppp, ppp_debug, "PPP");
|
g_at_ppp_set_debug(gcd->ppp, ppp_debug, "PPP");
|
||||||
|
|
||||||
|
g_at_ppp_set_auth_method(gcd->ppp, gcd->auth_method);
|
||||||
g_at_ppp_set_credentials(gcd->ppp, gcd->username, gcd->password);
|
g_at_ppp_set_credentials(gcd->ppp, gcd->username, gcd->password);
|
||||||
|
|
||||||
/* set connect and disconnect callbacks */
|
/* set connect and disconnect callbacks */
|
||||||
@@ -208,7 +212,7 @@ static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gcd->vendor == OFONO_VENDOR_SIMCOM_SIM900)
|
if (gcd->use_atd99)
|
||||||
sprintf(buf, "ATD*99***%u#", gcd->active_context);
|
sprintf(buf, "ATD*99***%u#", gcd->active_context);
|
||||||
else
|
else
|
||||||
sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
|
sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
|
||||||
@@ -243,6 +247,20 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
|||||||
memcpy(gcd->username, ctx->username, sizeof(ctx->username));
|
memcpy(gcd->username, ctx->username, sizeof(ctx->username));
|
||||||
memcpy(gcd->password, ctx->password, sizeof(ctx->password));
|
memcpy(gcd->password, ctx->password, sizeof(ctx->password));
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||||
|
gcd->auth_method = G_AT_PPP_AUTH_METHOD_PAP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
gcd->state = STATE_ENABLING;
|
gcd->state = STATE_ENABLING;
|
||||||
|
|
||||||
if (gcd->vendor == OFONO_VENDOR_ZTE) {
|
if (gcd->vendor == OFONO_VENDOR_ZTE) {
|
||||||
@@ -268,9 +286,36 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
|||||||
|
|
||||||
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid);
|
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid);
|
||||||
|
|
||||||
if (ctx->apn)
|
if (ctx->apn) {
|
||||||
|
switch (gcd->vendor) {
|
||||||
|
case OFONO_VENDOR_UBLOX:
|
||||||
|
/*
|
||||||
|
* U-blox modems require a magic prefix to the APN to
|
||||||
|
* specify the authentication method to use in the
|
||||||
|
* network. See UBX-13002752 - R21.
|
||||||
|
*
|
||||||
|
* As the response of the read command omits this magic
|
||||||
|
* 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);
|
||||||
|
break;
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||||
|
snprintf(buf + len, sizeof(buf) - len - 3,
|
||||||
|
",\"PAP:%s\"", ctx->apn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
|
snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
|
||||||
ctx->apn);
|
ctx->apn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||||
at_cgdcont_cb, gc, NULL) > 0)
|
at_cgdcont_cb, gc, NULL) > 0)
|
||||||
@@ -339,6 +384,43 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
|||||||
g_at_ppp_shutdown(gcd->ppp);
|
g_at_ppp_shutdown(gcd->ppp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void at_cgdata_test_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs_context *gc = user_data;
|
||||||
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *data_type;
|
||||||
|
gboolean found = FALSE;
|
||||||
|
|
||||||
|
gcd->use_atd99 = TRUE;
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
DBG("not ok");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
if (!g_at_result_iter_next(&iter, "+CGDATA:")) {
|
||||||
|
DBG("no +CGDATA line");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_at_result_iter_open_list(&iter)) {
|
||||||
|
DBG("no list found");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!found && g_at_result_iter_next_string(&iter, &data_type)) {
|
||||||
|
if (g_str_equal(data_type, "PPP")) {
|
||||||
|
found = TRUE;
|
||||||
|
gcd->use_atd99 = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error:
|
||||||
|
DBG("use_atd99:%d", gcd->use_atd99);
|
||||||
|
}
|
||||||
|
|
||||||
static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||||
unsigned int vendor, void *data)
|
unsigned int vendor, void *data)
|
||||||
{
|
{
|
||||||
@@ -348,7 +430,7 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
if (stat(TUN_DEV, &st) < 0) {
|
||||||
ofono_error("Missing support for TUN/TAP devices");
|
ofono_error("Missing support for TUN/TAP devices");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@@ -366,6 +448,15 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
|||||||
if (chat == NULL)
|
if (chat == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
switch (vendor) {
|
||||||
|
case OFONO_VENDOR_SIMCOM_SIM900:
|
||||||
|
gcd->use_atd99 = FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_at_chat_send(chat, "AT+CGDATA=?", cgdata_prefix,
|
||||||
|
at_cgdata_test_cb, gc, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ static const char *none_prefix[] = { NULL };
|
|||||||
struct gprs_data {
|
struct gprs_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
unsigned int vendor;
|
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)
|
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);
|
snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
|
||||||
|
|
||||||
if (g_at_chat_send(gd->chat, buf, none_prefix,
|
if (g_at_chat_send(gd->chat, buf, none_prefix,
|
||||||
at_cgatt_cb, cbd, g_free) > 0)
|
at_cgatt_cb, cbd, g_free) > 0) {
|
||||||
|
gd->attached = attached;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
|
|
||||||
@@ -141,6 +146,48 @@ static void at_gprs_registration_status(struct ofono_gprs *gprs,
|
|||||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
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)
|
static void cgreg_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs *gprs = 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)
|
NULL, NULL, NULL, gd->vendor) == FALSE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Telit AT modem firmware (tested with UE910-EUR) generates
|
||||||
|
* +CGREG: 0\r\n\r\n+CGEV: NW DETACH
|
||||||
|
* after a context is de-activated and ppp connection closed.
|
||||||
|
* Then, after a random amount of time (observed from a few seconds
|
||||||
|
* to a few hours), an unsolicited +CGREG: 1 arrives.
|
||||||
|
* Attempt to fix the problem, by sending AT+CGATT=1 once.
|
||||||
|
* This does not re-activate the context, but if a network connection
|
||||||
|
* is still correct, will generate an immediate +CGREG: 1.
|
||||||
|
*/
|
||||||
|
if (gd->vendor == OFONO_VENDOR_TELIT) {
|
||||||
|
if (gd->attached && !status && !gd->telit_try_reattach) {
|
||||||
|
DBG("Trying to re-attach gprs network");
|
||||||
|
gd->telit_try_reattach = TRUE;
|
||||||
|
g_at_chat_send(gd->chat, "AT+CGATT=1", none_prefix,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gd->telit_try_reattach = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
ofono_gprs_status_notify(gprs, status);
|
ofono_gprs_status_notify(gprs, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs *gprs = user_data;
|
struct ofono_gprs *gprs = user_data;
|
||||||
|
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||||
GAtResultIter iter;
|
GAtResultIter iter;
|
||||||
const char *event;
|
const char *event;
|
||||||
|
|
||||||
@@ -170,8 +240,18 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
if (g_str_equal(event, "NW DETACH") ||
|
if (g_str_equal(event, "NW DETACH") ||
|
||||||
g_str_equal(event, "ME DETACH")) {
|
g_str_equal(event, "ME DETACH")) {
|
||||||
|
if (gd->vendor == OFONO_VENDOR_TELIT &&
|
||||||
|
gd->telit_try_reattach)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gd->attached = FALSE;
|
||||||
ofono_gprs_detached_notify(gprs);
|
ofono_gprs_detached_notify(gprs);
|
||||||
return;
|
return;
|
||||||
|
} else if (g_str_has_prefix(event, "ME PDN ACT")) {
|
||||||
|
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);
|
ofono_gprs_bearer_notify(gprs, bearer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs *gprs = user_data;
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *mode;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strcmp("LTE", mode))
|
||||||
|
ofono_gprs_bearer_notify(gprs, 7); /* LTE */
|
||||||
|
|
||||||
|
/* in other modes, notification ^MODE is used */
|
||||||
|
}
|
||||||
|
|
||||||
static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs *gprs = user_data;
|
struct ofono_gprs *gprs = user_data;
|
||||||
@@ -274,6 +374,9 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
|||||||
case 3:
|
case 3:
|
||||||
bearer = 5; /* HSDPA */
|
bearer = 5; /* HSDPA */
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
bearer = 7; /* LTE */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
bearer = 0;
|
bearer = 0;
|
||||||
break;
|
break;
|
||||||
@@ -282,6 +385,40 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
|||||||
ofono_gprs_bearer_notify(gprs, bearer);
|
ofono_gprs_bearer_notify(gprs, bearer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ublox_ureg_notify(GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs *gprs = user_data;
|
||||||
|
GAtResultIter iter;
|
||||||
|
gint state, bearer;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "+UREG:"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case 4:
|
||||||
|
bearer = 5;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
bearer = 4;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
bearer = 1;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
bearer = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bearer = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_gprs_bearer_notify(gprs, bearer);
|
||||||
|
}
|
||||||
|
|
||||||
static void cpsb_notify(GAtResult *result, gpointer user_data)
|
static void cpsb_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs *gprs = user_data;
|
struct ofono_gprs *gprs = user_data;
|
||||||
@@ -315,12 +452,22 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
case OFONO_VENDOR_HUAWEI:
|
case OFONO_VENDOR_HUAWEI:
|
||||||
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
||||||
FALSE, gprs, NULL);
|
FALSE, gprs, NULL);
|
||||||
|
g_at_chat_register(gd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||||
|
FALSE, gprs, NULL);
|
||||||
|
break;
|
||||||
|
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,
|
||||||
|
NULL, NULL, NULL);
|
||||||
break;
|
break;
|
||||||
case OFONO_VENDOR_TELIT:
|
case OFONO_VENDOR_TELIT:
|
||||||
g_at_chat_register(gd->chat, "#PSNT:", telit_mode_notify,
|
g_at_chat_register(gd->chat, "#PSNT:", telit_mode_notify,
|
||||||
FALSE, gprs, NULL);
|
FALSE, gprs, NULL);
|
||||||
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
|
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
|
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
|
||||||
FALSE, gprs, NULL);
|
FALSE, gprs, NULL);
|
||||||
@@ -432,7 +579,7 @@ static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
|
|||||||
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
|
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!g_at_result_iter_close_list(&iter))
|
if (!g_at_result_iter_skip_next(&iter))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (g_at_result_iter_open_list(&iter))
|
if (g_at_result_iter_open_list(&iter))
|
||||||
|
|||||||
142
ofono/drivers/atmodem/lte.c
Normal file
142
ofono/drivers/atmodem/lte.c
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
#include <ofono/gprs-context.h>
|
||||||
|
#include <ofono/log.h>
|
||||||
|
#include <ofono/lte.h>
|
||||||
|
|
||||||
|
#include "gatchat.h"
|
||||||
|
#include "gatresult.h"
|
||||||
|
|
||||||
|
#include "atmodem.h"
|
||||||
|
|
||||||
|
struct lte_driver_data {
|
||||||
|
GAtChat *chat;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_lte_cb_t cb = cbd->cb;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
cb(&error, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||||
|
const struct ofono_lte_default_attach_info *info,
|
||||||
|
ofono_lte_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||||
|
char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
|
DBG("LTE config with APN: %s", info->apn);
|
||||||
|
|
||||||
|
if (strlen(info->apn) > 0)
|
||||||
|
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"",
|
||||||
|
info->apn);
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\"");
|
||||||
|
|
||||||
|
/* We can't do much in case of failure so don't check response. */
|
||||||
|
if (g_at_chat_send(ldd->chat, buf, NULL,
|
||||||
|
at_lte_set_default_attach_info_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean lte_delayed_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_lte *lte = user_data;
|
||||||
|
|
||||||
|
ofono_lte_register(lte);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int at_lte_probe(struct ofono_lte *lte, void *data)
|
||||||
|
{
|
||||||
|
GAtChat *chat = data;
|
||||||
|
struct lte_driver_data *ldd;
|
||||||
|
|
||||||
|
DBG("at lte probe");
|
||||||
|
|
||||||
|
ldd = g_try_new0(struct lte_driver_data, 1);
|
||||||
|
if (!ldd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ldd->chat = g_at_chat_clone(chat);
|
||||||
|
|
||||||
|
ofono_lte_set_data(lte, ldd);
|
||||||
|
|
||||||
|
g_idle_add(lte_delayed_register, lte);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void at_lte_remove(struct ofono_lte *lte)
|
||||||
|
{
|
||||||
|
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||||
|
|
||||||
|
DBG("at lte remove");
|
||||||
|
|
||||||
|
g_at_chat_unref(ldd->chat);
|
||||||
|
|
||||||
|
ofono_lte_set_data(lte, NULL);
|
||||||
|
|
||||||
|
g_free(ldd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ofono_lte_driver driver = {
|
||||||
|
.name = "atmodem",
|
||||||
|
.probe = at_lte_probe,
|
||||||
|
.remove = at_lte_remove,
|
||||||
|
.set_default_attach_info = at_lte_set_default_attach_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
void at_lte_init(void)
|
||||||
|
{
|
||||||
|
ofono_lte_driver_register(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void at_lte_exit(void)
|
||||||
|
{
|
||||||
|
ofono_lte_driver_unregister(&driver);
|
||||||
|
}
|
||||||
@@ -838,6 +838,39 @@ static void telit_ciev_notify(GAtResult *result, gpointer user_data)
|
|||||||
ofono_netreg_strength_notify(netreg, strength);
|
ofono_netreg_strength_notify(netreg, strength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cinterion_ciev_notify(GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_netreg *netreg = user_data;
|
||||||
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||||
|
const char *signal_identifier = "rssi";
|
||||||
|
const char *ind_str;
|
||||||
|
int strength;
|
||||||
|
GAtResultIter iter;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "+CIEV:"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_unquoted_string(&iter, &ind_str))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_str_equal(signal_identifier, ind_str))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &strength))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DBG("rssi %d", strength);
|
||||||
|
|
||||||
|
if (strength == nd->signal_invalid)
|
||||||
|
strength = -1;
|
||||||
|
else
|
||||||
|
strength = (strength * 100) / (nd->signal_max - nd->signal_min);
|
||||||
|
|
||||||
|
ofono_netreg_strength_notify(netreg, strength);
|
||||||
|
}
|
||||||
|
|
||||||
static void ctzv_notify(GAtResult *result, gpointer user_data)
|
static void ctzv_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_netreg *netreg = user_data;
|
struct ofono_netreg *netreg = user_data;
|
||||||
@@ -1055,6 +1088,27 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_netreg *netreg = user_data;
|
||||||
|
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *mode;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strcmp("LTE", mode))
|
||||||
|
nd->tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||||
|
|
||||||
|
/* for other technologies, notification ^MODE is used */
|
||||||
|
}
|
||||||
|
|
||||||
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
|
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_netreg *netreg = user_data;
|
struct ofono_netreg *netreg = user_data;
|
||||||
@@ -1547,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,
|
static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||||
struct netreg_data *nd)
|
struct netreg_data *nd)
|
||||||
{
|
{
|
||||||
const char *mode;
|
const char *ind;
|
||||||
int len = sprintf(buf, "AT+CMER=");
|
int len = sprintf(buf, "AT+CMER=");
|
||||||
|
const char *mode;
|
||||||
|
|
||||||
DBG("");
|
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;
|
* Forward unsolicited result codes directly to the TE;
|
||||||
* TA‑TE link specific inband technique used to embed result codes and
|
* TA‑TE link specific inband technique used to embed result codes and
|
||||||
* data when TA is in on‑line data mode
|
* 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;
|
return FALSE;
|
||||||
|
|
||||||
/* No keypad event reporting */
|
/* No keypad event reporting */
|
||||||
@@ -1574,14 +1639,14 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
|||||||
* Telit does not support mode 1.
|
* Telit does not support mode 1.
|
||||||
* All indicator events shall be directed from TA to TE.
|
* All indicator events shall be directed from TA to TE.
|
||||||
*/
|
*/
|
||||||
mode = "2";
|
ind = "2";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
* Only those indicator events, which are not caused by +CIND
|
* Only those indicator events, which are not caused by +CIND
|
||||||
* shall be indicated by the TA to the TE.
|
* shall be indicated by the TA to the TE.
|
||||||
*/
|
*/
|
||||||
mode = "1";
|
ind = "1";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1590,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)
|
* <ind> indicates the indicator order number (as specified for +CIND)
|
||||||
* and <value> is the new value of indicator.
|
* 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 FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -1852,6 +1917,10 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
|
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
|
||||||
FALSE, netreg, NULL);
|
FALSE, netreg, NULL);
|
||||||
|
|
||||||
|
/* Register for 4G system mode reports */
|
||||||
|
g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||||
|
FALSE, netreg, NULL);
|
||||||
|
|
||||||
/* Register for network time reports */
|
/* Register for network time reports */
|
||||||
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
||||||
FALSE, netreg, NULL);
|
FALSE, netreg, NULL);
|
||||||
@@ -1915,6 +1984,27 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
g_at_chat_send(nd->chat, "AT*TLTS=1", none_prefix,
|
g_at_chat_send(nd->chat, "AT*TLTS=1", none_prefix,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
break;
|
break;
|
||||||
|
case OFONO_VENDOR_CINTERION:
|
||||||
|
/*
|
||||||
|
* We can't set rssi bounds from Cinterion responses
|
||||||
|
* so set them up to specified values here
|
||||||
|
*
|
||||||
|
* Cinterion rssi signal strength specified as:
|
||||||
|
* 0 <= -112dBm
|
||||||
|
* 1 - 4 signal strengh in 15 dB steps
|
||||||
|
* 5 >= -51 dBm
|
||||||
|
* 99 not known or undetectable
|
||||||
|
*/
|
||||||
|
nd->signal_min = 0;
|
||||||
|
nd->signal_max = 5;
|
||||||
|
nd->signal_invalid = 99;
|
||||||
|
|
||||||
|
/* Register for specific signal strength reports */
|
||||||
|
g_at_chat_send(nd->chat, "AT^SIND=\"rssi\",1", none_prefix,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
g_at_chat_register(nd->chat, "+CIEV:",
|
||||||
|
cinterion_ciev_notify, FALSE, netreg, NULL);
|
||||||
|
break;
|
||||||
case OFONO_VENDOR_NOKIA:
|
case OFONO_VENDOR_NOKIA:
|
||||||
case OFONO_VENDOR_SAMSUNG:
|
case OFONO_VENDOR_SAMSUNG:
|
||||||
/* Signal strength reporting via CIND is not supported */
|
/* Signal strength reporting via CIND is not supported */
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ struct sim_data {
|
|||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
unsigned int vendor;
|
unsigned int vendor;
|
||||||
guint ready_id;
|
guint ready_id;
|
||||||
|
guint passwd_type_mask;
|
||||||
struct at_util_sim_state_query *sim_state_query;
|
struct at_util_sim_state_query *sim_state_query;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,6 +68,8 @@ static const char *epin_prefix[] = { "*EPIN:", NULL };
|
|||||||
static const char *spic_prefix[] = { "+SPIC:", NULL };
|
static const char *spic_prefix[] = { "+SPIC:", NULL };
|
||||||
static const char *pct_prefix[] = { "#PCT:", NULL };
|
static const char *pct_prefix[] = { "#PCT:", NULL };
|
||||||
static const char *pnnm_prefix[] = { "+PNNM:", 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 *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
|
|
||||||
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
@@ -825,7 +828,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
for (i = 1; i < len; i++) {
|
for (i = 1; i < len; i++) {
|
||||||
if (!strcmp(name, at_sim_name[i].name)) {
|
if (!strcmp(name, at_sim_name[i].name)) {
|
||||||
retries[i] = val;
|
retries[at_sim_name[i].type] = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -967,6 +970,90 @@ error:
|
|||||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void at_qpinc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
while (g_at_result_iter_next(&iter, "+QPINC:")) {
|
||||||
|
const char *name;
|
||||||
|
int pin, puk;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &name))
|
||||||
|
continue;
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &pin))
|
||||||
|
continue;
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &puk))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!strcmp(name, "SC")) {
|
||||||
|
retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin;
|
||||||
|
retries[OFONO_SIM_PASSWORD_SIM_PUK] = puk;
|
||||||
|
} else if (!strcmp(name, "P2")) {
|
||||||
|
retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin;
|
||||||
|
retries[OFONO_SIM_PASSWORD_SIM_PUK2] = puk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(&error, retries, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void upincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
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;
|
||||||
|
static enum ofono_sim_password_type password_types[] = {
|
||||||
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
||||||
|
OFONO_SIM_PASSWORD_SIM_PIN2,
|
||||||
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
||||||
|
OFONO_SIM_PASSWORD_SIM_PUK2,
|
||||||
|
};
|
||||||
|
|
||||||
|
decode_at_error(&error, final);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
cb(&error, NULL, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "+UPINCNT:"))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
||||||
|
retries);
|
||||||
|
|
||||||
|
cb(&error, retries, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
static void at_pin_retries_query(struct ofono_sim *sim,
|
static void at_pin_retries_query(struct ofono_sim *sim,
|
||||||
ofono_sim_pin_retries_cb_t cb,
|
ofono_sim_pin_retries_cb_t cb,
|
||||||
void *data)
|
void *data)
|
||||||
@@ -1028,6 +1115,17 @@ static void at_pin_retries_query(struct ofono_sim *sim,
|
|||||||
at_pnnm_cb, cbd, g_free) > 0)
|
at_pnnm_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
case OFONO_VENDOR_QUECTEL:
|
||||||
|
if (g_at_chat_send(sd->chat, "AT+QPINC?", qpinc_prefix,
|
||||||
|
at_qpinc_cb, cbd, g_free) > 0)
|
||||||
|
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;
|
||||||
default:
|
default:
|
||||||
if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
|
if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
|
||||||
at_cpinr_cb, cbd, g_free) > 0)
|
at_cpinr_cb, cbd, g_free) > 0)
|
||||||
@@ -1196,14 +1294,15 @@ static void sim_state_cb(gboolean present, gpointer user_data)
|
|||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
struct sim_data *sd = cbd->user;
|
struct sim_data *sd = cbd->user;
|
||||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||||
|
void *data = cbd->data;
|
||||||
|
|
||||||
at_util_sim_state_query_free(sd->sim_state_query);
|
at_util_sim_state_query_free(sd->sim_state_query);
|
||||||
sd->sim_state_query = NULL;
|
sd->sim_state_query = NULL;
|
||||||
|
|
||||||
if (present == 1)
|
if (present == 1)
|
||||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
CALLBACK_WITH_SUCCESS(cb, data);
|
||||||
else
|
else
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||||
@@ -1254,6 +1353,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
|||||||
case OFONO_VENDOR_ALCATEL:
|
case OFONO_VENDOR_ALCATEL:
|
||||||
case OFONO_VENDOR_HUAWEI:
|
case OFONO_VENDOR_HUAWEI:
|
||||||
case OFONO_VENDOR_SIMCOM:
|
case OFONO_VENDOR_SIMCOM:
|
||||||
|
case OFONO_VENDOR_SIERRA:
|
||||||
/*
|
/*
|
||||||
* On ZTE modems, after pin is entered, SIM state is checked
|
* On ZTE modems, after pin is entered, SIM state is checked
|
||||||
* by polling CPIN as their modem doesn't provide unsolicited
|
* by polling CPIN as their modem doesn't provide unsolicited
|
||||||
@@ -1360,9 +1460,8 @@ static void at_pin_enable(struct ofono_sim *sim,
|
|||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[64];
|
char buf[64];
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
|
||||||
|
|
||||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
||||||
@@ -1391,10 +1490,8 @@ static void at_change_passwd(struct ofono_sim *sim,
|
|||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[64];
|
char buf[64];
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
|
||||||
|
|
||||||
if (passwd_type >= len ||
|
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||||
at_clck_cpwd_fac[passwd_type] == NULL)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
||||||
@@ -1419,7 +1516,7 @@ static void at_lock_status_cb(gboolean ok, GAtResult *result,
|
|||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
GAtResultIter iter;
|
GAtResultIter iter;
|
||||||
ofono_sim_locked_cb_t cb = cbd->cb;
|
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
||||||
struct ofono_error error;
|
struct ofono_error error;
|
||||||
int locked;
|
int locked;
|
||||||
|
|
||||||
@@ -1444,16 +1541,15 @@ static void at_lock_status_cb(gboolean ok, GAtResult *result,
|
|||||||
cb(&error, locked, cbd->data);
|
cb(&error, locked, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void at_pin_query_enabled(struct ofono_sim *sim,
|
static void at_query_clck(struct ofono_sim *sim,
|
||||||
enum ofono_sim_password_type passwd_type,
|
enum ofono_sim_password_type passwd_type,
|
||||||
ofono_sim_locked_cb_t cb, void *data)
|
ofono_query_facility_lock_cb_t cb, void *data)
|
||||||
{
|
{
|
||||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[64];
|
char buf[64];
|
||||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
|
||||||
|
|
||||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
||||||
@@ -1469,13 +1565,42 @@ error:
|
|||||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean at_sim_register(gpointer user)
|
static void at_clck_query_cb(gboolean ok, GAtResult *result, gpointer user)
|
||||||
{
|
{
|
||||||
struct ofono_sim *sim = user;
|
struct ofono_sim *sim = user;
|
||||||
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *fac;
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
/* e.g. +CLCK: ("SC","FD","PN","PU","PP","PC","PF") */
|
||||||
|
if (!g_at_result_iter_next(&iter, "+CLCK:") ||
|
||||||
|
!g_at_result_iter_open_list(&iter))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Clear the default mask */
|
||||||
|
sd->passwd_type_mask = 0;
|
||||||
|
|
||||||
|
/* Set the bits for <fac>s that are actually supported */
|
||||||
|
while (g_at_result_iter_next_string(&iter, &fac)) {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* Find it in the list of known <fac>s */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++) {
|
||||||
|
if (!g_strcmp0(at_clck_cpwd_fac[i], fac)) {
|
||||||
|
sd->passwd_type_mask |= (1 << i);
|
||||||
|
DBG("found %s", fac);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
ofono_sim_register(sim);
|
ofono_sim_register(sim);
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||||
@@ -1483,6 +1608,7 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
|||||||
{
|
{
|
||||||
GAtChat *chat = data;
|
GAtChat *chat = data;
|
||||||
struct sim_data *sd;
|
struct sim_data *sd;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
sd = g_new0(struct sim_data, 1);
|
sd = g_new0(struct sim_data, 1);
|
||||||
sd->chat = g_at_chat_clone(chat);
|
sd->chat = g_at_chat_clone(chat);
|
||||||
@@ -1492,9 +1618,15 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
|||||||
g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
|
g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
ofono_sim_set_data(sim, sd);
|
ofono_sim_set_data(sim, sd);
|
||||||
g_idle_add(at_sim_register, sim);
|
|
||||||
|
|
||||||
return 0;
|
/* <fac>s supported by default */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++)
|
||||||
|
if (at_clck_cpwd_fac[i])
|
||||||
|
sd->passwd_type_mask |= (1 << i);
|
||||||
|
|
||||||
|
/* Query supported <fac>s */
|
||||||
|
return g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
|
||||||
|
at_clck_query_cb, sim, NULL) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void at_sim_remove(struct ofono_sim *sim)
|
static void at_sim_remove(struct ofono_sim *sim)
|
||||||
@@ -1529,7 +1661,7 @@ static struct ofono_sim_driver driver = {
|
|||||||
.reset_passwd = at_pin_send_puk,
|
.reset_passwd = at_pin_send_puk,
|
||||||
.lock = at_pin_enable,
|
.lock = at_pin_enable,
|
||||||
.change_passwd = at_change_passwd,
|
.change_passwd = at_change_passwd,
|
||||||
.query_locked = at_pin_query_enabled,
|
.query_facility_lock = at_query_clck,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ofono_sim_driver driver_noef = {
|
static struct ofono_sim_driver driver_noef = {
|
||||||
@@ -1543,7 +1675,7 @@ static struct ofono_sim_driver driver_noef = {
|
|||||||
.reset_passwd = at_pin_send_puk,
|
.reset_passwd = at_pin_send_puk,
|
||||||
.lock = at_pin_enable,
|
.lock = at_pin_enable,
|
||||||
.change_passwd = at_change_passwd,
|
.change_passwd = at_change_passwd,
|
||||||
.query_locked = at_pin_query_enabled,
|
.query_facility_lock = at_query_clck,
|
||||||
};
|
};
|
||||||
|
|
||||||
void at_sim_init(void)
|
void at_sim_init(void)
|
||||||
|
|||||||
@@ -319,26 +319,6 @@ static void at_cnma_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
"Further SMS reception is not guaranteed");
|
"Further SMS reception is not guaranteed");
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean at_parse_cmt(GAtResult *result, const char **pdu, int *pdulen)
|
|
||||||
{
|
|
||||||
GAtResultIter iter;
|
|
||||||
|
|
||||||
g_at_result_iter_init(&iter, result);
|
|
||||||
|
|
||||||
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!g_at_result_iter_skip_next(&iter))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!g_at_result_iter_next_number(&iter, pdulen))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
*pdu = g_at_result_pdu(result);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void at_ack_delivery(struct ofono_sms *sms)
|
static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||||
{
|
{
|
||||||
struct sms_data *data = ofono_sms_get_data(sms);
|
struct sms_data *data = ofono_sms_get_data(sms);
|
||||||
@@ -347,11 +327,21 @@ static inline void at_ack_delivery(struct ofono_sms *sms)
|
|||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
/* We must acknowledge the PDU using CNMA */
|
/* We must acknowledge the PDU using CNMA */
|
||||||
if (data->cnma_ack_pdu)
|
if (data->cnma_ack_pdu) {
|
||||||
|
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",
|
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
||||||
data->cnma_ack_pdu_len, data->cnma_ack_pdu);
|
data->cnma_ack_pdu_len,
|
||||||
else /* Should be a safe fallback */
|
data->cnma_ack_pdu);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Should be a safe fallback */
|
||||||
snprintf(buf, sizeof(buf), "AT+CNMA=0");
|
snprintf(buf, sizeof(buf), "AT+CNMA=0");
|
||||||
|
}
|
||||||
|
|
||||||
g_at_chat_send(data->chat, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
g_at_chat_send(data->chat, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
||||||
}
|
}
|
||||||
@@ -409,16 +399,34 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
|||||||
{
|
{
|
||||||
struct ofono_sms *sms = user_data;
|
struct ofono_sms *sms = user_data;
|
||||||
struct sms_data *data = ofono_sms_get_data(sms);
|
struct sms_data *data = ofono_sms_get_data(sms);
|
||||||
|
GAtResultIter iter;
|
||||||
const char *hexpdu;
|
const char *hexpdu;
|
||||||
|
unsigned char pdu[176];
|
||||||
long pdu_len;
|
long pdu_len;
|
||||||
int tpdu_len;
|
int tpdu_len;
|
||||||
unsigned char pdu[176];
|
|
||||||
|
|
||||||
if (!at_parse_cmt(result, &hexpdu, &tpdu_len)) {
|
g_at_result_iter_init(&iter, result);
|
||||||
ofono_error("Unable to parse CMT notification");
|
|
||||||
return;
|
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
switch (data->vendor) {
|
||||||
|
case OFONO_VENDOR_CINTERION:
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||||
|
goto err;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!g_at_result_iter_skip_next(&iter))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hexpdu = g_at_result_pdu(result);
|
||||||
|
|
||||||
if (strlen(hexpdu) > sizeof(pdu) * 2) {
|
if (strlen(hexpdu) > sizeof(pdu) * 2) {
|
||||||
ofono_error("Bad PDU length in CMT notification");
|
ofono_error("Bad PDU length in CMT notification");
|
||||||
return;
|
return;
|
||||||
@@ -431,6 +439,9 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
if (data->vendor != OFONO_VENDOR_SIMCOM)
|
if (data->vendor != OFONO_VENDOR_SIMCOM)
|
||||||
at_ack_delivery(sms);
|
at_ack_delivery(sms);
|
||||||
|
|
||||||
|
err:
|
||||||
|
ofono_error("Unable to parse CMT notification");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void at_cmgr_notify(GAtResult *result, gpointer user_data)
|
static void at_cmgr_notify(GAtResult *result, gpointer user_data)
|
||||||
@@ -742,7 +753,7 @@ static void at_sms_initialized(struct ofono_sms *sms)
|
|||||||
|
|
||||||
static void at_sms_not_supported(struct ofono_sms *sms)
|
static void at_sms_not_supported(struct ofono_sms *sms)
|
||||||
{
|
{
|
||||||
ofono_error("SMS not supported by this modem. If this is in error"
|
ofono_error("SMS not supported by this modem. If this is an error"
|
||||||
" please submit patches to support this hardware");
|
" please submit patches to support this hardware");
|
||||||
|
|
||||||
ofono_sms_remove(sms);
|
ofono_sms_remove(sms);
|
||||||
|
|||||||
@@ -42,5 +42,10 @@ enum ofono_vendor {
|
|||||||
OFONO_VENDOR_SIMCOM_SIM900,
|
OFONO_VENDOR_SIMCOM_SIM900,
|
||||||
OFONO_VENDOR_ICERA,
|
OFONO_VENDOR_ICERA,
|
||||||
OFONO_VENDOR_WAVECOM_Q2XXX,
|
OFONO_VENDOR_WAVECOM_Q2XXX,
|
||||||
OFONO_VENDOR_ALCATEL
|
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_full(vd->calls, g_free);
|
||||||
g_slist_free(vd->calls);
|
|
||||||
|
|
||||||
vd->calls = calls;
|
vd->calls = calls;
|
||||||
|
|
||||||
@@ -1147,8 +1146,7 @@ static void at_voicecall_remove(struct ofono_voicecall *vc)
|
|||||||
if (vd->vts_source)
|
if (vd->vts_source)
|
||||||
g_source_remove(vd->vts_source);
|
g_source_remove(vd->vts_source);
|
||||||
|
|
||||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
g_slist_free_full(vd->calls, g_free);
|
||||||
g_slist_free(vd->calls);
|
|
||||||
|
|
||||||
ofono_voicecall_set_data(vc, NULL);
|
ofono_voicecall_set_data(vc, NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
#include "cdmamodem.h"
|
#include "cdmamodem.h"
|
||||||
#include "drivers/atmodem/vendor.h"
|
#include "drivers/atmodem/vendor.h"
|
||||||
|
|
||||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
#define TUN_DEV "/dev/net/tun"
|
||||||
|
|
||||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ static int cdma_connman_probe(struct ofono_cdma_connman *cm,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
if (stat(TUN_DEV, &st) < 0) {
|
||||||
ofono_error("Missing support for TUN/TAP devices");
|
ofono_error("Missing support for TUN/TAP devices");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|||||||
49
ofono/drivers/gemaltomodem/gemaltomodem.c
Normal file
49
ofono/drivers/gemaltomodem/gemaltomodem.c
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gatchat.h>
|
||||||
|
|
||||||
|
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||||
|
#include <ofono/plugin.h>
|
||||||
|
#include <ofono/types.h>
|
||||||
|
|
||||||
|
#include "gemaltomodem.h"
|
||||||
|
|
||||||
|
static int gemaltomodem_init(void)
|
||||||
|
{
|
||||||
|
gemalto_location_reporting_init();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gemaltomodem_exit(void)
|
||||||
|
{
|
||||||
|
gemalto_location_reporting_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
|
||||||
|
OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||||
|
gemaltomodem_init, gemaltomodem_exit)
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* oFono - Open Source Telephony
|
* oFono - Open Source Telephony
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -19,11 +19,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#include <drivers/atmodem/atutil.h>
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
extern void gemalto_location_reporting_init();
|
||||||
{
|
extern void gemalto_location_reporting_exit();
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/log.h>
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
#include <ofono/location-reporting.h>
|
||||||
|
|
||||||
|
#include "gatchat.h"
|
||||||
|
#include "gatresult.h"
|
||||||
|
#include "gattty.h"
|
||||||
|
|
||||||
|
#include "gemaltomodem.h"
|
||||||
|
|
||||||
|
static const char *sgpsc_prefix[] = { "^SGPSC:", NULL };
|
||||||
|
|
||||||
|
struct gps_data {
|
||||||
|
GAtChat *chat;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gemalto_gps_disable_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
struct ofono_location_reporting *lr = cbd->user;
|
||||||
|
ofono_location_reporting_disable_cb_t cb = cbd->cb;
|
||||||
|
|
||||||
|
DBG("lr=%p, ok=%d", lr, ok);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
cb(&error, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gemalto_location_reporting_disable(
|
||||||
|
struct ofono_location_reporting *lr,
|
||||||
|
ofono_location_reporting_disable_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
|
DBG("lr=%p", lr);
|
||||||
|
|
||||||
|
cbd->user = lr;
|
||||||
|
|
||||||
|
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",0", sgpsc_prefix,
|
||||||
|
gemalto_gps_disable_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int enable_data_stream(struct ofono_location_reporting *lr)
|
||||||
|
{
|
||||||
|
struct ofono_modem *modem;
|
||||||
|
const char *gps_dev;
|
||||||
|
GHashTable *options;
|
||||||
|
GIOChannel *channel;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
modem = ofono_location_reporting_get_modem(lr);
|
||||||
|
gps_dev = ofono_modem_get_string(modem, "GPS");
|
||||||
|
|
||||||
|
options = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
|
if (options == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_hash_table_insert(options, "Baud", "115200");
|
||||||
|
|
||||||
|
channel = g_at_tty_open(gps_dev, options);
|
||||||
|
|
||||||
|
g_hash_table_destroy(options);
|
||||||
|
|
||||||
|
if (channel == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fd = g_io_channel_unix_get_fd(channel);
|
||||||
|
|
||||||
|
g_io_channel_set_close_on_unref(channel, FALSE);
|
||||||
|
g_io_channel_unref(channel);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gemalto_sgpsc_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_location_reporting_enable_cb_t cb = cbd->cb;
|
||||||
|
struct ofono_location_reporting *lr = cbd->user;
|
||||||
|
struct ofono_error error;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
DBG("lr=%p ok=%d", lr, ok);
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
cb(&error, -1, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = enable_data_stream(lr);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(&error, fd, cbd->data);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gemalto_location_reporting_enable(struct ofono_location_reporting *lr,
|
||||||
|
ofono_location_reporting_enable_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
|
DBG("lr=%p", lr);
|
||||||
|
|
||||||
|
cbd->user = lr;
|
||||||
|
|
||||||
|
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",2", sgpsc_prefix,
|
||||||
|
gemalto_sgpsc_cb, cbd, NULL) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gemalto_location_reporting_support_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_location_reporting *lr = user_data;
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
ofono_location_reporting_remove(lr);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_location_reporting_register(lr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gemalto_location_reporting_probe(struct ofono_location_reporting *lr,
|
||||||
|
unsigned int vendor, void *data)
|
||||||
|
{
|
||||||
|
GAtChat *chat = data;
|
||||||
|
struct gps_data *gd;
|
||||||
|
|
||||||
|
gd = g_try_new0(struct gps_data, 1);
|
||||||
|
if (gd == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gd->chat = g_at_chat_clone(chat);
|
||||||
|
|
||||||
|
ofono_location_reporting_set_data(lr, gd);
|
||||||
|
|
||||||
|
g_at_chat_send(gd->chat, "AT^SGPSC=?", sgpsc_prefix,
|
||||||
|
gemalto_location_reporting_support_cb,
|
||||||
|
lr, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gemalto_location_reporting_remove(struct ofono_location_reporting *lr)
|
||||||
|
{
|
||||||
|
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||||
|
|
||||||
|
ofono_location_reporting_set_data(lr, NULL);
|
||||||
|
|
||||||
|
g_at_chat_unref(gd->chat);
|
||||||
|
g_free(gd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ofono_location_reporting_driver driver = {
|
||||||
|
.name = "gemaltomodem",
|
||||||
|
.type = OFONO_LOCATION_REPORTING_TYPE_NMEA,
|
||||||
|
.probe = gemalto_location_reporting_probe,
|
||||||
|
.remove = gemalto_location_reporting_remove,
|
||||||
|
.enable = gemalto_location_reporting_enable,
|
||||||
|
.disable = gemalto_location_reporting_disable,
|
||||||
|
};
|
||||||
|
|
||||||
|
void gemalto_location_reporting_init()
|
||||||
|
{
|
||||||
|
ofono_location_reporting_driver_register(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gemalto_location_reporting_exit()
|
||||||
|
{
|
||||||
|
ofono_location_reporting_driver_unregister(&driver);
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
static const char *binp_prefix[] = { "+BINP:", NULL };
|
static const char *binp_prefix[] = { "+BINP:", NULL };
|
||||||
static const char *bvra_prefix[] = { "+BVRA:", NULL };
|
static const char *bvra_prefix[] = { "+BVRA:", NULL };
|
||||||
|
static const char *none_prefix[] = { NULL };
|
||||||
|
|
||||||
struct hf_data {
|
struct hf_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
@@ -197,7 +198,7 @@ static void hfp_cnum_query(struct ofono_handsfree *hf,
|
|||||||
struct hf_data *hd = ofono_handsfree_get_data(hf);
|
struct hf_data *hd = ofono_handsfree_get_data(hf);
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
if (g_at_chat_send(hd->chat, "AT+CNUM", NULL,
|
if (g_at_chat_send(hd->chat, "AT+CNUM", none_prefix,
|
||||||
cnum_query_cb, cbd, g_free) > 0)
|
cnum_query_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -206,6 +207,27 @@ static void hfp_cnum_query(struct ofono_handsfree *hf,
|
|||||||
CALLBACK_WITH_FAILURE(cb, -1, NULL, data);
|
CALLBACK_WITH_FAILURE(cb, -1, NULL, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bind_notify(GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_handsfree *hf = user_data;
|
||||||
|
int hf_indicator;
|
||||||
|
int active;
|
||||||
|
GAtResultIter iter;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "+BIND:"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &hf_indicator))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &active))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ofono_handsfree_hf_indicator_active_notify(hf, hf_indicator, active);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean hfp_handsfree_register(gpointer user_data)
|
static gboolean hfp_handsfree_register(gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_handsfree *hf = user_data;
|
struct ofono_handsfree *hf = user_data;
|
||||||
@@ -216,6 +238,7 @@ static gboolean hfp_handsfree_register(gpointer user_data)
|
|||||||
g_at_chat_register(hd->chat, "+BSIR:", bsir_notify, FALSE, hf, NULL);
|
g_at_chat_register(hd->chat, "+BSIR:", bsir_notify, FALSE, hf, NULL);
|
||||||
g_at_chat_register(hd->chat, "+BVRA:", bvra_notify, FALSE, hf, NULL);
|
g_at_chat_register(hd->chat, "+BVRA:", bvra_notify, FALSE, hf, NULL);
|
||||||
g_at_chat_register(hd->chat, "+CIEV:", ciev_notify, FALSE, hf, NULL);
|
g_at_chat_register(hd->chat, "+CIEV:", ciev_notify, FALSE, hf, NULL);
|
||||||
|
g_at_chat_register(hd->chat, "+BIND:", bind_notify, FALSE, hf, NULL);
|
||||||
|
|
||||||
if (hd->ag_features & HFP_AG_FEATURE_IN_BAND_RING_TONE)
|
if (hd->ag_features & HFP_AG_FEATURE_IN_BAND_RING_TONE)
|
||||||
ofono_handsfree_set_inband_ringing(hf, TRUE);
|
ofono_handsfree_set_inband_ringing(hf, TRUE);
|
||||||
@@ -232,6 +255,7 @@ static int hfp_handsfree_probe(struct ofono_handsfree *hf,
|
|||||||
{
|
{
|
||||||
struct hfp_slc_info *info = data;
|
struct hfp_slc_info *info = data;
|
||||||
struct hf_data *hd;
|
struct hf_data *hd;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
hd = g_new0(struct hf_data, 1);
|
hd = g_new0(struct hf_data, 1);
|
||||||
@@ -245,6 +269,14 @@ static int hfp_handsfree_probe(struct ofono_handsfree *hf,
|
|||||||
ofono_handsfree_battchg_notify(hf,
|
ofono_handsfree_battchg_notify(hf,
|
||||||
info->cind_val[HFP_INDICATOR_BATTCHG]);
|
info->cind_val[HFP_INDICATOR_BATTCHG]);
|
||||||
|
|
||||||
|
ofono_handsfree_set_hf_indicators(hf, info->hf_indicators,
|
||||||
|
info->num_hf_indicators);
|
||||||
|
|
||||||
|
for (i = 0; i < info->num_hf_indicators; i++)
|
||||||
|
ofono_handsfree_hf_indicator_active_notify(hf,
|
||||||
|
info->hf_indicators[i],
|
||||||
|
info->hf_indicator_active_map & (1 << i));
|
||||||
|
|
||||||
hd->register_source = g_idle_add(hfp_handsfree_register, hf);
|
hd->register_source = g_idle_add(hfp_handsfree_register, hf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -351,8 +383,27 @@ static void hfp_disable_nrec(struct ofono_handsfree *hf,
|
|||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
const char *buf = "AT+NREC=0";
|
const char *buf = "AT+NREC=0";
|
||||||
|
|
||||||
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
|
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||||
cbd, g_free) > 0)
|
hf_generic_set_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hfp_hf_indicator(struct ofono_handsfree *hf,
|
||||||
|
unsigned short indicator, unsigned int value,
|
||||||
|
ofono_handsfree_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct hf_data *hd = ofono_handsfree_get_data(hf);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "AT+BIEV=%u,%u", indicator, value);
|
||||||
|
|
||||||
|
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||||
|
hf_generic_set_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
@@ -368,6 +419,7 @@ static struct ofono_handsfree_driver driver = {
|
|||||||
.request_phone_number = hfp_request_phone_number,
|
.request_phone_number = hfp_request_phone_number,
|
||||||
.voice_recognition = hfp_voice_recognition,
|
.voice_recognition = hfp_voice_recognition,
|
||||||
.disable_nrec = hfp_disable_nrec,
|
.disable_nrec = hfp_disable_nrec,
|
||||||
|
.hf_indicator = hfp_hf_indicator,
|
||||||
};
|
};
|
||||||
|
|
||||||
void hfp_handsfree_init(void)
|
void hfp_handsfree_init(void)
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
|
|
||||||
static const char *cops_prefix[] = { "+COPS:", NULL };
|
static const char *cops_prefix[] = { "+COPS:", NULL };
|
||||||
static const char *cind_prefix[] = { "+CIND:", NULL };
|
static const char *cind_prefix[] = { "+CIND:", NULL };
|
||||||
|
static const char *none_prefix[] = { NULL };
|
||||||
|
|
||||||
struct netreg_data {
|
struct netreg_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
@@ -263,7 +264,7 @@ static void hfp_current_operator(struct ofono_netreg *netreg,
|
|||||||
|
|
||||||
cbd->user = netreg;
|
cbd->user = netreg;
|
||||||
|
|
||||||
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", NULL,
|
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
|
||||||
NULL, cbd, NULL);
|
NULL, cbd, NULL);
|
||||||
|
|
||||||
if (ok)
|
if (ok)
|
||||||
|
|||||||
@@ -41,10 +41,12 @@
|
|||||||
#include "hfp.h"
|
#include "hfp.h"
|
||||||
#include "slc.h"
|
#include "slc.h"
|
||||||
|
|
||||||
|
static const char *none_prefix[] = { NULL };
|
||||||
static const char *brsf_prefix[] = { "+BRSF:", NULL };
|
static const char *brsf_prefix[] = { "+BRSF:", NULL };
|
||||||
static const char *cind_prefix[] = { "+CIND:", NULL };
|
static const char *cind_prefix[] = { "+CIND:", NULL };
|
||||||
static const char *cmer_prefix[] = { "+CMER:", NULL };
|
static const char *cmer_prefix[] = { "+CMER:", NULL };
|
||||||
static const char *chld_prefix[] = { "+CHLD:", NULL };
|
static const char *chld_prefix[] = { "+CHLD:", NULL };
|
||||||
|
static const char *bind_prefix[] = { "+BIND:", NULL };
|
||||||
|
|
||||||
struct slc_establish_data {
|
struct slc_establish_data {
|
||||||
gint ref_count;
|
gint ref_count;
|
||||||
@@ -76,6 +78,14 @@ void hfp_slc_info_init(struct hfp_slc_info *info, guint16 version)
|
|||||||
|
|
||||||
info->hf_features |= HFP_HF_FEATURE_CODEC_NEGOTIATION;
|
info->hf_features |= HFP_HF_FEATURE_CODEC_NEGOTIATION;
|
||||||
|
|
||||||
|
if (version < HFP_VERSION_1_7)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
info->hf_features |= HFP_HF_FEATURE_HF_INDICATORS;
|
||||||
|
memset(info->hf_indicators, 0, sizeof(info->hf_indicators));
|
||||||
|
info->num_hf_indicators = 0;
|
||||||
|
info->hf_indicator_active_map = 0;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
memset(info->cind_val, 0, sizeof(info->cind_val));
|
memset(info->cind_val, 0, sizeof(info->cind_val));
|
||||||
memset(info->cind_pos, 0, sizeof(info->cind_pos));
|
memset(info->cind_pos, 0, sizeof(info->cind_pos));
|
||||||
@@ -103,10 +113,109 @@ static void slc_established(struct slc_establish_data *sed)
|
|||||||
{
|
{
|
||||||
struct hfp_slc_info *info = sed->info;
|
struct hfp_slc_info *info = sed->info;
|
||||||
|
|
||||||
g_at_chat_send(info->chat, "AT+CMEE=1", NULL, NULL, NULL, NULL);
|
g_at_chat_send(info->chat, "AT+CMEE=1", none_prefix,
|
||||||
|
NULL, NULL, NULL);
|
||||||
sed->connect_cb(sed->userdata);
|
sed->connect_cb(sed->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bind_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct slc_establish_data *sed = user_data;
|
||||||
|
struct hfp_slc_info *info = sed->info;
|
||||||
|
GAtResultIter iter;
|
||||||
|
int hf_indicator;
|
||||||
|
int enabled;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
while (g_at_result_iter_next(&iter, "+BIND:")) {
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &hf_indicator))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_number(&iter, &enabled))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ofono_info("AG wants indicator %d %s",
|
||||||
|
hf_indicator, enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
for (i = 0; i < info->num_hf_indicators; i++) {
|
||||||
|
if (info->hf_indicators[i] != hf_indicator)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
info->hf_indicator_active_map |= enabled << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_info("Active map: %02x", info->hf_indicator_active_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
slc_established(sed);
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
slc_failed(sed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bind_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct slc_establish_data *sed = user_data;
|
||||||
|
struct hfp_slc_info *info = sed->info;
|
||||||
|
GAtResultIter iter;
|
||||||
|
int hf_indicator;
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next(&iter, "+BIND:"))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_open_list(&iter))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
while (g_at_result_iter_next_number(&iter, &hf_indicator)) {
|
||||||
|
if (info->num_hf_indicators >= 20)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ofono_info("AG supports the following HF indicator: %d",
|
||||||
|
hf_indicator);
|
||||||
|
|
||||||
|
info->hf_indicators[info->num_hf_indicators] = hf_indicator;
|
||||||
|
info->num_hf_indicators += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_at_result_iter_close_list(&iter))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
slc_establish_data_ref(sed);
|
||||||
|
g_at_chat_send(info->chat, "AT+BIND?", bind_prefix,
|
||||||
|
bind_query_cb, sed, slc_establish_data_unref);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
slc_failed(sed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bind_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct slc_establish_data *sed = user_data;
|
||||||
|
struct hfp_slc_info *info = sed->info;
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
slc_failed(sed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
slc_establish_data_ref(sed);
|
||||||
|
g_at_chat_send(info->chat, "AT+BIND=?", bind_prefix,
|
||||||
|
bind_support_cb, sed, slc_establish_data_unref);
|
||||||
|
}
|
||||||
|
|
||||||
static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct slc_establish_data *sed = user_data;
|
struct slc_establish_data *sed = user_data;
|
||||||
@@ -148,7 +257,14 @@ static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
info->ag_mpty_features = ag_mpty_feature;
|
info->ag_mpty_features = ag_mpty_feature;
|
||||||
|
|
||||||
|
if ((info->ag_features & HFP_AG_FEATURE_HF_INDICATORS) &&
|
||||||
|
(info->hf_features & HFP_HF_FEATURE_HF_INDICATORS)) {
|
||||||
|
slc_establish_data_ref(sed);
|
||||||
|
g_at_chat_send(info->chat, "AT+BIND=1", none_prefix,
|
||||||
|
bind_set_cb, sed, slc_establish_data_unref);
|
||||||
|
} else
|
||||||
slc_established(sed);
|
slc_established(sed);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -319,8 +435,8 @@ static void brsf_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
sprintf(str, "AT+BAC=%d", HFP_CODEC_CVSD);
|
sprintf(str, "AT+BAC=%d", HFP_CODEC_CVSD);
|
||||||
|
|
||||||
slc_establish_data_ref(sed);
|
slc_establish_data_ref(sed);
|
||||||
g_at_chat_send(info->chat, str, NULL, bac_cb, sed,
|
g_at_chat_send(info->chat, str, none_prefix, bac_cb,
|
||||||
slc_establish_data_unref);
|
sed, slc_establish_data_unref);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ struct hfp_slc_info {
|
|||||||
unsigned int hf_features;
|
unsigned int hf_features;
|
||||||
unsigned char cind_pos[HFP_INDICATOR_LAST];
|
unsigned char cind_pos[HFP_INDICATOR_LAST];
|
||||||
unsigned int cind_val[HFP_INDICATOR_LAST];
|
unsigned int cind_val[HFP_INDICATOR_LAST];
|
||||||
|
unsigned short hf_indicators[20];
|
||||||
|
unsigned char num_hf_indicators;
|
||||||
|
unsigned int hf_indicator_active_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
void hfp_slc_info_init(struct hfp_slc_info *info, guint16 version);
|
void hfp_slc_info_init(struct hfp_slc_info *info, guint16 version);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
#define POLL_CLCC_DELAY 50
|
#define POLL_CLCC_DELAY 50
|
||||||
#define EXPECT_RELEASE_DELAY 50
|
#define EXPECT_RELEASE_DELAY 50
|
||||||
#define CLIP_TIMEOUT 500
|
#define CLIP_TIMEOUT 500
|
||||||
|
#define EXPECT_RING_DELAY 200
|
||||||
|
|
||||||
static const char *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
static const char *clcc_prefix[] = { "+CLCC:", NULL };
|
static const char *clcc_prefix[] = { "+CLCC:", NULL };
|
||||||
@@ -285,8 +286,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||||
|
|
||||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
g_slist_free_full(vd->calls, g_free);
|
||||||
g_slist_free(vd->calls);
|
|
||||||
|
|
||||||
vd->calls = calls;
|
vd->calls = calls;
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
* we won't get indicator update if any of them is released by CHLD=1x.
|
* we won't get indicator update if any of them is released by CHLD=1x.
|
||||||
* So we have to poll it.
|
* So we have to poll it.
|
||||||
*/
|
*/
|
||||||
if (num_active > 1 || num_held > 1)
|
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
|
||||||
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc,
|
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc,
|
||||||
vc);
|
vc);
|
||||||
}
|
}
|
||||||
@@ -332,6 +332,10 @@ static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ok && vd->calls)
|
||||||
|
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
|
||||||
|
clcc_poll_cb, req->vc, NULL);
|
||||||
|
|
||||||
req->cb(&error, req->data);
|
req->cb(&error, req->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,6 +503,19 @@ static gboolean expect_release(gpointer user_data)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean expect_ring(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_voicecall *vc = user_data;
|
||||||
|
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||||
|
|
||||||
|
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
|
||||||
|
clcc_poll_cb, vc, NULL);
|
||||||
|
|
||||||
|
vd->clip_source = 0;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void release_all_active_cb(gboolean ok, GAtResult *result,
|
static void release_all_active_cb(gboolean ok, GAtResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
@@ -640,8 +657,10 @@ static void hfp_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
|
|||||||
{
|
{
|
||||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||||
struct change_state_req *req = g_try_new0(struct change_state_req, 1);
|
struct change_state_req *req = g_try_new0(struct change_state_req, 1);
|
||||||
|
int len = strlen(dtmf);
|
||||||
char *buf;
|
char *buf;
|
||||||
int s;
|
int s;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (req == NULL)
|
if (req == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
@@ -651,12 +670,15 @@ static void hfp_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
|
|||||||
req->data = data;
|
req->data = data;
|
||||||
req->affected_types = 0;
|
req->affected_types = 0;
|
||||||
|
|
||||||
/* strlen("AT+VTS=) = 7 + NULL */
|
/* strlen("AT") + (n-1) * strlen("+VTS=T;") + strlen(+VTS=T) + null */
|
||||||
buf = g_try_new(char, strlen(dtmf) + 8);
|
buf = g_try_new(char, len * 7 + 2);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
sprintf(buf, "AT+VTS=%s", dtmf);
|
s = sprintf(buf, "AT+VTS=%c", dtmf[0]);
|
||||||
|
|
||||||
|
for (i = 1; i < len; i++)
|
||||||
|
s += sprintf(buf + s, ";+VTS=%c", dtmf[i]);
|
||||||
|
|
||||||
s = g_at_chat_send(vd->chat, buf, none_prefix,
|
s = g_at_chat_send(vd->chat, buf, none_prefix,
|
||||||
generic_cb, req, g_free);
|
generic_cb, req, g_free);
|
||||||
@@ -686,12 +708,31 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
|
|||||||
int num_type, validity;
|
int num_type, validity;
|
||||||
struct ofono_call *call;
|
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 */
|
/* CCWA can repeat, ignore if we already have an waiting call */
|
||||||
if (g_slist_find_custom(vd->calls,
|
if (g_slist_find_custom(vd->calls,
|
||||||
GINT_TO_POINTER(CALL_STATUS_WAITING),
|
GINT_TO_POINTER(CALL_STATUS_WAITING),
|
||||||
at_util_call_compare_by_status))
|
at_util_call_compare_by_status))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* some phones may send extra CCWA after active call is ended
|
||||||
|
* this would trigger creation of second call in state 'WAITING'
|
||||||
|
* as our previous WAITING call has been promoted to INCOMING
|
||||||
|
*/
|
||||||
|
if (g_slist_find_custom(vd->calls,
|
||||||
|
GINT_TO_POINTER(CALL_STATUS_INCOMING),
|
||||||
|
at_util_call_compare_by_status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
g_at_result_iter_init(&iter, result);
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
if (!g_at_result_iter_next(&iter, "+CCWA:"))
|
if (!g_at_result_iter_next(&iter, "+CCWA:"))
|
||||||
@@ -752,6 +793,11 @@ static void ring_notify(GAtResult *result, gpointer user_data)
|
|||||||
struct ofono_call *call;
|
struct ofono_call *call;
|
||||||
GSList *waiting;
|
GSList *waiting;
|
||||||
|
|
||||||
|
if (vd->clip_source) {
|
||||||
|
g_source_remove(vd->clip_source);
|
||||||
|
vd->clip_source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* RING can repeat, ignore if we already have an incoming call */
|
/* RING can repeat, ignore if we already have an incoming call */
|
||||||
if (g_slist_find_custom(vd->calls,
|
if (g_slist_find_custom(vd->calls,
|
||||||
GINT_TO_POINTER(CALL_STATUS_INCOMING),
|
GINT_TO_POINTER(CALL_STATUS_INCOMING),
|
||||||
@@ -976,7 +1022,15 @@ static void ciev_callsetup_notify(struct ofono_voicecall *vc,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
/* Handled in RING/CCWA */
|
/*
|
||||||
|
* Handled in RING/CCWA most of the time, however sometimes
|
||||||
|
* the call is answered before the RING unsolicited
|
||||||
|
* notification has a chance to be generated on the device.
|
||||||
|
* In this case, we use a failsafe CLCC poll in expect_ring
|
||||||
|
* callback.
|
||||||
|
* */
|
||||||
|
vd->clip_source = g_timeout_add(EXPECT_RING_DELAY,
|
||||||
|
expect_ring, vc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
@@ -1064,6 +1118,17 @@ static void ciev_callheld_notify(struct ofono_voicecall *vc,
|
|||||||
*/
|
*/
|
||||||
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
||||||
poll_clcc, vc);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1102,6 +1167,10 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
struct ofono_voicecall *vc = user_data;
|
struct ofono_voicecall *vc = user_data;
|
||||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||||
unsigned int mpty_ids;
|
unsigned int mpty_ids;
|
||||||
|
GSList *n;
|
||||||
|
struct ofono_call *nc;
|
||||||
|
unsigned int num_active = 0;
|
||||||
|
unsigned int num_held = 0;
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return;
|
return;
|
||||||
@@ -1110,6 +1179,22 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
g_slist_foreach(vd->calls, voicecall_notify, vc);
|
g_slist_foreach(vd->calls, voicecall_notify, vc);
|
||||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||||
|
|
||||||
|
n = vd->calls;
|
||||||
|
|
||||||
|
while (n) {
|
||||||
|
nc = n->data;
|
||||||
|
|
||||||
|
if (nc->status == CALL_STATUS_ACTIVE)
|
||||||
|
num_active++;
|
||||||
|
else if (nc->status == CALL_STATUS_HELD)
|
||||||
|
num_held++;
|
||||||
|
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
|
||||||
|
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc, vc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hfp_voicecall_initialized(gboolean ok, GAtResult *result,
|
static void hfp_voicecall_initialized(gboolean ok, GAtResult *result,
|
||||||
@@ -1151,8 +1236,8 @@ static int hfp_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
|||||||
|
|
||||||
ofono_voicecall_set_data(vc, vd);
|
ofono_voicecall_set_data(vc, vd);
|
||||||
|
|
||||||
g_at_chat_send(vd->chat, "AT+CLIP=1", NULL, NULL, NULL, NULL);
|
g_at_chat_send(vd->chat, "AT+CLIP=1", none_prefix, NULL, NULL, NULL);
|
||||||
g_at_chat_send(vd->chat, "AT+CCWA=1", NULL,
|
g_at_chat_send(vd->chat, "AT+CCWA=1", none_prefix,
|
||||||
hfp_voicecall_initialized, vc, NULL);
|
hfp_voicecall_initialized, vc, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1170,8 +1255,7 @@ static void hfp_voicecall_remove(struct ofono_voicecall *vc)
|
|||||||
if (vd->expect_release_source)
|
if (vd->expect_release_source)
|
||||||
g_source_remove(vd->expect_release_source);
|
g_source_remove(vd->expect_release_source);
|
||||||
|
|
||||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
g_slist_free_full(vd->calls, g_free);
|
||||||
g_slist_free(vd->calls);
|
|
||||||
|
|
||||||
ofono_voicecall_set_data(vc, NULL);
|
ofono_voicecall_set_data(vc, NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ static gboolean get_next_addr(GAtResultIter *iter, char **addr)
|
|||||||
if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
|
if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
val = strtol(str, NULL, 16);
|
val = strtoul(str, NULL, 16);
|
||||||
|
|
||||||
if (addr)
|
if (addr)
|
||||||
*addr = g_strdup_printf("%u.%u.%u.%u",
|
*addr = g_strdup_printf("%u.%u.%u.%u",
|
||||||
|
|||||||
@@ -42,11 +42,13 @@
|
|||||||
|
|
||||||
static const char *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
|
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
|
||||||
|
static const char *syscfgex_prefix[] = { "^SYSCFGEX:", NULL };
|
||||||
|
|
||||||
#define HUAWEI_BAND_ANY 0x3FFFFFFF
|
#define HUAWEI_BAND_ANY 0x3FFFFFFF
|
||||||
|
|
||||||
struct radio_settings_data {
|
struct radio_settings_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
|
ofono_bool_t syscfgex_cap;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct huawei_band_gsm_table {
|
static const struct huawei_band_gsm_table {
|
||||||
@@ -176,20 +178,76 @@ error:
|
|||||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void syscfgex_query_mode_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||||
|
enum ofono_radio_access_mode mode;
|
||||||
|
struct ofono_error error;
|
||||||
|
GAtResultIter iter;
|
||||||
|
const char *acqorder;
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
cb(&error, -1, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
if (g_at_result_iter_next(&iter, "^SYSCFGEX:") == FALSE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (g_at_result_iter_next_string(&iter, &acqorder) == FALSE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if ((strcmp(acqorder, "00") == 0) ||
|
||||||
|
(strstr(acqorder, "01") &&
|
||||||
|
strstr(acqorder, "02") &&
|
||||||
|
strstr(acqorder, "03")))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||||
|
else if (strstr(acqorder, "03"))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
else if (strstr(acqorder, "02"))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
else if (strstr(acqorder, "01"))
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
cb(&error, mode, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
|
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
|
||||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||||
{
|
{
|
||||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
if (g_at_chat_send(rsd->chat, "AT^SYSCFG?", syscfg_prefix,
|
if (rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFGEX?",
|
||||||
syscfg_query_mode_cb, cbd, g_free) == 0) {
|
syscfgex_prefix,
|
||||||
|
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);
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
static void syscfgxx_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
@@ -200,12 +258,11 @@ static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
|||||||
cb(&error, cbd->data);
|
cb(&error, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
static void syscfg_set_rat_mode(struct radio_settings_data *rsd,
|
||||||
enum ofono_radio_access_mode mode,
|
enum ofono_radio_access_mode mode,
|
||||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[40];
|
char buf[40];
|
||||||
unsigned int value = 2, acq_order = 0;
|
unsigned int value = 2, acq_order = 0;
|
||||||
@@ -231,7 +288,7 @@ static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
|||||||
value, acq_order);
|
value, acq_order);
|
||||||
|
|
||||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
syscfg_modify_mode_cb, cbd, g_free) > 0)
|
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -239,7 +296,55 @@ error:
|
|||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
static void syscfgex_set_rat_mode(struct radio_settings_data *rsd,
|
||||||
|
enum ofono_radio_access_mode mode,
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
char buf[50];
|
||||||
|
char *atcmd = "AT^SYSCFGEX=\"%s\",40000000,2,4,40000000,,";
|
||||||
|
char *acqorder = "030201";
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||||
|
acqorder = "00";
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||||
|
acqorder = "01";
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||||
|
acqorder = "02";
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||||
|
acqorder = "03";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), atcmd, acqorder);
|
||||||
|
|
||||||
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
|
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
enum ofono_radio_access_mode mode,
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
if (rsd->syscfgex_cap)
|
||||||
|
syscfgex_set_rat_mode(rsd, mode, cb, data);
|
||||||
|
else
|
||||||
|
syscfg_set_rat_mode(rsd, mode, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syscfgxx_modify_band_cb(gboolean ok, GAtResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
@@ -250,13 +355,54 @@ static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
|||||||
cb(&error, cbd->data);
|
cb(&error, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
static void syscfgex_set_band(struct radio_settings_data *rsd,
|
||||||
|
enum ofono_radio_band_gsm band_gsm,
|
||||||
|
enum ofono_radio_band_umts band_umts,
|
||||||
|
ofono_radio_settings_band_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
char buf[50];
|
||||||
|
char *atcmd = "AT^SYSCFGEX=\"99\",%x,2,4,40000000,,";
|
||||||
|
unsigned int huawei_band;
|
||||||
|
|
||||||
|
if (band_gsm == OFONO_RADIO_BAND_GSM_ANY
|
||||||
|
&& band_umts == OFONO_RADIO_BAND_UMTS_ANY) {
|
||||||
|
huawei_band = HUAWEI_BAND_ANY;
|
||||||
|
} else {
|
||||||
|
unsigned int huawei_band_gsm;
|
||||||
|
unsigned int huawei_band_umts;
|
||||||
|
|
||||||
|
huawei_band_gsm = band_gsm_to_huawei(band_gsm);
|
||||||
|
|
||||||
|
if (!huawei_band_gsm)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
huawei_band_umts = band_umts_to_huawei(band_umts);
|
||||||
|
|
||||||
|
if (!huawei_band_umts)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
huawei_band = huawei_band_gsm | huawei_band_umts;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), atcmd, huawei_band);
|
||||||
|
|
||||||
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
|
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syscfg_set_band(struct radio_settings_data *rsd,
|
||||||
enum ofono_radio_band_gsm band_gsm,
|
enum ofono_radio_band_gsm band_gsm,
|
||||||
enum ofono_radio_band_umts band_umts,
|
enum ofono_radio_band_umts band_umts,
|
||||||
ofono_radio_settings_band_set_cb_t cb,
|
ofono_radio_settings_band_set_cb_t cb,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
|
||||||
struct cb_data *cbd = cb_data_new(cb, data);
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
char buf[40];
|
char buf[40];
|
||||||
unsigned int huawei_band;
|
unsigned int huawei_band;
|
||||||
@@ -284,7 +430,7 @@ static void huawei_set_band(struct ofono_radio_settings *rs,
|
|||||||
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
|
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
|
||||||
|
|
||||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||||
syscfg_modify_band_cb, cbd, g_free) > 0)
|
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -292,6 +438,20 @@ error:
|
|||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||||
|
enum ofono_radio_band_gsm band_gsm,
|
||||||
|
enum ofono_radio_band_umts band_umts,
|
||||||
|
ofono_radio_settings_band_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
if (rsd->syscfgex_cap)
|
||||||
|
syscfgex_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||||
|
else
|
||||||
|
syscfg_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
|
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
@@ -364,6 +524,21 @@ static void syscfg_support_cb(gboolean ok, GAtResult *result,
|
|||||||
ofono_radio_settings_register(rs);
|
ofono_radio_settings_register(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void syscfgex_support_cb(gboolean ok, GAtResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_radio_settings *rs = user_data;
|
||||||
|
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||||
|
syscfg_support_cb, rs, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
rsd->syscfgex_cap = 1;
|
||||||
|
ofono_radio_settings_register(rs);
|
||||||
|
}
|
||||||
|
|
||||||
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||||
unsigned int vendor, void *data)
|
unsigned int vendor, void *data)
|
||||||
{
|
{
|
||||||
@@ -378,8 +553,8 @@ static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
|||||||
|
|
||||||
ofono_radio_settings_set_data(rs, rsd);
|
ofono_radio_settings_set_data(rs, rsd);
|
||||||
|
|
||||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
g_at_chat_send(rsd->chat, "AT^SYSCFGEX=?", syscfgex_prefix,
|
||||||
syscfg_support_cb, rs, NULL);
|
syscfgex_support_cb, rs, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,13 +42,14 @@
|
|||||||
|
|
||||||
#include "ifxmodem.h"
|
#include "ifxmodem.h"
|
||||||
|
|
||||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
#define TUN_DEV "/dev/net/tun"
|
||||||
|
|
||||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||||
|
|
||||||
static const char *none_prefix[] = { NULL };
|
static const char *none_prefix[] = { NULL };
|
||||||
static const char *xdns_prefix[] = { "+XDNS:", NULL };
|
static const char *xdns_prefix[] = { "+XDNS:", NULL };
|
||||||
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
||||||
|
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||||
|
|
||||||
enum state {
|
enum state {
|
||||||
STATE_IDLE,
|
STATE_IDLE,
|
||||||
@@ -59,17 +60,20 @@ enum state {
|
|||||||
|
|
||||||
struct gprs_context_data {
|
struct gprs_context_data {
|
||||||
GAtChat *chat;
|
GAtChat *chat;
|
||||||
|
unsigned int vendor;
|
||||||
unsigned int active_context;
|
unsigned int active_context;
|
||||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||||
GAtRawIP *rawip;
|
GAtRawIP *rawip;
|
||||||
enum state state;
|
enum state state;
|
||||||
enum ofono_gprs_proto proto;
|
enum ofono_gprs_proto proto;
|
||||||
char address[32];
|
char address[64];
|
||||||
char dns1[32];
|
char gateway[64];
|
||||||
char dns2[32];
|
char netmask[64];
|
||||||
|
char dns1[64];
|
||||||
|
char dns2[64];
|
||||||
ofono_gprs_context_cb_t cb;
|
ofono_gprs_context_cb_t cb;
|
||||||
void *cb_data; /* Callback data */
|
void *cb_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void rawip_debug(const char *str, void *data)
|
static void rawip_debug(const char *str, void *data)
|
||||||
@@ -257,11 +261,136 @@ error:
|
|||||||
failed_setup(gc, NULL, TRUE);
|
failed_setup(gc, NULL, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs_context *gc = user_data;
|
||||||
|
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
|
||||||
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
|
GAtResultIter iter;
|
||||||
|
|
||||||
|
const char *laddrnetmask = NULL;
|
||||||
|
const char *gw = NULL;
|
||||||
|
const char *interface;
|
||||||
|
const char *dns[3];
|
||||||
|
|
||||||
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
decode_at_error(&error, g_at_result_final_response(result));
|
||||||
|
gcd->cb(&error, gcd->cb_data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_at_result_iter_init(&iter, result);
|
||||||
|
|
||||||
|
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
|
||||||
|
/* skip cid, bearer_id, apn */
|
||||||
|
g_at_result_iter_skip_next(&iter);
|
||||||
|
g_at_result_iter_skip_next(&iter);
|
||||||
|
g_at_result_iter_skip_next(&iter);
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &laddrnetmask))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &dns[0]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!g_at_result_iter_next_string(&iter, &dns[1]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(gcd->dns1, dns[0], sizeof(gcd->dns1));
|
||||||
|
strncpy(gcd->dns2, dns[1], sizeof(gcd->dns2));
|
||||||
|
dns[2] = 0;
|
||||||
|
|
||||||
|
DBG("DNS: %s, %s\n", gcd->dns1, gcd->dns2);
|
||||||
|
|
||||||
|
if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
|
||||||
|
gcd->address, gcd->netmask) < 0) {
|
||||||
|
failed_setup(gc, NULL, TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gw)
|
||||||
|
strncpy(gcd->gateway, gw, sizeof(gcd->gateway));
|
||||||
|
|
||||||
|
gcd->state = STATE_ACTIVE;
|
||||||
|
|
||||||
|
DBG("address: %s\n", gcd->address);
|
||||||
|
DBG("netmask: %s\n", gcd->netmask);
|
||||||
|
DBG("DNS1: %s\n", gcd->dns1);
|
||||||
|
DBG("DNS2: %s\n", gcd->dns2);
|
||||||
|
DBG("Gateway: %s\n", gcd->gateway);
|
||||||
|
|
||||||
|
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||||
|
|
||||||
|
ofono_gprs_context_set_interface(gc, interface);
|
||||||
|
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
|
||||||
|
|
||||||
|
if (gcd->netmask[0])
|
||||||
|
ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
|
||||||
|
|
||||||
|
if (gcd->gateway[0])
|
||||||
|
ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
|
||||||
|
|
||||||
|
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ifx_read_settings(struct ofono_gprs_context *gc)
|
||||||
|
{
|
||||||
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
gcd->address[0] = '\0';
|
||||||
|
gcd->gateway[0] = '\0';
|
||||||
|
gcd->netmask[0] = '\0';
|
||||||
|
gcd->dns1[0] = '\0';
|
||||||
|
gcd->dns2[0] = '\0';
|
||||||
|
|
||||||
|
/* read IP configuration info */
|
||||||
|
if(gcd->vendor == OFONO_VENDOR_XMM) {
|
||||||
|
snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%u",
|
||||||
|
gcd->active_context);
|
||||||
|
|
||||||
|
if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
|
||||||
|
cgcontrdp_cb, gc, NULL) > 0)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||||
|
|
||||||
|
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||||
|
address_cb, gc, NULL) > 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
failed_setup(gc, NULL, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ifx_gprs_read_settings(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int cid,
|
||||||
|
ofono_gprs_context_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
|
DBG("cid %u", cid);
|
||||||
|
|
||||||
|
gcd->active_context = cid;
|
||||||
|
gcd->cb = cb;
|
||||||
|
gcd->cb_data = data;
|
||||||
|
|
||||||
|
ifx_read_settings(gc);
|
||||||
|
}
|
||||||
|
|
||||||
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs_context *gc = user_data;
|
struct ofono_gprs_context *gc = user_data;
|
||||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
DBG("ok %d", ok);
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
@@ -271,19 +400,14 @@ static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
ifx_read_settings(gc);
|
||||||
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
|
||||||
address_cb, gc, NULL) > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
failed_setup(gc, NULL, TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs_context *gc = user_data;
|
struct ofono_gprs_context *gc = user_data;
|
||||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||||
char buf[128];
|
char buf[384];
|
||||||
|
|
||||||
DBG("ok %d", ok);
|
DBG("ok %d", ok);
|
||||||
|
|
||||||
@@ -387,6 +511,7 @@ static void deactivate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||||||
gcd->active_context = 0;
|
gcd->active_context = 0;
|
||||||
gcd->state = STATE_IDLE;
|
gcd->state = STATE_IDLE;
|
||||||
|
|
||||||
|
if (gcd->vendor != OFONO_VENDOR_XMM)
|
||||||
g_at_chat_resume(gcd->chat);
|
g_at_chat_resume(gcd->chat);
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||||
@@ -409,11 +534,25 @@ static void ifx_gprs_deactivate_primary(struct ofono_gprs_context *gc,
|
|||||||
g_at_rawip_shutdown(gcd->rawip);
|
g_at_rawip_shutdown(gcd->rawip);
|
||||||
|
|
||||||
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
||||||
|
|
||||||
|
if (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,
|
if (g_at_chat_send(chat, buf, none_prefix,
|
||||||
deactivate_cb, gc, NULL) > 0)
|
deactivate_cb, gc, NULL) > 0)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, data);
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ifx_gprs_detach_shutdown(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int cid)
|
||||||
|
{
|
||||||
|
DBG("");
|
||||||
|
ifx_gprs_deactivate_primary(gc, cid, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||||
@@ -451,14 +590,13 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
|||||||
|
|
||||||
g_at_rawip_unref(gcd->rawip);
|
g_at_rawip_unref(gcd->rawip);
|
||||||
gcd->rawip = NULL;
|
gcd->rawip = NULL;
|
||||||
|
g_at_chat_resume(gcd->chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
||||||
|
|
||||||
gcd->active_context = 0;
|
gcd->active_context = 0;
|
||||||
gcd->state = STATE_IDLE;
|
gcd->state = STATE_IDLE;
|
||||||
|
|
||||||
g_at_chat_resume(gcd->chat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||||
@@ -470,22 +608,26 @@ static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
if (stat(TUN_DEV, &st) < 0) {
|
||||||
ofono_error("Missing support for TUN/TAP devices");
|
ofono_error("Missing support for TUN/TAP devices");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vendor != OFONO_VENDOR_XMM) {
|
||||||
if (g_at_chat_get_slave(chat) == NULL)
|
if (g_at_chat_get_slave(chat) == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
gcd = g_try_new0(struct gprs_context_data, 1);
|
gcd = g_try_new0(struct gprs_context_data, 1);
|
||||||
if (gcd == NULL)
|
if (gcd == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gcd->vendor = vendor;
|
||||||
gcd->chat = g_at_chat_clone(chat);
|
gcd->chat = g_at_chat_clone(chat);
|
||||||
|
|
||||||
ofono_gprs_context_set_data(gc, gcd);
|
ofono_gprs_context_set_data(gc, gcd);
|
||||||
|
|
||||||
|
if (vendor != OFONO_VENDOR_XMM)
|
||||||
chat = g_at_chat_get_slave(gcd->chat);
|
chat = g_at_chat_get_slave(gcd->chat);
|
||||||
|
|
||||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||||
@@ -516,6 +658,8 @@ static struct ofono_gprs_context_driver driver = {
|
|||||||
.remove = ifx_gprs_context_remove,
|
.remove = ifx_gprs_context_remove,
|
||||||
.activate_primary = ifx_gprs_activate_primary,
|
.activate_primary = ifx_gprs_activate_primary,
|
||||||
.deactivate_primary = ifx_gprs_deactivate_primary,
|
.deactivate_primary = ifx_gprs_deactivate_primary,
|
||||||
|
.read_settings = ifx_gprs_read_settings,
|
||||||
|
.detach_shutdown = ifx_gprs_detach_shutdown
|
||||||
};
|
};
|
||||||
|
|
||||||
void ifx_gprs_context_init(void)
|
void ifx_gprs_context_init(void)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <drivers/atmodem/atutil.h>
|
#include <drivers/atmodem/atutil.h>
|
||||||
|
#include <drivers/atmodem/vendor.h>
|
||||||
|
|
||||||
extern void ifx_voicecall_init(void);
|
extern void ifx_voicecall_init(void);
|
||||||
extern void ifx_voicecall_exit(void);
|
extern void ifx_voicecall_exit(void);
|
||||||
|
|||||||
@@ -1009,8 +1009,7 @@ static void ifx_voicecall_remove(struct ofono_voicecall *vc)
|
|||||||
{
|
{
|
||||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||||
|
|
||||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
g_slist_free_full(vd->calls, g_free);
|
||||||
g_slist_free(vd->calls);
|
|
||||||
|
|
||||||
g_strfreev(vd->en_list);
|
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 */
|
||||||
@@ -134,6 +134,8 @@ static void routing_resp_cb(const GIsiMessage *msg, void *data)
|
|||||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||||
|
|
||||||
if (!check_resp(msg, SMS_GSM_CB_ROUTING_RESP)) {
|
if (!check_resp(msg, SMS_GSM_CB_ROUTING_RESP)) {
|
||||||
|
/* on shutdown, cbs is already being removed */
|
||||||
|
if (g_isi_msg_error(msg) != -ESHUTDOWN)
|
||||||
ofono_cbs_remove(cbs);
|
ofono_cbs_remove(cbs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -646,13 +646,36 @@ error:
|
|||||||
/* ISI callback: PIN state (enabled/disabled) query */
|
/* ISI callback: PIN state (enabled/disabled) query */
|
||||||
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
||||||
{
|
{
|
||||||
check_sec_response(msg, opaque, SEC_CODE_STATE_OK_RESP,
|
struct isi_cb_data *cbd = opaque;
|
||||||
SEC_CODE_STATE_FAIL_RESP);
|
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
||||||
|
int locked;
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
|
||||||
|
!g_isi_msg_data_get_byte(msg, 1, &status))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (state != SEC_CODE_STATE_OK_RESP)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (status == SEC_CODE_ENABLE)
|
||||||
|
locked = 1;
|
||||||
|
else if (status == SEC_CODE_DISABLE)
|
||||||
|
locked = 0;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, locked, cbd->data);
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isi_query_locked(struct ofono_sim *sim,
|
static void isi_query_locked(struct ofono_sim *sim,
|
||||||
enum ofono_sim_password_type passwd_type,
|
enum ofono_sim_password_type passwd_type,
|
||||||
ofono_sim_locked_cb_t cb, void *data)
|
ofono_query_facility_lock_cb_t cb, void *data)
|
||||||
{
|
{
|
||||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||||
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
|
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
|
||||||
@@ -963,7 +986,7 @@ static struct ofono_sim_driver driver = {
|
|||||||
.reset_passwd = isi_reset_passwd,
|
.reset_passwd = isi_reset_passwd,
|
||||||
.lock = isi_lock,
|
.lock = isi_lock,
|
||||||
.change_passwd = isi_change_passwd,
|
.change_passwd = isi_change_passwd,
|
||||||
.query_locked = isi_query_locked,
|
.query_facility_lock = isi_query_locked,
|
||||||
};
|
};
|
||||||
|
|
||||||
void isi_sim_init(void)
|
void isi_sim_init(void)
|
||||||
|
|||||||
@@ -1032,14 +1032,6 @@ static void uicc_lock(struct ofono_sim *sim, enum ofono_sim_password_type type,
|
|||||||
CALLBACK_WITH_FAILURE(cb, data);
|
CALLBACK_WITH_FAILURE(cb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uicc_query_locked(struct ofono_sim *sim,
|
|
||||||
enum ofono_sim_password_type type,
|
|
||||||
ofono_sim_locked_cb_t cb, void *data)
|
|
||||||
{
|
|
||||||
DBG("Not implemented");
|
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean decode_fcp_pin_status(const GIsiSubBlockIter *iter, uint8_t read,
|
static gboolean decode_fcp_pin_status(const GIsiSubBlockIter *iter, uint8_t read,
|
||||||
uint8_t *pin1, uint8_t *pin2)
|
uint8_t *pin1, uint8_t *pin2)
|
||||||
{
|
{
|
||||||
@@ -1677,7 +1669,6 @@ static struct ofono_sim_driver driver = {
|
|||||||
.reset_passwd = uicc_reset_passwd,
|
.reset_passwd = uicc_reset_passwd,
|
||||||
.change_passwd = uicc_change_passwd,
|
.change_passwd = uicc_change_passwd,
|
||||||
.lock = uicc_lock,
|
.lock = uicc_lock,
|
||||||
.query_locked = uicc_query_locked,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void isi_uicc_init(void)
|
void isi_uicc_init(void)
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <ofono/log.h>
|
#include <ofono/log.h>
|
||||||
#include <ofono/modem.h>
|
#include <ofono/modem.h>
|
||||||
#include <ofono/devinfo.h>
|
#include <ofono/devinfo.h>
|
||||||
@@ -125,7 +127,8 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
|
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
|
||||||
if (!str) {
|
/* Telit qmi modems return a "0" string when ESN is not available. */
|
||||||
|
if (!str || strcmp(str, "0") == 0) {
|
||||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
|
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
|||||||
@@ -24,18 +24,22 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include <ofono/log.h>
|
#include <ofono/log.h>
|
||||||
#include <ofono/modem.h>
|
#include <ofono/modem.h>
|
||||||
#include <ofono/gprs-context.h>
|
#include <ofono/gprs-context.h>
|
||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
|
#include "wda.h"
|
||||||
#include "wds.h"
|
#include "wds.h"
|
||||||
|
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
|
|
||||||
struct gprs_context_data {
|
struct gprs_context_data {
|
||||||
struct qmi_service *wds;
|
struct qmi_service *wds;
|
||||||
|
struct qmi_service *wda;
|
||||||
|
struct qmi_device *dev;
|
||||||
unsigned int active_context;
|
unsigned int active_context;
|
||||||
uint32_t pkt_handle;
|
uint32_t pkt_handle;
|
||||||
};
|
};
|
||||||
@@ -61,8 +65,12 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
|
|||||||
|
|
||||||
switch (status->status) {
|
switch (status->status) {
|
||||||
case QMI_WDS_CONN_STATUS_DISCONNECTED:
|
case QMI_WDS_CONN_STATUS_DISCONNECTED:
|
||||||
|
if (data->pkt_handle) {
|
||||||
|
/* The context has been disconnected by the network */
|
||||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||||
|
data->pkt_handle = 0;
|
||||||
data->active_context = 0;
|
data->active_context = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,18 +83,68 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
|
|||||||
struct ofono_modem *modem;
|
struct ofono_modem *modem;
|
||||||
const char *interface;
|
const char *interface;
|
||||||
uint8_t pdp_type, ip_family;
|
uint8_t pdp_type, ip_family;
|
||||||
|
uint32_t ip_addr;
|
||||||
|
struct in_addr addr;
|
||||||
|
char* straddr;
|
||||||
|
char* apn;
|
||||||
|
const char *dns[3] = { NULL, NULL, NULL };
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL))
|
if (qmi_result_set_error(result, NULL))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
apn = qmi_result_get_string(result, QMI_WDS_RESULT_APN);
|
||||||
|
if (apn) {
|
||||||
|
DBG("APN: %s", apn);
|
||||||
|
g_free(apn);
|
||||||
|
}
|
||||||
|
|
||||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_PDP_TYPE, &pdp_type))
|
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_PDP_TYPE, &pdp_type))
|
||||||
DBG("PDP type %d", pdp_type);
|
DBG("PDP type %d", pdp_type);
|
||||||
|
|
||||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
|
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
|
||||||
DBG("IP family %d", ip_family);
|
DBG("IP family %d", ip_family);
|
||||||
|
|
||||||
|
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_IP_ADDRESS, &ip_addr)) {
|
||||||
|
addr.s_addr = htonl(ip_addr);
|
||||||
|
straddr = inet_ntoa(addr);
|
||||||
|
DBG("IP addr: %s", straddr);
|
||||||
|
ofono_gprs_context_set_ipv4_address(gc, straddr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_GATEWAY, &ip_addr)) {
|
||||||
|
addr.s_addr = htonl(ip_addr);
|
||||||
|
straddr = inet_ntoa(addr);
|
||||||
|
DBG("Gateway: %s", straddr);
|
||||||
|
ofono_gprs_context_set_ipv4_gateway(gc, straddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qmi_result_get_uint32(result,
|
||||||
|
QMI_WDS_RESULT_GATEWAY_NETMASK, &ip_addr)) {
|
||||||
|
addr.s_addr = htonl(ip_addr);
|
||||||
|
straddr = inet_ntoa(addr);
|
||||||
|
DBG("Gateway netmask: %s", straddr);
|
||||||
|
ofono_gprs_context_set_ipv4_netmask(gc, straddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qmi_result_get_uint32(result,
|
||||||
|
QMI_WDS_RESULT_PRIMARY_DNS, &ip_addr)) {
|
||||||
|
addr.s_addr = htonl(ip_addr);
|
||||||
|
dns[0] = inet_ntoa(addr);
|
||||||
|
DBG("Primary DNS: %s", dns[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qmi_result_get_uint32(result,
|
||||||
|
QMI_WDS_RESULT_SECONDARY_DNS, &ip_addr)) {
|
||||||
|
addr.s_addr = htonl(ip_addr);
|
||||||
|
dns[1] = inet_ntoa(addr);
|
||||||
|
DBG("Secondary DNS: %s", dns[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dns[0])
|
||||||
|
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
modem = ofono_gprs_context_get_modem(gc);
|
modem = ofono_gprs_context_get_modem(gc);
|
||||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||||
@@ -94,8 +152,6 @@ done:
|
|||||||
ofono_gprs_context_set_interface(gc, interface);
|
ofono_gprs_context_set_interface(gc, interface);
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
|
||||||
g_free(cbd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_net_cb(struct qmi_result *result, void *user_data)
|
static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||||
@@ -120,8 +176,12 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
|||||||
|
|
||||||
data->pkt_handle = handle;
|
data->pkt_handle = handle;
|
||||||
|
|
||||||
|
/* Duplicate cbd, the old one will be freed when this method returns */
|
||||||
|
cbd = cb_data_new(cb, cbd->data);
|
||||||
|
cbd->user = gc;
|
||||||
|
|
||||||
if (qmi_service_send(data->wds, QMI_WDS_GET_SETTINGS, NULL,
|
if (qmi_service_send(data->wds, QMI_WDS_GET_SETTINGS, NULL,
|
||||||
get_settings_cb, cbd, NULL) > 0)
|
get_settings_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
modem = ofono_gprs_context_get_modem(gc);
|
modem = ofono_gprs_context_get_modem(gc);
|
||||||
@@ -131,12 +191,39 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
|||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
|
||||||
g_free(cbd);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
data->active_context = 0;
|
data->active_context = 0;
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function gets called for "automatic" contexts, those which are
|
||||||
|
* not activated via activate_primary. For these, we will still need
|
||||||
|
* to call start_net in order to get the packet handle for the context.
|
||||||
|
* The process for automatic contexts is essentially identical to that
|
||||||
|
* for others.
|
||||||
|
*/
|
||||||
|
static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
|
||||||
|
unsigned int cid,
|
||||||
|
ofono_gprs_context_cb_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
|
||||||
|
DBG("cid %u", cid);
|
||||||
|
|
||||||
|
data->active_context = cid;
|
||||||
|
|
||||||
|
cbd->user = gc;
|
||||||
|
|
||||||
|
if (qmi_service_send(data->wds, QMI_WDS_START_NET, NULL,
|
||||||
|
start_net_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data->active_context = 0;
|
||||||
|
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
|
||||||
@@ -151,6 +238,7 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
|||||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
struct qmi_param *param;
|
struct qmi_param *param;
|
||||||
uint8_t ip_family;
|
uint8_t ip_family;
|
||||||
|
uint8_t auth;
|
||||||
|
|
||||||
DBG("cid %u", ctx->cid);
|
DBG("cid %u", ctx->cid);
|
||||||
|
|
||||||
@@ -178,8 +266,31 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
|||||||
|
|
||||||
qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
|
qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
|
||||||
|
|
||||||
|
switch (ctx->auth_method) {
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||||
|
auth = QMI_WDS_AUTHENTICATION_CHAP;
|
||||||
|
break;
|
||||||
|
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||||
|
auth = QMI_WDS_AUTHENTICATION_PAP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
auth = QMI_WDS_AUTHENTICATION_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmi_param_append_uint8(param, QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE,
|
||||||
|
auth);
|
||||||
|
|
||||||
|
if (ctx->username[0] != '\0')
|
||||||
|
qmi_param_append(param, QMI_WDS_PARAM_USERNAME,
|
||||||
|
strlen(ctx->username), ctx->username);
|
||||||
|
|
||||||
|
if (ctx->password[0] != '\0')
|
||||||
|
qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
|
||||||
|
strlen(ctx->password), ctx->password);
|
||||||
|
|
||||||
if (qmi_service_send(data->wds, QMI_WDS_START_NET, param,
|
if (qmi_service_send(data->wds, QMI_WDS_START_NET, param,
|
||||||
start_net_cb, cbd, NULL) > 0)
|
start_net_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qmi_param_free(param);
|
qmi_param_free(param);
|
||||||
@@ -202,17 +313,19 @@ static void stop_net_cb(struct qmi_result *result, void *user_data)
|
|||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL)) {
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
if (cb)
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->active_context = 0;
|
|
||||||
|
|
||||||
data->pkt_handle = 0;
|
data->pkt_handle = 0;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
else
|
||||||
|
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||||
|
|
||||||
g_free(cbd);
|
data->active_context = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
||||||
@@ -233,17 +346,26 @@ static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (qmi_service_send(data->wds, QMI_WDS_STOP_NET, param,
|
if (qmi_service_send(data->wds, QMI_WDS_STOP_NET, param,
|
||||||
stop_net_cb, cbd, NULL) > 0)
|
stop_net_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qmi_param_free(param);
|
qmi_param_free(param);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
if (cb)
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
|
||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int cid)
|
||||||
|
{
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
qmi_deactivate_primary(gc, cid, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs_context *gc = user_data;
|
struct ofono_gprs_context *gc = user_data;
|
||||||
@@ -263,6 +385,69 @@ static void create_wds_cb(struct qmi_service *service, void *user_data)
|
|||||||
pkt_status_notify, gc, NULL);
|
pkt_status_notify, gc, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_data_format_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs_context *gc = user_data;
|
||||||
|
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||||
|
uint32_t llproto;
|
||||||
|
enum qmi_device_expected_data_format expected_llproto;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (!qmi_result_get_uint32(result, QMI_WDA_LL_PROTOCOL, &llproto))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
expected_llproto = qmi_device_get_expected_data_format(data->dev);
|
||||||
|
|
||||||
|
if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_802_3) &&
|
||||||
|
(expected_llproto ==
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP)) {
|
||||||
|
if (!qmi_device_set_expected_data_format(data->dev,
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3))
|
||||||
|
DBG("Fail to set expected data to 802.3");
|
||||||
|
else
|
||||||
|
DBG("expected data set to 802.3");
|
||||||
|
} else if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP) &&
|
||||||
|
(expected_llproto ==
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3)) {
|
||||||
|
if (!qmi_device_set_expected_data_format(data->dev,
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP))
|
||||||
|
DBG("Fail to set expected data to raw-ip");
|
||||||
|
else
|
||||||
|
DBG("expected data set to raw-ip");
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_wda_cb(struct qmi_service *service, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_gprs_context *gc = user_data;
|
||||||
|
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
DBG("Failed to request WDA service, continue initialization");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->wda = qmi_service_ref(service);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->wda, QMI_WDA_GET_DATA_FORMAT, NULL,
|
||||||
|
get_data_format_cb, gc, NULL) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||||
unsigned int vendor, void *user_data)
|
unsigned int vendor, void *user_data)
|
||||||
{
|
{
|
||||||
@@ -274,8 +459,9 @@ static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
|||||||
data = g_new0(struct gprs_context_data, 1);
|
data = g_new0(struct gprs_context_data, 1);
|
||||||
|
|
||||||
ofono_gprs_context_set_data(gc, data);
|
ofono_gprs_context_set_data(gc, data);
|
||||||
|
data->dev = device;
|
||||||
|
|
||||||
qmi_service_create(device, QMI_SERVICE_WDS, create_wds_cb, gc, NULL);
|
qmi_service_create(device, QMI_SERVICE_WDA, create_wda_cb, gc, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -288,9 +474,15 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
|
|||||||
|
|
||||||
ofono_gprs_context_set_data(gc, NULL);
|
ofono_gprs_context_set_data(gc, NULL);
|
||||||
|
|
||||||
|
if (data->wds) {
|
||||||
qmi_service_unregister_all(data->wds);
|
qmi_service_unregister_all(data->wds);
|
||||||
|
|
||||||
qmi_service_unref(data->wds);
|
qmi_service_unref(data->wds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->wda) {
|
||||||
|
qmi_service_unregister_all(data->wda);
|
||||||
|
qmi_service_unref(data->wda);
|
||||||
|
}
|
||||||
|
|
||||||
g_free(data);
|
g_free(data);
|
||||||
}
|
}
|
||||||
@@ -301,6 +493,8 @@ static struct ofono_gprs_context_driver driver = {
|
|||||||
.remove = qmi_gprs_context_remove,
|
.remove = qmi_gprs_context_remove,
|
||||||
.activate_primary = qmi_activate_primary,
|
.activate_primary = qmi_activate_primary,
|
||||||
.deactivate_primary = qmi_deactivate_primary,
|
.deactivate_primary = qmi_deactivate_primary,
|
||||||
|
.read_settings = qmi_gprs_read_settings,
|
||||||
|
.detach_shutdown = qmi_gprs_context_detach_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
void qmi_gprs_context_init(void)
|
void qmi_gprs_context_init(void)
|
||||||
|
|||||||
@@ -30,16 +30,18 @@
|
|||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
#include "nas.h"
|
#include "nas.h"
|
||||||
|
|
||||||
|
#include "src/common.h"
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
|
|
||||||
struct gprs_data {
|
struct gprs_data {
|
||||||
struct qmi_service *nas;
|
struct qmi_service *nas;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool extract_ss_info(struct qmi_result *result, int *status)
|
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||||
{
|
{
|
||||||
const struct qmi_nas_serving_system *ss;
|
const struct qmi_nas_serving_system *ss;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
|
int i;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
@@ -47,14 +49,46 @@ static bool extract_ss_info(struct qmi_result *result, int *status)
|
|||||||
if (!ss)
|
if (!ss)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ss->ps_state == QMI_NAS_ATTACH_STATUS_ATTACHED)
|
if (ss->ps_state == QMI_NAS_ATTACH_STATE_ATTACHED)
|
||||||
*status = 0x01;
|
*status = NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||||
else
|
else
|
||||||
*status = 0x00;
|
*status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||||
|
|
||||||
|
*tech = -1;
|
||||||
|
for (i = 0; i < ss->radio_if_count; i++) {
|
||||||
|
DBG("radio in use %d", ss->radio_if[i]);
|
||||||
|
|
||||||
|
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
int tech;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!extract_ss_info(result, &status, &tech))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED)
|
||||||
|
if (tech == ACCESS_TECHNOLOGY_EUTRAN) {
|
||||||
|
/* On LTE we are effectively always attached; and
|
||||||
|
* the default bearer is established as soon as the
|
||||||
|
* network is joined.
|
||||||
|
*/
|
||||||
|
/* FIXME: query default profile number and APN
|
||||||
|
* instead of assuming profile 1 and ""
|
||||||
|
*/
|
||||||
|
ofono_gprs_cid_activated(gprs, 1 , "automatic");
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_gprs *gprs = user_data;
|
struct ofono_gprs *gprs = user_data;
|
||||||
@@ -62,9 +96,9 @@ static void ss_info_notify(struct qmi_result *result, void *user_data)
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (!extract_ss_info(result, &status))
|
status = handle_ss_info(result, gprs);
|
||||||
return;
|
|
||||||
|
|
||||||
|
if (status >= 0)
|
||||||
ofono_gprs_status_notify(gprs, status);
|
ofono_gprs_status_notify(gprs, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,22 +158,26 @@ error:
|
|||||||
static void get_ss_info_cb(struct qmi_result *result, void *user_data)
|
static void get_ss_info_cb(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct cb_data *cbd = user_data;
|
struct cb_data *cbd = user_data;
|
||||||
|
struct ofono_gprs *gprs = cbd->user;
|
||||||
ofono_gprs_status_cb_t cb = cbd->cb;
|
ofono_gprs_status_cb_t cb = cbd->cb;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL)) {
|
if (qmi_result_set_error(result, NULL))
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
goto error;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!extract_ss_info(result, &status)) {
|
status = handle_ss_info(result, gprs);
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
|
||||||
return;
|
if (status < 0)
|
||||||
}
|
goto error;
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
|
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmi_attached_status(struct ofono_gprs *gprs,
|
static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||||
@@ -150,6 +188,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
|
cbd->user = gprs;
|
||||||
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||||
get_ss_info_cb, cbd, g_free) > 0)
|
get_ss_info_cb, cbd, g_free) > 0)
|
||||||
return;
|
return;
|
||||||
@@ -174,6 +213,13 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
|||||||
|
|
||||||
data->nas = qmi_service_ref(service);
|
data->nas = qmi_service_ref(service);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First get the SS info - the modem may already be connected,
|
||||||
|
* and the state-change notification may never arrive
|
||||||
|
*/
|
||||||
|
qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||||
|
ss_info_notify, gprs, NULL);
|
||||||
|
|
||||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||||
ss_info_notify, gprs, NULL);
|
ss_info_notify, gprs, NULL);
|
||||||
|
|
||||||
@@ -194,7 +240,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
|||||||
|
|
||||||
ofono_gprs_set_data(gprs, data);
|
ofono_gprs_set_data(gprs, data);
|
||||||
|
|
||||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, gprs, NULL);
|
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||||
|
create_nas_cb, gprs, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
38
ofono/drivers/qmimodem/nas.c
Normal file
38
ofono/drivers/qmimodem/nas.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nas.h"
|
||||||
|
|
||||||
|
#include "src/common.h"
|
||||||
|
|
||||||
|
int qmi_nas_rat_to_tech(uint8_t rat)
|
||||||
|
{
|
||||||
|
switch (rat) {
|
||||||
|
case QMI_NAS_NETWORK_RAT_GSM:
|
||||||
|
return ACCESS_TECHNOLOGY_GSM;
|
||||||
|
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||||
|
return ACCESS_TECHNOLOGY_UTRAN;
|
||||||
|
case QMI_NAS_NETWORK_RAT_LTE:
|
||||||
|
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define QMI_NAS_RESET 0 /* Reset NAS service state variables */
|
#define QMI_NAS_RESET 0 /* Reset NAS service state variables */
|
||||||
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
|
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
|
||||||
#define QMI_NAS_EVENT 2 /* Connection state report indication */
|
#define QMI_NAS_EVENT 2 /* Connection state report indication */
|
||||||
@@ -33,6 +35,8 @@
|
|||||||
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
|
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
|
||||||
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
|
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
|
||||||
|
|
||||||
|
#define QMI_NAS_SET_SYSTEM_SELECTION_PREF 51
|
||||||
|
#define QMI_NAS_GET_SYSTEM_SELECTION_PREF 52
|
||||||
|
|
||||||
/* Set NAS state report conditions */
|
/* Set NAS state report conditions */
|
||||||
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
|
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
|
||||||
@@ -63,7 +67,7 @@ struct qmi_nas_rf_info {
|
|||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
/* Get the signal strength */
|
/* Get the signal strength */
|
||||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x10
|
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x01
|
||||||
|
|
||||||
/* Scan for visible network */
|
/* Scan for visible network */
|
||||||
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
|
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
|
||||||
@@ -95,6 +99,7 @@ struct qmi_nas_network_rat {
|
|||||||
} __attribute__((__packed__)) info[0];
|
} __attribute__((__packed__)) info[0];
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#define QMI_NAS_NETWORK_RAT_NONE 0x00
|
||||||
#define QMI_NAS_NETWORK_RAT_GSM 0x04
|
#define QMI_NAS_NETWORK_RAT_GSM 0x04
|
||||||
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
|
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
|
||||||
#define QMI_NAS_NETWORK_RAT_LTE 0x08
|
#define QMI_NAS_NETWORK_RAT_LTE 0x08
|
||||||
@@ -140,9 +145,29 @@ struct qmi_nas_current_plmn {
|
|||||||
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
|
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
|
||||||
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
|
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
|
||||||
|
|
||||||
#define QMI_NAS_ATTACH_STATUS_INVALID 0x00
|
/* qmi_nas_serving_system.status */
|
||||||
#define QMI_NAS_ATTACH_STATUS_ATTACHED 0x01
|
#define QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED 0x00
|
||||||
#define QMI_NAS_ATTACH_STATUS_DETACHED 0x02
|
#define QMI_NAS_REGISTRATION_STATE_REGISTERED 0x01
|
||||||
|
#define QMI_NAS_REGISTRATION_STATE_SEARCHING 0x02
|
||||||
|
#define QMI_NAS_REGISTRATION_STATE_DENIED 0x03
|
||||||
|
#define QMI_NAS_REGISTRATION_STATE_UNKNOWN 0x04
|
||||||
|
|
||||||
|
#define QMI_NAS_RESULT_3GGP_DST 0x1b
|
||||||
|
#define QMI_NAS_RESULT_3GPP_TIME 0x1c
|
||||||
|
struct qmi_nas_3gpp_time {
|
||||||
|
uint16_t year;
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t day;
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t second;
|
||||||
|
uint8_t timezone;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* cs_state/ps_state */
|
||||||
|
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
|
||||||
|
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
|
||||||
|
#define QMI_NAS_ATTACH_STATE_DETACHED 0x02
|
||||||
|
|
||||||
/* Get info about home network */
|
/* Get info about home network */
|
||||||
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
|
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
|
||||||
@@ -152,3 +177,14 @@ struct qmi_nas_home_network {
|
|||||||
uint8_t desc_len;
|
uint8_t desc_len;
|
||||||
char desc[0];
|
char desc[0];
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_ANY (-1)
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_GSM (1 << 2)
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_UMTS (1 << 3)
|
||||||
|
#define QMI_NAS_RAT_MODE_PREF_LTE (1 << 4)
|
||||||
|
|
||||||
|
#define QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||||
|
|
||||||
|
#define QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||||
|
|
||||||
|
int qmi_nas_rat_to_tech(uint8_t rat);
|
||||||
|
|||||||
286
ofono/drivers/qmimodem/netmon.c
Normal file
286
ofono/drivers/qmimodem/netmon.c
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/log.h>
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
#include <ofono/netmon.h>
|
||||||
|
|
||||||
|
#include "qmi.h"
|
||||||
|
#include "nas.h"
|
||||||
|
|
||||||
|
#include "qmimodem.h"
|
||||||
|
#include "src/common.h"
|
||||||
|
|
||||||
|
struct netmon_data {
|
||||||
|
struct qmi_service *nas;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void get_rssi_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
struct ofono_netmon *netmon = cbd->user;
|
||||||
|
ofono_netmon_cb_t cb = cbd->cb;
|
||||||
|
struct {
|
||||||
|
enum ofono_netmon_cell_type type;
|
||||||
|
int rssi;
|
||||||
|
int ber;
|
||||||
|
int rsrq;
|
||||||
|
int rsrp;
|
||||||
|
} props;
|
||||||
|
uint16_t len;
|
||||||
|
int16_t rsrp;
|
||||||
|
const struct {
|
||||||
|
int8_t value;
|
||||||
|
int8_t rat;
|
||||||
|
} __attribute__((__packed__)) *rsrq;
|
||||||
|
const struct {
|
||||||
|
uint16_t count;
|
||||||
|
struct {
|
||||||
|
uint8_t rssi;
|
||||||
|
int8_t rat;
|
||||||
|
} __attribute__((__packed__)) info[0];
|
||||||
|
} __attribute__((__packed__)) *rssi;
|
||||||
|
const struct {
|
||||||
|
uint16_t count;
|
||||||
|
struct {
|
||||||
|
uint16_t rate;
|
||||||
|
int8_t rat;
|
||||||
|
} __attribute__((__packed__)) info[0];
|
||||||
|
} __attribute__((__packed__)) *ber;
|
||||||
|
int i;
|
||||||
|
uint16_t num;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSSI */
|
||||||
|
rssi = qmi_result_get(result, 0x11, &len);
|
||||||
|
num = GUINT16_FROM_LE(rssi->count);
|
||||||
|
if (rssi) {
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
DBG("RSSI: %hhu on RAT %hhd",
|
||||||
|
rssi->info[i].rssi,
|
||||||
|
rssi->info[i].rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get cell type from RSSI info... it will be the same
|
||||||
|
* for all the other entries
|
||||||
|
*/
|
||||||
|
props.type = qmi_nas_rat_to_tech(rssi->info[0].rat);
|
||||||
|
switch (rssi->info[0].rat) {
|
||||||
|
case QMI_NAS_NETWORK_RAT_GSM:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_UMTS;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_NETWORK_RAT_LTE:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_LTE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
props.rssi = (rssi->info[0].rssi + 113) / 2;
|
||||||
|
if (props.rssi > 31) props.rssi = 31;
|
||||||
|
if (props.rssi < 0) props.rssi = 0;
|
||||||
|
} else {
|
||||||
|
props.type = QMI_NAS_NETWORK_RAT_GSM;
|
||||||
|
props.rssi = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bit error rate */
|
||||||
|
ber = qmi_result_get(result, 0x15, &len);
|
||||||
|
num = GUINT16_FROM_LE(ber->count);
|
||||||
|
if (ber) {
|
||||||
|
for (i = 0; i < ber->count; i++) {
|
||||||
|
DBG("Bit error rate: %hu on RAT %hhd",
|
||||||
|
GUINT16_FROM_LE(ber->info[i].rate),
|
||||||
|
ber->info[i].rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
props.ber = GUINT16_FROM_LE(ber->info[0].rate);
|
||||||
|
if (props.ber > 7)
|
||||||
|
props.ber = -1;
|
||||||
|
} else {
|
||||||
|
props.ber = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LTE RSRQ */
|
||||||
|
rsrq = qmi_result_get(result, 0x16, &len);
|
||||||
|
if (rsrq) {
|
||||||
|
DBG("RSRQ: %hhd on RAT %hhd",
|
||||||
|
rsrq->value,
|
||||||
|
rsrq->rat);
|
||||||
|
|
||||||
|
if (rsrq->value == 0) {
|
||||||
|
props.rsrq = -1;
|
||||||
|
} else {
|
||||||
|
props.rsrq = (rsrq->value + 19) * 2;
|
||||||
|
if (props.rsrq > 34) props.rsrq = 34;
|
||||||
|
if (props.rsrq < 0) props.rsrq = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.rsrq = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LTE RSRP */
|
||||||
|
if (qmi_result_get_int16(result, 0x18, &rsrp)) {
|
||||||
|
DBG("Got LTE RSRP: %hd", rsrp);
|
||||||
|
|
||||||
|
if (rsrp == 0) {
|
||||||
|
props.rsrp = -1;
|
||||||
|
} else {
|
||||||
|
props.rsrp = rsrp + 140;
|
||||||
|
if (props.rsrp > 97) props.rsrp = 97;
|
||||||
|
if (props.rsrp < 0) props.rsrp = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.rsrp = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_netmon_serving_cell_notify(netmon,
|
||||||
|
props.type,
|
||||||
|
OFONO_NETMON_INFO_RSSI, props.rssi,
|
||||||
|
OFONO_NETMON_INFO_BER, props.ber,
|
||||||
|
OFONO_NETMON_INFO_RSRQ, props.rsrq,
|
||||||
|
OFONO_NETMON_INFO_RSRP, props.rsrp,
|
||||||
|
OFONO_NETMON_INFO_INVALID);
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_netmon_request_update(struct ofono_netmon *netmon,
|
||||||
|
ofono_netmon_cb_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct netmon_data *data = ofono_netmon_get_data(netmon);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
struct qmi_param *param;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
cbd->user = netmon;
|
||||||
|
|
||||||
|
param = qmi_param_new();
|
||||||
|
if (!param)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Request all signal strength items: mask=0xff */
|
||||||
|
qmi_param_append_uint16(param, 0x10, 255);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->nas, QMI_NAS_GET_RSSI, param,
|
||||||
|
get_rssi_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qmi_param_free(param);
|
||||||
|
|
||||||
|
out:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_netmon *netmon = user_data;
|
||||||
|
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
ofono_error("Failed to request NAS service");
|
||||||
|
ofono_netmon_remove(netmon);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nmd->nas = qmi_service_ref(service);
|
||||||
|
|
||||||
|
ofono_netmon_register(netmon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qmi_netmon_probe(struct ofono_netmon *netmon,
|
||||||
|
unsigned int vendor, void *user_data)
|
||||||
|
{
|
||||||
|
struct qmi_device *device = user_data;
|
||||||
|
struct netmon_data *nmd;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
nmd = g_new0(struct netmon_data, 1);
|
||||||
|
|
||||||
|
ofono_netmon_set_data(netmon, nmd);
|
||||||
|
|
||||||
|
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||||
|
create_nas_cb, netmon, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_netmon_remove(struct ofono_netmon *netmon)
|
||||||
|
{
|
||||||
|
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
ofono_netmon_set_data(netmon, NULL);
|
||||||
|
|
||||||
|
qmi_service_unregister_all(nmd->nas);
|
||||||
|
|
||||||
|
qmi_service_unref(nmd->nas);
|
||||||
|
|
||||||
|
g_free(nmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ofono_netmon_driver driver = {
|
||||||
|
.name = "qmimodem",
|
||||||
|
.probe = qmi_netmon_probe,
|
||||||
|
.remove = qmi_netmon_remove,
|
||||||
|
.request_update = qmi_netmon_request_update,
|
||||||
|
};
|
||||||
|
|
||||||
|
void qmi_netmon_init(void)
|
||||||
|
{
|
||||||
|
ofono_netmon_driver_register(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qmi_netmon_exit(void)
|
||||||
|
{
|
||||||
|
ofono_netmon_driver_unregister(&driver);
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <endian.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -43,18 +44,36 @@ struct netreg_data {
|
|||||||
uint8_t current_rat;
|
uint8_t current_rat;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rat_to_tech(uint8_t rat)
|
static bool extract_ss_info_time(
|
||||||
|
struct qmi_result *result,
|
||||||
|
struct ofono_network_time *time)
|
||||||
{
|
{
|
||||||
switch (rat) {
|
const struct qmi_nas_3gpp_time *time_3gpp = NULL;
|
||||||
case QMI_NAS_NETWORK_RAT_GSM:
|
uint8_t dst_3gpp;
|
||||||
return ACCESS_TECHNOLOGY_GSM;
|
bool dst_3gpp_valid;
|
||||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
uint16_t len;
|
||||||
return ACCESS_TECHNOLOGY_UTRAN;
|
|
||||||
case QMI_NAS_NETWORK_RAT_LTE:
|
/* parse 3gpp time & dst */
|
||||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
dst_3gpp_valid = qmi_result_get_uint8(result, QMI_NAS_RESULT_3GGP_DST,
|
||||||
|
&dst_3gpp);
|
||||||
|
|
||||||
|
time_3gpp = qmi_result_get(result, QMI_NAS_RESULT_3GPP_TIME, &len);
|
||||||
|
if (time_3gpp && len == sizeof(struct qmi_nas_3gpp_time) &&
|
||||||
|
dst_3gpp_valid) {
|
||||||
|
time->year = le16toh(time_3gpp->year);
|
||||||
|
time->mon = time_3gpp->month;
|
||||||
|
time->mday = time_3gpp->day;
|
||||||
|
time->hour = time_3gpp->hour;
|
||||||
|
time->min = time_3gpp->minute;
|
||||||
|
time->sec = time_3gpp->second;
|
||||||
|
time->utcoff = time_3gpp->timezone * 15 * 60;
|
||||||
|
time->dst = dst_3gpp;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
/* TODO: 3gpp2 */
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||||
@@ -64,7 +83,7 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
const struct qmi_nas_serving_system *ss;
|
const struct qmi_nas_serving_system *ss;
|
||||||
const struct qmi_nas_current_plmn *plmn;
|
const struct qmi_nas_current_plmn *plmn;
|
||||||
uint8_t i, roaming;
|
uint8_t i, roaming;
|
||||||
uint16_t value16, len;
|
uint16_t value16, len, opname_len;
|
||||||
uint32_t value32;
|
uint32_t value32;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
@@ -82,13 +101,13 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
for (i = 0; i < ss->radio_if_count; i++) {
|
for (i = 0; i < ss->radio_if_count; i++) {
|
||||||
DBG("radio in use %d", ss->radio_if[i]);
|
DBG("radio in use %d", ss->radio_if[i]);
|
||||||
|
|
||||||
*tech = rat_to_tech(ss->radio_if[i]);
|
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qmi_result_get_uint8(result, QMI_NAS_RESULT_ROAMING_STATUS,
|
if (qmi_result_get_uint8(result, QMI_NAS_RESULT_ROAMING_STATUS,
|
||||||
&roaming)) {
|
&roaming)) {
|
||||||
if (ss->status == 1 && roaming == 0)
|
if (ss->status == 1 && roaming == 0)
|
||||||
*status = 5;
|
*status = NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!operator)
|
if (!operator)
|
||||||
@@ -100,8 +119,21 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
GUINT16_FROM_LE(plmn->mcc));
|
GUINT16_FROM_LE(plmn->mcc));
|
||||||
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
|
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
|
||||||
GUINT16_FROM_LE(plmn->mnc));
|
GUINT16_FROM_LE(plmn->mnc));
|
||||||
strncpy(operator->name, plmn->desc, plmn->desc_len);
|
opname_len = plmn->desc_len;
|
||||||
operator->name[plmn->desc_len] = '\0';
|
if (opname_len > OFONO_MAX_OPERATOR_NAME_LENGTH)
|
||||||
|
opname_len = OFONO_MAX_OPERATOR_NAME_LENGTH;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Telit QMI modems can return non-utf-8 characters in
|
||||||
|
* plmn-desc. When that happens, libdbus will abort ofono.
|
||||||
|
* If non-utf-8 characters are detected, use mccmnc string.
|
||||||
|
*/
|
||||||
|
if (g_utf8_validate(plmn->desc, opname_len, NULL)) {
|
||||||
|
strncpy(operator->name, plmn->desc, opname_len);
|
||||||
|
operator->name[opname_len] = '\0';
|
||||||
|
} else
|
||||||
|
snprintf(operator->name, OFONO_MAX_OPERATOR_NAME_LENGTH,
|
||||||
|
"%s%s", operator->mcc, operator->mnc);
|
||||||
|
|
||||||
DBG("%s (%s:%s)", operator->name, operator->mcc, operator->mnc);
|
DBG("%s (%s:%s)", operator->name, operator->mcc, operator->mnc);
|
||||||
}
|
}
|
||||||
@@ -125,11 +157,15 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
|||||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_netreg *netreg = user_data;
|
struct ofono_netreg *netreg = user_data;
|
||||||
|
struct ofono_network_time net_time;
|
||||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||||
int status, lac, cellid, tech;
|
int status, lac, cellid, tech;
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
|
if (extract_ss_info_time(result, &net_time))
|
||||||
|
ofono_netreg_time_notify(netreg, &net_time);
|
||||||
|
|
||||||
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
|
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
|
||||||
&data->operator))
|
&data->operator))
|
||||||
return;
|
return;
|
||||||
@@ -265,7 +301,7 @@ static void scan_nets_cb(struct qmi_result *result, void *user_data)
|
|||||||
DBG("%03d:%02d %d", netrat->info[i].mcc, netrat->info[i].mnc,
|
DBG("%03d:%02d %d", netrat->info[i].mcc, netrat->info[i].mnc,
|
||||||
netrat->info[i].rat);
|
netrat->info[i].rat);
|
||||||
|
|
||||||
list[i].tech = rat_to_tech(netrat->info[i].rat);
|
list[i].tech = qmi_nas_rat_to_tech(netrat->info[i].rat);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@@ -357,7 +393,7 @@ static void qmi_register_manual(struct ofono_netreg *netreg,
|
|||||||
|
|
||||||
info.mcc = atoi(mcc);
|
info.mcc = atoi(mcc);
|
||||||
info.mnc = atoi(mnc);
|
info.mnc = atoi(mnc);
|
||||||
info.rat = data->current_rat;
|
info.rat = QMI_NAS_NETWORK_RAT_NO_CHANGE;
|
||||||
|
|
||||||
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
|
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
|
||||||
sizeof(info), &info);
|
sizeof(info), &info);
|
||||||
@@ -451,10 +487,11 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
|||||||
if (ss) {
|
if (ss) {
|
||||||
int strength;
|
int strength;
|
||||||
|
|
||||||
DBG("signal with %d dBm on %d", ss->dbm, ss->rat);
|
|
||||||
|
|
||||||
strength = dbm_to_strength(ss->dbm);
|
strength = dbm_to_strength(ss->dbm);
|
||||||
|
|
||||||
|
DBG("signal with %d%%(%d dBm) on %d",
|
||||||
|
strength, ss->dbm, ss->rat);
|
||||||
|
|
||||||
ofono_netreg_strength_notify(netreg, strength);
|
ofono_netreg_strength_notify(netreg, strength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,10 +511,17 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
|||||||
static void set_event_cb(struct qmi_result *result, void *user_data)
|
static void set_event_cb(struct qmi_result *result, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_netreg *netreg = user_data;
|
struct ofono_netreg *netreg = user_data;
|
||||||
|
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
ofono_netreg_register(netreg);
|
ofono_netreg_register(netreg);
|
||||||
|
|
||||||
|
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||||
|
event_notify, netreg, NULL);
|
||||||
|
|
||||||
|
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||||
|
ss_info_notify, netreg, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||||
@@ -499,12 +543,6 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
|||||||
|
|
||||||
data->nas = qmi_service_ref(service);
|
data->nas = qmi_service_ref(service);
|
||||||
|
|
||||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
|
||||||
event_notify, netreg, NULL);
|
|
||||||
|
|
||||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
|
||||||
ss_info_notify, netreg, NULL);
|
|
||||||
|
|
||||||
param = qmi_param_new();
|
param = qmi_param_new();
|
||||||
if (!param)
|
if (!param)
|
||||||
goto done;
|
goto done;
|
||||||
@@ -543,7 +581,7 @@ static int qmi_netreg_probe(struct ofono_netreg *netreg,
|
|||||||
|
|
||||||
ofono_netreg_set_data(netreg, data);
|
ofono_netreg_set_data(netreg, data);
|
||||||
|
|
||||||
qmi_service_create(device, QMI_SERVICE_NAS,
|
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||||
create_nas_cb, netreg, NULL);
|
create_nas_cb, netreg, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -33,12 +35,18 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <ofono/log.h>
|
||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
#include "ctl.h"
|
#include "ctl.h"
|
||||||
|
|
||||||
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
|
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
|
||||||
const void *buffer, void *user_data);
|
const void *buffer, void *user_data);
|
||||||
|
|
||||||
|
struct discovery {
|
||||||
|
qmi_destroy_func_t destroy;
|
||||||
|
};
|
||||||
|
|
||||||
struct qmi_device {
|
struct qmi_device {
|
||||||
int ref_count;
|
int ref_count;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -49,6 +57,7 @@ struct qmi_device {
|
|||||||
GQueue *req_queue;
|
GQueue *req_queue;
|
||||||
GQueue *control_queue;
|
GQueue *control_queue;
|
||||||
GQueue *service_queue;
|
GQueue *service_queue;
|
||||||
|
GQueue *discovery_queue;
|
||||||
uint8_t next_control_tid;
|
uint8_t next_control_tid;
|
||||||
uint16_t next_service_tid;
|
uint16_t next_service_tid;
|
||||||
qmi_debug_func_t debug_func;
|
qmi_debug_func_t debug_func;
|
||||||
@@ -60,6 +69,12 @@ struct qmi_device {
|
|||||||
uint8_t version_count;
|
uint8_t version_count;
|
||||||
GHashTable *service_list;
|
GHashTable *service_list;
|
||||||
unsigned int release_users;
|
unsigned int release_users;
|
||||||
|
qmi_shutdown_func_t shutdown_func;
|
||||||
|
void *shutdown_user_data;
|
||||||
|
qmi_destroy_func_t shutdown_destroy;
|
||||||
|
guint shutdown_source;
|
||||||
|
bool shutting_down : 1;
|
||||||
|
bool destroyed : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qmi_service {
|
struct qmi_service {
|
||||||
@@ -209,6 +224,14 @@ static gint __request_compare(gconstpointer a, gconstpointer b)
|
|||||||
return req->tid - tid;
|
return req->tid - tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __discovery_free(gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct discovery *d = data;
|
||||||
|
qmi_destroy_func_t destroy = d->destroy;
|
||||||
|
|
||||||
|
destroy(d);
|
||||||
|
}
|
||||||
|
|
||||||
static void __notify_free(gpointer data, gpointer user_data)
|
static void __notify_free(gpointer data, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct qmi_notify *notify = data;
|
struct qmi_notify *notify = data;
|
||||||
@@ -313,8 +336,12 @@ static const char *__service_type_to_string(uint8_t type)
|
|||||||
return "UIM";
|
return "UIM";
|
||||||
case QMI_SERVICE_PBM:
|
case QMI_SERVICE_PBM:
|
||||||
return "PBM";
|
return "PBM";
|
||||||
|
case QMI_SERVICE_QCHAT:
|
||||||
|
return "QCHAT";
|
||||||
case QMI_SERVICE_RMTFS:
|
case QMI_SERVICE_RMTFS:
|
||||||
return "RMTFS";
|
return "RMTFS";
|
||||||
|
case QMI_SERVICE_TEST:
|
||||||
|
return "TEST";
|
||||||
case QMI_SERVICE_LOC:
|
case QMI_SERVICE_LOC:
|
||||||
return "LOC";
|
return "LOC";
|
||||||
case QMI_SERVICE_SAR:
|
case QMI_SERVICE_SAR:
|
||||||
@@ -326,9 +353,21 @@ static const char *__service_type_to_string(uint8_t type)
|
|||||||
case QMI_SERVICE_TS:
|
case QMI_SERVICE_TS:
|
||||||
return "TS";
|
return "TS";
|
||||||
case QMI_SERVICE_TMD:
|
case QMI_SERVICE_TMD:
|
||||||
return "TMS";
|
return "TMD";
|
||||||
|
case QMI_SERVICE_WDA:
|
||||||
|
return "WDA";
|
||||||
|
case QMI_SERVICE_CSVT:
|
||||||
|
return "CSVT";
|
||||||
|
case QMI_SERVICE_COEX:
|
||||||
|
return "COEX";
|
||||||
case QMI_SERVICE_PDC:
|
case QMI_SERVICE_PDC:
|
||||||
return "PDC";
|
return "PDC";
|
||||||
|
case QMI_SERVICE_RFRPE:
|
||||||
|
return "RFRPE";
|
||||||
|
case QMI_SERVICE_DSD:
|
||||||
|
return "DSD";
|
||||||
|
case QMI_SERVICE_SSCTL:
|
||||||
|
return "SSCTL";
|
||||||
case QMI_SERVICE_CAT_OLD:
|
case QMI_SERVICE_CAT_OLD:
|
||||||
return "CAT";
|
return "CAT";
|
||||||
case QMI_SERVICE_RMS:
|
case QMI_SERVICE_RMS:
|
||||||
@@ -758,7 +797,7 @@ static void handle_packet(struct qmi_device *device,
|
|||||||
|
|
||||||
tid = GUINT16_FROM_LE(service->transaction);
|
tid = GUINT16_FROM_LE(service->transaction);
|
||||||
|
|
||||||
if (service->type == 0x04 && tid == 0x0000) {
|
if (service->type == 0x04) {
|
||||||
handle_indication(device, hdr->service, hdr->client,
|
handle_indication(device, hdr->service, hdr->client,
|
||||||
message, length, data);
|
message, length, data);
|
||||||
return;
|
return;
|
||||||
@@ -838,6 +877,21 @@ static void read_watch_destroy(gpointer user_data)
|
|||||||
device->read_watch = 0;
|
device->read_watch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __qmi_device_discovery_started(struct qmi_device *device,
|
||||||
|
struct discovery *d)
|
||||||
|
{
|
||||||
|
g_queue_push_tail(device->discovery_queue, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __qmi_device_discovery_complete(struct qmi_device *device,
|
||||||
|
struct discovery *d)
|
||||||
|
{
|
||||||
|
if (g_queue_remove(device->discovery_queue, d) != TRUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
__discovery_free(d, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void service_destroy(gpointer data)
|
static void service_destroy(gpointer data)
|
||||||
{
|
{
|
||||||
struct qmi_service *service = data;
|
struct qmi_service *service = data;
|
||||||
@@ -891,6 +945,7 @@ struct qmi_device *qmi_device_new(int fd)
|
|||||||
device->req_queue = g_queue_new();
|
device->req_queue = g_queue_new();
|
||||||
device->control_queue = g_queue_new();
|
device->control_queue = g_queue_new();
|
||||||
device->service_queue = g_queue_new();
|
device->service_queue = g_queue_new();
|
||||||
|
device->discovery_queue = g_queue_new();
|
||||||
|
|
||||||
device->service_list = g_hash_table_new_full(g_direct_hash,
|
device->service_list = g_hash_table_new_full(g_direct_hash,
|
||||||
g_direct_equal, NULL, service_destroy);
|
g_direct_equal, NULL, service_destroy);
|
||||||
@@ -927,6 +982,9 @@ void qmi_device_unref(struct qmi_device *device)
|
|||||||
g_queue_foreach(device->req_queue, __request_free, NULL);
|
g_queue_foreach(device->req_queue, __request_free, NULL);
|
||||||
g_queue_free(device->req_queue);
|
g_queue_free(device->req_queue);
|
||||||
|
|
||||||
|
g_queue_foreach(device->discovery_queue, __discovery_free, NULL);
|
||||||
|
g_queue_free(device->discovery_queue);
|
||||||
|
|
||||||
if (device->write_watch > 0)
|
if (device->write_watch > 0)
|
||||||
g_source_remove(device->write_watch);
|
g_source_remove(device->write_watch);
|
||||||
|
|
||||||
@@ -936,11 +994,17 @@ void qmi_device_unref(struct qmi_device *device)
|
|||||||
if (device->close_on_unref)
|
if (device->close_on_unref)
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
|
|
||||||
|
if (device->shutdown_source)
|
||||||
|
g_source_remove(device->shutdown_source);
|
||||||
|
|
||||||
g_hash_table_destroy(device->service_list);
|
g_hash_table_destroy(device->service_list);
|
||||||
|
|
||||||
g_free(device->version_str);
|
g_free(device->version_str);
|
||||||
g_free(device->version_list);
|
g_free(device->version_list);
|
||||||
|
|
||||||
|
if (device->shutting_down)
|
||||||
|
device->destroyed = true;
|
||||||
|
else
|
||||||
g_free(device);
|
g_free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,6 +1026,23 @@ void qmi_device_set_close_on_unref(struct qmi_device *device, bool do_close)
|
|||||||
device->close_on_unref = do_close;
|
device->close_on_unref = do_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qmi_result_print_tlvs(struct qmi_result *result)
|
||||||
|
{
|
||||||
|
const void *ptr = result->data;
|
||||||
|
uint16_t len = result->length;
|
||||||
|
|
||||||
|
while (len > QMI_TLV_HDR_SIZE) {
|
||||||
|
const struct qmi_tlv_hdr *tlv = ptr;
|
||||||
|
uint16_t tlv_length = GUINT16_FROM_LE(tlv->length);
|
||||||
|
|
||||||
|
DBG("tlv: 0x%02x len 0x%04x", tlv->type, tlv->length);
|
||||||
|
|
||||||
|
ptr += QMI_TLV_HDR_SIZE + tlv_length;
|
||||||
|
len -= QMI_TLV_HDR_SIZE + tlv_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const void *tlv_get(const void *data, uint16_t size,
|
static const void *tlv_get(const void *data, uint16_t size,
|
||||||
uint8_t type, uint16_t *length)
|
uint8_t type, uint16_t *length)
|
||||||
{
|
{
|
||||||
@@ -987,6 +1068,7 @@ static const void *tlv_get(const void *data, uint16_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct discover_data {
|
struct discover_data {
|
||||||
|
struct discovery super;
|
||||||
struct qmi_device *device;
|
struct qmi_device *device;
|
||||||
qmi_discover_func_t func;
|
qmi_discover_func_t func;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
@@ -994,6 +1076,21 @@ struct discover_data {
|
|||||||
guint timeout;
|
guint timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void discover_data_free(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct discover_data *data = user_data;
|
||||||
|
|
||||||
|
if (data->timeout) {
|
||||||
|
g_source_remove(data->timeout);
|
||||||
|
data->timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->destroy)
|
||||||
|
data->destroy(data->user_data);
|
||||||
|
|
||||||
|
g_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
static void discover_callback(uint16_t message, uint16_t length,
|
static void discover_callback(uint16_t message, uint16_t length,
|
||||||
const void *buffer, void *user_data)
|
const void *buffer, void *user_data)
|
||||||
{
|
{
|
||||||
@@ -1007,8 +1104,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
|||||||
uint8_t count;
|
uint8_t count;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
g_source_remove(data->timeout);
|
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
list = NULL;
|
list = NULL;
|
||||||
|
|
||||||
@@ -1079,10 +1174,7 @@ done:
|
|||||||
if (data->func)
|
if (data->func)
|
||||||
data->func(count, list, data->user_data);
|
data->func(count, list, data->user_data);
|
||||||
|
|
||||||
if (data->destroy)
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
data->destroy(data->user_data);
|
|
||||||
|
|
||||||
g_free(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean discover_reply(gpointer user_data)
|
static gboolean discover_reply(gpointer user_data)
|
||||||
@@ -1096,10 +1188,7 @@ static gboolean discover_reply(gpointer user_data)
|
|||||||
data->func(device->version_count,
|
data->func(device->version_count,
|
||||||
device->version_list, data->user_data);
|
device->version_list, data->user_data);
|
||||||
|
|
||||||
if (data->destroy)
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
data->destroy(data->user_data);
|
|
||||||
|
|
||||||
g_free(data);
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1120,13 +1209,15 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
data->super.destroy = discover_data_free;
|
||||||
data->device = device;
|
data->device = device;
|
||||||
data->func = func;
|
data->func = func;
|
||||||
data->user_data = user_data;
|
data->user_data = user_data;
|
||||||
data->destroy = destroy;
|
data->destroy = destroy;
|
||||||
|
|
||||||
if (device->version_list) {
|
if (device->version_list) {
|
||||||
g_timeout_add_seconds(0, discover_reply, data);
|
data->timeout = g_timeout_add_seconds(0, discover_reply, data);
|
||||||
|
__qmi_device_discovery_started(device, &data->super);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1147,6 +1238,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
|||||||
__request_submit(device, req, hdr->transaction);
|
__request_submit(device, req, hdr->transaction);
|
||||||
|
|
||||||
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
||||||
|
__qmi_device_discovery_started(device, &data->super);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1177,63 +1269,256 @@ static void release_client(struct qmi_device *device,
|
|||||||
__request_submit(device, req, hdr->transaction);
|
__request_submit(device, req, hdr->transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct shutdown_data {
|
static void shutdown_destroy(gpointer user_data)
|
||||||
struct qmi_device *device;
|
|
||||||
qmi_shutdown_func_t func;
|
|
||||||
void *user_data;
|
|
||||||
qmi_destroy_func_t destroy;
|
|
||||||
};
|
|
||||||
|
|
||||||
static gboolean shutdown_reply(gpointer user_data)
|
|
||||||
{
|
{
|
||||||
struct shutdown_data *data = user_data;
|
struct qmi_device *device = user_data;
|
||||||
|
|
||||||
if (data->func)
|
if (device->shutdown_destroy)
|
||||||
data->func(data->user_data);
|
device->shutdown_destroy(device->shutdown_user_data);
|
||||||
|
|
||||||
g_free(data);
|
device->shutdown_source = 0;
|
||||||
|
|
||||||
return FALSE;
|
if (device->destroyed)
|
||||||
|
g_free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean shutdown_timeout(gpointer user_data)
|
static gboolean shutdown_callback(gpointer user_data)
|
||||||
{
|
{
|
||||||
struct shutdown_data *data = user_data;
|
struct qmi_device *device = user_data;
|
||||||
struct qmi_device *device = data->device;
|
|
||||||
|
|
||||||
if (device->release_users > 0)
|
if (device->release_users > 0)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return shutdown_reply(data);
|
device->shutting_down = true;
|
||||||
|
|
||||||
|
if (device->shutdown_func)
|
||||||
|
device->shutdown_func(device->shutdown_user_data);
|
||||||
|
|
||||||
|
device->shutting_down = true;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||||
void *user_data, qmi_destroy_func_t destroy)
|
void *user_data, qmi_destroy_func_t destroy)
|
||||||
{
|
{
|
||||||
struct shutdown_data *data;
|
|
||||||
|
|
||||||
if (!device)
|
if (!device)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (device->shutdown_source > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
__debug_device(device, "device %p shutdown", device);
|
__debug_device(device, "device %p shutdown", device);
|
||||||
|
|
||||||
data = g_try_new0(struct shutdown_data, 1);
|
device->shutdown_source = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
|
||||||
if (!data)
|
0, shutdown_callback, device,
|
||||||
|
shutdown_destroy);
|
||||||
|
if (device->shutdown_source == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
data->device = device;
|
device->shutdown_func = func;
|
||||||
data->func = func;
|
device->shutdown_user_data = user_data;
|
||||||
data->user_data = user_data;
|
device->shutdown_destroy = destroy;
|
||||||
data->destroy = destroy;
|
|
||||||
|
|
||||||
if (device->release_users > 0)
|
|
||||||
g_timeout_add_seconds(0, shutdown_timeout, data);
|
|
||||||
else
|
|
||||||
g_timeout_add_seconds(0, shutdown_reply, data);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool get_device_file_name(struct qmi_device *device,
|
||||||
|
char *file_name, int size)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
char temp[100];
|
||||||
|
ssize_t result;
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pid = getpid();
|
||||||
|
|
||||||
|
snprintf(temp, 100, "/proc/%d/fd/%d", (int) pid, device->fd);
|
||||||
|
temp[99] = 0;
|
||||||
|
|
||||||
|
result = readlink(temp, file_name, size - 1);
|
||||||
|
|
||||||
|
if (result == -1 || result >= size - 1) {
|
||||||
|
DBG("Error %d in readlink", errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_name[result] = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_first_dir_in_directory(char *dir_path)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *dir_entry;
|
||||||
|
char *dir_name = NULL;
|
||||||
|
|
||||||
|
dir = opendir(dir_path);
|
||||||
|
|
||||||
|
if (!dir)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dir_entry = readdir(dir);
|
||||||
|
|
||||||
|
while ((dir_entry != NULL)) {
|
||||||
|
if (dir_entry->d_type == DT_DIR &&
|
||||||
|
strcmp(dir_entry->d_name, ".") != 0 &&
|
||||||
|
strcmp(dir_entry->d_name, "..") != 0) {
|
||||||
|
dir_name = g_strdup(dir_entry->d_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_entry = readdir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return dir_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_device_interface(struct qmi_device *device)
|
||||||
|
{
|
||||||
|
char * const driver_names[] = { "usbmisc", "usb" };
|
||||||
|
unsigned int i;
|
||||||
|
char file_path[PATH_MAX];
|
||||||
|
char *file_name;
|
||||||
|
char *interface = NULL;
|
||||||
|
|
||||||
|
if (!get_device_file_name(device, file_path, sizeof(file_path)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
file_name = basename(file_path);
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS(driver_names) && !interface; i++) {
|
||||||
|
gchar *sysfs_path;
|
||||||
|
|
||||||
|
sysfs_path = g_strdup_printf("/sys/class/%s/%s/device/net/",
|
||||||
|
driver_names[i], file_name);
|
||||||
|
interface = get_first_dir_in_directory(sysfs_path);
|
||||||
|
g_free(sysfs_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
|
||||||
|
struct qmi_device *device)
|
||||||
|
{
|
||||||
|
char *sysfs_path = NULL;
|
||||||
|
char *interface = NULL;
|
||||||
|
int fd = -1;
|
||||||
|
char value;
|
||||||
|
enum qmi_device_expected_data_format expected =
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
interface = get_device_interface(device);
|
||||||
|
|
||||||
|
if (!interface) {
|
||||||
|
DBG("Error while getting interface name");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build sysfs file path and open it */
|
||||||
|
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||||
|
|
||||||
|
fd = open(sysfs_path, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
/* maybe not supported by kernel */
|
||||||
|
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(fd, &value, 1) != 1) {
|
||||||
|
DBG("Error %d in read(%s)", errno, sysfs_path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == 'Y')
|
||||||
|
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP;
|
||||||
|
else if (value == 'N')
|
||||||
|
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3;
|
||||||
|
else
|
||||||
|
DBG("Unexpected sysfs file contents");
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (sysfs_path)
|
||||||
|
g_free(sysfs_path);
|
||||||
|
|
||||||
|
if (interface)
|
||||||
|
g_free(interface);
|
||||||
|
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qmi_device_set_expected_data_format(struct qmi_device *device,
|
||||||
|
enum qmi_device_expected_data_format format)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
char *sysfs_path = NULL;
|
||||||
|
char *interface = NULL;
|
||||||
|
int fd = -1;
|
||||||
|
char value;
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3:
|
||||||
|
value = 'N';
|
||||||
|
break;
|
||||||
|
case QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP:
|
||||||
|
value = 'Y';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG("Unhandled format: %d", (int) format);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface = get_device_interface(device);
|
||||||
|
|
||||||
|
if (!interface) {
|
||||||
|
DBG("Error while getting interface name");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build sysfs file path and open it */
|
||||||
|
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||||
|
|
||||||
|
fd = open(sysfs_path, O_WRONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
/* maybe not supported by kernel */
|
||||||
|
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write(fd, &value, 1) != 1) {
|
||||||
|
DBG("Error %d in write(%s)", errno, sysfs_path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = true;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (sysfs_path)
|
||||||
|
g_free(sysfs_path);
|
||||||
|
|
||||||
|
if (interface)
|
||||||
|
g_free(interface);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
struct qmi_param *qmi_param_new(void)
|
struct qmi_param *qmi_param_new(void)
|
||||||
{
|
{
|
||||||
struct qmi_param *param;
|
struct qmi_param *param;
|
||||||
@@ -1435,6 +1720,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||||
|
int16_t *value)
|
||||||
|
{
|
||||||
|
const unsigned char *ptr;
|
||||||
|
uint16_t len, tmp;
|
||||||
|
|
||||||
|
if (!result || !type)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ptr = tlv_get(result->data, result->length, type, &len);
|
||||||
|
if (!ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(&tmp, ptr, 2);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
*value = GINT16_FROM_LE(tmp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||||
uint16_t *value)
|
uint16_t *value)
|
||||||
{
|
{
|
||||||
@@ -1501,6 +1807,7 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct service_create_data {
|
struct service_create_data {
|
||||||
|
struct discovery super;
|
||||||
struct qmi_device *device;
|
struct qmi_device *device;
|
||||||
bool shared;
|
bool shared;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -1512,16 +1819,29 @@ struct service_create_data {
|
|||||||
guint timeout;
|
guint timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean service_create_reply(gpointer user_data)
|
static void service_create_data_free(gpointer user_data)
|
||||||
{
|
{
|
||||||
struct service_create_data *data = user_data;
|
struct service_create_data *data = user_data;
|
||||||
|
|
||||||
data->func(NULL, data->user_data);
|
if (data->timeout) {
|
||||||
|
g_source_remove(data->timeout);
|
||||||
|
data->timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (data->destroy)
|
if (data->destroy)
|
||||||
data->destroy(data->user_data);
|
data->destroy(data->user_data);
|
||||||
|
|
||||||
g_free(data);
|
g_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean service_create_reply(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct service_create_data *data = user_data;
|
||||||
|
|
||||||
|
data->timeout = 0;
|
||||||
|
data->func(NULL, data->user_data);
|
||||||
|
|
||||||
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1537,8 +1857,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
|||||||
uint16_t len;
|
uint16_t len;
|
||||||
unsigned int hash_id;
|
unsigned int hash_id;
|
||||||
|
|
||||||
g_source_remove(data->timeout);
|
|
||||||
|
|
||||||
result_code = tlv_get(buffer, length, 0x02, &len);
|
result_code = tlv_get(buffer, length, 0x02, &len);
|
||||||
if (!result_code)
|
if (!result_code)
|
||||||
goto done;
|
goto done;
|
||||||
@@ -1580,13 +1898,9 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
data->func(service, data->user_data);
|
data->func(service, data->user_data);
|
||||||
|
|
||||||
qmi_service_unref(service);
|
qmi_service_unref(service);
|
||||||
|
|
||||||
if (data->destroy)
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
data->destroy(data->user_data);
|
|
||||||
|
|
||||||
g_free(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_create_discover(uint8_t count,
|
static void service_create_discover(uint8_t count,
|
||||||
@@ -1617,7 +1931,9 @@ static void service_create_discover(uint8_t count,
|
|||||||
if (data->timeout > 0)
|
if (data->timeout > 0)
|
||||||
g_source_remove(data->timeout);
|
g_source_remove(data->timeout);
|
||||||
|
|
||||||
g_timeout_add_seconds(0, service_create_reply, data);
|
data->timeout = g_timeout_add_seconds(0,
|
||||||
|
service_create_reply, data);
|
||||||
|
__qmi_device_discovery_started(device, &data->super);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1640,6 +1956,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
data->super.destroy = service_create_data_free;
|
||||||
data->device = device;
|
data->device = device;
|
||||||
data->shared = shared;
|
data->shared = shared;
|
||||||
data->type = type;
|
data->type = type;
|
||||||
@@ -1662,6 +1979,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
||||||
|
__qmi_device_discovery_started(device, &data->super);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1680,17 +1998,23 @@ bool qmi_service_create(struct qmi_device *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct service_create_shared_data {
|
struct service_create_shared_data {
|
||||||
|
struct discovery super;
|
||||||
struct qmi_service *service;
|
struct qmi_service *service;
|
||||||
|
struct qmi_device *device;
|
||||||
qmi_create_func_t func;
|
qmi_create_func_t func;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
qmi_destroy_func_t destroy;
|
qmi_destroy_func_t destroy;
|
||||||
|
guint timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean service_create_shared_reply(gpointer user_data)
|
static void service_create_shared_data_free(gpointer user_data)
|
||||||
{
|
{
|
||||||
struct service_create_shared_data *data = user_data;
|
struct service_create_shared_data *data = user_data;
|
||||||
|
|
||||||
data->func(data->service, data->user_data);
|
if (data->timeout) {
|
||||||
|
g_source_remove(data->timeout);
|
||||||
|
data->timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
qmi_service_unref(data->service);
|
qmi_service_unref(data->service);
|
||||||
|
|
||||||
@@ -1698,6 +2022,16 @@ static gboolean service_create_shared_reply(gpointer user_data)
|
|||||||
data->destroy(data->user_data);
|
data->destroy(data->user_data);
|
||||||
|
|
||||||
g_free(data);
|
g_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean service_create_shared_reply(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct service_create_shared_data *data = user_data;
|
||||||
|
|
||||||
|
data->timeout = 0;
|
||||||
|
data->func(data->service, data->user_data);
|
||||||
|
|
||||||
|
__qmi_device_discovery_complete(data->device, &data->super);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1724,13 +2058,16 @@ bool qmi_service_create_shared(struct qmi_device *device,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
data->super.destroy = service_create_shared_data_free;
|
||||||
data->service = qmi_service_ref(service);
|
data->service = qmi_service_ref(service);
|
||||||
|
data->device = device;
|
||||||
data->func = func;
|
data->func = func;
|
||||||
data->user_data = user_data;
|
data->user_data = user_data;
|
||||||
data->destroy = destroy;
|
data->destroy = destroy;
|
||||||
|
|
||||||
g_timeout_add(0, service_create_shared_reply, data);
|
data->timeout = g_timeout_add(0,
|
||||||
|
service_create_shared_reply, data);
|
||||||
|
__qmi_device_discovery_started(device, &data->super);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,18 +35,32 @@
|
|||||||
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
|
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
|
||||||
#define QMI_SERVICE_UIM 11 /* UIM service */
|
#define QMI_SERVICE_UIM 11 /* UIM service */
|
||||||
#define QMI_SERVICE_PBM 12 /* Phonebook service */
|
#define QMI_SERVICE_PBM 12 /* Phonebook service */
|
||||||
|
#define QMI_SERVICE_QCHAT 13
|
||||||
#define QMI_SERVICE_RMTFS 14 /* Remote file system service */
|
#define QMI_SERVICE_RMTFS 14 /* Remote file system service */
|
||||||
|
#define QMI_SERVICE_TEST 15
|
||||||
#define QMI_SERVICE_LOC 16 /* Location service */
|
#define QMI_SERVICE_LOC 16 /* Location service */
|
||||||
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
|
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
|
||||||
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
|
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
|
||||||
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
|
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
|
||||||
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
|
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
|
||||||
#define QMI_SERVICE_TMD 24 /* Thermal mitigation device service */
|
#define QMI_SERVICE_TMD 24 /* Thermal mitigation device service */
|
||||||
|
#define QMI_SERVICE_WDA 26 /* Wireless data administrative service */
|
||||||
|
#define QMI_SERVICE_CSVT 29
|
||||||
|
#define QMI_SERVICE_COEX 34
|
||||||
#define QMI_SERVICE_PDC 36 /* Persistent device configuration service */
|
#define QMI_SERVICE_PDC 36 /* Persistent device configuration service */
|
||||||
|
#define QMI_SERVICE_RFRPE 41
|
||||||
|
#define QMI_SERVICE_DSD 42
|
||||||
|
#define QMI_SERVICE_SSCTL 43
|
||||||
#define QMI_SERVICE_CAT_OLD 224 /* Card application toolkit service */
|
#define QMI_SERVICE_CAT_OLD 224 /* Card application toolkit service */
|
||||||
#define QMI_SERVICE_RMS 225 /* Remote management service */
|
#define QMI_SERVICE_RMS 225 /* Remote management service */
|
||||||
#define QMI_SERVICE_OMA 226 /* OMA device management service */
|
#define QMI_SERVICE_OMA 226 /* OMA device management service */
|
||||||
|
|
||||||
|
enum qmi_device_expected_data_format {
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN,
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3,
|
||||||
|
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
|
||||||
|
};
|
||||||
|
|
||||||
struct qmi_version {
|
struct qmi_version {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint16_t major;
|
uint16_t major;
|
||||||
@@ -82,6 +96,10 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
|||||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||||
void *user_data, qmi_destroy_func_t destroy);
|
void *user_data, qmi_destroy_func_t destroy);
|
||||||
|
|
||||||
|
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
|
||||||
|
struct qmi_device *device);
|
||||||
|
bool qmi_device_set_expected_data_format(struct qmi_device *device,
|
||||||
|
enum qmi_device_expected_data_format format);
|
||||||
|
|
||||||
struct qmi_param;
|
struct qmi_param;
|
||||||
|
|
||||||
@@ -112,13 +130,15 @@ const void *qmi_result_get(struct qmi_result *result, uint8_t type,
|
|||||||
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
|
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
|
||||||
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||||
uint8_t *value);
|
uint8_t *value);
|
||||||
|
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||||
|
int16_t *value);
|
||||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||||
uint16_t *value);
|
uint16_t *value);
|
||||||
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
||||||
uint32_t *value);
|
uint32_t *value);
|
||||||
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||||
uint64_t *value);
|
uint64_t *value);
|
||||||
|
void qmi_result_print_tlvs(struct qmi_result *result);
|
||||||
|
|
||||||
struct qmi_service;
|
struct qmi_service;
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,14 @@ static int qmimodem_init(void)
|
|||||||
qmi_gprs_context_init();
|
qmi_gprs_context_init();
|
||||||
qmi_radio_settings_init();
|
qmi_radio_settings_init();
|
||||||
qmi_location_reporting_init();
|
qmi_location_reporting_init();
|
||||||
|
qmi_netmon_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmimodem_exit(void)
|
static void qmimodem_exit(void)
|
||||||
{
|
{
|
||||||
|
qmi_netmon_exit();
|
||||||
qmi_location_reporting_exit();
|
qmi_location_reporting_exit();
|
||||||
qmi_radio_settings_exit();
|
qmi_radio_settings_exit();
|
||||||
qmi_gprs_context_exit();
|
qmi_gprs_context_exit();
|
||||||
|
|||||||
@@ -53,3 +53,6 @@ extern void qmi_radio_settings_exit(void);
|
|||||||
|
|
||||||
extern void qmi_location_reporting_init(void);
|
extern void qmi_location_reporting_init(void);
|
||||||
extern void qmi_location_reporting_exit(void);
|
extern void qmi_location_reporting_exit(void);
|
||||||
|
|
||||||
|
extern void qmi_netmon_init(void);
|
||||||
|
extern void qmi_netmon_exit(void);
|
||||||
|
|||||||
@@ -29,15 +29,202 @@
|
|||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
#include "nas.h"
|
#include "nas.h"
|
||||||
|
#include "dms.h"
|
||||||
|
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
|
|
||||||
struct settings_data {
|
struct settings_data {
|
||||||
struct qmi_service *nas;
|
struct qmi_service *nas;
|
||||||
|
struct qmi_service *dms;
|
||||||
uint16_t major;
|
uint16_t major;
|
||||||
uint16_t minor;
|
uint16_t minor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void get_system_selection_pref_cb(struct qmi_result *result,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||||
|
enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||||
|
uint16_t pref;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmi_result_get_uint16(result,
|
||||||
|
QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref);
|
||||||
|
|
||||||
|
switch (pref) {
|
||||||
|
case QMI_NAS_RAT_MODE_PREF_GSM:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_RAT_MODE_PREF_UMTS:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
break;
|
||||||
|
case QMI_NAS_RAT_MODE_PREF_LTE:
|
||||||
|
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_query_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_service_send(data->nas,
|
||||||
|
QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL,
|
||||||
|
get_system_selection_pref_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_system_selection_pref_cb(struct qmi_result *result,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_set_rat_mode(struct ofono_radio_settings *rs,
|
||||||
|
enum ofono_radio_access_mode mode,
|
||||||
|
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||||
|
struct qmi_param *param;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_GSM;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_UMTS;
|
||||||
|
break;
|
||||||
|
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||||
|
pref = QMI_NAS_RAT_MODE_PREF_LTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
param = qmi_param_new();
|
||||||
|
if (!param) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE,
|
||||||
|
pref);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->nas,
|
||||||
|
QMI_NAS_SET_SYSTEM_SELECTION_PREF, param,
|
||||||
|
set_system_selection_pref_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qmi_param_free(param);
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_caps_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
|
||||||
|
const struct qmi_dms_device_caps *caps;
|
||||||
|
unsigned int available_rats;
|
||||||
|
uint16_t len;
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
|
||||||
|
if (!caps)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
available_rats = 0;
|
||||||
|
for (i = 0; i < caps->radio_if_count; i++) {
|
||||||
|
switch (caps->radio_if[i]) {
|
||||||
|
case QMI_DMS_RADIO_IF_GSM:
|
||||||
|
available_rats |= OFONO_RADIO_ACCESS_MODE_GSM;
|
||||||
|
break;
|
||||||
|
case QMI_DMS_RADIO_IF_UMTS:
|
||||||
|
available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||||
|
break;
|
||||||
|
case QMI_DMS_RADIO_IF_LTE:
|
||||||
|
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_query_available_rats(struct ofono_radio_settings *rs,
|
||||||
|
ofono_radio_settings_available_rats_query_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, data);
|
||||||
|
|
||||||
|
if (!rsd->dms)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL,
|
||||||
|
get_caps_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_free(cbd);
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_radio_settings *rs = user_data;
|
||||||
|
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!service)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data->dms = qmi_service_ref(service);
|
||||||
|
}
|
||||||
|
|
||||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||||
{
|
{
|
||||||
struct ofono_radio_settings *rs = user_data;
|
struct ofono_radio_settings *rs = user_data;
|
||||||
@@ -74,10 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
|
|||||||
|
|
||||||
ofono_radio_settings_set_data(rs, data);
|
ofono_radio_settings_set_data(rs, data);
|
||||||
|
|
||||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, rs, NULL);
|
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||||
|
create_dms_cb, rs, NULL);
|
||||||
|
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||||
|
create_nas_cb, rs, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||||
@@ -99,6 +288,9 @@ static struct ofono_radio_settings_driver driver = {
|
|||||||
.name = "qmimodem",
|
.name = "qmimodem",
|
||||||
.probe = qmi_radio_settings_probe,
|
.probe = qmi_radio_settings_probe,
|
||||||
.remove = qmi_radio_settings_remove,
|
.remove = qmi_radio_settings_remove,
|
||||||
|
.set_rat_mode = qmi_set_rat_mode,
|
||||||
|
.query_rat_mode = qmi_query_rat_mode,
|
||||||
|
.query_available_rats = qmi_query_available_rats,
|
||||||
};
|
};
|
||||||
|
|
||||||
void qmi_radio_settings_init(void)
|
void qmi_radio_settings_init(void)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <ofono/sim.h>
|
#include <ofono/sim.h>
|
||||||
|
|
||||||
#include "qmi.h"
|
#include "qmi.h"
|
||||||
|
#include "dms.h"
|
||||||
#include "uim.h"
|
#include "uim.h"
|
||||||
|
|
||||||
#include "qmimodem.h"
|
#include "qmimodem.h"
|
||||||
@@ -38,15 +39,36 @@
|
|||||||
#define EF_STATUS_INVALIDATED 0
|
#define EF_STATUS_INVALIDATED 0
|
||||||
#define EF_STATUS_VALID 1
|
#define EF_STATUS_VALID 1
|
||||||
|
|
||||||
struct sim_data {
|
/* max number of retry of commands that can temporary fail */
|
||||||
struct qmi_service *uim;
|
#define MAX_RETRY_COUNT 100
|
||||||
uint32_t event_mask;
|
|
||||||
|
enum get_card_status_result {
|
||||||
|
GET_CARD_STATUS_RESULT_OK, /* No error */
|
||||||
|
GET_CARD_STATUS_RESULT_ERROR, /* Definitive error */
|
||||||
|
GET_CARD_STATUS_RESULT_TEMP_ERROR, /* error, a retry could work */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* information from QMI_UIM_GET_CARD_STATUS command */
|
||||||
|
struct sim_status {
|
||||||
uint8_t card_state;
|
uint8_t card_state;
|
||||||
uint8_t app_type;
|
uint8_t app_type;
|
||||||
uint8_t passwd_state;
|
uint8_t passwd_state;
|
||||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sim_data {
|
||||||
|
struct qmi_device *qmi_dev;
|
||||||
|
struct qmi_service *dms;
|
||||||
|
struct qmi_service *uim;
|
||||||
|
uint32_t event_mask;
|
||||||
|
uint8_t app_type;
|
||||||
|
uint32_t retry_count;
|
||||||
|
guint poll_source;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||||
|
ofono_sim_passwd_cb_t cb, void *user_data);
|
||||||
|
|
||||||
static int create_fileid_data(uint8_t app_type, int fileid,
|
static int create_fileid_data(uint8_t app_type, int fileid,
|
||||||
const unsigned char *path,
|
const unsigned char *path,
|
||||||
unsigned int path_len,
|
unsigned int path_len,
|
||||||
@@ -146,7 +168,7 @@ static void qmi_read_attributes(struct ofono_sim *sim, int fileid,
|
|||||||
{
|
{
|
||||||
struct sim_data *data = ofono_sim_get_data(sim);
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||||
unsigned char fileid_data[9];
|
unsigned char fileid_data[9];
|
||||||
int fileid_len;
|
int fileid_len;
|
||||||
struct qmi_param *param;
|
struct qmi_param *param;
|
||||||
@@ -211,7 +233,7 @@ static void qmi_read_transparent(struct ofono_sim *sim,
|
|||||||
{
|
{
|
||||||
struct sim_data *data = ofono_sim_get_data(sim);
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||||
unsigned char read_data[4];
|
unsigned char read_data[4];
|
||||||
unsigned char fileid_data[9];
|
unsigned char fileid_data[9];
|
||||||
int fileid_len;
|
int fileid_len;
|
||||||
@@ -257,7 +279,7 @@ static void qmi_read_record(struct ofono_sim *sim,
|
|||||||
{
|
{
|
||||||
struct sim_data *data = ofono_sim_get_data(sim);
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||||
unsigned char read_data[4];
|
unsigned char read_data[4];
|
||||||
unsigned char fileid_data[9];
|
unsigned char fileid_data[9];
|
||||||
int fileid_len;
|
int fileid_len;
|
||||||
@@ -295,76 +317,214 @@ error:
|
|||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
static void write_generic_cb(struct qmi_result *result, void *user_data)
|
||||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
|
||||||
{
|
{
|
||||||
struct sim_data *data = ofono_sim_get_data(sim);
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_sim_write_cb_t cb = cbd->cb;
|
||||||
|
uint16_t len;
|
||||||
|
const uint8_t *card_result;
|
||||||
|
uint8_t sw1, sw2;
|
||||||
|
|
||||||
DBG("passwd state %d", data->passwd_state);
|
card_result = qmi_result_get(result, 0x10, &len);
|
||||||
|
if (card_result == NULL || len != 2) {
|
||||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
DBG("card_result: %p, len: %d", card_result, (int) len);
|
||||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_data);
|
sw1 = card_result[0];
|
||||||
}
|
sw2 = card_result[1];
|
||||||
|
|
||||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
DBG("%02x, %02x", sw1, sw2);
|
||||||
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
|
||||||
{
|
|
||||||
struct sim_data *data = ofono_sim_get_data(sim);
|
|
||||||
|
|
||||||
DBG("passwd state %d", data->passwd_state);
|
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
||||||
|
(sw1 == 0x90 && sw2 != 0x00)) {
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
ofono_error("%s: error sw1 %02x sw2 %02x", __func__, sw1, sw2);
|
||||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
|
||||||
|
error.type = OFONO_ERROR_TYPE_SIM;
|
||||||
|
error.error = (sw1 << 8) | sw2;
|
||||||
|
|
||||||
|
cb(&error, cbd->data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, data->retries, user_data);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void card_setup(const struct qmi_uim_slot_info *slot,
|
static void write_generic(struct ofono_sim *sim,
|
||||||
|
uint16_t qmi_message, int fileid,
|
||||||
|
int start_or_recordnum,
|
||||||
|
int length, const unsigned char *value,
|
||||||
|
const unsigned char *path, unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||||
|
unsigned char write_data[4 + length];
|
||||||
|
unsigned char fileid_data[9];
|
||||||
|
int fileid_len;
|
||||||
|
struct qmi_param *param;
|
||||||
|
|
||||||
|
DBG("file id 0x%04x path len %d", fileid, path_len);
|
||||||
|
|
||||||
|
fileid_len = create_fileid_data(data->app_type, fileid,
|
||||||
|
path, path_len, fileid_data);
|
||||||
|
|
||||||
|
if (fileid_len < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
write_data[0] = start_or_recordnum & 0xff;
|
||||||
|
write_data[1] = (start_or_recordnum & 0xff00) >> 8;
|
||||||
|
write_data[2] = length & 0xff;
|
||||||
|
write_data[3] = (length & 0xff00) >> 8;
|
||||||
|
memcpy(&write_data[4], value, length);
|
||||||
|
|
||||||
|
param = qmi_param_new();
|
||||||
|
if (!param)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
|
||||||
|
qmi_param_append(param, 0x02, fileid_len, fileid_data);
|
||||||
|
qmi_param_append(param, 0x03, 4 + length, write_data);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->uim, qmi_message, param,
|
||||||
|
write_generic_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qmi_param_free(param);
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_write_transparent(struct ofono_sim *sim,
|
||||||
|
int fileid, int start, int length,
|
||||||
|
const unsigned char *value,
|
||||||
|
const unsigned char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
write_generic(sim, QMI_UIM_WRITE_TRANSPARENT, fileid, start,
|
||||||
|
length, value, path, path_len, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_write_linear(struct ofono_sim *sim,
|
||||||
|
int fileid, int record, int length,
|
||||||
|
const unsigned char *value,
|
||||||
|
const unsigned char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, record,
|
||||||
|
length, value, path, path_len, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_write_cyclic(struct ofono_sim *sim,
|
||||||
|
int fileid, int length,
|
||||||
|
const unsigned char *value,
|
||||||
|
const unsigned char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
ofono_sim_write_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, 0,
|
||||||
|
length, value, path, path_len, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_imsi_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_sim_imsi_cb_t cb = cbd->cb;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMSI);
|
||||||
|
if (!str) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
|
||||||
|
|
||||||
|
qmi_free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_read_imsi(struct ofono_sim *sim,
|
||||||
|
ofono_sim_imsi_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_service_send(data->dms, QMI_DMS_GET_IMSI, NULL,
|
||||||
|
get_imsi_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if a retry could give another (better) result */
|
||||||
|
static bool get_card_status(const struct qmi_uim_slot_info *slot,
|
||||||
const struct qmi_uim_app_info1 *info1,
|
const struct qmi_uim_app_info1 *info1,
|
||||||
const struct qmi_uim_app_info2 *info2,
|
const struct qmi_uim_app_info2 *info2,
|
||||||
struct sim_data *data)
|
struct sim_status *sim_stat)
|
||||||
{
|
{
|
||||||
data->card_state = slot->card_state;
|
bool need_retry = false;
|
||||||
data->app_type = info1->app_type;
|
sim_stat->card_state = slot->card_state;
|
||||||
|
sim_stat->app_type = info1->app_type;
|
||||||
|
|
||||||
switch (info1->app_state) {
|
switch (info1->app_state) {
|
||||||
case 0x02: /* PIN1 or UPIN is required */
|
case 0x02: /* PIN1 or UPIN is required */
|
||||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
||||||
break;
|
break;
|
||||||
case 0x03: /* PUK1 or PUK for UPIN is required */
|
case 0x03: /* PUK1 or PUK for UPIN is required */
|
||||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||||
|
break;
|
||||||
|
case 0x04: /* Personalization state must be checked. */
|
||||||
|
/* This is temporary, we could retry and get another result */
|
||||||
|
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||||
|
need_retry = true;
|
||||||
break;
|
break;
|
||||||
case 0x07: /* Ready */
|
case 0x07: /* Ready */
|
||||||
data->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
sim_stat->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
DBG("info1->app_state:0x%x: OFONO_SIM_PASSWORD_INVALID",
|
||||||
|
info1->app_state);
|
||||||
|
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
||||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
||||||
|
|
||||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
||||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
||||||
|
|
||||||
|
return need_retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
static enum get_card_status_result handle_get_card_status_result(
|
||||||
|
struct qmi_result *result, struct sim_status *sim_stat)
|
||||||
{
|
{
|
||||||
struct ofono_sim *sim = user_data;
|
|
||||||
struct sim_data *data = ofono_sim_get_data(sim);
|
|
||||||
const void *ptr;
|
const void *ptr;
|
||||||
const struct qmi_uim_card_status *status;
|
const struct qmi_uim_card_status *status;
|
||||||
uint16_t len, offset;
|
uint16_t len, offset;
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
enum get_card_status_result res = GET_CARD_STATUS_RESULT_ERROR;
|
||||||
DBG("");
|
|
||||||
|
|
||||||
if (qmi_result_set_error(result, NULL))
|
if (qmi_result_set_error(result, NULL))
|
||||||
goto done;
|
goto done;
|
||||||
@@ -397,15 +557,211 @@ static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
|||||||
|
|
||||||
index = GUINT16_FROM_LE(status->index_gw_pri);
|
index = GUINT16_FROM_LE(status->index_gw_pri);
|
||||||
|
|
||||||
if ((index & 0xff) == i && (index >> 8) == n)
|
if ((index & 0xff) == i && (index >> 8) == n) {
|
||||||
card_setup(slot, info1, info2, data);
|
if (get_card_status(slot, info1, info2,
|
||||||
|
sim_stat))
|
||||||
|
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
|
||||||
|
else
|
||||||
|
res = GET_CARD_STATUS_RESULT_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean query_passwd_state_retry(gpointer userdata)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = userdata;
|
||||||
|
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||||
|
struct ofono_sim *sim = cbd->user;
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
|
||||||
|
data->poll_source = 0;
|
||||||
|
|
||||||
|
qmi_query_passwd_state(sim, cb, cbd->data);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void query_passwd_state_cb(struct qmi_result *result,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||||
|
struct ofono_sim *sim = cbd->user;
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct sim_status sim_stat;
|
||||||
|
enum get_card_status_result res;
|
||||||
|
struct cb_data *retry_cbd;
|
||||||
|
|
||||||
|
res = handle_get_card_status_result(result, &sim_stat);
|
||||||
|
switch (res) {
|
||||||
|
case GET_CARD_STATUS_RESULT_OK:
|
||||||
|
DBG("passwd state %d", sim_stat.passwd_state);
|
||||||
|
data->retry_count = 0;
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
|
||||||
|
break;
|
||||||
|
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
|
||||||
|
data->retry_count++;
|
||||||
|
if (data->retry_count > MAX_RETRY_COUNT) {
|
||||||
|
DBG("Failed after %d attempts", data->retry_count);
|
||||||
|
data->retry_count = 0;
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
} else {
|
||||||
|
DBG("Retry command");
|
||||||
|
retry_cbd = cb_data_new(cb, cbd->data);
|
||||||
|
retry_cbd->user = sim;
|
||||||
|
data->poll_source = g_timeout_add(20,
|
||||||
|
query_passwd_state_retry,
|
||||||
|
retry_cbd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GET_CARD_STATUS_RESULT_ERROR:
|
||||||
|
DBG("Command failed");
|
||||||
|
data->retry_count = 0;
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||||
|
ofono_sim_passwd_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
cbd->user = sim;
|
||||||
|
|
||||||
|
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||||
|
query_passwd_state_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||||
|
struct sim_status sim_stat;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||||
|
GET_CARD_STATUS_RESULT_OK) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, sim_stat.retries, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
||||||
|
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||||
|
query_pin_retries_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pin_send_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct cb_data *cbd = user_data;
|
||||||
|
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (qmi_result_set_error(result, NULL)) {
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmi_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||||
|
ofono_sim_lock_unlock_cb_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||||
|
int passwd_len;
|
||||||
|
struct qmi_param *param;
|
||||||
|
struct qmi_uim_param_message_info *info_data;
|
||||||
|
unsigned char session_info_data[2];
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!passwd)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
passwd_len = strlen(passwd);
|
||||||
|
|
||||||
|
if (passwd_len <= 0 || passwd_len > 0xFF)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
param = qmi_param_new();
|
||||||
|
if (!param)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* param info */
|
||||||
|
info_data = alloca(2 + passwd_len);
|
||||||
|
info_data->pin_id = 0x01; /* PIN 1 */
|
||||||
|
info_data->length = (uint8_t) passwd_len;
|
||||||
|
memcpy(info_data->pin_value, passwd, passwd_len);
|
||||||
|
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_INFO, 2 + passwd_len,
|
||||||
|
info_data);
|
||||||
|
/* param Session Information */
|
||||||
|
session_info_data[0] = 0x6;
|
||||||
|
session_info_data[1] = 0x0;
|
||||||
|
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_SESSION_INFO, 2,
|
||||||
|
session_info_data);
|
||||||
|
|
||||||
|
if (qmi_service_send(data->uim, QMI_UIM_VERIFY_PIN, param,
|
||||||
|
pin_send_cb, cbd, g_free) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qmi_param_free(param);
|
||||||
|
|
||||||
|
error:
|
||||||
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
|
|
||||||
|
g_free(cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_sim *sim = user_data;
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
struct sim_status sim_stat;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||||
|
GET_CARD_STATUS_RESULT_OK) {
|
||||||
|
data->app_type = 0; /* Unknown */
|
||||||
|
sim_stat.card_state = 0x00; /* Absent */
|
||||||
|
} else {
|
||||||
|
data->app_type = sim_stat.app_type;
|
||||||
|
}
|
||||||
|
|
||||||
ofono_sim_register(sim);
|
ofono_sim_register(sim);
|
||||||
|
|
||||||
switch (data->card_state) {
|
switch (sim_stat.card_state) {
|
||||||
case 0x00: /* Absent */
|
case 0x00: /* Absent */
|
||||||
case 0x02: /* Error */
|
case 0x02: /* Error */
|
||||||
break;
|
break;
|
||||||
@@ -465,30 +821,44 @@ static void create_uim_cb(struct qmi_service *service, void *user_data)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
qmi_service_unref(data->uim);
|
|
||||||
|
|
||||||
ofono_sim_remove(sim);
|
ofono_sim_remove(sim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_sim *sim = user_data;
|
||||||
|
struct sim_data *data = ofono_sim_get_data(sim);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
ofono_error("Failed to request DMS service");
|
||||||
|
ofono_sim_remove(sim);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->dms = qmi_service_ref(service);
|
||||||
|
|
||||||
|
qmi_service_create(data->qmi_dev, QMI_SERVICE_UIM, create_uim_cb, sim,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int qmi_sim_probe(struct ofono_sim *sim,
|
static int qmi_sim_probe(struct ofono_sim *sim,
|
||||||
unsigned int vendor, void *user_data)
|
unsigned int vendor, void *user_data)
|
||||||
{
|
{
|
||||||
struct qmi_device *device = user_data;
|
struct qmi_device *device = user_data;
|
||||||
struct sim_data *data;
|
struct sim_data *data;
|
||||||
int i;
|
|
||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
data = g_new0(struct sim_data, 1);
|
data = g_new0(struct sim_data, 1);
|
||||||
|
|
||||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
data->qmi_dev = device;
|
||||||
|
|
||||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
||||||
data->retries[i] = -1;
|
|
||||||
|
|
||||||
ofono_sim_set_data(sim, data);
|
ofono_sim_set_data(sim, data);
|
||||||
|
|
||||||
qmi_service_create(device, QMI_SERVICE_UIM, create_uim_cb, sim, NULL);
|
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||||
|
create_dms_cb, sim, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -501,9 +871,18 @@ static void qmi_sim_remove(struct ofono_sim *sim)
|
|||||||
|
|
||||||
ofono_sim_set_data(sim, NULL);
|
ofono_sim_set_data(sim, NULL);
|
||||||
|
|
||||||
qmi_service_unregister_all(data->uim);
|
if (data->poll_source > 0)
|
||||||
|
g_source_remove(data->poll_source);
|
||||||
|
|
||||||
|
if (data->uim) {
|
||||||
|
qmi_service_unregister_all(data->uim);
|
||||||
qmi_service_unref(data->uim);
|
qmi_service_unref(data->uim);
|
||||||
|
data->uim = NULL;
|
||||||
|
}
|
||||||
|
if (data->dms) {
|
||||||
|
qmi_service_unregister_all(data->dms);
|
||||||
|
qmi_service_unref(data->dms);
|
||||||
|
}
|
||||||
|
|
||||||
g_free(data);
|
g_free(data);
|
||||||
}
|
}
|
||||||
@@ -516,8 +895,13 @@ static struct ofono_sim_driver driver = {
|
|||||||
.read_file_transparent = qmi_read_transparent,
|
.read_file_transparent = qmi_read_transparent,
|
||||||
.read_file_linear = qmi_read_record,
|
.read_file_linear = qmi_read_record,
|
||||||
.read_file_cyclic = qmi_read_record,
|
.read_file_cyclic = qmi_read_record,
|
||||||
|
.write_file_transparent = qmi_write_transparent,
|
||||||
|
.write_file_linear = qmi_write_linear,
|
||||||
|
.write_file_cyclic = qmi_write_cyclic,
|
||||||
|
.read_imsi = qmi_read_imsi,
|
||||||
.query_passwd_state = qmi_query_passwd_state,
|
.query_passwd_state = qmi_query_passwd_state,
|
||||||
.query_pin_retries = qmi_query_pin_retries,
|
.query_pin_retries = qmi_query_pin_retries,
|
||||||
|
.send_passwd = qmi_pin_send,
|
||||||
};
|
};
|
||||||
|
|
||||||
void qmi_sim_init(void)
|
void qmi_sim_init(void)
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ static void qmi_bearer_query(struct ofono_sms *sms,
|
|||||||
|
|
||||||
DBG("");
|
DBG("");
|
||||||
|
|
||||||
if (data->major < 1 && data->minor < 2)
|
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
|
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
|
||||||
@@ -315,7 +315,7 @@ static void qmi_bearer_set(struct ofono_sms *sms, int bearer,
|
|||||||
|
|
||||||
DBG("bearer %d", bearer);
|
DBG("bearer %d", bearer);
|
||||||
|
|
||||||
if (data->major < 1 && data->minor < 2)
|
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
domain = bearer_to_domain(bearer);
|
domain = bearer_to_domain(bearer);
|
||||||
@@ -411,7 +411,7 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
|
|||||||
new_list->count = GUINT16_TO_LE(1);
|
new_list->count = GUINT16_TO_LE(1);
|
||||||
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
|
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
|
||||||
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
|
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
|
||||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NV;
|
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NONE;
|
||||||
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
|
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
|
||||||
|
|
||||||
param = qmi_param_new();
|
param = qmi_param_new();
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
|
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
|
||||||
#define QMI_UIM_GET_FILE_ATTRIBUTES 36 /* Get file attributes */
|
#define QMI_UIM_GET_FILE_ATTRIBUTES 36 /* Get file attributes */
|
||||||
|
|
||||||
|
#define QMI_UIM_VERIFY_PIN 38 /* Verify PIN */
|
||||||
|
|
||||||
#define QMI_UIM_EVENT_REGISTRATION 46 /* Register for indications */
|
#define QMI_UIM_EVENT_REGISTRATION 46 /* Register for indications */
|
||||||
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
|
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
|
||||||
|
|
||||||
@@ -91,3 +93,12 @@ struct qmi_uim_file_attributes {
|
|||||||
uint16_t raw_len;
|
uint16_t raw_len;
|
||||||
uint8_t raw_value[0];
|
uint8_t raw_value[0];
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Verify PIN parameter */
|
||||||
|
#define QMI_UIM_PARAM_MESSAGE_SESSION_INFO 0x01
|
||||||
|
#define QMI_UIM_PARAM_MESSAGE_INFO 0x02
|
||||||
|
struct qmi_uim_param_message_info {
|
||||||
|
uint8_t pin_id;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t pin_value[0];
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|||||||
25
ofono/drivers/qmimodem/wda.h
Normal file
25
ofono/drivers/qmimodem/wda.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* oFono - Open Source Telephony
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Kerlink SA. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define QMI_WDA_SET_DATA_FORMAT 32 /* Set data format */
|
||||||
|
#define QMI_WDA_GET_DATA_FORMAT 33 /* Get data format */
|
||||||
|
|
||||||
|
/* Get and set data format interface */
|
||||||
|
#define QMI_WDA_LL_PROTOCOL 0x11 /* uint32_t */
|
||||||
|
#define QMI_WDA_DATA_LINK_PROTOCOL_UNKNOWN 0
|
||||||
|
#define QMI_WDA_DATA_LINK_PROTOCOL_802_3 1
|
||||||
|
#define QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP 2
|
||||||
@@ -30,6 +30,13 @@
|
|||||||
/* Start WDS network interface */
|
/* Start WDS network interface */
|
||||||
#define QMI_WDS_PARAM_APN 0x14 /* string */
|
#define QMI_WDS_PARAM_APN 0x14 /* string */
|
||||||
#define QMI_WDS_PARAM_IP_FAMILY 0x19 /* uint8 */
|
#define QMI_WDS_PARAM_IP_FAMILY 0x19 /* uint8 */
|
||||||
|
#define QMI_WDS_PARAM_USERNAME 0x17 /* string */
|
||||||
|
#define QMI_WDS_PARAM_PASSWORD 0x18 /* string */
|
||||||
|
#define QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE 0x16 /* uint8 */
|
||||||
|
|
||||||
|
#define QMI_WDS_AUTHENTICATION_NONE 0x0
|
||||||
|
#define QMI_WDS_AUTHENTICATION_PAP 0x1
|
||||||
|
#define QMI_WDS_AUTHENTICATION_CHAP 0x2
|
||||||
|
|
||||||
#define QMI_WDS_RESULT_PKT_HANDLE 0x01 /* uint32 */
|
#define QMI_WDS_RESULT_PKT_HANDLE 0x01 /* uint32 */
|
||||||
|
|
||||||
@@ -51,10 +58,12 @@ struct qmi_wds_notify_conn_status {
|
|||||||
|
|
||||||
/* Get the runtime data session settings */
|
/* Get the runtime data session settings */
|
||||||
#define QMI_WDS_RESULT_PDP_TYPE 0x11 /* uint8 */
|
#define QMI_WDS_RESULT_PDP_TYPE 0x11 /* uint8 */
|
||||||
|
#define QMI_WDS_RESULT_APN 0x14 /* string */
|
||||||
#define QMI_WDS_RESULT_PRIMARY_DNS 0x15 /* uint32 IPv4 */
|
#define QMI_WDS_RESULT_PRIMARY_DNS 0x15 /* uint32 IPv4 */
|
||||||
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
|
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
|
||||||
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
|
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
|
||||||
#define QMI_WDS_RESULT_GATEWAY 0x20 /* uint32 IPv4 */
|
#define QMI_WDS_RESULT_GATEWAY 0x20 /* uint32 IPv4 */
|
||||||
|
#define QMI_WDS_RESULT_GATEWAY_NETMASK 0x21 /* uint32 IPv4 */
|
||||||
#define QMI_WDS_RESULT_IP_FAMILY 0x2b /* uint8 */
|
#define QMI_WDS_RESULT_IP_FAMILY 0x2b /* uint8 */
|
||||||
|
|
||||||
#define QMI_WDS_PDP_TYPE_IPV4 0x00
|
#define QMI_WDS_PDP_TYPE_IPV4 0x00
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ struct qmi_wms_param_message {
|
|||||||
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
||||||
#define QMI_WMS_STORAGE_TYPE_NV 1
|
#define QMI_WMS_STORAGE_TYPE_NV 1
|
||||||
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
||||||
|
#define QMI_WMS_STORAGE_TYPE_NONE 255
|
||||||
|
|
||||||
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
||||||
|
|
||||||
|
|||||||
280
ofono/drivers/ril/ril_call_barring.c
Normal file
280
ofono/drivers/ril/ril_call_barring.c
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_sim_card.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/* See 3GPP 27.007 7.4 for possible values */
|
||||||
|
#define RIL_MAX_SERVICE_LENGTH 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ril.h does not state that string count must be given, but that is
|
||||||
|
* still expected by the modem
|
||||||
|
*/
|
||||||
|
#define RIL_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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_call_barring_cbd {
|
||||||
|
struct ril_call_barring *bd;
|
||||||
|
union _ofono_call_barring_cb {
|
||||||
|
ofono_call_barring_query_cb_t query;
|
||||||
|
ofono_call_barring_set_cb_t set;
|
||||||
|
gpointer ptr;
|
||||||
|
} cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ril_call_barring_cbd_free g_free
|
||||||
|
|
||||||
|
static inline struct ril_call_barring *ril_call_barring_get_data(
|
||||||
|
struct ofono_call_barring *b)
|
||||||
|
{
|
||||||
|
return ofono_call_barring_get_data(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_call_barring_cbd *ril_call_barring_cbd_new(
|
||||||
|
struct ril_call_barring *bd, void *cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_barring_cbd *cbd;
|
||||||
|
|
||||||
|
cbd = g_new0(struct ril_call_barring_cbd, 1);
|
||||||
|
cbd->bd = bd;
|
||||||
|
cbd->cb.ptr = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
return cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ril_call_barring_submit_request(struct ril_call_barring *bd,
|
||||||
|
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||||
|
void *cb, void *data)
|
||||||
|
{
|
||||||
|
grilio_queue_send_request_full(bd->q, req, code, response,
|
||||||
|
ril_call_barring_cbd_free,
|
||||||
|
ril_call_barring_cbd_new(bd, cb, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_barring_query_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_barring_cbd *cbd = user_data;
|
||||||
|
ofono_call_barring_query_cb_t cb = cbd->cb.query;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
int bearer_class = 0;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Services for which the specified barring facility is active.
|
||||||
|
* "0" means "disabled for all, -1 if unknown"
|
||||||
|
*/
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
grilio_parser_get_int32(&rilp, NULL); /* count */
|
||||||
|
grilio_parser_get_int32(&rilp, &bearer_class);
|
||||||
|
DBG("Active services: %d", bearer_class);
|
||||||
|
cb(ril_error_ok(&error), bearer_class, cbd->data);
|
||||||
|
} else {
|
||||||
|
ofono_error("Call Barring query error %d", status);
|
||||||
|
cb(ril_error_failure(&error), 0, cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||||
|
const char *lock, int cls,
|
||||||
|
ofono_call_barring_query_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||||
|
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||||
|
GRilIoRequest *req;
|
||||||
|
|
||||||
|
DBG("lock: %s, services to query: %d", lock, cls);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RIL modems do not support 7 as default bearer class. According to
|
||||||
|
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||||
|
* "All tele and bearer services"
|
||||||
|
*/
|
||||||
|
if (cls == BEARER_CLASS_DEFAULT) {
|
||||||
|
cls = SERVICE_CLASS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(cls_textual, "%d", cls);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See 3GPP 27.007 7.4 for parameter descriptions.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_barring_set_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_barring_cbd *cbd = user_data;
|
||||||
|
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
cb(ril_error_ok(&error), cbd->data);
|
||||||
|
} else {
|
||||||
|
ofono_error("Call Barring Set error %d", status);
|
||||||
|
cb(ril_error_failure(&error), cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_barring_set(struct ofono_call_barring *b,
|
||||||
|
const char *lock, int enable, const char *passwd, int cls,
|
||||||
|
ofono_call_barring_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||||
|
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
|
DBG("lock: %s, enable: %i, bearer class: %i", lock, enable, cls);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RIL modem does not support 7 as default bearer class. According to
|
||||||
|
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||||
|
* "All tele and bearer services"
|
||||||
|
*/
|
||||||
|
if (cls == BEARER_CLASS_DEFAULT) {
|
||||||
|
cls = SERVICE_CLASS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(cls_textual, "%d", cls);
|
||||||
|
|
||||||
|
/* See 3GPP 27.007 7.4 for parameter descriptions */
|
||||||
|
grilio_request_append_int32(req, RIL_SET_STRING_COUNT);
|
||||||
|
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||||
|
grilio_request_append_utf8(req, enable ?
|
||||||
|
RIL_FACILITY_LOCK :
|
||||||
|
RIL_FACILITY_UNLOCK);
|
||||||
|
grilio_request_append_utf8(req, passwd);
|
||||||
|
grilio_request_append_utf8(req, cls_textual);
|
||||||
|
grilio_request_append_utf8(req, ril_sim_card_app_aid(bd->card));
|
||||||
|
|
||||||
|
ril_call_barring_submit_request(bd, req,
|
||||||
|
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||||
|
ril_call_barring_set_cb, cb, data);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_barring_set_passwd_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_barring_cbd *cbd = user_data;
|
||||||
|
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
cb(ril_error_ok(&error), cbd->data);
|
||||||
|
} else {
|
||||||
|
ofono_error("Call Barring Set PW error %d", status);
|
||||||
|
cb(ril_error_failure(&error), cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_barring_set_passwd(struct ofono_call_barring *b,
|
||||||
|
const char *lock, const char *old_passwd,
|
||||||
|
const char *new_passwd, ofono_call_barring_set_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
grilio_request_append_int32(req, RIL_SET_PW_STRING_COUNT);
|
||||||
|
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||||
|
grilio_request_append_utf8(req, old_passwd);
|
||||||
|
grilio_request_append_utf8(req, new_passwd);
|
||||||
|
|
||||||
|
ril_call_barring_submit_request(bd, req,
|
||||||
|
RIL_REQUEST_CHANGE_BARRING_PASSWORD,
|
||||||
|
ril_call_barring_set_passwd_cb, cb, data);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_call_barring_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_call_barring *b = user_data;
|
||||||
|
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||||
|
|
||||||
|
GASSERT(bd->timer_id);
|
||||||
|
bd->timer_id = 0;
|
||||||
|
ofono_call_barring_register(b);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_call_barring_probe(struct ofono_call_barring *b,
|
||||||
|
unsigned int vendor, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
bd->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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_barring_remove(struct ofono_call_barring *b)
|
||||||
|
{
|
||||||
|
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
ofono_call_barring_set_data(b, NULL);
|
||||||
|
|
||||||
|
if (bd->timer_id > 0) {
|
||||||
|
g_source_remove(bd->timer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_sim_card_unref(bd->card);
|
||||||
|
grilio_queue_cancel_all(bd->q, FALSE);
|
||||||
|
grilio_queue_unref(bd->q);
|
||||||
|
g_free(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_call_barring_driver ril_call_barring_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_call_barring_probe,
|
||||||
|
.remove = ril_call_barring_remove,
|
||||||
|
.query = ril_call_barring_query,
|
||||||
|
.set = ril_call_barring_set,
|
||||||
|
.set_passwd = ril_call_barring_set_passwd
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
274
ofono/drivers/ril/ril_call_forward.c
Normal file
274
ofono/drivers/ril/ril_call_forward.c
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct ril_call_forward {
|
||||||
|
GRilIoQueue *q;
|
||||||
|
guint timer_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_call_forward_action {
|
||||||
|
CF_ACTION_DISABLE,
|
||||||
|
CF_ACTION_ENABLE,
|
||||||
|
CF_ACTION_INTERROGATE,
|
||||||
|
CF_ACTION_REGISTRATION,
|
||||||
|
CF_ACTION_ERASURE
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CF_TIME_DEFAULT (0)
|
||||||
|
|
||||||
|
struct ril_call_forward_cbd {
|
||||||
|
struct ril_call_forward *fd;
|
||||||
|
union _ofono_call_forward_cb {
|
||||||
|
ofono_call_forwarding_query_cb_t query;
|
||||||
|
ofono_call_forwarding_set_cb_t set;
|
||||||
|
gpointer ptr;
|
||||||
|
} cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct ril_call_forward *ril_call_forward_get_data(
|
||||||
|
struct ofono_call_forwarding *cf)
|
||||||
|
{
|
||||||
|
return ofono_call_forwarding_get_data(cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_cbd_free(gpointer cbd)
|
||||||
|
{
|
||||||
|
g_slice_free(struct ril_call_forward_cbd, cbd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_call_forward_cbd *ril_call_forward_cbd_new(void *cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_forward_cbd *cbd;
|
||||||
|
|
||||||
|
cbd = g_slice_new0(struct ril_call_forward_cbd);
|
||||||
|
cbd->cb.ptr = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
return cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
|
||||||
|
int type, int cls, const struct ofono_phone_number *number, int time)
|
||||||
|
{
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modem seems to respond with error to all requests
|
||||||
|
* made with bearer class BEARER_CLASS_DEFAULT.
|
||||||
|
*/
|
||||||
|
if (cls == BEARER_CLASS_DEFAULT) {
|
||||||
|
cls = SERVICE_CLASS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, action);
|
||||||
|
grilio_request_append_int32(req, type);
|
||||||
|
grilio_request_append_int32(req, cls); /* Service class */
|
||||||
|
if (number) {
|
||||||
|
grilio_request_append_int32(req, number->type);
|
||||||
|
grilio_request_append_utf8(req, number->number);
|
||||||
|
} else {
|
||||||
|
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||||
|
grilio_request_append_utf8(req, NULL); /* No number */
|
||||||
|
}
|
||||||
|
grilio_request_append_int32(req, time);
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_forward_cbd *cbd = user_data;
|
||||||
|
ofono_call_forwarding_set_cb_t cb = cbd->cb.set;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
cb(ril_error_ok(&error), cbd->data);
|
||||||
|
} else {
|
||||||
|
ofono_error("CF setting failed");
|
||||||
|
cb(ril_error_failure(&error), cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_set(struct ofono_call_forwarding *cf,
|
||||||
|
enum ril_call_forward_action cmd, int type, int cls,
|
||||||
|
const struct ofono_phone_number *number, int time,
|
||||||
|
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||||
|
GRilIoRequest *req = ril_call_forward_req(cmd, type, cls, number, time);
|
||||||
|
|
||||||
|
grilio_queue_send_request_full(fd->q, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||||
|
ril_call_forward_set_cb, ril_call_forward_cbd_free,
|
||||||
|
ril_call_forward_cbd_new(cb, data));
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
|
||||||
|
int type, int cls, const struct ofono_phone_number *number,
|
||||||
|
int time, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
ofono_info("cf registration");
|
||||||
|
ril_call_forward_set(cf, CF_ACTION_REGISTRATION, type, cls,
|
||||||
|
number, time, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_erasure(struct ofono_call_forwarding *cf,
|
||||||
|
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
ofono_info("cf erasure");
|
||||||
|
ril_call_forward_set(cf, CF_ACTION_ERASURE, type, cls,
|
||||||
|
NULL, CF_TIME_DEFAULT, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_deactivate(struct ofono_call_forwarding *cf,
|
||||||
|
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
ofono_info("cf disable");
|
||||||
|
ril_call_forward_set(cf, CF_ACTION_DISABLE, type, cls,
|
||||||
|
NULL, CF_TIME_DEFAULT, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_activate(struct ofono_call_forwarding *cf,
|
||||||
|
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
ofono_info("cf enable");
|
||||||
|
ril_call_forward_set(cf, CF_ACTION_ENABLE, type, cls,
|
||||||
|
NULL, CF_TIME_DEFAULT, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_query_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_forward_cbd *cbd = user_data;
|
||||||
|
ofono_call_forwarding_query_cb_t cb = cbd->cb.query;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
struct ofono_call_forwarding_condition *list = NULL;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int count = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
grilio_parser_get_int32(&rilp, &count);
|
||||||
|
|
||||||
|
list = g_new0(struct ofono_call_forwarding_condition, count);
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
struct ofono_call_forwarding_condition *fw = list + i;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
grilio_parser_get_int32(&rilp, &fw->status);
|
||||||
|
grilio_parser_get_int32(&rilp, NULL);
|
||||||
|
grilio_parser_get_int32(&rilp, &fw->cls);
|
||||||
|
grilio_parser_get_int32(&rilp, &fw->phone_number.type);
|
||||||
|
str = grilio_parser_get_utf8(&rilp);
|
||||||
|
if (str) {
|
||||||
|
strncpy(fw->phone_number.number, str,
|
||||||
|
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||||
|
fw->phone_number.number[
|
||||||
|
OFONO_MAX_PHONE_NUMBER_LENGTH] = 0;
|
||||||
|
g_free(str);
|
||||||
|
}
|
||||||
|
grilio_parser_get_int32(&rilp, &fw->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(ril_error_ok(&error), count, list, cbd->data);
|
||||||
|
g_free(list);
|
||||||
|
} else {
|
||||||
|
ofono_error("CF query failed");
|
||||||
|
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_query(struct ofono_call_forwarding *cf, int type,
|
||||||
|
int cls, ofono_call_forwarding_query_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||||
|
GRilIoRequest *req = ril_call_forward_req(CF_ACTION_INTERROGATE,
|
||||||
|
type, cls, NULL, CF_TIME_DEFAULT);
|
||||||
|
|
||||||
|
ofono_info("cf query");
|
||||||
|
grilio_queue_send_request_full(fd->q, req,
|
||||||
|
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||||
|
ril_call_forward_query_cb, ril_call_forward_cbd_free,
|
||||||
|
ril_call_forward_cbd_new(cb, data));
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_call_forward_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_call_forwarding *cf = user_data;
|
||||||
|
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||||
|
|
||||||
|
fd->timer_id = 0;
|
||||||
|
ofono_call_forwarding_register(cf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_call_forward_probe(struct ofono_call_forwarding *cf,
|
||||||
|
unsigned int vendor, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_call_forward *fd = g_try_new0(struct ril_call_forward, 1);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
fd->q = grilio_queue_new(ril_modem_io(modem));
|
||||||
|
fd->timer_id = g_idle_add(ril_call_forward_register, cf);
|
||||||
|
ofono_call_forwarding_set_data(cf, fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_forward_remove(struct ofono_call_forwarding *cf)
|
||||||
|
{
|
||||||
|
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
ofono_call_forwarding_set_data(cf, NULL);
|
||||||
|
|
||||||
|
if (fd->timer_id) {
|
||||||
|
g_source_remove(fd->timer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_queue_cancel_all(fd->q, FALSE);
|
||||||
|
grilio_queue_unref(fd->q);
|
||||||
|
g_free(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_call_forwarding_driver ril_call_forwarding_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_call_forward_probe,
|
||||||
|
.remove = ril_call_forward_remove,
|
||||||
|
.erasure = ril_call_forward_erasure,
|
||||||
|
.deactivation = ril_call_forward_deactivate,
|
||||||
|
.query = ril_call_forward_query,
|
||||||
|
.registration = ril_call_forward_registration,
|
||||||
|
.activation = ril_call_forward_activate
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
308
ofono/drivers/ril/ril_call_settings.c
Normal file
308
ofono/drivers/ril/ril_call_settings.c
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct ril_call_settings {
|
||||||
|
GRilIoQueue *q;
|
||||||
|
guint timer_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_call_settings_cbd {
|
||||||
|
union _ofono_call_settings_cb {
|
||||||
|
ofono_call_settings_status_cb_t status;
|
||||||
|
ofono_call_settings_set_cb_t set;
|
||||||
|
ofono_call_settings_clir_cb_t clir;
|
||||||
|
gpointer ptr;
|
||||||
|
} cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ril_call_settings_cbd_free g_free
|
||||||
|
|
||||||
|
static inline struct ril_call_settings *ril_call_settings_get_data(
|
||||||
|
struct ofono_call_settings *b)
|
||||||
|
{
|
||||||
|
return ofono_call_settings_get_data(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_call_settings_cbd *ril_call_settings_cbd_new(void *cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_settings_cbd *cbd;
|
||||||
|
|
||||||
|
cbd = g_new0(struct ril_call_settings_cbd, 1);
|
||||||
|
cbd->cb.ptr = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
return cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ril_call_settings_submit_req(struct ril_call_settings *sd,
|
||||||
|
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||||
|
void *cb, void *data)
|
||||||
|
{
|
||||||
|
grilio_queue_send_request_full(sd->q, req, code, response,
|
||||||
|
ril_call_settings_cbd_free,
|
||||||
|
ril_call_settings_cbd_new(cb, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_clip_query_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_settings_cbd *cbd = user_data;
|
||||||
|
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
/* data length of the response */
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
if (grilio_parser_get_int32(&rilp, &res) && res > 0) {
|
||||||
|
grilio_parser_get_int32(&rilp, &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(ril_error_ok(&error), res, cbd->data);
|
||||||
|
} else {
|
||||||
|
cb(ril_error_failure(&error), -1, cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_set_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_settings_cbd *cbd = user_data;
|
||||||
|
ofono_call_settings_set_cb_t cb = cbd->cb.set;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
cb(ril_error_ok(&error), cbd->data);
|
||||||
|
} else {
|
||||||
|
cb(ril_error_failure(&error), cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_cw_set(struct ofono_call_settings *cs, int mode,
|
||||||
|
int cls, ofono_call_settings_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||||
|
GRilIoRequest *req = grilio_request_sized_new(12);
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, 2); /* Number of params */
|
||||||
|
grilio_request_append_int32(req, mode); /* on/off */
|
||||||
|
|
||||||
|
/* Modem seems to respond with error to all queries
|
||||||
|
* or settings made with bearer class
|
||||||
|
* BEARER_CLASS_DEFAULT. Design decision: If given
|
||||||
|
* class is BEARER_CLASS_DEFAULT let's map it to
|
||||||
|
* SERVICE_CLASS_VOICE effectively making it the
|
||||||
|
* default bearer. This in line with API which is
|
||||||
|
* contains only voice anyways.
|
||||||
|
*/
|
||||||
|
if (cls == BEARER_CLASS_DEFAULT) {
|
||||||
|
cls = BEARER_CLASS_VOICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, cls); /* Service class */
|
||||||
|
|
||||||
|
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CALL_WAITING,
|
||||||
|
ril_call_settings_set_cb, cb, data);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_cw_query_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_settings_cbd *cbd = user_data;
|
||||||
|
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int res = 0;
|
||||||
|
int sv = 0;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
|
||||||
|
/* first value in int[] is len so let's skip that */
|
||||||
|
grilio_parser_get_int32(&rilp, NULL);
|
||||||
|
|
||||||
|
/* status of call waiting service, disabled is returned only if
|
||||||
|
* service is not active for any service class */
|
||||||
|
grilio_parser_get_int32(&rilp, &res);
|
||||||
|
DBG("CW enabled/disabled: %d", res);
|
||||||
|
|
||||||
|
if (res > 0) {
|
||||||
|
/* services for which call waiting is enabled,
|
||||||
|
27.007 7.12 */
|
||||||
|
grilio_parser_get_int32(&rilp, &sv);
|
||||||
|
DBG("CW enabled for: %d", sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(ril_error_ok(&error), sv, cbd->data);
|
||||||
|
} else {
|
||||||
|
cb(ril_error_failure(&error), -1, cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_cw_query(struct ofono_call_settings *cs, int cls,
|
||||||
|
ofono_call_settings_status_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||||
|
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, 1); /* Number of params */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RILD expects service class to be 0 as certain carriers can reject
|
||||||
|
* the query with specific service class
|
||||||
|
*/
|
||||||
|
grilio_request_append_int32(req, 0);
|
||||||
|
|
||||||
|
ril_call_settings_submit_req(sd, req, RIL_REQUEST_QUERY_CALL_WAITING,
|
||||||
|
ril_call_settings_cw_query_cb, cb, data);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_clip_query(struct ofono_call_settings *cs,
|
||||||
|
ofono_call_settings_status_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||||
|
|
||||||
|
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_QUERY_CLIP,
|
||||||
|
ril_call_settings_clip_query_cb, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_clir_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_settings_cbd *cbd = user_data;
|
||||||
|
ofono_call_settings_clir_cb_t cb = cbd->cb.clir;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int override = -1, network = -1;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
/*first value in int[] is len so let's skip that*/
|
||||||
|
grilio_parser_get_int32(&rilp, NULL);
|
||||||
|
/* Set HideCallerId property from network */
|
||||||
|
grilio_parser_get_int32(&rilp, &override);
|
||||||
|
/* CallingLineRestriction indicates the state of
|
||||||
|
the CLIR supplementary service in the network */
|
||||||
|
grilio_parser_get_int32(&rilp, &network);
|
||||||
|
|
||||||
|
cb(ril_error_ok(&error), override, network, cbd->data);
|
||||||
|
} else {
|
||||||
|
cb(ril_error_failure(&error), -1, -1, cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_clir_query(struct ofono_call_settings *cs,
|
||||||
|
ofono_call_settings_clir_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||||
|
|
||||||
|
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_GET_CLIR,
|
||||||
|
ril_call_settings_clir_cb, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_clir_set(struct ofono_call_settings *cs,
|
||||||
|
int mode, ofono_call_settings_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||||
|
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, 1); /* Number of params */
|
||||||
|
grilio_request_append_int32(req, mode); /* for outgoing calls */
|
||||||
|
|
||||||
|
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CLIR,
|
||||||
|
ril_call_settings_set_cb, cb, data);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_call_settings_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_call_settings *cs = user_data;
|
||||||
|
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
GASSERT(sd->timer_id);
|
||||||
|
sd->timer_id = 0;
|
||||||
|
ofono_call_settings_register(cs);
|
||||||
|
|
||||||
|
/* Single-shot */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_call_settings_probe(struct ofono_call_settings *cs,
|
||||||
|
unsigned int vendor, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_call_settings *sd = g_try_new0(struct ril_call_settings, 1);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
sd->q = grilio_queue_new(ril_modem_io(modem));
|
||||||
|
sd->timer_id = g_idle_add(ril_call_settings_register, cs);
|
||||||
|
ofono_call_settings_set_data(cs, sd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_settings_remove(struct ofono_call_settings *cs)
|
||||||
|
{
|
||||||
|
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
ofono_call_settings_set_data(cs, NULL);
|
||||||
|
|
||||||
|
if (sd->timer_id > 0) {
|
||||||
|
g_source_remove(sd->timer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_queue_cancel_all(sd->q, FALSE);
|
||||||
|
grilio_queue_unref(sd->q);
|
||||||
|
g_free(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_call_settings_driver ril_call_settings_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_call_settings_probe,
|
||||||
|
.remove = ril_call_settings_remove,
|
||||||
|
.clip_query = ril_call_settings_clip_query,
|
||||||
|
.cw_query = ril_call_settings_cw_query,
|
||||||
|
.cw_set = ril_call_settings_cw_set,
|
||||||
|
.clir_query = ril_call_settings_clir_query,
|
||||||
|
.clir_set = ril_call_settings_clir_set
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not supported in RIL API
|
||||||
|
* .colp_query = ril_call_settings_colp_query,
|
||||||
|
* .colr_query = ril_call_settings_colr_query
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
150
ofono/drivers/ril/ril_call_volume.c
Normal file
150
ofono/drivers/ril/ril_call_volume.c
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
struct ril_call_volume {
|
||||||
|
struct ofono_call_volume *v;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
guint timer_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_call_volume_req {
|
||||||
|
ofono_call_volume_cb_t cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct ril_call_volume *ril_call_volume_get_data(
|
||||||
|
struct ofono_call_volume *v)
|
||||||
|
{
|
||||||
|
return ofono_call_volume_get_data(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_volume_mute_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_call_volume_req *cbd = user_data;
|
||||||
|
ofono_call_volume_cb_t cb = cbd->cb;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
cb(ril_error_ok(&error), cbd->data);
|
||||||
|
} else {
|
||||||
|
ofono_error("Could not set the ril mute state");
|
||||||
|
cb(ril_error_failure(&error), cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_volume_mute(struct ofono_call_volume *v, int muted,
|
||||||
|
ofono_call_volume_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||||
|
struct ril_call_volume_req *cbd;
|
||||||
|
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||||
|
|
||||||
|
cbd = g_new(struct ril_call_volume_req, 1);
|
||||||
|
cbd->cb = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
|
||||||
|
DBG("%d", muted);
|
||||||
|
grilio_request_append_int32(req, 1);
|
||||||
|
grilio_request_append_int32(req, muted);
|
||||||
|
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_SET_MUTE,
|
||||||
|
ril_call_volume_mute_cb, g_free, cbd);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_volume_query_mute_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_call_volume *vd = user_data;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
int muted = 0;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
grilio_parser_get_int32(&rilp, NULL); /* Array length */
|
||||||
|
grilio_parser_get_int32(&rilp, &muted);
|
||||||
|
DBG("{%d}", muted);
|
||||||
|
ofono_call_volume_set_muted(vd->v, muted);
|
||||||
|
} else {
|
||||||
|
ofono_error("Could not retrive the ril mute state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_call_volume_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_call_volume *vd = user_data;
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
GASSERT(vd->timer_id);
|
||||||
|
vd->timer_id = 0;
|
||||||
|
ofono_call_volume_register(vd->v);
|
||||||
|
|
||||||
|
/* Probe the mute state */
|
||||||
|
grilio_queue_send_request_full(vd->q, NULL,
|
||||||
|
RIL_REQUEST_GET_MUTE, ril_call_volume_query_mute_cb, NULL, vd);
|
||||||
|
|
||||||
|
/* This makes the timeout a single-shot */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_call_volume_probe(struct ofono_call_volume *v,
|
||||||
|
unsigned int vendor, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_call_volume *vd = g_new0(struct ril_call_volume, 1);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
vd->v = v;
|
||||||
|
vd->q = grilio_queue_new(ril_modem_io(modem));
|
||||||
|
vd->timer_id = g_idle_add(ril_call_volume_register, vd);
|
||||||
|
ofono_call_volume_set_data(v, vd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_call_volume_remove(struct ofono_call_volume *v)
|
||||||
|
{
|
||||||
|
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
ofono_call_volume_set_data(v, NULL);
|
||||||
|
|
||||||
|
if (vd->timer_id) {
|
||||||
|
g_source_remove(vd->timer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_queue_cancel_all(vd->q, FALSE);
|
||||||
|
grilio_queue_unref(vd->q);
|
||||||
|
g_free(vd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_call_volume_driver ril_call_volume_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_call_volume_probe,
|
||||||
|
.remove = ril_call_volume_remove,
|
||||||
|
.mute = ril_call_volume_mute,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
230
ofono/drivers/ril/ril_cbs.c
Normal file
230
ofono/drivers/ril/ril_cbs.c
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <gutil_strv.h>
|
||||||
|
|
||||||
|
struct ril_cbs {
|
||||||
|
struct ofono_cbs *cbs;
|
||||||
|
GRilIoChannel *io;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
char *log_prefix;
|
||||||
|
gulong event_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_cbs_cbd {
|
||||||
|
struct ril_cbs *cd;
|
||||||
|
ofono_cbs_set_cb_t cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RIL_CBS_CHECK_RETRY_MS 1000
|
||||||
|
#define RIL_CBS_CHECK_RETRY_COUNT 30
|
||||||
|
|
||||||
|
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
|
||||||
|
|
||||||
|
#define ril_cbs_cbd_free g_free
|
||||||
|
|
||||||
|
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||||
|
ofono_cbs_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
|
||||||
|
|
||||||
|
cbd->cd = cd;
|
||||||
|
cbd->cb = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
return cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||||
|
gboolean activate, GRilIoChannelResponseFunc response,
|
||||||
|
GDestroyNotify destroy, void* user_data)
|
||||||
|
{
|
||||||
|
GRilIoRequest* req = grilio_request_sized_new(8);
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, 1);
|
||||||
|
grilio_request_append_int32(req, activate ? 0 :1);
|
||||||
|
|
||||||
|
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||||
|
grilio_queue_send_request_full(cd->q, req,
|
||||||
|
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||||
|
response, destroy, user_data);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||||
|
GRilIoChannelResponseFunc response,
|
||||||
|
GDestroyNotify destroy, void* user_data)
|
||||||
|
{
|
||||||
|
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
|
||||||
|
int i, n = gutil_strv_length(list);
|
||||||
|
GRilIoRequest* req = grilio_request_new();
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, n);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
const char *entry = list[i];
|
||||||
|
const char *delim = strchr(entry, '-');
|
||||||
|
int from, to;
|
||||||
|
if (delim) {
|
||||||
|
char **range = g_strsplit(topics, "-", 0);
|
||||||
|
from = atoi(range[0]);
|
||||||
|
to = atoi(range[1]);
|
||||||
|
g_strfreev(range);
|
||||||
|
} else {
|
||||||
|
from = to = atoi(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, from);
|
||||||
|
grilio_request_append_int32(req, to);
|
||||||
|
grilio_request_append_int32(req, 0);
|
||||||
|
grilio_request_append_int32(req, 0xff);
|
||||||
|
grilio_request_append_int32(req, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG_(cd, "configuring CB");
|
||||||
|
grilio_queue_send_request_full(cd->q, req,
|
||||||
|
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||||
|
response, destroy, user_data);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
g_strfreev(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_cbs_cbd *cbd = user_data;
|
||||||
|
|
||||||
|
if (cbd->cb) {
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
if (ril_status == RIL_E_SUCCESS) {
|
||||||
|
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||||
|
} else {
|
||||||
|
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||||
|
ofono_cbs_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||||
|
|
||||||
|
DBG_(cd, "%s", topics);
|
||||||
|
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
|
||||||
|
ril_cbs_cbd_new(cd, cb, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||||
|
ofono_cbs_set_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||||
|
|
||||||
|
DBG_(cd, "");
|
||||||
|
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
|
||||||
|
ril_cbs_cbd_new(cd, cb, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_cbs *cd = user_data;
|
||||||
|
|
||||||
|
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||||
|
DBG_(cd, "%u bytes", len);
|
||||||
|
ofono_cbs_notify(cd->cbs, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_cbs *cd = user_data;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
DBG_(cd, "registering for CB");
|
||||||
|
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||||
|
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||||
|
cd);
|
||||||
|
ofono_cbs_register(cd->cbs);
|
||||||
|
} else {
|
||||||
|
DBG_(cd, "failed to query CB config");
|
||||||
|
ofono_cbs_remove(cd->cbs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||||
|
GRilIoRequest* req = grilio_request_new();
|
||||||
|
|
||||||
|
ofono_cbs_set_data(cbs, cd);
|
||||||
|
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||||
|
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||||
|
cd->cbs = cbs;
|
||||||
|
|
||||||
|
DBG_(cd, "");
|
||||||
|
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||||
|
cd->q = grilio_queue_new(cd->io);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup
|
||||||
|
* especially if other RIL requests are running in parallel. We may
|
||||||
|
* have to retry a few times. Also, make it blocking in order to
|
||||||
|
* improve the chance of success.
|
||||||
|
*/
|
||||||
|
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||||
|
RIL_CBS_CHECK_RETRY_COUNT);
|
||||||
|
grilio_request_set_blocking(req, TRUE);
|
||||||
|
grilio_queue_send_request_full(cd->q, req,
|
||||||
|
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
|
||||||
|
ril_cbs_probe_done_cb, NULL, cd);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||||
|
{
|
||||||
|
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||||
|
|
||||||
|
DBG_(cd, "");
|
||||||
|
ofono_cbs_set_data(cbs, NULL);
|
||||||
|
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||||
|
grilio_channel_unref(cd->io);
|
||||||
|
grilio_queue_cancel_all(cd->q, FALSE);
|
||||||
|
grilio_queue_unref(cd->q);
|
||||||
|
g_free(cd->log_prefix);
|
||||||
|
g_free(cd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_cbs_driver ril_cbs_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_cbs_probe,
|
||||||
|
.remove = ril_cbs_remove,
|
||||||
|
.set_topics = ril_cbs_set_topics,
|
||||||
|
.clear_topics = ril_cbs_clear_topics
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
578
ofono/drivers/ril/ril_cell_info.c
Normal file
578
ofono/drivers/ril/ril_cell_info.c
Normal file
@@ -0,0 +1,578 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_cell_info.h"
|
||||||
|
#include "ril_sim_card.h"
|
||||||
|
#include "ril_radio.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <grilio_channel.h>
|
||||||
|
#include <grilio_request.h>
|
||||||
|
#include <grilio_parser.h>
|
||||||
|
|
||||||
|
#include <gutil_idlepool.h>
|
||||||
|
#include <gutil_misc.h>
|
||||||
|
|
||||||
|
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||||
|
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||||
|
#define MAX_RETRIES (5)
|
||||||
|
|
||||||
|
typedef GObjectClass RilCellInfoClass;
|
||||||
|
typedef struct ril_cell_info RilCellInfo;
|
||||||
|
|
||||||
|
struct ril_cell_info {
|
||||||
|
GObject object;
|
||||||
|
struct sailfish_cell_info info;
|
||||||
|
GRilIoChannel *io;
|
||||||
|
MceDisplay *display;
|
||||||
|
struct ril_radio *radio;
|
||||||
|
struct ril_sim_card *sim_card;
|
||||||
|
gulong display_state_event_id;
|
||||||
|
gulong radio_state_event_id;
|
||||||
|
gulong sim_status_event_id;
|
||||||
|
gboolean sim_card_ready;
|
||||||
|
char *log_prefix;
|
||||||
|
gulong event_id;
|
||||||
|
guint query_id;
|
||||||
|
guint set_rate_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_cell_info_signal {
|
||||||
|
SIGNAL_CELLS_CHANGED,
|
||||||
|
SIGNAL_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIGNAL_CELLS_CHANGED_NAME "ril-cell-info-cells-changed"
|
||||||
|
|
||||||
|
static guint ril_cell_info_signals[SIGNAL_COUNT] = { 0 };
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||||
|
#define RIL_CELL_INFO_TYPE (ril_cell_info_get_type())
|
||||||
|
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||||
|
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||||
|
|
||||||
|
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||||
|
|
||||||
|
static inline void ril_cell_free(struct sailfish_cell *cell)
|
||||||
|
{
|
||||||
|
g_slice_free(struct sailfish_cell, cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_free1(gpointer cell)
|
||||||
|
{
|
||||||
|
ril_cell_free(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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 sailfish_cell))) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
l1 = l1->next;
|
||||||
|
l2 = l2->next;
|
||||||
|
}
|
||||||
|
return !l1 && !l2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||||
|
{
|
||||||
|
if (!ril_cell_info_list_identical(self->info.cells, l)) {
|
||||||
|
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||||
|
self->info.cells = l;
|
||||||
|
g_signal_emit(self, ril_cell_info_signals
|
||||||
|
[SIGNAL_CELLS_CHANGED], 0);
|
||||||
|
} else {
|
||||||
|
g_slist_free_full(l, ril_cell_free1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||||
|
guint version, gboolean registered)
|
||||||
|
{
|
||||||
|
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||||
|
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||||
|
|
||||||
|
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||||
|
gsm->arfcn = 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) &&
|
||||||
|
(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");
|
||||||
|
ril_cell_free(cell);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||||
|
guint version, gboolean registered)
|
||||||
|
{
|
||||||
|
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||||
|
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||||
|
|
||||||
|
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||||
|
wcdma->uarfcn = 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%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");
|
||||||
|
ril_cell_free(cell);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||||
|
guint version, gboolean registered)
|
||||||
|
{
|
||||||
|
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||||
|
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||||
|
|
||||||
|
/* Optional RIL_CellIdentityLte_v12 part */
|
||||||
|
lte->earfcn = 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%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");
|
||||||
|
ril_cell_free(cell);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
|
||||||
|
struct sailfish_cell **cell_ptr)
|
||||||
|
{
|
||||||
|
int type, reg;
|
||||||
|
|
||||||
|
if (grilio_parser_get_int32(rilp, &type) &&
|
||||||
|
grilio_parser_get_int32(rilp, ®) &&
|
||||||
|
/* Skip timestamp */
|
||||||
|
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||||
|
int skip = 0;
|
||||||
|
struct sailfish_cell *cell = NULL;
|
||||||
|
|
||||||
|
/* Normalize the boolean value */
|
||||||
|
reg = (reg != FALSE);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case RIL_CELL_INFO_TYPE_GSM:
|
||||||
|
cell = ril_cell_info_parse_cell_gsm(rilp, v, reg);
|
||||||
|
break;
|
||||||
|
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||||
|
cell = ril_cell_info_parse_cell_wcdma(rilp, v, reg);
|
||||||
|
break;
|
||||||
|
case RIL_CELL_INFO_TYPE_LTE:
|
||||||
|
cell = ril_cell_info_parse_cell_lte(rilp, v, reg);
|
||||||
|
break;
|
||||||
|
case RIL_CELL_INFO_TYPE_CDMA:
|
||||||
|
skip = 10;
|
||||||
|
break;
|
||||||
|
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||||
|
skip = 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
skip = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell) {
|
||||||
|
*cell_ptr = cell;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||||
|
*cell_ptr = NULL;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*cell_ptr = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
|
||||||
|
{
|
||||||
|
GSList *l = NULL;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||||
|
struct sailfish_cell *c;
|
||||||
|
|
||||||
|
DBG("%d cell(s):", n);
|
||||||
|
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
|
||||||
|
if (c) {
|
||||||
|
l = g_slist_insert_sorted(l, c,
|
||||||
|
sailfish_cell_compare_func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GASSERT(grilio_parser_at_end(&rilp));
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||||
|
|
||||||
|
DBG_(self, "");
|
||||||
|
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||||
|
(io->ril_version, data, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||||
|
|
||||||
|
DBG_(self, "");
|
||||||
|
GASSERT(self->query_id);
|
||||||
|
self->query_id = 0;
|
||||||
|
ril_cell_info_update_cells(self, (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);
|
||||||
|
|
||||||
|
DBG_(self, "");
|
||||||
|
GASSERT(self->set_rate_id);
|
||||||
|
self->set_rate_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||||
|
{
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
|
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||||
|
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||||
|
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||||
|
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||||
|
NULL, self);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||||
|
{
|
||||||
|
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||||
|
|
||||||
|
grilio_request_append_int32(req, 1);
|
||||||
|
grilio_request_append_int32(req, ms);
|
||||||
|
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (self->sim_card_ready) {
|
||||||
|
ril_cell_info_set_rate(self,
|
||||||
|
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||||
|
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
|
||||||
|
{
|
||||||
|
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||||
|
{
|
||||||
|
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||||
|
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||||
|
ril_cell_info_query(self);
|
||||||
|
} else {
|
||||||
|
ril_cell_info_update_cells(self, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||||
|
{
|
||||||
|
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||||
|
|
||||||
|
DBG_(self, "%s", ril_radio_state_to_string(radio->state));
|
||||||
|
ril_cell_info_refresh(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||||
|
{
|
||||||
|
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||||
|
|
||||||
|
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||||
|
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||||
|
ril_cell_info_refresh(self);
|
||||||
|
ril_cell_info_update_rate(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sailfish_cell_info interface callbacks */
|
||||||
|
|
||||||
|
struct ril_cell_info_signal_data {
|
||||||
|
sailfish_cell_info_cb_t cb;
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct ril_cell_info *ril_cell_info_cast
|
||||||
|
(struct sailfish_cell_info *info)
|
||||||
|
{
|
||||||
|
return G_CAST(info, struct ril_cell_info, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
|
||||||
|
{
|
||||||
|
g_object_ref(ril_cell_info_cast(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
|
||||||
|
{
|
||||||
|
g_object_unref(ril_cell_info_cast(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_cell_info_signal_data *data = user_data;
|
||||||
|
|
||||||
|
data->cb(&self->info, data->arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_cells_disconnect_notify(gpointer data,
|
||||||
|
GClosure *closure)
|
||||||
|
{
|
||||||
|
g_slice_free1(sizeof(struct ril_cell_info_signal_data), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gulong ril_cell_info_add_cells_changed_handler_proc
|
||||||
|
(struct sailfish_cell_info *info,
|
||||||
|
sailfish_cell_info_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
if (cb) {
|
||||||
|
struct ril_cell_info_signal_data *data =
|
||||||
|
g_slice_new(struct ril_cell_info_signal_data);
|
||||||
|
|
||||||
|
data->cb = cb;
|
||||||
|
data->arg = arg;
|
||||||
|
return g_signal_connect_data(ril_cell_info_cast(info),
|
||||||
|
SIGNAL_CELLS_CHANGED_NAME,
|
||||||
|
G_CALLBACK(ril_cell_info_cells_changed_cb),
|
||||||
|
data, ril_cell_info_cells_disconnect_notify,
|
||||||
|
G_CONNECT_AFTER);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
|
||||||
|
gulong id)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(id)) {
|
||||||
|
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||||
|
const char *log_prefix, MceDisplay *display,
|
||||||
|
struct ril_radio *radio, struct ril_sim_card *sim_card)
|
||||||
|
{
|
||||||
|
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
|
||||||
|
ril_cell_info_ref_proc,
|
||||||
|
ril_cell_info_unref_proc,
|
||||||
|
ril_cell_info_add_cells_changed_handler_proc,
|
||||||
|
ril_cell_info_remove_handler_proc
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||||
|
|
||||||
|
self->info.proc = &ril_cell_info_proc;
|
||||||
|
self->io = grilio_channel_ref(io);
|
||||||
|
self->display = mce_display_ref(display);
|
||||||
|
self->radio = ril_radio_ref(radio);
|
||||||
|
self->sim_card = ril_sim_card_ref(sim_card);
|
||||||
|
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||||
|
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||||
|
DBG_(self, "");
|
||||||
|
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
|
||||||
|
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||||
|
self->display_state_event_id =
|
||||||
|
mce_display_add_state_changed_handler(display,
|
||||||
|
ril_cell_info_display_state_cb, self);
|
||||||
|
self->radio_state_event_id =
|
||||||
|
ril_radio_add_state_changed_handler(radio,
|
||||||
|
ril_cell_info_radio_state_cb, self);
|
||||||
|
self->sim_status_event_id =
|
||||||
|
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||||
|
ril_cell_info_sim_status_cb, self);
|
||||||
|
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||||
|
ril_cell_info_refresh(self);
|
||||||
|
ril_cell_info_update_rate(self);
|
||||||
|
return &self->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_dispose(GObject *object)
|
||||||
|
{
|
||||||
|
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||||
|
|
||||||
|
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
|
||||||
|
if (self->query_id) {
|
||||||
|
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||||
|
self->query_id = 0;
|
||||||
|
}
|
||||||
|
if (self->set_rate_id) {
|
||||||
|
grilio_channel_cancel_request(self->io, self->set_rate_id,
|
||||||
|
FALSE);
|
||||||
|
self->set_rate_id = 0;
|
||||||
|
}
|
||||||
|
gutil_disconnect_handlers(self->display,
|
||||||
|
&self->display_state_event_id, 1);
|
||||||
|
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
|
||||||
|
ril_sim_card_remove_handlers(self->sim_card,
|
||||||
|
&self->sim_status_event_id, 1);
|
||||||
|
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_finalize(GObject *object)
|
||||||
|
{
|
||||||
|
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||||
|
|
||||||
|
DBG_(self, "");
|
||||||
|
g_free(self->log_prefix);
|
||||||
|
grilio_channel_unref(self->io);
|
||||||
|
mce_display_unref(self->display);
|
||||||
|
ril_radio_unref(self->radio);
|
||||||
|
ril_sim_card_unref(self->sim_card);
|
||||||
|
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||||
|
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->dispose = ril_cell_info_dispose;
|
||||||
|
object_class->finalize = ril_cell_info_finalize;
|
||||||
|
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||||
|
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||||
|
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||||
|
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
35
ofono/drivers/ril/ril_cell_info.h
Normal file
35
ofono/drivers/ril/ril_cell_info.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_CELL_INFO_H
|
||||||
|
#define RIL_CELL_INFO_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
#include <mce_display.h>
|
||||||
|
#include <sailfish_cell_info.h>
|
||||||
|
|
||||||
|
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||||
|
const char *log_prefix, MceDisplay *display,
|
||||||
|
struct ril_radio *radio, struct ril_sim_card *sim_card);
|
||||||
|
|
||||||
|
#endif /* RIL_CELL_INFO_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
577
ofono/drivers/ril/ril_config.c
Normal file
577
ofono/drivers/ril/ril_config.c
Normal file
@@ -0,0 +1,577 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_config.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <gutil_intarray.h>
|
||||||
|
#include <gutil_ints.h>
|
||||||
|
#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 *val = g_key_file_get_string(file, group, key, NULL);
|
||||||
|
|
||||||
|
if (!val && strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||||
|
/* Check the common section */
|
||||||
|
val = g_key_file_get_string(file, RILCONF_SETTINGS_GROUP, key,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||||
|
const char *key, char delimiter)
|
||||||
|
{
|
||||||
|
char *str = ril_config_get_string(file, group, key);
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
char **strv, **p;
|
||||||
|
char delimiter_str[2];
|
||||||
|
|
||||||
|
delimiter_str[0] = delimiter;
|
||||||
|
delimiter_str[1] = 0;
|
||||||
|
strv = g_strsplit(str, delimiter_str, -1);
|
||||||
|
|
||||||
|
/* Strip whitespaces */
|
||||||
|
for (p = strv; *p; p++) {
|
||||||
|
*p = g_strstrip(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(str);
|
||||||
|
return strv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||||
|
const char *key, int *out_value)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
int value = g_key_file_get_integer(file, group, key, &error);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
if (out_value) {
|
||||||
|
*out_value = value;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
g_error_free(error);
|
||||||
|
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||||
|
/* Check the common section */
|
||||||
|
error = NULL;
|
||||||
|
value = g_key_file_get_integer(file,
|
||||||
|
RILCONF_SETTINGS_GROUP, key, &error);
|
||||||
|
if (!error) {
|
||||||
|
if (out_value) {
|
||||||
|
*out_value = value;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
g_error_free(error);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||||
|
const char *key, gboolean *out_value)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean value = g_key_file_get_boolean(file, group, key, &error);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
if (out_value) {
|
||||||
|
*out_value = value;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
g_error_free(error);
|
||||||
|
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||||
|
/* Check the common section */
|
||||||
|
error = NULL;
|
||||||
|
value = g_key_file_get_boolean(file,
|
||||||
|
RILCONF_SETTINGS_GROUP, key, &error);
|
||||||
|
if (!error) {
|
||||||
|
if (out_value) {
|
||||||
|
*out_value = value;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
g_error_free(error);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||||
|
const char *key, int flag, int *flags)
|
||||||
|
{
|
||||||
|
gboolean value;
|
||||||
|
|
||||||
|
if (ril_config_get_boolean(file, group, key, &value)) {
|
||||||
|
if (value) {
|
||||||
|
*flags |= flag;
|
||||||
|
} else {
|
||||||
|
*flags &= ~flag;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||||
|
const char *key, int *result,
|
||||||
|
const char *name, int value, ...)
|
||||||
|
{
|
||||||
|
char *str = ril_config_get_string(file, group, key);
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
/*
|
||||||
|
* Some people are thinking that # is a comment
|
||||||
|
* anywhere on the line, not just at the beginning
|
||||||
|
*/
|
||||||
|
char *comment = strchr(str, '#');
|
||||||
|
|
||||||
|
if (comment) *comment = 0;
|
||||||
|
g_strstrip(str);
|
||||||
|
if (strcasecmp(str, name)) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, value);
|
||||||
|
while ((name = va_arg(args, char*)) != NULL) {
|
||||||
|
value = va_arg(args, int);
|
||||||
|
if (!strcasecmp(str, name)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
ofono_error("Invalid %s config value (%s)", key, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(str);
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
if (result) {
|
||||||
|
*result = value;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||||
|
const char *key)
|
||||||
|
{
|
||||||
|
char *value = ril_config_get_string(file, group, key);
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ril_config_merge_files() function does the following:
|
||||||
|
*
|
||||||
|
* 1. Loads the specified key file (say, "/etc/foo.conf")
|
||||||
|
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
|
||||||
|
* for the files with the same suffix as the main file (e.g. "*.conf")
|
||||||
|
* 3. Sorts the files from the subdirectory (alphabetically)
|
||||||
|
* 4. Merges the contents of the additional files with the main file
|
||||||
|
* according to their sort order.
|
||||||
|
*
|
||||||
|
* When the entries are merged, keys and groups overwrite the exising
|
||||||
|
* ones by default. Keys can be suffixed with special characters to
|
||||||
|
* remove or modify the existing entries instead:
|
||||||
|
*
|
||||||
|
* ':' Sets the (default) value if the key is missing
|
||||||
|
* '+' Appends values to the string list
|
||||||
|
* '?' Appends only new (non-existent) values to the string list
|
||||||
|
* '-' Removes the values from the string list
|
||||||
|
*
|
||||||
|
* Both keys and groups can be prefixed with '!' to remove the entire key
|
||||||
|
* or group.
|
||||||
|
*
|
||||||
|
* For example if we merge these two files:
|
||||||
|
*
|
||||||
|
* /etc/foo.conf:
|
||||||
|
*
|
||||||
|
* [foo]
|
||||||
|
* a=1
|
||||||
|
* b=2,3
|
||||||
|
* c=4
|
||||||
|
* d=5
|
||||||
|
* [bar]
|
||||||
|
* e=5
|
||||||
|
*
|
||||||
|
* /etc/foo.d/bar.conf:
|
||||||
|
*
|
||||||
|
* [foo]
|
||||||
|
* a+=2
|
||||||
|
* b-=2
|
||||||
|
* c=5
|
||||||
|
* !d
|
||||||
|
* [!bar]
|
||||||
|
*
|
||||||
|
* we end up with this:
|
||||||
|
*
|
||||||
|
* [foo]
|
||||||
|
* a=1
|
||||||
|
* b=2,3
|
||||||
|
* c=5
|
||||||
|
*
|
||||||
|
* Not that the list separator is assumed to be ',' (rather than default ';').
|
||||||
|
* The keyfile passed to ril_config_merge_files() should use the same list
|
||||||
|
* separator, because the default values are copied from the config files
|
||||||
|
* as is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static gint ril_config_sort_files(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
/* The comparison function for g_ptr_array_sort() doesn't take
|
||||||
|
* the pointers from the array as arguments, it takes pointers
|
||||||
|
* to the pointers in the array. */
|
||||||
|
return strcmp(*(char**)a, *(char**)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **ril_config_collect_files(const char *path, const char *suffix)
|
||||||
|
{
|
||||||
|
/* Returns sorted list of regular files in the directory,
|
||||||
|
* optionally having the specified suffix (e.g. ".conf").
|
||||||
|
* Returns NULL if nothing appropriate has been found. */
|
||||||
|
char **files = NULL;
|
||||||
|
DIR *d = opendir(path);
|
||||||
|
|
||||||
|
if (d) {
|
||||||
|
GPtrArray *list = g_ptr_array_new();
|
||||||
|
const struct dirent *p;
|
||||||
|
|
||||||
|
while ((p = readdir(d)) != NULL) {
|
||||||
|
/* No need to even stat . and .. */
|
||||||
|
if (strcmp(p->d_name, ".") &&
|
||||||
|
strcmp(p->d_name, "..") && (!suffix ||
|
||||||
|
g_str_has_suffix(p->d_name, suffix))) {
|
||||||
|
struct stat st;
|
||||||
|
char *buf = g_strconcat(path, "/", p->d_name,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
|
||||||
|
g_ptr_array_add(list, buf);
|
||||||
|
} else {
|
||||||
|
g_free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list->len > 0) {
|
||||||
|
g_ptr_array_sort(list, ril_config_sort_files);
|
||||||
|
g_ptr_array_add(list, NULL);
|
||||||
|
files = (char**)g_ptr_array_free(list, FALSE);
|
||||||
|
} else {
|
||||||
|
g_ptr_array_free(list, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(d);
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_config_list_find(char **list, gsize len, const char *value)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (!strcmp(list[i], value)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_list_append(GKeyFile *conf, GKeyFile *k,
|
||||||
|
const char *group, const char *key,
|
||||||
|
char **values, gsize n, gboolean unique)
|
||||||
|
{
|
||||||
|
/* Note: will steal strings from values */
|
||||||
|
if (n > 0) {
|
||||||
|
int i;
|
||||||
|
gsize len = 0;
|
||||||
|
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||||
|
&len, NULL);
|
||||||
|
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
|
||||||
|
|
||||||
|
for (i = 0; i < (int)len; i++) {
|
||||||
|
g_ptr_array_add(newlist, list[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (int)n; i++) {
|
||||||
|
char *val = values[i];
|
||||||
|
|
||||||
|
if (!unique || ril_config_list_find((char**)
|
||||||
|
newlist->pdata, newlist->len, val) < 0) {
|
||||||
|
/* Move the string to the new list */
|
||||||
|
g_ptr_array_add(newlist, val);
|
||||||
|
memmove(values + i, values + i + 1,
|
||||||
|
sizeof(char*) * (n - i));
|
||||||
|
i--;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newlist->len > len) {
|
||||||
|
g_key_file_set_string_list(conf, group, key,
|
||||||
|
(const gchar * const *) newlist->pdata,
|
||||||
|
newlist->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strings are deallocated by GPtrArray */
|
||||||
|
g_ptr_array_free(newlist, TRUE);
|
||||||
|
g_free(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_list_remove(GKeyFile *conf, GKeyFile *k,
|
||||||
|
const char *group, const char *key, char **values, gsize n)
|
||||||
|
{
|
||||||
|
if (n > 0) {
|
||||||
|
gsize len = 0;
|
||||||
|
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||||
|
&len, NULL);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
gsize i;
|
||||||
|
const gsize oldlen = len;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
/* Remove all matching values */
|
||||||
|
while ((pos = ril_config_list_find(list, len,
|
||||||
|
values[i])) >= 0) {
|
||||||
|
g_free(list[pos]);
|
||||||
|
memmove(list + pos, list + pos + 1,
|
||||||
|
sizeof(char*) * (len - pos));
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < oldlen) {
|
||||||
|
g_key_file_set_string_list(conf, group, key,
|
||||||
|
(const gchar * const *) list, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_merge_group(GKeyFile *conf, GKeyFile *k,
|
||||||
|
const char *group)
|
||||||
|
{
|
||||||
|
gsize i, n = 0;
|
||||||
|
char **keys = g_key_file_get_keys(k, group, &n, NULL);
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
char *key = keys[i];
|
||||||
|
|
||||||
|
if (key[0] == '!') {
|
||||||
|
if (key[1]) {
|
||||||
|
g_key_file_remove_key(conf, group, key+1, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const gsize len = strlen(key);
|
||||||
|
const char last = (len > 0) ? key[len-1] : 0;
|
||||||
|
|
||||||
|
if (last == '+' || last == '?') {
|
||||||
|
gsize count = 0;
|
||||||
|
gchar **values = g_key_file_get_string_list(k,
|
||||||
|
group, key, &count, NULL);
|
||||||
|
|
||||||
|
key[len-1] = 0;
|
||||||
|
ril_config_list_append(conf, k, group, key,
|
||||||
|
values, count, last == '?');
|
||||||
|
g_strfreev(values);
|
||||||
|
} else if (last == '-') {
|
||||||
|
gsize count = 0;
|
||||||
|
gchar **values = g_key_file_get_string_list(k,
|
||||||
|
group, key, &count, NULL);
|
||||||
|
|
||||||
|
key[len-1] = 0;
|
||||||
|
ril_config_list_remove(conf, k, group, key,
|
||||||
|
values, count);
|
||||||
|
g_strfreev(values);
|
||||||
|
} else {
|
||||||
|
/* Overwrite the value (it must exist in k) */
|
||||||
|
gchar *value = g_key_file_get_value(k, group,
|
||||||
|
key, NULL);
|
||||||
|
|
||||||
|
if (last == ':') {
|
||||||
|
/* Default value */
|
||||||
|
key[len-1] = 0;
|
||||||
|
if (!g_key_file_has_key(conf,
|
||||||
|
group, key, NULL)) {
|
||||||
|
g_key_file_set_value(conf,
|
||||||
|
group, key, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_key_file_set_value(conf, group, key,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
g_free(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
|
||||||
|
{
|
||||||
|
gsize i, n = 0;
|
||||||
|
char **groups = g_key_file_get_groups(k, &n);
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
const char *group = groups[i];
|
||||||
|
|
||||||
|
if (group[0] == '!') {
|
||||||
|
g_key_file_remove_group(conf, group + 1, NULL);
|
||||||
|
} else {
|
||||||
|
ril_config_merge_group(conf, k, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_config_merge_file(GKeyFile *conf, const char *file)
|
||||||
|
{
|
||||||
|
GKeyFile *k = g_key_file_new();
|
||||||
|
|
||||||
|
g_key_file_set_list_separator(k, ',');
|
||||||
|
|
||||||
|
if (g_key_file_load_from_file(k, file, 0, NULL)) {
|
||||||
|
ril_config_merge_keyfile(conf, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_key_file_unref(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_config_merge_files(GKeyFile *conf, const char *file)
|
||||||
|
{
|
||||||
|
if (conf && file && file[0]) {
|
||||||
|
char *dot = strrchr(file, '.');
|
||||||
|
const char *suffix;
|
||||||
|
char *dir;
|
||||||
|
char **files;
|
||||||
|
|
||||||
|
if (!dot) {
|
||||||
|
dir = g_strconcat(file, ".d", NULL);
|
||||||
|
suffix = NULL;
|
||||||
|
} else if (!dot[1]) {
|
||||||
|
dir = g_strconcat(file, "d", NULL);
|
||||||
|
suffix = NULL;
|
||||||
|
} else {
|
||||||
|
/* 2 bytes for ".d" and 1 for NULL terminator */
|
||||||
|
dir = g_malloc(dot - file + 3);
|
||||||
|
strncpy(dir, file, dot - file);
|
||||||
|
strcpy(dir + (dot - file), ".d");
|
||||||
|
suffix = dot + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
files = ril_config_collect_files(dir, suffix);
|
||||||
|
g_free(dir);
|
||||||
|
|
||||||
|
/* Load the main config */
|
||||||
|
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
|
||||||
|
DBG("Loading %s", file);
|
||||||
|
ril_config_merge_file(conf, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files) {
|
||||||
|
char **ptr;
|
||||||
|
|
||||||
|
for (ptr = files; *ptr; ptr++) {
|
||||||
|
DBG("Merging %s", *ptr);
|
||||||
|
ril_config_merge_file(conf, *ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev(files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
52
ofono/drivers/ril/ril_config.h
Normal file
52
ofono/drivers/ril/ril_config.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_CONFIG_H
|
||||||
|
#define RIL_CONFIG_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
/* Utilities for parsing ril_subscription.conf */
|
||||||
|
|
||||||
|
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||||
|
|
||||||
|
void ril_config_merge_files(GKeyFile *conf, const char *file);
|
||||||
|
|
||||||
|
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||||
|
const char *key);
|
||||||
|
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||||
|
const char *key, char delimiter);
|
||||||
|
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||||
|
const char *key, int *value);
|
||||||
|
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||||
|
const char *key, gboolean *value);
|
||||||
|
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||||
|
const char *key, int flag, int *flags);
|
||||||
|
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||||
|
const char *key, int *result,
|
||||||
|
const char *name, int value, ...);
|
||||||
|
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||||
|
const char *key);
|
||||||
|
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||||
|
|
||||||
|
#endif /* RIL_CONFIG_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
348
ofono/drivers/ril/ril_constants.h
Normal file
348
ofono/drivers/ril/ril_constants.h
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Canonical Ltd.
|
||||||
|
* Copyright (C) 2013-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_CONSTANTS_H
|
||||||
|
#define __RIL_CONSTANTS_H 1
|
||||||
|
|
||||||
|
#include <ofono/ril-constants.h>
|
||||||
|
|
||||||
|
#define RIL_MAX_UUID_LENGTH 64
|
||||||
|
|
||||||
|
/* Radio state */
|
||||||
|
enum ril_radio_state {
|
||||||
|
RADIO_STATE_OFF = 0,
|
||||||
|
RADIO_STATE_UNAVAILABLE = 1,
|
||||||
|
RADIO_STATE_SIM_NOT_READY = 2,
|
||||||
|
RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3,
|
||||||
|
RADIO_STATE_SIM_READY = 4,
|
||||||
|
RADIO_STATE_RUIM_NOT_READY = 5,
|
||||||
|
RADIO_STATE_RUIM_READY = 6,
|
||||||
|
RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7,
|
||||||
|
RADIO_STATE_NV_NOT_READY = 8,
|
||||||
|
RADIO_STATE_NV_READY = 9,
|
||||||
|
RADIO_STATE_ON = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Preferred network types */
|
||||||
|
enum ril_pref_net_type {
|
||||||
|
PREF_NET_TYPE_GSM_WCDMA = 0,
|
||||||
|
PREF_NET_TYPE_GSM_ONLY = 1,
|
||||||
|
PREF_NET_TYPE_WCDMA = 2,
|
||||||
|
PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,
|
||||||
|
PREF_NET_TYPE_CDMA_EVDO_AUTO = 4,
|
||||||
|
PREF_NET_TYPE_CDMA_ONLY = 5,
|
||||||
|
PREF_NET_TYPE_EVDO_ONLY = 6,
|
||||||
|
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7,
|
||||||
|
PREF_NET_TYPE_LTE_CDMA_EVDO = 8,
|
||||||
|
PREF_NET_TYPE_LTE_GSM_WCDMA = 9,
|
||||||
|
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10,
|
||||||
|
PREF_NET_TYPE_LTE_ONLY = 11,
|
||||||
|
PREF_NET_TYPE_LTE_WCDMA = 12
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Radio technologies */
|
||||||
|
enum ril_radio_tech {
|
||||||
|
RADIO_TECH_UNKNOWN = 0,
|
||||||
|
RADIO_TECH_GPRS = 1,
|
||||||
|
RADIO_TECH_EDGE = 2,
|
||||||
|
RADIO_TECH_UMTS = 3,
|
||||||
|
RADIO_TECH_IS95A = 4,
|
||||||
|
RADIO_TECH_IS95B = 5,
|
||||||
|
RADIO_TECH_1xRTT = 6,
|
||||||
|
RADIO_TECH_EVDO_0 = 7,
|
||||||
|
RADIO_TECH_EVDO_A = 8,
|
||||||
|
RADIO_TECH_HSDPA = 9,
|
||||||
|
RADIO_TECH_HSUPA = 10,
|
||||||
|
RADIO_TECH_HSPA = 11,
|
||||||
|
RADIO_TECH_EVDO_B = 12,
|
||||||
|
RADIO_TECH_EHRPD = 13,
|
||||||
|
RADIO_TECH_LTE = 14,
|
||||||
|
RADIO_TECH_HSPAP = 15,
|
||||||
|
RADIO_TECH_GSM = 16,
|
||||||
|
RADIO_TECH_TD_SCDMA = 17,
|
||||||
|
RADIO_TECH_IWLAN = 18,
|
||||||
|
RADIO_TECH_LTE_CA = 19
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Radio capabilities */
|
||||||
|
enum ril_radio_access_family {
|
||||||
|
RAF_GPRS = (1 << RADIO_TECH_GPRS),
|
||||||
|
RAF_EDGE = (1 << RADIO_TECH_EDGE),
|
||||||
|
RAF_UMTS = (1 << RADIO_TECH_UMTS),
|
||||||
|
RAF_IS95A = (1 << RADIO_TECH_IS95A),
|
||||||
|
RAF_IS95B = (1 << RADIO_TECH_IS95B),
|
||||||
|
RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
|
||||||
|
RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
|
||||||
|
RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
|
||||||
|
RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
|
||||||
|
RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
|
||||||
|
RAF_HSPA = (1 << RADIO_TECH_HSPA),
|
||||||
|
RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
|
||||||
|
RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
|
||||||
|
RAF_LTE = (1 << RADIO_TECH_LTE),
|
||||||
|
RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
|
||||||
|
RAF_GSM = (1 << RADIO_TECH_GSM),
|
||||||
|
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
|
||||||
|
RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_radio_capability_phase {
|
||||||
|
RC_PHASE_CONFIGURED = 0,
|
||||||
|
RC_PHASE_START = 1,
|
||||||
|
RC_PHASE_APPLY = 2,
|
||||||
|
RC_PHASE_UNSOL_RSP = 3,
|
||||||
|
RC_PHASE_FINISH = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_radio_capability_status {
|
||||||
|
RC_STATUS_NONE = 0,
|
||||||
|
RC_STATUS_SUCCESS = 1,
|
||||||
|
RC_STATUS_FAIL = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RIL_RADIO_CAPABILITY_VERSION 1
|
||||||
|
|
||||||
|
struct ril_radio_capability {
|
||||||
|
int version;
|
||||||
|
int session;
|
||||||
|
enum ril_radio_capability_phase phase;
|
||||||
|
enum ril_radio_access_family rat;
|
||||||
|
char logicalModemUuid[RIL_MAX_UUID_LENGTH];
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_uicc_subscription_action {
|
||||||
|
RIL_UICC_SUBSCRIPTION_DEACTIVATE = 0,
|
||||||
|
RIL_UICC_SUBSCRIPTION_ACTIVATE = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
|
||||||
|
enum ril_call_fail_cause {
|
||||||
|
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
|
||||||
|
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
|
||||||
|
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
|
||||||
|
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
|
||||||
|
CALL_FAIL_NORMAL = 16,
|
||||||
|
CALL_FAIL_BUSY = 17,
|
||||||
|
CALL_FAIL_NO_USER_RESPONDING = 18,
|
||||||
|
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
|
||||||
|
CALL_FAIL_CALL_REJECTED = 21,
|
||||||
|
CALL_FAIL_NUMBER_CHANGED = 22,
|
||||||
|
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
|
||||||
|
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
|
||||||
|
CALL_FAIL_FACILITY_REJECTED = 29,
|
||||||
|
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
|
||||||
|
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
|
||||||
|
CALL_FAIL_CONGESTION = 34,
|
||||||
|
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
|
||||||
|
CALL_FAIL_TEMPORARY_FAILURE = 41,
|
||||||
|
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
|
||||||
|
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
|
||||||
|
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
|
||||||
|
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
|
||||||
|
CALL_FAIL_QOS_UNAVAILABLE = 49,
|
||||||
|
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
|
||||||
|
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
|
||||||
|
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
|
||||||
|
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
|
||||||
|
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
|
||||||
|
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
|
||||||
|
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
|
||||||
|
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
|
||||||
|
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
|
||||||
|
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
|
||||||
|
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
|
||||||
|
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
|
||||||
|
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
|
||||||
|
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
|
||||||
|
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
|
||||||
|
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
|
||||||
|
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
|
||||||
|
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
|
||||||
|
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
|
||||||
|
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
|
||||||
|
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
|
||||||
|
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
|
||||||
|
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
|
||||||
|
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
|
||||||
|
CALL_FAIL_CALL_BARRED = 240,
|
||||||
|
CALL_FAIL_FDN_BLOCKED = 241,
|
||||||
|
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
|
||||||
|
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
|
||||||
|
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
|
||||||
|
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
|
||||||
|
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
|
||||||
|
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
|
||||||
|
|
||||||
|
/* Not defined in ril.h but valid 3GPP specific cause values
|
||||||
|
* for call control. See 3GPP TS 24.008 Annex H. */
|
||||||
|
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
|
||||||
|
CALL_FAIL_PRE_EMPTION = 25
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_data_call_fail_cause {
|
||||||
|
PDP_FAIL_NONE = 0,
|
||||||
|
PDP_FAIL_OPERATOR_BARRED = 0x08,
|
||||||
|
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
|
||||||
|
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
|
||||||
|
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
|
||||||
|
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
|
||||||
|
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
|
||||||
|
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
|
||||||
|
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
|
||||||
|
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
|
||||||
|
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||||
|
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||||
|
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||||
|
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||||
|
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||||
|
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||||
|
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||||
|
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||||
|
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||||
|
PDP_FAIL_SIGNAL_LOST = -3,
|
||||||
|
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
|
||||||
|
PDP_FAIL_RADIO_POWER_OFF = -5,
|
||||||
|
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
|
||||||
|
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
|
||||||
|
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
|
||||||
|
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
|
||||||
|
|
||||||
|
/* RIL_REQUEST_SETUP_DATA_CALL */
|
||||||
|
enum ril_data_profile {
|
||||||
|
RIL_DATA_PROFILE_DEFAULT = 0,
|
||||||
|
RIL_DATA_PROFILE_TETHERED = 1,
|
||||||
|
RIL_DATA_PROFILE_IMS = 2,
|
||||||
|
RIL_DATA_PROFILE_FOTA = 3,
|
||||||
|
RIL_DATA_PROFILE_CBS = 4,
|
||||||
|
RIL_DATA_PROFILE_OEM_BASE = 1000,
|
||||||
|
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_auth {
|
||||||
|
RIL_AUTH_NONE = 0,
|
||||||
|
RIL_AUTH_PAP = 1,
|
||||||
|
RIL_AUTH_CHAP = 2,
|
||||||
|
RIL_AUTH_BOTH = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RIL_CARD_MAX_APPS 8
|
||||||
|
|
||||||
|
/* SIM card states */
|
||||||
|
enum ril_card_state {
|
||||||
|
RIL_CARDSTATE_UNKNOWN = -1,
|
||||||
|
RIL_CARDSTATE_ABSENT = 0,
|
||||||
|
RIL_CARDSTATE_PRESENT = 1,
|
||||||
|
RIL_CARDSTATE_ERROR = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SIM personalization substates */
|
||||||
|
enum ril_perso_substate {
|
||||||
|
RIL_PERSOSUBSTATE_UNKNOWN = 0,
|
||||||
|
RIL_PERSOSUBSTATE_IN_PROGRESS = 1,
|
||||||
|
RIL_PERSOSUBSTATE_READY = 2,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_NETWORK = 3,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_CORPORATE = 5,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_SIM = 7,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_NETWORK_PUK = 8,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11,
|
||||||
|
RIL_PERSOSUBSTATE_SIM_SIM_PUK = 12,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_NETWORK1 = 13,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_NETWORK2 = 14,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_HRPD = 15,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_CORPORATE = 16,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_RUIM = 18,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_HRPD_PUK = 21,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
|
||||||
|
RIL_PERSOSUBSTATE_RUIM_RUIM_PUK = 24
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SIM - App states */
|
||||||
|
enum ril_app_state {
|
||||||
|
RIL_APPSTATE_ILLEGAL = -1,
|
||||||
|
RIL_APPSTATE_UNKNOWN = 0,
|
||||||
|
RIL_APPSTATE_DETECTED = 1,
|
||||||
|
RIL_APPSTATE_PIN = 2,
|
||||||
|
RIL_APPSTATE_PUK = 3,
|
||||||
|
RIL_APPSTATE_SUBSCRIPTION_PERSO = 4,
|
||||||
|
RIL_APPSTATE_READY = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SIM - PIN states */
|
||||||
|
enum ril_pin_state {
|
||||||
|
RIL_PINSTATE_UNKNOWN = 0,
|
||||||
|
RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
|
||||||
|
RIL_PINSTATE_ENABLED_VERIFIED = 2,
|
||||||
|
RIL_PINSTATE_DISABLED = 3,
|
||||||
|
RIL_PINSTATE_ENABLED_BLOCKED = 4,
|
||||||
|
RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SIM - App types */
|
||||||
|
enum ril_app_type {
|
||||||
|
RIL_APPTYPE_UNKNOWN = 0,
|
||||||
|
RIL_APPTYPE_SIM = 1,
|
||||||
|
RIL_APPTYPE_USIM = 2,
|
||||||
|
RIL_APPTYPE_RUIM = 3,
|
||||||
|
RIL_APPTYPE_CSIM = 4,
|
||||||
|
RIL_APPTYPE_ISIM = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Cell info */
|
||||||
|
enum ril_cell_info_type {
|
||||||
|
RIL_CELL_INFO_TYPE_NONE = 0,
|
||||||
|
RIL_CELL_INFO_TYPE_GSM = 1,
|
||||||
|
RIL_CELL_INFO_TYPE_CDMA = 2,
|
||||||
|
RIL_CELL_INFO_TYPE_LTE = 3,
|
||||||
|
RIL_CELL_INFO_TYPE_WCDMA = 4,
|
||||||
|
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_restricted_state {
|
||||||
|
RIL_RESTRICTED_STATE_NONE = 0x00,
|
||||||
|
RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
|
||||||
|
RIL_RESTRICTED_STATE_CS_NORMAL = 0x02,
|
||||||
|
RIL_RESTRICTED_STATE_CS_ALL = 0x04,
|
||||||
|
RIL_RESTRICTED_STATE_PS_ALL = 0x10
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DATA_PROFILE_DEFAULT_STR "0"
|
||||||
|
|
||||||
|
/* Suplementary services Service class*/
|
||||||
|
#define SERVICE_CLASS_NONE 0
|
||||||
|
|
||||||
|
/* RIL_FACILITY_LOCK parameters */
|
||||||
|
#define RIL_FACILITY_UNLOCK "0"
|
||||||
|
#define RIL_FACILITY_LOCK "1"
|
||||||
|
|
||||||
|
#endif /*__RIL_CONSTANTS_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
1756
ofono/drivers/ril/ril_data.c
Normal file
1756
ofono/drivers/ril/ril_data.c
Normal file
File diff suppressed because it is too large
Load Diff
146
ofono/drivers/ril/ril_data.h
Normal file
146
ofono/drivers/ril/ril_data.h
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_DATA_H
|
||||||
|
#define RIL_DATA_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <ofono/gprs-context.h>
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
enum ril_data_call_active {
|
||||||
|
RIL_DATA_CALL_INACTIVE = 0,
|
||||||
|
RIL_DATA_CALL_LINK_DOWN = 1,
|
||||||
|
RIL_DATA_CALL_ACTIVE = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_data_call {
|
||||||
|
int cid;
|
||||||
|
enum ril_data_call_fail_cause status;
|
||||||
|
enum ril_data_call_active active;
|
||||||
|
enum ofono_gprs_proto prot;
|
||||||
|
int retry_time;
|
||||||
|
int mtu;
|
||||||
|
char *ifname;
|
||||||
|
char **dnses;
|
||||||
|
char **gateways;
|
||||||
|
char **addresses;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_data_call_list {
|
||||||
|
guint version;
|
||||||
|
guint num;
|
||||||
|
GSList *calls;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_data {
|
||||||
|
GObject object;
|
||||||
|
struct ril_data_priv *priv;
|
||||||
|
struct ril_data_call_list *data_calls;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_data_manager_flags {
|
||||||
|
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_data_allow_data_opt {
|
||||||
|
RIL_ALLOW_DATA_AUTO,
|
||||||
|
RIL_ALLOW_DATA_ENABLED,
|
||||||
|
RIL_ALLOW_DATA_DISABLED
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_data_call_format {
|
||||||
|
RIL_DATA_CALL_FORMAT_AUTO,
|
||||||
|
RIL_DATA_CALL_FORMAT_6 = 6,
|
||||||
|
RIL_DATA_CALL_FORMAT_9 = 9,
|
||||||
|
RIL_DATA_CALL_FORMAT_11 = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_data_options {
|
||||||
|
enum ril_data_allow_data_opt allow_data;
|
||||||
|
enum ril_data_call_format data_call_format;
|
||||||
|
unsigned int data_call_retry_limit;
|
||||||
|
unsigned int data_call_retry_delay_ms;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_data_role {
|
||||||
|
RIL_DATA_ROLE_NONE, /* Data not allowed */
|
||||||
|
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
|
||||||
|
RIL_DATA_ROLE_INTERNET /* Data is allowed at full speed */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_data_manager;
|
||||||
|
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||||
|
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||||
|
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||||
|
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
|
||||||
|
|
||||||
|
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||||
|
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
|
||||||
|
int ril_status, const struct ril_data_call *call,
|
||||||
|
void *arg);
|
||||||
|
typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
||||||
|
int ril_status, void *arg);
|
||||||
|
|
||||||
|
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||||
|
struct ril_radio *radio, struct ril_network *network,
|
||||||
|
GRilIoChannel *io, const struct ril_data_options *options,
|
||||||
|
const struct ril_slot_config *config,
|
||||||
|
struct ril_vendor *vendor);
|
||||||
|
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||||
|
void ril_data_unref(struct ril_data *data);
|
||||||
|
gboolean ril_data_allowed(struct ril_data *data);
|
||||||
|
void ril_data_poll_call_state(struct ril_data *data);
|
||||||
|
|
||||||
|
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||||
|
ril_data_cb_t cb, void *arg);
|
||||||
|
gulong ril_data_add_calls_changed_handler(struct ril_data *data,
|
||||||
|
ril_data_cb_t cb, void *arg);
|
||||||
|
void ril_data_remove_handler(struct ril_data *data, gulong id);
|
||||||
|
|
||||||
|
void ril_data_allow(struct ril_data *data, enum ril_data_role role);
|
||||||
|
|
||||||
|
struct ril_data_request;
|
||||||
|
struct ril_data_request *ril_data_call_setup(struct ril_data *data,
|
||||||
|
const struct ofono_gprs_primary_context *ctx,
|
||||||
|
ril_data_call_setup_cb_t cb, void *arg);
|
||||||
|
struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
|
||||||
|
int cid, ril_data_call_deactivate_cb_t cb, void *arg);
|
||||||
|
void ril_data_request_detach(struct ril_data_request *req);
|
||||||
|
void ril_data_request_cancel(struct ril_data_request *req);
|
||||||
|
|
||||||
|
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
|
||||||
|
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
|
||||||
|
|
||||||
|
void ril_data_call_free(struct ril_data_call *call);
|
||||||
|
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
||||||
|
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||||
|
int cid);
|
||||||
|
|
||||||
|
/* Constructors of various kinds of RIL requests */
|
||||||
|
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||||
|
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||||
|
|
||||||
|
#endif /* RIL_DATA_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
225
ofono/drivers/ril/ril_devinfo.c
Normal file
225
ofono/drivers/ril/ril_devinfo.c
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <gutil_idlequeue.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: No public RIL api to query manufacturer or model.
|
||||||
|
* Check where to get, could /system/build.prop be updated to have good values?
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ril_devinfo_cb_tag {
|
||||||
|
DEVINFO_QUERY_SERIAL = 1,
|
||||||
|
DEVINFO_QUERY_SVN
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_devinfo {
|
||||||
|
struct ofono_devinfo *info;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
GUtilIdleQueue *iq;
|
||||||
|
char *log_prefix;
|
||||||
|
char *imeisv;
|
||||||
|
char *imei;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_devinfo_cbd {
|
||||||
|
struct ril_devinfo *di;
|
||||||
|
ofono_devinfo_query_cb_t cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||||
|
#define ril_devinfo_cbd_free g_free
|
||||||
|
|
||||||
|
static inline struct ril_devinfo *ril_devinfo_get_data(
|
||||||
|
struct ofono_devinfo *info)
|
||||||
|
{
|
||||||
|
return ofono_devinfo_get_data(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_devinfo_cbd *ril_devinfo_cbd_new(struct ril_devinfo *di,
|
||||||
|
ofono_devinfo_query_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_devinfo_cbd *cbd = g_new0(struct ril_devinfo_cbd, 1);
|
||||||
|
|
||||||
|
cbd->di = di;
|
||||||
|
cbd->cb = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
return cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
|
||||||
|
ofono_devinfo_query_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
cb(ril_error_failure(&error), "", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query_revision_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_devinfo_cbd *cbd = user_data;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
char *res;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
res = grilio_parser_get_utf8(&rilp);
|
||||||
|
DBG_(cbd->di, "%s", res);
|
||||||
|
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
|
||||||
|
g_free(res);
|
||||||
|
} else {
|
||||||
|
cbd->cb(ril_error_failure(&error), NULL, cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||||
|
ofono_devinfo_query_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||||
|
|
||||||
|
DBG_(di, "");
|
||||||
|
grilio_queue_send_request_full(di->q, NULL,
|
||||||
|
RIL_REQUEST_BASEBAND_VERSION,
|
||||||
|
ril_devinfo_query_revision_cb,
|
||||||
|
ril_devinfo_cbd_free,
|
||||||
|
ril_devinfo_cbd_new(di, cb, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query_serial_cb(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_devinfo_cbd *cbd = user_data;
|
||||||
|
struct ril_devinfo *di = cbd->di;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
DBG_(di, "%s", di->imei);
|
||||||
|
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query_svn_cb(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_devinfo_cbd *cbd = user_data;
|
||||||
|
struct ril_devinfo *di = cbd->di;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
DBG_(di, "%s", di->imeisv);
|
||||||
|
if (di->imeisv && di->imeisv[0]) {
|
||||||
|
cbd->cb(ril_error_ok(&error), di->imeisv, cbd->data);
|
||||||
|
} else {
|
||||||
|
cbd->cb(ril_error_failure(&error), "", cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query(struct ril_devinfo *di,
|
||||||
|
enum ril_devinfo_cb_tag tag, GUtilIdleFunc fn,
|
||||||
|
ofono_devinfo_query_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
GVERIFY_FALSE(gutil_idle_queue_cancel_tag(di->iq, tag));
|
||||||
|
gutil_idle_queue_add_tag_full(di->iq, tag, fn,
|
||||||
|
ril_devinfo_cbd_new(di, cb, data),
|
||||||
|
ril_devinfo_cbd_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||||
|
ofono_devinfo_query_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||||
|
|
||||||
|
DBG_(di, "");
|
||||||
|
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
|
||||||
|
ril_devinfo_query_serial_cb, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_query_svn(struct ofono_devinfo *info,
|
||||||
|
ofono_devinfo_query_cb_t cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||||
|
|
||||||
|
DBG_(di, "");
|
||||||
|
ril_devinfo_query(di, DEVINFO_QUERY_SVN,
|
||||||
|
ril_devinfo_query_svn_cb, cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_devinfo *di = user_data;
|
||||||
|
|
||||||
|
DBG_(di, "");
|
||||||
|
ofono_devinfo_register(di->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
|
||||||
|
|
||||||
|
di->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||||
|
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||||
|
|
||||||
|
DBG_(di, "%s", modem->imei);
|
||||||
|
GASSERT(modem->imei);
|
||||||
|
|
||||||
|
di->q = grilio_queue_new(ril_modem_io(modem));
|
||||||
|
di->info = info;
|
||||||
|
di->imeisv = g_strdup(modem->imeisv);
|
||||||
|
di->imei = g_strdup(modem->imei);
|
||||||
|
di->iq = gutil_idle_queue_new();
|
||||||
|
gutil_idle_queue_add(di->iq, ril_devinfo_register, di);
|
||||||
|
ofono_devinfo_set_data(info, di);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||||
|
{
|
||||||
|
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||||
|
|
||||||
|
DBG_(di, "");
|
||||||
|
ofono_devinfo_set_data(info, NULL);
|
||||||
|
gutil_idle_queue_cancel_all(di->iq);
|
||||||
|
gutil_idle_queue_unref(di->iq);
|
||||||
|
grilio_queue_cancel_all(di->q, FALSE);
|
||||||
|
grilio_queue_unref(di->q);
|
||||||
|
g_free(di->log_prefix);
|
||||||
|
g_free(di->imeisv);
|
||||||
|
g_free(di->imei);
|
||||||
|
g_free(di);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_devinfo_driver ril_devinfo_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_devinfo_probe,
|
||||||
|
.remove = ril_devinfo_remove,
|
||||||
|
/* query_revision won't be called if query_model is missing */
|
||||||
|
.query_model = ril_devinfo_query_unsupported,
|
||||||
|
.query_revision = ril_devinfo_query_revision,
|
||||||
|
.query_serial = ril_devinfo_query_serial,
|
||||||
|
.query_svn = ril_devinfo_query_svn
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
258
ofono/drivers/ril/ril_ecclist.c
Normal file
258
ofono/drivers/ril/ril_ecclist.c
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_ecclist.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <gutil_strv.h>
|
||||||
|
#include <gutil_inotify.h>
|
||||||
|
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
|
||||||
|
typedef GObjectClass RilEccListClass;
|
||||||
|
typedef struct ril_ecclist RilEccList;
|
||||||
|
|
||||||
|
struct ril_ecclist_priv {
|
||||||
|
struct ofono_sim *sim;
|
||||||
|
GUtilInotifyWatchCallback *dir_watch;
|
||||||
|
GUtilInotifyWatchCallback *file_watch;
|
||||||
|
char *dir;
|
||||||
|
char *path;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_ecclist_signal {
|
||||||
|
SIGNAL_LIST_CHANGED,
|
||||||
|
SIGNAL_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIGNAL_LIST_CHANGED_NAME "ril-ecclist-changed"
|
||||||
|
|
||||||
|
static guint ril_ecclist_signals[SIGNAL_COUNT] = { 0 };
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
|
||||||
|
#define RIL_ECCLIST_TYPE (ril_ecclist_get_type())
|
||||||
|
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||||
|
RIL_ECCLIST_TYPE, RilEccList))
|
||||||
|
|
||||||
|
static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||||
|
{
|
||||||
|
struct ril_ecclist_priv *priv = self->priv;
|
||||||
|
char **list = NULL;
|
||||||
|
|
||||||
|
if (g_file_test(priv->path, G_FILE_TEST_EXISTS)) {
|
||||||
|
gsize len = 0;
|
||||||
|
gchar *content = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (g_file_get_contents(priv->path, &content, &len, &error)) {
|
||||||
|
char **ptr;
|
||||||
|
|
||||||
|
DBG("%s = %s", priv->name, content);
|
||||||
|
list = g_strsplit(content, ",", 0);
|
||||||
|
for (ptr = list; *ptr; ptr++) {
|
||||||
|
*ptr = g_strstrip(*ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
gutil_strv_sort(list, TRUE);
|
||||||
|
} else if (error) {
|
||||||
|
DBG("%s: %s", priv->path, GERRMSG(error));
|
||||||
|
g_error_free(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (content);
|
||||||
|
} else {
|
||||||
|
DBG("%s doesn't exist", priv->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_ecclist_update(struct ril_ecclist *self)
|
||||||
|
{
|
||||||
|
struct ril_ecclist_priv *priv = self->priv;
|
||||||
|
char **list = ril_ecclist_read(self);
|
||||||
|
|
||||||
|
if (!gutil_strv_equal(self->list, list)) {
|
||||||
|
DBG("%s changed", priv->name);
|
||||||
|
g_strfreev(self->list);
|
||||||
|
self->list = list;
|
||||||
|
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0);
|
||||||
|
} else {
|
||||||
|
g_strfreev(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_ecclist_changed(GUtilInotifyWatch *watch, guint mask,
|
||||||
|
guint cookie, const char *name, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||||
|
struct ril_ecclist_priv *priv = self->priv;
|
||||||
|
|
||||||
|
ril_ecclist_update(self);
|
||||||
|
|
||||||
|
if (mask & IN_IGNORED) {
|
||||||
|
DBG("file %s is gone", priv->path);
|
||||||
|
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||||
|
priv->file_watch = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
|
||||||
|
guint cookie, const char *name, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||||
|
struct ril_ecclist_priv *priv = self->priv;
|
||||||
|
|
||||||
|
DBG("0x%04x %s", mask, name);
|
||||||
|
if (!priv->file_watch && !g_strcmp0(name, priv->name)) {
|
||||||
|
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||||
|
IN_MODIFY | IN_CLOSE_WRITE,
|
||||||
|
ril_ecclist_changed, self);
|
||||||
|
if (priv->file_watch) {
|
||||||
|
DBG("watching %s", priv->path);
|
||||||
|
ril_ecclist_update(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & IN_IGNORED) {
|
||||||
|
DBG("%s is gone", priv->dir);
|
||||||
|
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||||
|
priv->dir_watch = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *self,
|
||||||
|
ril_ecclist_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||||
|
SIGNAL_LIST_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_ecclist_remove_handler(struct ril_ecclist *self, gulong id)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||||
|
g_signal_handler_disconnect(self, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_ecclist *ril_ecclist_new(const char *path)
|
||||||
|
{
|
||||||
|
if (path) {
|
||||||
|
struct ril_ecclist *self = g_object_new(RIL_ECCLIST_TYPE, 0);
|
||||||
|
struct ril_ecclist_priv *priv = self->priv;
|
||||||
|
|
||||||
|
DBG("%s", path);
|
||||||
|
priv->path = g_strdup(path);
|
||||||
|
priv->name = g_path_get_basename(path);
|
||||||
|
priv->dir = g_path_get_dirname(path);
|
||||||
|
priv->dir_watch = gutil_inotify_watch_callback_new(priv->dir,
|
||||||
|
IN_MODIFY|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|
|
||||||
|
IN_CREATE|IN_DELETE_SELF|IN_CLOSE_WRITE,
|
||||||
|
ril_ecclist_dir_changed, self);
|
||||||
|
if (priv->dir_watch) {
|
||||||
|
DBG("watching %s", priv->dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->list = ril_ecclist_read(self);
|
||||||
|
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||||
|
IN_MODIFY | IN_CLOSE_WRITE,
|
||||||
|
ril_ecclist_changed, self);
|
||||||
|
if (priv->file_watch) {
|
||||||
|
DBG("watching %s", priv->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
g_object_ref(RIL_ECCLIST(self));
|
||||||
|
return self;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_ecclist_unref(struct ril_ecclist *self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
g_object_unref(RIL_ECCLIST(self));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_ecclist_init(struct ril_ecclist *self)
|
||||||
|
{
|
||||||
|
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_ECCLIST_TYPE,
|
||||||
|
struct ril_ecclist_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_ecclist_dispose(GObject *object)
|
||||||
|
{
|
||||||
|
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||||
|
struct ril_ecclist_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (priv->dir_watch) {
|
||||||
|
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||||
|
priv->dir_watch = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->file_watch) {
|
||||||
|
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||||
|
priv->file_watch = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(ril_ecclist_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_ecclist_finalize(GObject *object)
|
||||||
|
{
|
||||||
|
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||||
|
struct ril_ecclist_priv *priv = self->priv;
|
||||||
|
|
||||||
|
GASSERT(!priv->dir_watch);
|
||||||
|
GASSERT(!priv->file_watch);
|
||||||
|
g_free(priv->dir);
|
||||||
|
g_free(priv->path);
|
||||||
|
g_free(priv->name);
|
||||||
|
g_strfreev(self->list);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(ril_ecclist_parent_class)->finalize(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_ecclist_class_init(RilEccListClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->dispose = ril_ecclist_dispose;
|
||||||
|
object_class->finalize = ril_ecclist_finalize;
|
||||||
|
g_type_class_add_private(klass, sizeof(struct ril_ecclist_priv));
|
||||||
|
ril_ecclist_signals[SIGNAL_LIST_CHANGED] =
|
||||||
|
g_signal_new(SIGNAL_LIST_CHANGED_NAME,
|
||||||
|
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||||
|
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
48
ofono/drivers/ril/ril_ecclist.h
Normal file
48
ofono/drivers/ril/ril_ecclist.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_ECCLIST_H
|
||||||
|
#define RIL_ECCLIST_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
struct ril_ecclist_priv;
|
||||||
|
|
||||||
|
struct ril_ecclist {
|
||||||
|
GObject object;
|
||||||
|
struct ril_ecclist_priv *priv;
|
||||||
|
char **list;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*ril_ecclist_cb_t)(struct ril_ecclist *ecc, void *arg);
|
||||||
|
|
||||||
|
struct ril_ecclist *ril_ecclist_new(const char *path);
|
||||||
|
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *ecc);
|
||||||
|
void ril_ecclist_unref(struct ril_ecclist *ecc);
|
||||||
|
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *ecc,
|
||||||
|
ril_ecclist_cb_t cb, void *arg);
|
||||||
|
void ril_ecclist_remove_handler(struct ril_ecclist *ecc, gulong id);
|
||||||
|
|
||||||
|
#endif /* RIL_ECCLIST_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
283
ofono/drivers/ril/ril_gprs.c
Normal file
283
ofono/drivers/ril/ril_gprs.c
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_network.h"
|
||||||
|
#include "ril_data.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module is the ofono_gprs_driver implementation for rilmodem.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
*
|
||||||
|
* 1. ofono_gprs_suspend/resume() are not used by this module, as
|
||||||
|
* the concept of suspended GPRS is not exposed by RILD.
|
||||||
|
*
|
||||||
|
* 2. ofono_gprs_bearer_notify() is never called as RILD does not
|
||||||
|
* expose an unsolicited event equivalent to +CPSB ( see 27.007
|
||||||
|
* 7.29 ), and the tech values returned by REQUEST_DATA/VOICE
|
||||||
|
* _REGISTRATION requests do not match the values defined for
|
||||||
|
* <AcT> in the +CPSB definition. Note, the values returned by
|
||||||
|
* the *REGISTRATION commands are aligned with those defined by
|
||||||
|
* +CREG ( see 27.003 7.2 ).
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ril_gprs {
|
||||||
|
struct ofono_gprs *gprs;
|
||||||
|
struct ril_modem *md;
|
||||||
|
struct ril_data *data;
|
||||||
|
struct ril_network *network;
|
||||||
|
GRilIoChannel *io;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
gboolean attached;
|
||||||
|
int max_cids;
|
||||||
|
enum network_registration_status registration_status;
|
||||||
|
guint register_id;
|
||||||
|
gulong network_event_id;
|
||||||
|
gulong data_event_id;
|
||||||
|
guint set_attached_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_gprs_cbd {
|
||||||
|
struct ril_gprs *gd;
|
||||||
|
ofono_gprs_cb_t cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ril_gprs_cbd_free g_free
|
||||||
|
|
||||||
|
static struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *ofono)
|
||||||
|
{
|
||||||
|
return ofono ? ofono_gprs_get_data(ofono) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
|
||||||
|
ofono_gprs_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_gprs_cbd *cbd = g_new0(struct ril_gprs_cbd, 1);
|
||||||
|
|
||||||
|
cbd->gd = gd;
|
||||||
|
cbd->cb = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
return cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum network_registration_status ril_gprs_fix_registration_status(
|
||||||
|
struct ril_gprs *gd, enum network_registration_status status)
|
||||||
|
{
|
||||||
|
if (!ril_data_allowed(gd->data)) {
|
||||||
|
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||||
|
} else {
|
||||||
|
/* TODO: need a way to make sure that SPDI information has
|
||||||
|
* already been read from the SIM (i.e. sim_spdi_read_cb in
|
||||||
|
* network.c has been called) */
|
||||||
|
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gd->md);
|
||||||
|
return ril_netreg_check_if_really_roaming(netreg, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
|
||||||
|
{
|
||||||
|
const enum network_registration_status status =
|
||||||
|
ril_gprs_fix_registration_status(gd, gd->network->data.status);
|
||||||
|
|
||||||
|
if (gd->registration_status != status) {
|
||||||
|
ofono_info("data reg changed %d -> %d (%s), attached %d",
|
||||||
|
gd->registration_status, status,
|
||||||
|
registration_status_to_string(status),
|
||||||
|
gd->attached);
|
||||||
|
gd->registration_status = status;
|
||||||
|
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_check_data_allowed(struct ril_gprs *gd)
|
||||||
|
{
|
||||||
|
DBG("%s %d %d", ril_modem_get_path(gd->md), ril_data_allowed(gd->data),
|
||||||
|
gd->attached);
|
||||||
|
if (!ril_data_allowed(gd->data) && gd->attached) {
|
||||||
|
gd->attached = FALSE;
|
||||||
|
if (gd->gprs) {
|
||||||
|
ofono_gprs_detached_notify(gd->gprs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_gprs_data_update_registration_state(gd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_gprs_set_attached_cb(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ofono_error error;
|
||||||
|
struct ril_gprs_cbd *cbd = user_data;
|
||||||
|
struct ril_gprs *gd = cbd->gd;
|
||||||
|
|
||||||
|
GASSERT(gd->set_attached_id);
|
||||||
|
gd->set_attached_id = 0;
|
||||||
|
ril_gprs_check_data_allowed(gd);
|
||||||
|
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||||
|
ofono_gprs_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||||
|
|
||||||
|
if (ril_data_allowed(gd->data) || !attached) {
|
||||||
|
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
|
||||||
|
if (gd->set_attached_id) {
|
||||||
|
g_source_remove(gd->set_attached_id);
|
||||||
|
}
|
||||||
|
gd->attached = attached;
|
||||||
|
gd->set_attached_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||||
|
ril_gprs_set_attached_cb,
|
||||||
|
ril_gprs_cbd_new(gd, cb, data),
|
||||||
|
ril_gprs_cbd_free);
|
||||||
|
} else {
|
||||||
|
struct ofono_error error;
|
||||||
|
DBG("%s not allowed to attach", ril_modem_get_path(gd->md));
|
||||||
|
cb(ril_error_failure(&error), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_allow_data_changed(struct ril_data *data, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_gprs *gd = user_data;
|
||||||
|
|
||||||
|
GASSERT(gd->data == data);
|
||||||
|
DBG("%s %d", ril_modem_get_path(gd->md), ril_data_allowed(data));
|
||||||
|
if (!gd->set_attached_id) {
|
||||||
|
ril_gprs_check_data_allowed(gd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_data_registration_state_changed(struct ril_network *net,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_gprs *gd = user_data;
|
||||||
|
const struct ril_registration_state *data = &net->data;
|
||||||
|
|
||||||
|
GASSERT(gd->network == net);
|
||||||
|
if (data->max_calls > gd->max_cids) {
|
||||||
|
DBG("Setting max cids to %d", data->max_calls);
|
||||||
|
gd->max_cids = data->max_calls;
|
||||||
|
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_gprs_data_update_registration_state(gd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
|
||||||
|
ofono_gprs_status_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||||
|
struct ofono_error error;
|
||||||
|
const enum network_registration_status status = gd->attached ?
|
||||||
|
gd->registration_status :
|
||||||
|
NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||||
|
|
||||||
|
|
||||||
|
DBG("%d (%s)", status, registration_status_to_string(status));
|
||||||
|
cb(ril_error_ok(&error), status, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_gprs_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_gprs *gd = user_data;
|
||||||
|
|
||||||
|
gd->register_id = 0;
|
||||||
|
gd->network_event_id = ril_network_add_data_state_changed_handler(
|
||||||
|
gd->network, ril_gprs_data_registration_state_changed, gd);
|
||||||
|
gd->data_event_id = ril_data_add_allow_changed_handler(gd->data,
|
||||||
|
ril_gprs_allow_data_changed, gd);
|
||||||
|
gd->registration_status = ril_gprs_fix_registration_status(gd,
|
||||||
|
gd->network->data.status);
|
||||||
|
|
||||||
|
gd->max_cids = gd->network->data.max_calls;
|
||||||
|
if (gd->max_cids > 0) {
|
||||||
|
DBG("Setting max cids to %d", gd->max_cids);
|
||||||
|
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_gprs_register(gd->gprs);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_gprs *gd = g_new0(struct ril_gprs, 1);
|
||||||
|
|
||||||
|
DBG("%s", ril_modem_get_path(modem));
|
||||||
|
gd->md = modem;
|
||||||
|
gd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||||
|
gd->q = grilio_queue_new(gd->io);
|
||||||
|
gd->data = ril_data_ref(modem->data);
|
||||||
|
gd->network = ril_network_ref(modem->network);
|
||||||
|
gd->gprs = gprs;
|
||||||
|
ofono_gprs_set_data(gprs, gd);
|
||||||
|
|
||||||
|
/* ofono crashes if we register right away */
|
||||||
|
gd->register_id = g_idle_add(ril_gprs_register, gd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_remove(struct ofono_gprs *gprs)
|
||||||
|
{
|
||||||
|
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||||
|
|
||||||
|
DBG("%s", ril_modem_get_path(gd->md));
|
||||||
|
ofono_gprs_set_data(gprs, NULL);
|
||||||
|
|
||||||
|
if (gd->set_attached_id) {
|
||||||
|
g_source_remove(gd->set_attached_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gd->register_id) {
|
||||||
|
g_source_remove(gd->register_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_network_remove_handler(gd->network, gd->network_event_id);
|
||||||
|
ril_network_unref(gd->network);
|
||||||
|
|
||||||
|
ril_data_remove_handler(gd->data, gd->data_event_id);
|
||||||
|
ril_data_unref(gd->data);
|
||||||
|
|
||||||
|
grilio_channel_unref(gd->io);
|
||||||
|
grilio_queue_cancel_all(gd->q, FALSE);
|
||||||
|
grilio_queue_unref(gd->q);
|
||||||
|
g_free(gd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_gprs_driver ril_gprs_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_gprs_probe,
|
||||||
|
.remove = ril_gprs_remove,
|
||||||
|
.set_attached = ril_gprs_set_attached,
|
||||||
|
.attached_status = ril_gprs_registration_status,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
601
ofono/drivers/ril/ril_gprs_context.c
Normal file
601
ofono/drivers/ril/ril_gprs_context.c
Normal file
@@ -0,0 +1,601 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_network.h"
|
||||||
|
#include "ril_data.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <gutil_strv.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ofono.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "mtu-watch.h"
|
||||||
|
|
||||||
|
#define CTX_ID_NONE ((unsigned int)(-1))
|
||||||
|
|
||||||
|
#define MAX_MTU 1280
|
||||||
|
|
||||||
|
struct ril_gprs_context_call {
|
||||||
|
struct ril_data_request *req;
|
||||||
|
ofono_gprs_context_cb_t cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_gprs_context {
|
||||||
|
struct ofono_gprs_context *gc;
|
||||||
|
struct ril_modem *modem;
|
||||||
|
struct ril_network *network;
|
||||||
|
struct ril_data *data;
|
||||||
|
guint active_ctx_cid;
|
||||||
|
gulong calls_changed_id;
|
||||||
|
struct mtu_watch *mtu_watch;
|
||||||
|
struct ril_data_call *active_call;
|
||||||
|
struct ril_gprs_context_call activate;
|
||||||
|
struct ril_gprs_context_call deactivate;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct ril_gprs_context *ril_gprs_context_get_data(
|
||||||
|
struct ofono_gprs_context *gprs)
|
||||||
|
{
|
||||||
|
return ofono_gprs_context_get_data(gprs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *ril_gprs_context_netmask(const char *bits)
|
||||||
|
{
|
||||||
|
if (bits) {
|
||||||
|
int nbits = atoi(bits);
|
||||||
|
if (nbits > 0 && nbits < 33) {
|
||||||
|
const char* str;
|
||||||
|
struct in_addr in;
|
||||||
|
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||||
|
((1u << nbits)-1) << (32-nbits));
|
||||||
|
str = inet_ntoa(in);
|
||||||
|
if (str) {
|
||||||
|
return g_strdup(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_gprs_context_address_family(const char *addr)
|
||||||
|
{
|
||||||
|
if (strchr(addr, ':')) {
|
||||||
|
return AF_INET6;
|
||||||
|
} else if (strchr(addr, '.')) {
|
||||||
|
return AF_INET;
|
||||||
|
} else {
|
||||||
|
return AF_UNSPEC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||||
|
{
|
||||||
|
if (gcd->active_call) {
|
||||||
|
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
|
||||||
|
ril_data_call_free(gcd->active_call);
|
||||||
|
gcd->active_call = NULL;
|
||||||
|
}
|
||||||
|
if (gcd->calls_changed_id) {
|
||||||
|
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||||
|
gcd->calls_changed_id = 0;
|
||||||
|
}
|
||||||
|
if (gcd->mtu_watch) {
|
||||||
|
mtu_watch_free(gcd->mtu_watch);
|
||||||
|
gcd->mtu_watch = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||||
|
const struct ril_data_call *call)
|
||||||
|
{
|
||||||
|
if (call) {
|
||||||
|
ril_data_call_free(gcd->active_call);
|
||||||
|
gcd->active_call = ril_data_call_dup(call);
|
||||||
|
if (!gcd->mtu_watch) {
|
||||||
|
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||||
|
}
|
||||||
|
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||||
|
ril_data_call_grab(gcd->data, call->cid, gcd);
|
||||||
|
} else {
|
||||||
|
ril_gprs_context_free_active_call(gcd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
|
||||||
|
{
|
||||||
|
if (gcd->active_call) {
|
||||||
|
ril_gprs_context_free_active_call(gcd);
|
||||||
|
if (gcd->deactivate.req) {
|
||||||
|
struct ril_gprs_context_call deact = gcd->deactivate;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Complete the deactivate request. We need to
|
||||||
|
* clear gcd->deactivate first because cancelling
|
||||||
|
* the deactivation request will probably result
|
||||||
|
* in ril_gprs_context_deactivate_primary_cb() being
|
||||||
|
* invoked with GRILIO_CANCELLED status. And we don't
|
||||||
|
* want to fail the disconnect request because this
|
||||||
|
* is a success (we wanted to disconnect the data
|
||||||
|
* call and it's gone).
|
||||||
|
*
|
||||||
|
* Additionally, we need to make sure that we don't
|
||||||
|
* complete the same request twice - that would crash
|
||||||
|
* the core.
|
||||||
|
*/
|
||||||
|
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||||
|
ril_data_request_cancel(deact.req);
|
||||||
|
if (deact.cb) {
|
||||||
|
struct ofono_error error;
|
||||||
|
ofono_info("Deactivated data call");
|
||||||
|
deact.cb(ril_error_ok(&error), deact.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gcd->active_ctx_cid != CTX_ID_NONE) {
|
||||||
|
guint id = gcd->active_ctx_cid;
|
||||||
|
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||||
|
DBG("ofono context %u deactivated", id);
|
||||||
|
ofono_gprs_context_deactivated(gcd->gc, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_set_address(struct ofono_gprs_context *gc,
|
||||||
|
const struct ril_data_call *call)
|
||||||
|
{
|
||||||
|
const char *ip_addr = NULL;
|
||||||
|
char *ip_mask = NULL;
|
||||||
|
const char *ipv6_addr = NULL;
|
||||||
|
unsigned char ipv6_prefix_length = 0;
|
||||||
|
char *tmp_ip_addr = NULL;
|
||||||
|
char *tmp_ipv6_addr = NULL;
|
||||||
|
char * const *list = call->addresses;
|
||||||
|
const int n = gutil_strv_length(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n && (!ipv6_addr || !ip_addr); i++) {
|
||||||
|
const char *addr = list[i];
|
||||||
|
switch (ril_gprs_context_address_family(addr)) {
|
||||||
|
case AF_INET:
|
||||||
|
if (!ip_addr) {
|
||||||
|
const char* s = strstr(addr, "/");
|
||||||
|
if (s) {
|
||||||
|
const gsize len = s - addr;
|
||||||
|
tmp_ip_addr = g_strndup(addr, len);
|
||||||
|
ip_addr = tmp_ip_addr;
|
||||||
|
ip_mask = ril_gprs_context_netmask(s+1);
|
||||||
|
} else {
|
||||||
|
ip_addr = addr;
|
||||||
|
}
|
||||||
|
if (!ip_mask) {
|
||||||
|
ip_mask = g_strdup("255.255.255.0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
if (!ipv6_addr) {
|
||||||
|
const char* s = strstr(addr, "/");
|
||||||
|
if (s) {
|
||||||
|
const gsize len = s - addr;
|
||||||
|
const int prefix = atoi(s + 1);
|
||||||
|
tmp_ipv6_addr = g_strndup(addr, len);
|
||||||
|
ipv6_addr = tmp_ipv6_addr;
|
||||||
|
if (prefix >= 0 && prefix <= 128) {
|
||||||
|
ipv6_prefix_length = prefix;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ipv6_addr = addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_gprs_context_set_ipv4_address(gc, ip_addr, TRUE);
|
||||||
|
ofono_gprs_context_set_ipv4_netmask(gc, ip_mask);
|
||||||
|
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr);
|
||||||
|
ofono_gprs_context_set_ipv6_prefix_length(gc, ipv6_prefix_length);
|
||||||
|
|
||||||
|
if (!ip_addr && !ipv6_addr) {
|
||||||
|
ofono_error("GPRS context: No IP address");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate temporary strings */
|
||||||
|
g_free(ip_mask);
|
||||||
|
g_free(tmp_ip_addr);
|
||||||
|
g_free(tmp_ipv6_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||||
|
const struct ril_data_call *call)
|
||||||
|
{
|
||||||
|
const char *ip_gw = NULL;
|
||||||
|
const char *ipv6_gw = NULL;
|
||||||
|
char * const *list = call->gateways;
|
||||||
|
const int n = gutil_strv_length(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Pick 1 gw for each protocol*/
|
||||||
|
for (i = 0; i < n && (!ipv6_gw || !ip_gw); i++) {
|
||||||
|
const char *addr = list[i];
|
||||||
|
switch (ril_gprs_context_address_family(addr)) {
|
||||||
|
case AF_INET:
|
||||||
|
if (!ip_gw) ip_gw = addr;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
if (!ipv6_gw) ipv6_gw = addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||||
|
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||||
|
const struct ril_data_call *call)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char * const *list = call->dnses;
|
||||||
|
const int n = gutil_strv_length(list);
|
||||||
|
const char **ip_dns = g_new0(const char *, n+1);
|
||||||
|
const char **ipv6_dns = g_new0(const char *, n+1);
|
||||||
|
const char **ip_ptr = ip_dns;
|
||||||
|
const char **ipv6_ptr = ipv6_dns;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
const char *addr = list[i];
|
||||||
|
switch (ril_gprs_context_address_family(addr)) {
|
||||||
|
case AF_INET:
|
||||||
|
*ip_ptr++ = addr;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
*ipv6_ptr++ = addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
|
||||||
|
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
|
||||||
|
|
||||||
|
g_free(ip_dns);
|
||||||
|
g_free(ipv6_dns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only compares the stuff that's important to us */
|
||||||
|
#define DATA_CALL_IFNAME_CHANGED (0x01)
|
||||||
|
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||||
|
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||||
|
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||||
|
#define DATA_CALL_ALL_CHANGED (0x0f)
|
||||||
|
static int ril_gprs_context_data_call_change(
|
||||||
|
const struct ril_data_call *c1,
|
||||||
|
const struct ril_data_call *c2)
|
||||||
|
{
|
||||||
|
if (!c1 && !c2) {
|
||||||
|
return 0;
|
||||||
|
} else if (c1 && c2) {
|
||||||
|
int changes = 0;
|
||||||
|
|
||||||
|
if (g_strcmp0(c1->ifname, c2->ifname)) {
|
||||||
|
changes |= DATA_CALL_IFNAME_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gutil_strv_equal(c1->addresses, c2->addresses)) {
|
||||||
|
changes |= DATA_CALL_ADDRESS_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gutil_strv_equal(c1->gateways, c2->gateways)) {
|
||||||
|
changes |= DATA_CALL_GATEWAY_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gutil_strv_equal(c1->dnses, c2->dnses)) {
|
||||||
|
changes |= DATA_CALL_DNS_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
} else {
|
||||||
|
return DATA_CALL_ALL_CHANGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||||
|
{
|
||||||
|
struct ril_gprs_context *gcd = arg;
|
||||||
|
struct ofono_gprs_context *gc = gcd->gc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gcd->active_call can't be NULL here because this callback
|
||||||
|
* is only registered when we have the active call and released
|
||||||
|
* when active call is dropped.
|
||||||
|
*/
|
||||||
|
struct ril_data_call *prev_call = gcd->active_call;
|
||||||
|
const struct ril_data_call *call =
|
||||||
|
ril_data_call_find(data->data_calls, prev_call->cid);
|
||||||
|
int change = 0;
|
||||||
|
|
||||||
|
if (call && call->active != RIL_DATA_CALL_INACTIVE) {
|
||||||
|
/* Compare it against the last known state */
|
||||||
|
change = ril_gprs_context_data_call_change(call, prev_call);
|
||||||
|
} else {
|
||||||
|
ofono_error("Clearing active context");
|
||||||
|
ril_gprs_context_set_disconnected(gcd);
|
||||||
|
call = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!call) {
|
||||||
|
/* We are not interested */
|
||||||
|
return;
|
||||||
|
} else if (!change) {
|
||||||
|
DBG("call %u didn't change", call->cid);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
DBG("call %u changed", call->cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prev_call points to the previous active call, and it will
|
||||||
|
* be deallocated at the end of the this function. Clear the
|
||||||
|
* gcd->active_call pointer so that we don't deallocate it twice.
|
||||||
|
*/
|
||||||
|
gcd->active_call = NULL;
|
||||||
|
ril_gprs_context_set_active_call(gcd, call);
|
||||||
|
|
||||||
|
if (call->status != PDP_FAIL_NONE) {
|
||||||
|
ofono_info("data call status: %d", call->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change & DATA_CALL_IFNAME_CHANGED) {
|
||||||
|
DBG("interface changed");
|
||||||
|
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change & DATA_CALL_ADDRESS_CHANGED) {
|
||||||
|
DBG("address changed");
|
||||||
|
ril_gprs_context_set_address(gc, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change & DATA_CALL_GATEWAY_CHANGED) {
|
||||||
|
DBG("gateway changed");
|
||||||
|
ril_gprs_context_set_gateway(gc, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change & DATA_CALL_DNS_CHANGED) {
|
||||||
|
DBG("name server(s) changed");
|
||||||
|
ril_gprs_context_set_dns_servers(gc, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
|
||||||
|
ril_data_call_free(prev_call);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||||
|
int ril_status, const struct ril_data_call *call,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_gprs_context *gcd = user_data;
|
||||||
|
struct ofono_gprs_context *gc = gcd->gc;
|
||||||
|
struct ofono_error error;
|
||||||
|
ofono_gprs_context_cb_t cb;
|
||||||
|
gpointer cb_data;
|
||||||
|
|
||||||
|
ril_error_init_failure(&error);
|
||||||
|
if (ril_status != RIL_E_SUCCESS) {
|
||||||
|
ofono_error("GPRS context: Reply failure: %s",
|
||||||
|
ril_error_to_string(ril_status));
|
||||||
|
} else if (!call) {
|
||||||
|
ofono_error("Unexpected data call failure");
|
||||||
|
} else if (call->status != PDP_FAIL_NONE) {
|
||||||
|
ofono_error("Unexpected data call status %d", call->status);
|
||||||
|
error.type = OFONO_ERROR_TYPE_CMS;
|
||||||
|
error.error = call->status;
|
||||||
|
} else if (!call->ifname) {
|
||||||
|
/* Must have interface */
|
||||||
|
ofono_error("GPRS context: No interface");
|
||||||
|
} else {
|
||||||
|
ofono_info("setting up data call");
|
||||||
|
|
||||||
|
GASSERT(!gcd->calls_changed_id);
|
||||||
|
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||||
|
gcd->calls_changed_id =
|
||||||
|
ril_data_add_calls_changed_handler(gcd->data,
|
||||||
|
ril_gprs_context_call_list_changed, gcd);
|
||||||
|
|
||||||
|
ril_gprs_context_set_active_call(gcd, call);
|
||||||
|
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||||
|
ril_gprs_context_set_address(gc, call);
|
||||||
|
ril_gprs_context_set_gateway(gc, call);
|
||||||
|
ril_gprs_context_set_dns_servers(gc, call);
|
||||||
|
ril_error_init_ok(&error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||||
|
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb = gcd->activate.cb;
|
||||||
|
cb_data = gcd->activate.data;
|
||||||
|
GASSERT(gcd->activate.req);
|
||||||
|
memset(&gcd->activate, 0, sizeof(gcd->activate));
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
cb(&error, cb_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||||
|
const struct ofono_gprs_primary_context *ctx,
|
||||||
|
ofono_gprs_context_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||||
|
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
|
||||||
|
const int rs = ofono_netreg_get_status(netreg);
|
||||||
|
|
||||||
|
/* Let's make sure that we aren't connecting when roaming not allowed */
|
||||||
|
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||||
|
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
|
||||||
|
if (!__ofono_gprs_get_roaming_allowed(gprs) &&
|
||||||
|
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||||
|
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||||
|
struct ofono_error error;
|
||||||
|
ofono_info("Can't activate context %u (roaming)",
|
||||||
|
ctx->cid);
|
||||||
|
cb(ril_error_failure(&error), data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_info("Activating context: %u", ctx->cid);
|
||||||
|
GASSERT(!gcd->activate.req);
|
||||||
|
GASSERT(ctx->cid != CTX_ID_NONE);
|
||||||
|
|
||||||
|
gcd->active_ctx_cid = ctx->cid;
|
||||||
|
gcd->activate.cb = cb;
|
||||||
|
gcd->activate.data = data;
|
||||||
|
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
|
||||||
|
ril_gprs_context_activate_primary_cb, gcd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
|
||||||
|
int ril_status, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_gprs_context *gcd = user_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data call list may change before the completion of the deactivate
|
||||||
|
* request, in that case ril_gprs_context_set_disconnected will be
|
||||||
|
* invoked and gcd->deactivate.req will be NULL.
|
||||||
|
*/
|
||||||
|
if (gcd->deactivate.req) {
|
||||||
|
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
|
||||||
|
gpointer cb_data = gcd->deactivate.data;
|
||||||
|
|
||||||
|
if (ril_status == RIL_E_SUCCESS) {
|
||||||
|
GASSERT(gcd->active_call);
|
||||||
|
ofono_info("Deactivated data call");
|
||||||
|
} else {
|
||||||
|
ofono_error("Deactivate failure: %s",
|
||||||
|
ril_error_to_string(ril_status));
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||||
|
if (cb) {
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
ril_gprs_context_free_active_call(gcd);
|
||||||
|
cb(ril_error_ok(&error), cb_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we are in the disconnected state */
|
||||||
|
ril_gprs_context_set_disconnected(gcd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int id, ofono_gprs_context_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||||
|
|
||||||
|
GASSERT(gcd->active_ctx_cid == id);
|
||||||
|
ofono_info("Deactivating context: %u", id);
|
||||||
|
|
||||||
|
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||||
|
gcd->deactivate.cb = cb;
|
||||||
|
gcd->deactivate.data = data;
|
||||||
|
gcd->deactivate.req = ril_data_call_deactivate(gcd->data,
|
||||||
|
gcd->active_call->cid,
|
||||||
|
ril_gprs_context_deactivate_primary_cb, gcd);
|
||||||
|
} else if (cb) {
|
||||||
|
struct ofono_error error;
|
||||||
|
cb(ril_error_ok(&error), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int id)
|
||||||
|
{
|
||||||
|
DBG("%u", id);
|
||||||
|
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||||
|
unsigned int vendor, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_gprs_context *gcd = g_new0(struct ril_gprs_context, 1);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
gcd->gc = gc;
|
||||||
|
gcd->modem = modem;
|
||||||
|
gcd->network = ril_network_ref(modem->network);
|
||||||
|
gcd->data = ril_data_ref(modem->data);
|
||||||
|
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||||
|
ofono_gprs_context_set_data(gc, gcd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||||
|
{
|
||||||
|
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
ofono_gprs_context_set_data(gc, NULL);
|
||||||
|
|
||||||
|
if (gcd->activate.req) {
|
||||||
|
/*
|
||||||
|
* The core has already completed its pending D-Bus
|
||||||
|
* request, invoking the completion callback will
|
||||||
|
* cause libdbus to panic.
|
||||||
|
*/
|
||||||
|
ril_data_request_detach(gcd->activate.req);
|
||||||
|
ril_data_request_cancel(gcd->activate.req);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gcd->deactivate.req) {
|
||||||
|
/* Let it complete but we won't be around to be notified. */
|
||||||
|
ril_data_request_detach(gcd->deactivate.req);
|
||||||
|
} else if (gcd->active_call) {
|
||||||
|
ril_data_call_deactivate(gcd->data, gcd->active_call->cid,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||||
|
ril_data_unref(gcd->data);
|
||||||
|
ril_network_unref(gcd->network);
|
||||||
|
ril_data_call_free(gcd->active_call);
|
||||||
|
mtu_watch_free(gcd->mtu_watch);
|
||||||
|
g_free(gcd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_gprs_context_driver ril_gprs_context_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_gprs_context_probe,
|
||||||
|
.remove = ril_gprs_context_remove,
|
||||||
|
.activate_primary = ril_gprs_context_activate_primary,
|
||||||
|
.deactivate_primary = ril_gprs_context_deactivate_primary,
|
||||||
|
.detach_shutdown = ril_gprs_context_detach_shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
31
ofono/drivers/ril/ril_log.h
Normal file
31
ofono/drivers/ril/ril_log.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 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_LOG_H
|
||||||
|
#define RIL_LOG_H
|
||||||
|
|
||||||
|
#define GLOG_MODULE_NAME ril_log
|
||||||
|
#include <gutil_log.h>
|
||||||
|
#include <ofono/log.h>
|
||||||
|
|
||||||
|
#endif /* RIL_LOG_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
520
ofono/drivers/ril/ril_modem.c
Normal file
520
ofono/drivers/ril/ril_modem.c
Normal file
@@ -0,0 +1,520 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_network.h"
|
||||||
|
#include "ril_radio.h"
|
||||||
|
#include "ril_sim_card.h"
|
||||||
|
#include "ril_sim_settings.h"
|
||||||
|
#include "ril_cell_info.h"
|
||||||
|
#include "ril_data.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "ofono.h"
|
||||||
|
|
||||||
|
#include <ofono/watch.h>
|
||||||
|
|
||||||
|
#define MAX_PDP_CONTEXTS (2)
|
||||||
|
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||||
|
|
||||||
|
enum ril_modem_power_state {
|
||||||
|
POWERED_OFF,
|
||||||
|
POWERED_ON,
|
||||||
|
POWERING_OFF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_modem_online_state {
|
||||||
|
OFFLINE,
|
||||||
|
GOING_ONLINE,
|
||||||
|
ONLINE,
|
||||||
|
GOING_OFFLINE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_modem_online_request {
|
||||||
|
ofono_modem_online_cb_t cb;
|
||||||
|
struct ril_modem_data *md;
|
||||||
|
void *data;
|
||||||
|
guint timeout_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_modem_data {
|
||||||
|
struct ril_modem modem;
|
||||||
|
struct ofono_watch *watch;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
char *log_prefix;
|
||||||
|
char *imeisv;
|
||||||
|
char *imei;
|
||||||
|
char *ecclist_file;
|
||||||
|
gulong imsi_event_id;
|
||||||
|
|
||||||
|
guint online_check_id;
|
||||||
|
enum ril_modem_power_state power_state;
|
||||||
|
gulong radio_state_event_id;
|
||||||
|
|
||||||
|
struct ril_modem_online_request set_online;
|
||||||
|
struct ril_modem_online_request set_offline;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RADIO_POWER_TAG(md) (md)
|
||||||
|
|
||||||
|
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
|
||||||
|
|
||||||
|
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ofono_modem_get_data(o);
|
||||||
|
GASSERT(md->modem.ofono == o);
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *ril_modem_get_atom_data(struct ril_modem *modem,
|
||||||
|
enum ofono_atom_type type)
|
||||||
|
{
|
||||||
|
if (modem && modem->ofono) {
|
||||||
|
struct ofono_atom *atom =
|
||||||
|
__ofono_modem_find_atom(modem->ofono, type);
|
||||||
|
|
||||||
|
if (atom) {
|
||||||
|
return __ofono_atom_get_data(atom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
|
||||||
|
{
|
||||||
|
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
|
||||||
|
{
|
||||||
|
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
|
||||||
|
{
|
||||||
|
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct ofono_radio_settings *ril_modem_radio_settings(
|
||||||
|
struct ril_modem *modem)
|
||||||
|
{
|
||||||
|
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_modem_delete(struct ril_modem *md)
|
||||||
|
{
|
||||||
|
if (md && md->ofono) {
|
||||||
|
ofono_modem_remove(md->ofono);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||||
|
{
|
||||||
|
if (req->timeout_id) {
|
||||||
|
g_source_remove(req->timeout_id);
|
||||||
|
req->timeout_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->cb) {
|
||||||
|
struct ofono_error error;
|
||||||
|
ofono_modem_online_cb_t cb = req->cb;
|
||||||
|
void *data = req->data;
|
||||||
|
|
||||||
|
req->cb = NULL;
|
||||||
|
req->data = NULL;
|
||||||
|
cb(ril_error_ok(&error), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||||
|
{
|
||||||
|
switch (md->modem.radio->state) {
|
||||||
|
case RADIO_STATE_ON:
|
||||||
|
DBG("online");
|
||||||
|
ril_modem_online_request_ok(&md->set_online);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RADIO_STATE_OFF:
|
||||||
|
case RADIO_STATE_UNAVAILABLE:
|
||||||
|
DBG("offline");
|
||||||
|
ril_modem_online_request_ok(&md->set_offline);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
|
||||||
|
md->power_state == POWERING_OFF) {
|
||||||
|
md->power_state = POWERED_OFF;
|
||||||
|
if (md->modem.ofono) {
|
||||||
|
ofono_modem_set_powered(md->modem.ofono, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_modem_online_request_timeout(gpointer data)
|
||||||
|
{
|
||||||
|
struct ril_modem_online_request *req = data;
|
||||||
|
struct ofono_error error;
|
||||||
|
ofono_modem_online_cb_t cb = req->cb;
|
||||||
|
void *cb_data = req->data;
|
||||||
|
|
||||||
|
GASSERT(req->timeout_id);
|
||||||
|
GASSERT(cb);
|
||||||
|
|
||||||
|
req->timeout_id = 0;
|
||||||
|
req->cb = NULL;
|
||||||
|
req->data = NULL;
|
||||||
|
cb(ril_error_failure(&error), cb_data);
|
||||||
|
ril_modem_update_online_state(req->md);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_modem_online_check(gpointer data)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = data;
|
||||||
|
|
||||||
|
GASSERT(md->online_check_id);
|
||||||
|
md->online_check_id = 0;
|
||||||
|
ril_modem_update_online_state(md);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||||
|
{
|
||||||
|
if (!md->online_check_id) {
|
||||||
|
md->online_check_id = g_idle_add(ril_modem_online_check, md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||||
|
{
|
||||||
|
struct ril_modem *m = &md->modem;
|
||||||
|
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
|
||||||
|
/* radio-settings.c assumes that IMSI is available */
|
||||||
|
if (!ril_modem_radio_settings(m)) {
|
||||||
|
DBG_(md, "initializing radio settings interface");
|
||||||
|
ofono_radio_settings_create(m->ofono, 0,
|
||||||
|
RILMODEM_DRIVER, md);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* ofono core may remove radio settings atom internally */
|
||||||
|
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||||
|
if (rs) {
|
||||||
|
DBG_(md, "removing radio settings interface");
|
||||||
|
ofono_radio_settings_remove(rs);
|
||||||
|
} else {
|
||||||
|
DBG_(md, "radio settings interface is already gone");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = data;
|
||||||
|
|
||||||
|
GASSERT(md->modem.radio == radio);
|
||||||
|
ril_modem_update_radio_settings(md);
|
||||||
|
ril_modem_update_online_state(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_imsi_cb(struct ofono_watch *watch, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = data;
|
||||||
|
|
||||||
|
GASSERT(md->watch == watch);
|
||||||
|
ril_modem_update_radio_settings(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||||
|
|
||||||
|
DBG("%s", ofono_modem_get_path(modem));
|
||||||
|
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
if (md->modem.config.enable_voicecall) {
|
||||||
|
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
}
|
||||||
|
if (!md->radio_state_event_id) {
|
||||||
|
md->radio_state_event_id =
|
||||||
|
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||||
|
ril_modem_radio_state_cb, md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||||
|
struct ofono_gprs *gprs;
|
||||||
|
|
||||||
|
DBG("%s", ofono_modem_get_path(modem));
|
||||||
|
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
if (gprs) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
|
||||||
|
struct ofono_gprs_context *gc =
|
||||||
|
ofono_gprs_context_create(modem, 0,
|
||||||
|
RILMODEM_DRIVER, md);
|
||||||
|
if (gc == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ofono_gprs_add_context(gprs, gc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_phonebook_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||||
|
if (md->modem.config.enable_stk) {
|
||||||
|
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
}
|
||||||
|
if (md->modem.config.enable_cbs) {
|
||||||
|
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||||
|
|
||||||
|
DBG("%s", ofono_modem_get_path(modem));
|
||||||
|
ofono_call_volume_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_call_settings_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
ofono_netmon_create(modem, 0, RILMODEM_DRIVER, md);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||||
|
ofono_modem_online_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||||
|
struct ril_radio *radio = md->modem.radio;
|
||||||
|
struct ril_modem_online_request *req;
|
||||||
|
|
||||||
|
DBG("%s going %sline", ofono_modem_get_path(modem),
|
||||||
|
online ? "on" : "off");
|
||||||
|
|
||||||
|
ril_radio_set_online(radio, online);
|
||||||
|
if (online) {
|
||||||
|
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
|
||||||
|
req = &md->set_online;
|
||||||
|
} else {
|
||||||
|
ril_radio_power_off(radio, RADIO_POWER_TAG(md));
|
||||||
|
req = &md->set_offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->cb = cb;
|
||||||
|
req->data = data;
|
||||||
|
if (req->timeout_id) {
|
||||||
|
g_source_remove(req->timeout_id);
|
||||||
|
}
|
||||||
|
req->timeout_id = g_timeout_add_seconds(ONLINE_TIMEOUT_SECS,
|
||||||
|
ril_modem_online_request_timeout, req);
|
||||||
|
ril_modem_schedule_online_check(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_modem_enable(struct ofono_modem *modem)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||||
|
|
||||||
|
DBG("%s", ofono_modem_get_path(modem));
|
||||||
|
md->power_state = POWERED_ON;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_modem_disable(struct ofono_modem *modem)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||||
|
|
||||||
|
DBG("%s", ofono_modem_get_path(modem));
|
||||||
|
if (md->set_online.timeout_id || md->set_offline.timeout_id) {
|
||||||
|
md->power_state = POWERING_OFF;
|
||||||
|
return -EINPROGRESS;
|
||||||
|
} else {
|
||||||
|
md->power_state = POWERED_OFF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_modem_probe(struct ofono_modem *modem)
|
||||||
|
{
|
||||||
|
DBG("%s", ofono_modem_get_path(modem));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_modem_remove(struct ofono_modem *ofono)
|
||||||
|
{
|
||||||
|
struct ril_modem_data *md = ril_modem_data_from_ofono(ofono);
|
||||||
|
struct ril_modem *modem = &md->modem;
|
||||||
|
|
||||||
|
DBG("%s", ril_modem_get_path(modem));
|
||||||
|
ofono_modem_set_data(ofono, NULL);
|
||||||
|
|
||||||
|
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||||
|
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||||
|
ril_radio_unref(modem->radio);
|
||||||
|
ril_sim_settings_unref(modem->sim_settings);
|
||||||
|
|
||||||
|
ofono_watch_remove_handler(md->watch, md->imsi_event_id);
|
||||||
|
ofono_watch_unref(md->watch);
|
||||||
|
|
||||||
|
if (md->online_check_id) {
|
||||||
|
g_source_remove(md->online_check_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (md->set_online.timeout_id) {
|
||||||
|
g_source_remove(md->set_online.timeout_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (md->set_offline.timeout_id) {
|
||||||
|
g_source_remove(md->set_offline.timeout_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_network_unref(modem->network);
|
||||||
|
ril_sim_card_unref(modem->sim_card);
|
||||||
|
ril_data_unref(modem->data);
|
||||||
|
sailfish_cell_info_unref(modem->cell_info);
|
||||||
|
grilio_channel_unref(modem->io);
|
||||||
|
grilio_queue_cancel_all(md->q, FALSE);
|
||||||
|
grilio_queue_unref(md->q);
|
||||||
|
g_free(md->ecclist_file);
|
||||||
|
g_free(md->log_prefix);
|
||||||
|
g_free(md->imeisv);
|
||||||
|
g_free(md->imei);
|
||||||
|
g_free(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||||
|
const char *path, const char *imei, const char *imeisv,
|
||||||
|
const char *ecclist_file, const struct ril_slot_config *config,
|
||||||
|
struct ril_radio *radio, struct ril_network *network,
|
||||||
|
struct ril_sim_card *card, struct ril_data *data,
|
||||||
|
struct ril_sim_settings *settings,
|
||||||
|
struct sailfish_cell_info *cell_info)
|
||||||
|
{
|
||||||
|
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||||
|
struct ofono_modem *ofono = ofono_modem_create(path + 1,
|
||||||
|
RILMODEM_DRIVER);
|
||||||
|
if (ofono) {
|
||||||
|
int err;
|
||||||
|
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
|
||||||
|
struct ril_modem *modem = &md->modem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ril_plugin.c must wait until IMEI becomes known before
|
||||||
|
* creating the modem
|
||||||
|
*/
|
||||||
|
GASSERT(imei);
|
||||||
|
|
||||||
|
/* Copy config */
|
||||||
|
modem->config = *config;
|
||||||
|
modem->imei = md->imei = g_strdup(imei);
|
||||||
|
modem->imeisv = md->imeisv = g_strdup(imeisv);
|
||||||
|
modem->log_prefix = log_prefix; /* No need to strdup */
|
||||||
|
modem->ecclist_file = ecclist_file; /* No need to strdup */
|
||||||
|
md->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||||
|
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||||
|
|
||||||
|
modem->ofono = ofono;
|
||||||
|
modem->radio = ril_radio_ref(radio);
|
||||||
|
modem->network = ril_network_ref(network);
|
||||||
|
modem->sim_card = ril_sim_card_ref(card);
|
||||||
|
modem->sim_settings = ril_sim_settings_ref(settings);
|
||||||
|
modem->cell_info = sailfish_cell_info_ref(cell_info);
|
||||||
|
modem->data = ril_data_ref(data);
|
||||||
|
modem->io = grilio_channel_ref(io);
|
||||||
|
md->q = grilio_queue_new(io);
|
||||||
|
md->watch = ofono_watch_new(path);
|
||||||
|
|
||||||
|
md->imsi_event_id =
|
||||||
|
ofono_watch_add_imsi_changed_handler(md->watch,
|
||||||
|
ril_modem_imsi_cb, md);
|
||||||
|
|
||||||
|
md->set_online.md = md;
|
||||||
|
md->set_offline.md = md;
|
||||||
|
ofono_modem_set_data(ofono, md);
|
||||||
|
err = ofono_modem_register(ofono);
|
||||||
|
if (!err) {
|
||||||
|
GASSERT(io->connected);
|
||||||
|
if (config->radio_power_cycle) {
|
||||||
|
ril_radio_power_cycle(modem->radio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ofono_modem_reset sets Powered to TRUE without
|
||||||
|
* issuing PropertyChange signal.
|
||||||
|
*/
|
||||||
|
ofono_modem_set_powered(modem->ofono, FALSE);
|
||||||
|
ofono_modem_set_powered(modem->ofono, TRUE);
|
||||||
|
md->power_state = POWERED_ON;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With some RIL implementations, querying available
|
||||||
|
* band modes causes some magic Android properties to
|
||||||
|
* appear.
|
||||||
|
*/
|
||||||
|
if (config->query_available_band_mode) {
|
||||||
|
grilio_queue_send_request(md->q, NULL,
|
||||||
|
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_modem_update_radio_settings(md);
|
||||||
|
return modem;
|
||||||
|
} else {
|
||||||
|
ofono_error("Error %d registering %s",
|
||||||
|
err, RILMODEM_DRIVER);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If ofono_modem_register() failed, then
|
||||||
|
* ofono_modem_remove() won't invoke
|
||||||
|
* ril_modem_remove() callback.
|
||||||
|
*/
|
||||||
|
ril_modem_remove(ofono);
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_modem_remove(ofono);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_modem_driver ril_modem_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_modem_probe,
|
||||||
|
.remove = ril_modem_remove,
|
||||||
|
.enable = ril_modem_enable,
|
||||||
|
.disable = ril_modem_disable,
|
||||||
|
.pre_sim = ril_modem_pre_sim,
|
||||||
|
.post_sim = ril_modem_post_sim,
|
||||||
|
.post_online = ril_modem_post_online,
|
||||||
|
.set_online = ril_modem_set_online
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
324
ofono/drivers/ril/ril_netmon.c
Normal file
324
ofono/drivers/ril/ril_netmon.c
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <sailfish_cell_info.h>
|
||||||
|
|
||||||
|
#include "ofono.h"
|
||||||
|
|
||||||
|
struct ril_netmon {
|
||||||
|
struct ofono_netmon *netmon;
|
||||||
|
struct sailfish_cell_info *cell_info;
|
||||||
|
guint register_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This number must be in sync with ril_netmon_notify_ofono: */
|
||||||
|
#define RIL_NETMON_MAX_OFONO_PARAMS (8)
|
||||||
|
|
||||||
|
struct ril_netmon_ofono_param {
|
||||||
|
enum ofono_netmon_info type;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
||||||
|
{
|
||||||
|
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||||
|
{
|
||||||
|
s_mcc[0] = 0;
|
||||||
|
s_mnc[0] = 0;
|
||||||
|
|
||||||
|
if (mcc >= 0 && mcc <= 999) {
|
||||||
|
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
|
||||||
|
if (mnc >= 0 && mnc <= 999) {
|
||||||
|
const unsigned int mnclen = mnclength(mcc, mnc);
|
||||||
|
const char *format[] = { "%d", "%02d", "%03d" };
|
||||||
|
const char *fmt = (mnclen > 0 &&
|
||||||
|
mnclen <= G_N_ELEMENTS(format)) ?
|
||||||
|
format[mnclen - 1] : format[0];
|
||||||
|
snprintf(s_mnc, OFONO_MAX_MNC_LENGTH + 1, fmt, mnc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
|
||||||
|
enum ofono_netmon_cell_type type, int mcc, int mnc,
|
||||||
|
struct ril_netmon_ofono_param *params, int nparams)
|
||||||
|
{
|
||||||
|
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||||
|
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Better not to push uninitialized data to the stack ... */
|
||||||
|
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
|
||||||
|
params[i].type = OFONO_NETMON_INFO_INVALID;
|
||||||
|
params[i].value = SAILFISH_CELL_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
|
||||||
|
ofono_netmon_serving_cell_notify(netmon, type,
|
||||||
|
OFONO_NETMON_INFO_MCC, s_mcc,
|
||||||
|
OFONO_NETMON_INFO_MNC, s_mnc,
|
||||||
|
params[0].type, params[0].value,
|
||||||
|
params[1].type, params[1].value,
|
||||||
|
params[2].type, params[2].value,
|
||||||
|
params[3].type, params[3].value,
|
||||||
|
params[4].type, params[4].value,
|
||||||
|
params[5].type, params[5].value,
|
||||||
|
params[6].type, params[6].value,
|
||||||
|
params[7].type, params[7].value,
|
||||||
|
OFONO_NETMON_INFO_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||||
|
const struct sailfish_cell_info_gsm *gsm)
|
||||||
|
{
|
||||||
|
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if (gsm->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||||
|
params[n].value = gsm->lac;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gsm->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_CI;
|
||||||
|
params[n].value = gsm->cid;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gsm->arfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||||
|
params[n].value = gsm->arfcn;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gsm->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||||
|
params[n].value = gsm->signalStrength;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gsm->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_BER;
|
||||||
|
params[n].value = gsm->bitErrorRate;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_GSM,
|
||||||
|
gsm->mcc, gsm->mnc, params, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||||
|
const struct sailfish_cell_info_wcdma *wcdma)
|
||||||
|
{
|
||||||
|
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if (wcdma->lac != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||||
|
params[n].value = wcdma->lac;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->cid != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_CI;
|
||||||
|
params[n].value = wcdma->cid;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->psc != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_PSC;
|
||||||
|
params[n].value = wcdma->psc;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->uarfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||||
|
params[n].value = wcdma->uarfcn;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||||
|
params[n].value = wcdma->signalStrength;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcdma->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_BER;
|
||||||
|
params[n].value = wcdma->bitErrorRate;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_UMTS,
|
||||||
|
wcdma->mcc, wcdma->mnc, params, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||||
|
const struct sailfish_cell_info_lte *lte)
|
||||||
|
{
|
||||||
|
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if (lte->ci != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_CI;
|
||||||
|
params[n].value = lte->ci;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->earfcn != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_EARFCN;
|
||||||
|
params[n].value = lte->earfcn;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||||
|
params[n].value = lte->signalStrength;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->rsrp != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSRQ;
|
||||||
|
params[n].value = lte->rsrp;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->rsrq != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_RSRP;
|
||||||
|
params[n].value = lte->rsrq;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->cqi != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_CQI;
|
||||||
|
params[n].value = lte->cqi;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lte->timingAdvance != SAILFISH_CELL_INVALID_VALUE) {
|
||||||
|
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
|
||||||
|
params[n].value = lte->timingAdvance;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_LTE,
|
||||||
|
lte->mcc, lte->mnc, params, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||||
|
ofono_netmon_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||||
|
struct ofono_error error;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
for (l = nm->cell_info->cells; l; l = l->next) {
|
||||||
|
const struct sailfish_cell *cell = l->data;
|
||||||
|
|
||||||
|
if (cell->registered) {
|
||||||
|
switch (cell->type) {
|
||||||
|
case SAILFISH_CELL_TYPE_GSM:
|
||||||
|
ril_netmon_notify_gsm(netmon,
|
||||||
|
&cell->info.gsm);
|
||||||
|
break;
|
||||||
|
case SAILFISH_CELL_TYPE_WCDMA:
|
||||||
|
ril_netmon_notify_wcdma(netmon,
|
||||||
|
&cell->info.wcdma);
|
||||||
|
break;
|
||||||
|
case SAILFISH_CELL_TYPE_LTE:
|
||||||
|
ril_netmon_notify_lte(netmon,
|
||||||
|
&cell->info.lte);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(ril_error_ok(&error), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_netmon_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_netmon *nm = user_data;
|
||||||
|
|
||||||
|
GASSERT(nm->register_id);
|
||||||
|
nm->register_id = 0;
|
||||||
|
ofono_netmon_register(nm->netmon);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (modem->cell_info) {
|
||||||
|
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
|
||||||
|
|
||||||
|
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
|
||||||
|
nm->netmon = netmon;
|
||||||
|
|
||||||
|
ofono_netmon_set_data(netmon, nm);
|
||||||
|
nm->register_id = g_idle_add(ril_netmon_register, nm);
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
DBG("%s no", modem->log_prefix ? modem->log_prefix : "");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("%s %d", modem->log_prefix ? modem->log_prefix : "", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netmon_remove(struct ofono_netmon *netmon)
|
||||||
|
{
|
||||||
|
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||||
|
|
||||||
|
DBG("");
|
||||||
|
ofono_netmon_set_data(netmon, NULL);
|
||||||
|
|
||||||
|
if (nm->register_id > 0) {
|
||||||
|
g_source_remove(nm->register_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
sailfish_cell_info_unref(nm->cell_info);
|
||||||
|
g_slice_free(struct ril_netmon, nm);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_netmon_driver ril_netmon_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_netmon_probe,
|
||||||
|
.remove = ril_netmon_remove,
|
||||||
|
.request_update = ril_netmon_request_update,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
618
ofono/drivers/ril/ril_netreg.c
Normal file
618
ofono/drivers/ril/ril_netreg.c
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_network.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "simutil.h"
|
||||||
|
|
||||||
|
#define REGISTRATION_TIMEOUT (100*1000) /* ms */
|
||||||
|
#define REGISTRATION_MAX_RETRIES (2)
|
||||||
|
|
||||||
|
enum ril_netreg_events {
|
||||||
|
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||||
|
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||||
|
NETREG_RIL_EVENT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_netreg_network_events {
|
||||||
|
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
|
||||||
|
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
|
||||||
|
NETREG_NETWORK_EVENT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_netreg {
|
||||||
|
GRilIoChannel *io;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
gboolean network_selection_manual_0;
|
||||||
|
struct ofono_netreg *netreg;
|
||||||
|
struct ril_network *network;
|
||||||
|
char *log_prefix;
|
||||||
|
guint timer_id;
|
||||||
|
guint notify_id;
|
||||||
|
guint current_operator_id;
|
||||||
|
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
|
||||||
|
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_netreg_cbd {
|
||||||
|
struct ril_netreg *nd;
|
||||||
|
union {
|
||||||
|
ofono_netreg_status_cb_t status;
|
||||||
|
ofono_netreg_operator_cb_t operator;
|
||||||
|
ofono_netreg_operator_list_cb_t operator_list;
|
||||||
|
ofono_netreg_register_cb_t reg;
|
||||||
|
ofono_netreg_strength_cb_t strength;
|
||||||
|
gpointer ptr;
|
||||||
|
} cb;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ril_netreg_cbd_free g_free
|
||||||
|
|
||||||
|
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
|
||||||
|
|
||||||
|
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
|
||||||
|
{
|
||||||
|
return ofono ? ofono_netreg_get_data(ofono) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
|
||||||
|
void *cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netreg_cbd *cbd = g_new0(struct ril_netreg_cbd, 1);
|
||||||
|
|
||||||
|
cbd->nd = nd;
|
||||||
|
cbd->cb.ptr = cb;
|
||||||
|
cbd->data = data;
|
||||||
|
return cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
|
||||||
|
gint status)
|
||||||
|
{
|
||||||
|
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||||
|
/* These functions tolerate NULL argument */
|
||||||
|
const char *net_mcc = ofono_netreg_get_mcc(netreg);
|
||||||
|
const char *net_mnc = ofono_netreg_get_mnc(netreg);
|
||||||
|
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
|
||||||
|
|
||||||
|
if (spdi && net_mcc && net_mnc) {
|
||||||
|
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
|
||||||
|
ofono_info("not roaming based on spdi");
|
||||||
|
return NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_netreg_check_status(struct ril_netreg *nd, int status)
|
||||||
|
{
|
||||||
|
return (nd && nd->netreg) ?
|
||||||
|
ril_netreg_check_if_really_roaming(nd->netreg, status) :
|
||||||
|
status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_netreg_status_notify_cb(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = user_data;
|
||||||
|
const struct ril_registration_state *reg = &nd->network->voice;
|
||||||
|
|
||||||
|
DBG_(nd, "");
|
||||||
|
GASSERT(nd->notify_id);
|
||||||
|
nd->notify_id = 0;
|
||||||
|
ofono_netreg_status_notify(nd->netreg,
|
||||||
|
ril_netreg_check_status(nd, reg->status),
|
||||||
|
reg->lac, reg->ci, reg->access_tech);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = user_data;
|
||||||
|
|
||||||
|
/* Coalesce multiple notifications into one */
|
||||||
|
if (nd->notify_id) {
|
||||||
|
DBG_(nd, "notification aready queued");
|
||||||
|
} else {
|
||||||
|
DBG_(nd, "queuing notification");
|
||||||
|
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_registration_status(struct ofono_netreg *netreg,
|
||||||
|
ofono_netreg_status_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
|
const struct ril_registration_state *reg = &nd->network->voice;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
DBG_(nd, "");
|
||||||
|
cb(ril_error_ok(&error),
|
||||||
|
ril_netreg_check_status(nd, reg->status),
|
||||||
|
reg->lac, reg->ci, reg->access_tech, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_netreg_current_operator_cb(void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg_cbd *cbd = user_data;
|
||||||
|
struct ril_netreg *nd = cbd->nd;
|
||||||
|
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
DBG_(nd, "");
|
||||||
|
GASSERT(nd->current_operator_id);
|
||||||
|
nd->current_operator_id = 0;
|
||||||
|
|
||||||
|
cb(ril_error_ok(&error), nd->network->operator, cbd->data);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||||
|
ofono_netreg_operator_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calling ofono_netreg_status_notify() may result in
|
||||||
|
* ril_netreg_current_operator() being invoked even if one
|
||||||
|
* is already pending. Since ofono core doesn't associate
|
||||||
|
* any context with individual calls, we can safely assume
|
||||||
|
* that such a call essentially cancels the previous one.
|
||||||
|
*/
|
||||||
|
if (nd->current_operator_id) {
|
||||||
|
g_source_remove(nd->current_operator_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
nd->current_operator_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||||
|
ril_netreg_current_operator_cb,
|
||||||
|
ril_netreg_cbd_new(nd, cb, data),
|
||||||
|
ril_netreg_cbd_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg_cbd *cbd = user_data;
|
||||||
|
ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list;
|
||||||
|
struct ofono_network_operator *list;
|
||||||
|
struct ofono_error error;
|
||||||
|
int noperators = 0, i;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
gboolean ok = TRUE;
|
||||||
|
|
||||||
|
if (status != RIL_E_SUCCESS) {
|
||||||
|
ofono_error("Failed to retrive the list of operators: %s",
|
||||||
|
ril_error_to_string(status));
|
||||||
|
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
|
||||||
|
/* Number of operators at the list (4 strings for every operator) */
|
||||||
|
grilio_parser_get_int32(&rilp, &noperators);
|
||||||
|
GASSERT(!(noperators % 4));
|
||||||
|
noperators /= 4;
|
||||||
|
ofono_info("noperators = %d", noperators);
|
||||||
|
|
||||||
|
list = g_new0(struct ofono_network_operator, noperators);
|
||||||
|
for (i = 0; i < noperators && ok; i++) {
|
||||||
|
struct ofono_network_operator *op = list + i;
|
||||||
|
char *lalpha = grilio_parser_get_utf8(&rilp);
|
||||||
|
char *salpha = grilio_parser_get_utf8(&rilp);
|
||||||
|
char *numeric = grilio_parser_get_utf8(&rilp);
|
||||||
|
char *status = grilio_parser_get_utf8(&rilp);
|
||||||
|
|
||||||
|
/* Try to use long by default */
|
||||||
|
if (lalpha) {
|
||||||
|
strncpy(op->name, lalpha,
|
||||||
|
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||||
|
} else if (salpha) {
|
||||||
|
strncpy(op->name, salpha,
|
||||||
|
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||||
|
} else {
|
||||||
|
op->name[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the proper status */
|
||||||
|
if (!strcmp(status, "available")) {
|
||||||
|
list[i].status = OPERATOR_STATUS_AVAILABLE;
|
||||||
|
} else if (!strcmp(status, "current")) {
|
||||||
|
list[i].status = OPERATOR_STATUS_CURRENT;
|
||||||
|
} else if (!strcmp(status, "forbidden")) {
|
||||||
|
list[i].status = OPERATOR_STATUS_FORBIDDEN;
|
||||||
|
} else {
|
||||||
|
list[i].status = OPERATOR_STATUS_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
op->tech = -1;
|
||||||
|
ok = ril_parse_mcc_mnc(numeric, op);
|
||||||
|
if (ok) {
|
||||||
|
if (op->tech < 0) {
|
||||||
|
op->tech = cbd->nd->network->voice.access_tech;
|
||||||
|
}
|
||||||
|
DBG("[operator=%s, %s, %s, status: %s]", op->name,
|
||||||
|
op->mcc, op->mnc, status);
|
||||||
|
} else {
|
||||||
|
DBG("failed to parse operator list");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(lalpha);
|
||||||
|
g_free(salpha);
|
||||||
|
g_free(numeric);
|
||||||
|
g_free(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
cb(ril_error_ok(&error), noperators, list, cbd->data);
|
||||||
|
} else {
|
||||||
|
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_list_operators(struct ofono_netreg *netreg,
|
||||||
|
ofono_netreg_operator_list_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
|
|
||||||
|
grilio_queue_send_request_full(nd->q, NULL,
|
||||||
|
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS,
|
||||||
|
ril_netreg_list_operators_cb, ril_netreg_cbd_free,
|
||||||
|
ril_netreg_cbd_new(nd, cb, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_register_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg_cbd *cbd = user_data;
|
||||||
|
ofono_netreg_register_cb_t cb = cbd->cb.reg;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
cb(ril_error_ok(&error), cbd->data);
|
||||||
|
} else {
|
||||||
|
ofono_error("registration failed, ril result %d", status);
|
||||||
|
cb(ril_error_failure(&error), cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_register_auto(struct ofono_netreg *netreg,
|
||||||
|
ofono_netreg_register_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
|
||||||
|
ofono_info("nw select automatic");
|
||||||
|
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT);
|
||||||
|
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||||
|
grilio_queue_send_request_full(nd->q, req,
|
||||||
|
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||||
|
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||||
|
ril_netreg_cbd_new(nd, cb, data));
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||||
|
const char *mcc, const char *mnc,
|
||||||
|
ofono_netreg_register_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
|
GRilIoRequest *req = grilio_request_new();
|
||||||
|
const char *suffix = nd->network_selection_manual_0 ? "+0" : "";
|
||||||
|
|
||||||
|
ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix);
|
||||||
|
grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix);
|
||||||
|
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT);
|
||||||
|
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||||
|
grilio_queue_send_request_full(nd->q, req,
|
||||||
|
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||||
|
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||||
|
ril_netreg_cbd_new(nd, cb, data));
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_netreg_dbm_to_percentage(int dbm)
|
||||||
|
{
|
||||||
|
const int min_dbm = -100; /* very weak signal, 0.0000000001 mW */
|
||||||
|
const int max_dbm = -60; /* strong signal, 0.000001 mW */
|
||||||
|
|
||||||
|
return (dbm <= min_dbm) ? 1 :
|
||||||
|
(dbm >= max_dbm) ? 100 :
|
||||||
|
(100 * (dbm - min_dbm) / (max_dbm - min_dbm));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||||
|
{
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||||
|
int rsrp = 0, tdscdma_dbm = 0;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
|
||||||
|
/* GW_SignalStrength */
|
||||||
|
grilio_parser_get_int32(&rilp, &gw_signal);
|
||||||
|
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||||
|
|
||||||
|
/* CDMA_SignalStrength */
|
||||||
|
grilio_parser_get_int32(&rilp, &cdma_dbm);
|
||||||
|
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||||
|
|
||||||
|
/* EVDO_SignalStrength */
|
||||||
|
grilio_parser_get_int32(&rilp, &evdo_dbm);
|
||||||
|
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||||
|
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||||
|
|
||||||
|
/* LTE_SignalStrength */
|
||||||
|
grilio_parser_get_int32(&rilp, <e_signal);
|
||||||
|
grilio_parser_get_int32(&rilp, &rsrp);
|
||||||
|
|
||||||
|
/* Skip the rest of LTE_SignalStrength_v8 */
|
||||||
|
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
|
||||||
|
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
|
||||||
|
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
|
||||||
|
grilio_parser_get_int32(&rilp, NULL)) { /* timingAdvance */
|
||||||
|
|
||||||
|
/* TD_SCDMA_SignalStrength */
|
||||||
|
grilio_parser_get_int32(&rilp, &tdscdma_dbm); /* rscp */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsrp == INT_MAX) {
|
||||||
|
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d, tdscdma: %d",
|
||||||
|
gw_signal, cdma_dbm, evdo_dbm,
|
||||||
|
lte_signal, tdscdma_dbm);
|
||||||
|
} else {
|
||||||
|
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d, tdscdma: %d",
|
||||||
|
gw_signal, cdma_dbm, evdo_dbm,
|
||||||
|
lte_signal, rsrp, tdscdma_dbm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the first valid one */
|
||||||
|
|
||||||
|
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
|
||||||
|
* RSRP value. If we've got zero, don't report it just yet. */
|
||||||
|
if (gw_signal >= 1 && gw_signal <= 31) {
|
||||||
|
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||||
|
return (gw_signal * 100) / 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||||
|
if (lte_signal >= 0 && lte_signal <= 31) {
|
||||||
|
return (lte_signal * 100) / 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSCP range: 25 to 120 dBm as defined in 3GPP TS 25.123 */
|
||||||
|
if (tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
|
||||||
|
return ril_netreg_dbm_to_percentage(-tdscdma_dbm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
|
||||||
|
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||||
|
return ril_netreg_dbm_to_percentage(-rsrp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we've got zero strength and no valid RSRP, then so be it */
|
||||||
|
if (gw_signal == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case of dbm, return the value directly */
|
||||||
|
if (cdma_dbm != -1) {
|
||||||
|
return MIN(cdma_dbm, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evdo_dbm != -1) {
|
||||||
|
return MIN(evdo_dbm, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = user_data;
|
||||||
|
int strength;
|
||||||
|
|
||||||
|
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
|
||||||
|
strength = ril_netreg_get_signal_strength(data, len);
|
||||||
|
DBG_(nd, "%d", strength);
|
||||||
|
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg_cbd *cbd = user_data;
|
||||||
|
ofono_netreg_strength_cb_t cb = cbd->cb.strength;
|
||||||
|
struct ofono_error error;
|
||||||
|
|
||||||
|
if (status == RIL_E_SUCCESS) {
|
||||||
|
int strength = ril_netreg_get_signal_strength(data, len);
|
||||||
|
cb(ril_error_ok(&error), strength, cbd->data);
|
||||||
|
} else {
|
||||||
|
ofono_error("Failed to retrive the signal strength: %s",
|
||||||
|
ril_error_to_string(status));
|
||||||
|
cb(ril_error_failure(&error), -1, cbd->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_strength(struct ofono_netreg *netreg,
|
||||||
|
ofono_netreg_strength_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
|
GRilIoRequest* req = grilio_request_new();
|
||||||
|
|
||||||
|
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||||
|
grilio_queue_send_request_full(nd->q, req,
|
||||||
|
RIL_REQUEST_SIGNAL_STRENGTH, ril_netreg_strength_cb,
|
||||||
|
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = user_data;
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int year, mon, mday, hour, min, sec, tzi, dst = 0;
|
||||||
|
char tzs;
|
||||||
|
gchar *nitz;
|
||||||
|
|
||||||
|
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
nitz = grilio_parser_get_utf8(&rilp);
|
||||||
|
|
||||||
|
DBG_(nd, "%s", nitz);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
|
||||||
|
* The ds part is considered optional, initialized to zero.
|
||||||
|
*/
|
||||||
|
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
|
||||||
|
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
|
||||||
|
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
|
||||||
|
struct ofono_network_time time;
|
||||||
|
char tz[4];
|
||||||
|
|
||||||
|
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||||
|
time.utcoff = atoi(tz) * 15 * 60;
|
||||||
|
time.dst = dst;
|
||||||
|
time.sec = sec;
|
||||||
|
time.min = min;
|
||||||
|
time.hour = hour;
|
||||||
|
time.mday = mday;
|
||||||
|
time.mon = mon;
|
||||||
|
time.year = 2000 + year;
|
||||||
|
|
||||||
|
ofono_netreg_time_notify(nd->netreg, &time);
|
||||||
|
} else {
|
||||||
|
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(nitz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_netreg_register(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = user_data;
|
||||||
|
|
||||||
|
GASSERT(nd->timer_id);
|
||||||
|
nd->timer_id = 0;
|
||||||
|
ofono_netreg_register(nd->netreg);
|
||||||
|
|
||||||
|
/* Register for network state changes */
|
||||||
|
nd->network_event_id[NETREG_NETWORK_EVENT_OPERATOR_CHANGED] =
|
||||||
|
ril_network_add_operator_changed_handler(nd->network,
|
||||||
|
ril_netreg_status_notify, nd);
|
||||||
|
nd->network_event_id[NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED] =
|
||||||
|
ril_network_add_voice_state_changed_handler(nd->network,
|
||||||
|
ril_netreg_status_notify, nd);
|
||||||
|
|
||||||
|
/* Register for network time updates */
|
||||||
|
nd->ril_event_id[NETREG_RIL_EVENT_NITZ_TIME_RECEIVED] =
|
||||||
|
grilio_channel_add_unsol_event_handler(nd->io,
|
||||||
|
ril_netreg_nitz_notify,
|
||||||
|
RIL_UNSOL_NITZ_TIME_RECEIVED, nd);
|
||||||
|
|
||||||
|
/* Register for signal strength changes */
|
||||||
|
nd->ril_event_id[NETREG_RIL_EVENT_SIGNAL_STRENGTH] =
|
||||||
|
grilio_channel_add_unsol_event_handler(nd->io,
|
||||||
|
ril_netreg_strength_notify,
|
||||||
|
RIL_UNSOL_SIGNAL_STRENGTH, nd);
|
||||||
|
|
||||||
|
/* This makes the timeout a single-shot */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct ril_modem *modem = data;
|
||||||
|
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
|
||||||
|
const struct ril_slot_config *config = &modem->config;
|
||||||
|
|
||||||
|
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||||
|
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||||
|
|
||||||
|
DBG_(nd, "%p", netreg);
|
||||||
|
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||||
|
nd->q = grilio_queue_new(nd->io);
|
||||||
|
nd->network = ril_network_ref(modem->network);
|
||||||
|
nd->netreg = netreg;
|
||||||
|
nd->network_selection_manual_0 = config->network_selection_manual_0;
|
||||||
|
|
||||||
|
ofono_netreg_set_data(netreg, nd);
|
||||||
|
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||||
|
{
|
||||||
|
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||||
|
|
||||||
|
DBG_(nd, "%p", netreg);
|
||||||
|
grilio_queue_cancel_all(nd->q, FALSE);
|
||||||
|
ofono_netreg_set_data(netreg, NULL);
|
||||||
|
|
||||||
|
if (nd->timer_id > 0) {
|
||||||
|
g_source_remove(nd->timer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nd->notify_id) {
|
||||||
|
g_source_remove(nd->notify_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nd->current_operator_id) {
|
||||||
|
g_source_remove(nd->current_operator_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
|
||||||
|
ril_network_unref(nd->network);
|
||||||
|
|
||||||
|
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
|
||||||
|
grilio_channel_unref(nd->io);
|
||||||
|
grilio_queue_unref(nd->q);
|
||||||
|
g_free(nd->log_prefix);
|
||||||
|
g_free(nd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ofono_netreg_driver ril_netreg_driver = {
|
||||||
|
.name = RILMODEM_DRIVER,
|
||||||
|
.probe = ril_netreg_probe,
|
||||||
|
.remove = ril_netreg_remove,
|
||||||
|
.registration_status = ril_netreg_registration_status,
|
||||||
|
.current_operator = ril_netreg_current_operator,
|
||||||
|
.list_operators = ril_netreg_list_operators,
|
||||||
|
.register_auto = ril_netreg_register_auto,
|
||||||
|
.register_manual = ril_netreg_register_manual,
|
||||||
|
.strength = ril_netreg_strength
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
1144
ofono/drivers/ril/ril_network.c
Normal file
1144
ofono/drivers/ril/ril_network.c
Normal file
File diff suppressed because it is too large
Load Diff
86
ofono/drivers/ril/ril_network.h
Normal file
86
ofono/drivers/ril/ril_network.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_NETWORK_H
|
||||||
|
#define RIL_NETWORK_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
struct ofono_network_operator;
|
||||||
|
|
||||||
|
struct ril_registration_state {
|
||||||
|
int status; /* enum network_registration_status */
|
||||||
|
int access_tech; /* enum access_technology or -1 if none */
|
||||||
|
int ril_tech;
|
||||||
|
int max_calls;
|
||||||
|
int lac;
|
||||||
|
int ci;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_network {
|
||||||
|
GObject object;
|
||||||
|
struct ril_network_priv *priv;
|
||||||
|
struct ril_registration_state voice;
|
||||||
|
struct ril_registration_state data;
|
||||||
|
const struct ofono_network_operator *operator;
|
||||||
|
enum ofono_radio_access_mode pref_mode;
|
||||||
|
enum ofono_radio_access_mode max_pref_mode;
|
||||||
|
struct ril_sim_settings *settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ofono_sim;
|
||||||
|
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
|
||||||
|
|
||||||
|
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||||
|
const char *log_prefix, struct ril_radio *radio,
|
||||||
|
struct ril_sim_card *sim_card,
|
||||||
|
struct ril_sim_settings *settings,
|
||||||
|
const struct ril_slot_config *ril_slot_config,
|
||||||
|
struct ril_vendor *vendor);
|
||||||
|
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||||
|
void ril_network_unref(struct ril_network *net);
|
||||||
|
|
||||||
|
void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||||
|
enum ofono_radio_access_mode max_pref_mode,
|
||||||
|
gboolean force_check);
|
||||||
|
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
||||||
|
void ril_network_query_registration_state(struct ril_network *net);
|
||||||
|
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||||
|
ril_network_cb_t cb, void *arg);
|
||||||
|
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||||
|
ril_network_cb_t cb, void *arg);
|
||||||
|
gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
|
||||||
|
ril_network_cb_t cb, void *arg);
|
||||||
|
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
|
||||||
|
ril_network_cb_t cb, void *arg);
|
||||||
|
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
|
||||||
|
ril_network_cb_t cb, void *arg);
|
||||||
|
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||||
|
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||||
|
|
||||||
|
#define ril_network_remove_all_handlers(net, ids) \
|
||||||
|
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||||
|
|
||||||
|
#endif /* RIL_NETWORK_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
162
ofono/drivers/ril/ril_oem_raw.c
Normal file
162
ofono/drivers/ril/ril_oem_raw.c
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_plugin.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include "gdbus.h"
|
||||||
|
#include "ofono.h"
|
||||||
|
|
||||||
|
#define RIL_OEM_RAW_INTERFACE "org.ofono.OemRaw"
|
||||||
|
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
|
||||||
|
|
||||||
|
struct ril_oem_raw {
|
||||||
|
GRilIoQueue *q;
|
||||||
|
DBusConnection *conn;
|
||||||
|
char *path;
|
||||||
|
char *log_prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
|
||||||
|
|
||||||
|
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
DBusMessage *msg = user_data;
|
||||||
|
DBusMessage *reply;
|
||||||
|
|
||||||
|
if (ril_status == RIL_E_SUCCESS) {
|
||||||
|
DBusMessageIter it, array;
|
||||||
|
const guchar* bytes = data;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
reply = dbus_message_new_method_return(msg);
|
||||||
|
dbus_message_iter_init_append(reply, &it);
|
||||||
|
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY,
|
||||||
|
DBUS_TYPE_BYTE_AS_STRING, &array);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
guchar byte = bytes[i];
|
||||||
|
dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
|
||||||
|
&byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_message_iter_close_container(&it, &array);
|
||||||
|
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
|
||||||
|
DBG("Timed out");
|
||||||
|
reply = __ofono_error_timed_out(msg);
|
||||||
|
} else {
|
||||||
|
DBG("Error %s", ril_error_to_string(ril_status));
|
||||||
|
reply = __ofono_error_failed(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ofono_dbus_pending_reply(&msg, reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
DBusMessageIter it;
|
||||||
|
struct ril_oem_raw *oem = user_data;
|
||||||
|
|
||||||
|
dbus_message_iter_init(msg, &it);
|
||||||
|
if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY &&
|
||||||
|
dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) {
|
||||||
|
char *data;
|
||||||
|
int data_len;
|
||||||
|
DBusMessageIter array;
|
||||||
|
GRilIoRequest *req;
|
||||||
|
|
||||||
|
/* Fetch the data */
|
||||||
|
dbus_message_iter_recurse(&it, &array);
|
||||||
|
dbus_message_iter_get_fixed_array(&array, &data, &data_len);
|
||||||
|
DBG_(oem, "%d bytes", data_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And forward it to rild. Set a timeout because rild may
|
||||||
|
* never respond to invalid requests.
|
||||||
|
*/
|
||||||
|
req = grilio_request_sized_new(data_len);
|
||||||
|
grilio_request_set_timeout(req, RIL_OEM_RAW_TIMEOUT);
|
||||||
|
grilio_request_append_bytes(req, data, data_len);
|
||||||
|
grilio_queue_send_request_full(oem->q, req,
|
||||||
|
RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb,
|
||||||
|
NULL, dbus_message_ref(msg));
|
||||||
|
grilio_request_unref(req);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
DBG_(oem, "Unexpected signature");
|
||||||
|
return __ofono_error_invalid_args(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GDBusMethodTable ril_oem_raw_methods[] = {
|
||||||
|
{ GDBUS_ASYNC_METHOD("Send",
|
||||||
|
GDBUS_ARGS({ "request", "ay" }),
|
||||||
|
GDBUS_ARGS({ "response", "ay" }),
|
||||||
|
ril_oem_raw_send) },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||||
|
const char *log_prefix)
|
||||||
|
{
|
||||||
|
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
|
||||||
|
|
||||||
|
DBG("%s", ril_modem_get_path(modem));
|
||||||
|
oem->path = g_strdup(ril_modem_get_path(modem));
|
||||||
|
oem->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||||
|
oem->q = grilio_queue_new(ril_modem_io(modem));
|
||||||
|
oem->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||||
|
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||||
|
|
||||||
|
/* Register D-Bus interface */
|
||||||
|
if (g_dbus_register_interface(oem->conn, oem->path,
|
||||||
|
RIL_OEM_RAW_INTERFACE, ril_oem_raw_methods,
|
||||||
|
NULL, NULL, oem, NULL)) {
|
||||||
|
ofono_modem_add_interface(modem->ofono, RIL_OEM_RAW_INTERFACE);
|
||||||
|
return oem;
|
||||||
|
} else {
|
||||||
|
ofono_error("OemRaw D-Bus register failed");
|
||||||
|
ril_oem_raw_free(oem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_oem_raw_free(struct ril_oem_raw *oem)
|
||||||
|
{
|
||||||
|
if (oem) {
|
||||||
|
DBG("%s", oem->path);
|
||||||
|
g_dbus_unregister_interface(oem->conn, oem->path,
|
||||||
|
RIL_OEM_RAW_INTERFACE);
|
||||||
|
dbus_connection_unref(oem->conn);
|
||||||
|
|
||||||
|
grilio_queue_cancel_all(oem->q, TRUE);
|
||||||
|
grilio_queue_unref(oem->q);
|
||||||
|
|
||||||
|
g_free(oem->log_prefix);
|
||||||
|
g_free(oem->path);
|
||||||
|
g_free(oem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
1067
ofono/drivers/ril/ril_phonebook.c
Normal file
1067
ofono/drivers/ril/ril_phonebook.c
Normal file
File diff suppressed because it is too large
Load Diff
2267
ofono/drivers/ril/ril_plugin.c
Normal file
2267
ofono/drivers/ril/ril_plugin.c
Normal file
File diff suppressed because it is too large
Load Diff
115
ofono/drivers/ril/ril_plugin.h
Normal file
115
ofono/drivers/ril/ril_plugin.h
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_PLUGIN_H
|
||||||
|
#define RIL_PLUGIN_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
#include "sailfish_manager.h"
|
||||||
|
|
||||||
|
#include <ofono/modem.h>
|
||||||
|
#include <ofono/call-barring.h>
|
||||||
|
#include <ofono/call-forwarding.h>
|
||||||
|
#include <ofono/call-settings.h>
|
||||||
|
#include <ofono/call-volume.h>
|
||||||
|
#include <ofono/cbs.h>
|
||||||
|
#include <ofono/devinfo.h>
|
||||||
|
#include <ofono/gprs-context.h>
|
||||||
|
#include <ofono/gprs.h>
|
||||||
|
#include <ofono/netreg.h>
|
||||||
|
#include <ofono/phonebook.h>
|
||||||
|
#include <ofono/radio-settings.h>
|
||||||
|
#include <ofono/sim.h>
|
||||||
|
#include <ofono/sms.h>
|
||||||
|
#include <ofono/stk.h>
|
||||||
|
#include <ofono/ussd.h>
|
||||||
|
#include <ofono/voicecall.h>
|
||||||
|
#include <ofono/netmon.h>
|
||||||
|
|
||||||
|
#include <grilio_queue.h>
|
||||||
|
#include <grilio_request.h>
|
||||||
|
#include <grilio_parser.h>
|
||||||
|
|
||||||
|
#define RILMODEM_DRIVER "ril"
|
||||||
|
|
||||||
|
struct ril_modem {
|
||||||
|
GRilIoChannel *io;
|
||||||
|
const char *imei;
|
||||||
|
const char *imeisv;
|
||||||
|
const char *log_prefix;
|
||||||
|
const char *ecclist_file;
|
||||||
|
struct ofono_modem *ofono;
|
||||||
|
struct sailfish_cell_info *cell_info;
|
||||||
|
struct ril_radio *radio;
|
||||||
|
struct ril_data *data;
|
||||||
|
struct ril_network *network;
|
||||||
|
struct ril_sim_card *sim_card;
|
||||||
|
struct ril_sim_settings *sim_settings;
|
||||||
|
struct ril_slot_config config;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ril_oem_raw;
|
||||||
|
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||||
|
const char *log_prefix);
|
||||||
|
void ril_oem_raw_free(struct ril_oem_raw *raw);
|
||||||
|
|
||||||
|
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||||
|
const char *path, const char *imei, const char *imeisv,
|
||||||
|
const char *ecclist_file, const struct ril_slot_config *config,
|
||||||
|
struct ril_radio *radio, struct ril_network *network,
|
||||||
|
struct ril_sim_card *card, struct ril_data *data,
|
||||||
|
struct ril_sim_settings *settings,
|
||||||
|
struct sailfish_cell_info *cell_info);
|
||||||
|
void ril_modem_delete(struct ril_modem *modem);
|
||||||
|
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||||
|
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
|
||||||
|
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
|
||||||
|
|
||||||
|
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
|
||||||
|
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
|
||||||
|
#define ril_modem_slot(modem) ((modem)->config.slot)
|
||||||
|
#define ril_modem_io(modem) ((modem)->io)
|
||||||
|
|
||||||
|
int ril_sim_app_type(struct ofono_sim *sim);
|
||||||
|
int ril_netreg_check_if_really_roaming(struct ofono_netreg *reg, gint status);
|
||||||
|
|
||||||
|
extern const struct ofono_call_barring_driver ril_call_barring_driver;
|
||||||
|
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
|
||||||
|
extern const struct ofono_call_settings_driver ril_call_settings_driver;
|
||||||
|
extern const struct ofono_call_volume_driver ril_call_volume_driver;
|
||||||
|
extern const struct ofono_cbs_driver ril_cbs_driver;
|
||||||
|
extern const struct ofono_devinfo_driver ril_devinfo_driver;
|
||||||
|
extern const struct ofono_gprs_context_driver ril_gprs_context_driver;
|
||||||
|
extern const struct ofono_gprs_driver ril_gprs_driver;
|
||||||
|
extern const struct ofono_modem_driver ril_modem_driver;
|
||||||
|
extern const struct ofono_netreg_driver ril_netreg_driver;
|
||||||
|
extern const struct ofono_phonebook_driver ril_phonebook_driver;
|
||||||
|
extern const struct ofono_radio_settings_driver ril_radio_settings_driver;
|
||||||
|
extern const struct ofono_sim_driver ril_sim_driver;
|
||||||
|
extern const struct ofono_sms_driver ril_sms_driver;
|
||||||
|
extern const struct ofono_stk_driver ril_stk_driver;
|
||||||
|
extern const struct ofono_ussd_driver ril_ussd_driver;
|
||||||
|
extern const struct ofono_voicecall_driver ril_voicecall_driver;
|
||||||
|
extern const struct ofono_netmon_driver ril_netmon_driver;
|
||||||
|
|
||||||
|
#endif /* RIL_PLUGIN_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
497
ofono/drivers/ril/ril_radio.c
Normal file
497
ofono/drivers/ril/ril_radio.c
Normal file
@@ -0,0 +1,497 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ril_radio.h"
|
||||||
|
#include "ril_util.h"
|
||||||
|
#include "ril_log.h"
|
||||||
|
|
||||||
|
#include <grilio_queue.h>
|
||||||
|
#include <grilio_request.h>
|
||||||
|
#include <grilio_parser.h>
|
||||||
|
|
||||||
|
#include <gutil_misc.h>
|
||||||
|
|
||||||
|
typedef GObjectClass RilRadioClass;
|
||||||
|
typedef struct ril_radio RilRadio;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Object states:
|
||||||
|
*
|
||||||
|
* 1. Idle (!pending && !retry)
|
||||||
|
* 2. Power on/off request pending (pending)
|
||||||
|
* 3. Power on retry has been scheduled (retry)
|
||||||
|
*/
|
||||||
|
struct ril_radio_priv {
|
||||||
|
GRilIoChannel *io;
|
||||||
|
GRilIoQueue *q;
|
||||||
|
gulong state_event_id;
|
||||||
|
char *log_prefix;
|
||||||
|
GHashTable *req_table;
|
||||||
|
guint pending_id;
|
||||||
|
guint retry_id;
|
||||||
|
guint state_changed_while_request_pending;
|
||||||
|
enum ril_radio_state last_known_state;
|
||||||
|
gboolean power_cycle;
|
||||||
|
gboolean next_state_valid;
|
||||||
|
gboolean next_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ril_radio_signal {
|
||||||
|
SIGNAL_STATE_CHANGED,
|
||||||
|
SIGNAL_ONLINE_CHANGED,
|
||||||
|
SIGNAL_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
#define POWER_RETRY_SECS (1)
|
||||||
|
|
||||||
|
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
|
||||||
|
#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
|
||||||
|
|
||||||
|
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
|
||||||
|
|
||||||
|
#define NEW_SIGNAL(klass,name) \
|
||||||
|
ril_radio_signals[SIGNAL_##name##_CHANGED] = \
|
||||||
|
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||||
|
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||||
|
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
|
||||||
|
#define RIL_RADIO_TYPE (ril_radio_get_type())
|
||||||
|
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
|
||||||
|
|
||||||
|
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||||
|
|
||||||
|
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
|
||||||
|
|
||||||
|
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
|
||||||
|
!priv->power_cycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||||
|
{
|
||||||
|
return radio_state == RADIO_STATE_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gboolean ril_radio_state_on(enum ril_radio_state radio_state)
|
||||||
|
{
|
||||||
|
return !ril_radio_state_off(radio_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ril_radio_emit_signal(struct ril_radio *self,
|
||||||
|
enum ril_radio_signal id)
|
||||||
|
{
|
||||||
|
g_signal_emit(self, ril_radio_signals[id], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct ril_radio *self = RIL_RADIO(user_data);
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
DBG_(self, "");
|
||||||
|
GASSERT(priv->retry_id);
|
||||||
|
priv->retry_id = 0;
|
||||||
|
ril_radio_submit_power_request(self,
|
||||||
|
ril_radio_power_should_be_on(self));
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_cancel_retry(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (priv->retry_id) {
|
||||||
|
DBG_(self, "retry cancelled");
|
||||||
|
g_source_remove(priv->retry_id);
|
||||||
|
priv->retry_id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_check_state(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (!priv->pending_id) {
|
||||||
|
gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||||
|
|
||||||
|
if (ril_radio_state_on(priv->last_known_state) ==
|
||||||
|
should_be_on) {
|
||||||
|
/* All is good, cancel pending retry if there is one */
|
||||||
|
ril_radio_cancel_retry(self);
|
||||||
|
} else if (priv->state_changed_while_request_pending) {
|
||||||
|
/* Hmm... RIL's reaction was inadequate, repeat */
|
||||||
|
ril_radio_submit_power_request(self, should_be_on);
|
||||||
|
} else if (!priv->retry_id) {
|
||||||
|
/* There has been no reaction so far, wait a bit */
|
||||||
|
DBG_(self, "retry scheduled");
|
||||||
|
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
|
||||||
|
ril_radio_power_request_retry_cb, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't update public state while something is pending */
|
||||||
|
if (!priv->pending_id && !priv->retry_id &&
|
||||||
|
self->state != priv->last_known_state) {
|
||||||
|
DBG_(self, "%s -> %s", ril_radio_state_to_string(self->state),
|
||||||
|
ril_radio_state_to_string(priv->last_known_state));
|
||||||
|
self->state = priv->last_known_state;
|
||||||
|
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_power_request_done(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
GASSERT(priv->pending_id);
|
||||||
|
priv->pending_id = 0;
|
||||||
|
|
||||||
|
if (priv->next_state_valid) {
|
||||||
|
ril_radio_submit_power_request(self, priv->next_state);
|
||||||
|
} else {
|
||||||
|
ril_radio_check_state(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_radio *self = RIL_RADIO(user_data);
|
||||||
|
|
||||||
|
if (ril_status != RIL_E_SUCCESS) {
|
||||||
|
ofono_error("Power request failed: %s",
|
||||||
|
ril_error_to_string(ril_status));
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_radio_power_request_done(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* RIL_REQUEST_RADIO_POWER
|
||||||
|
*
|
||||||
|
* "data" is int *
|
||||||
|
* ((int *)data)[0] is > 0 for "Radio On"
|
||||||
|
* ((int *)data)[0] is == 0 for "Radio Off"
|
||||||
|
*
|
||||||
|
* "response" is NULL
|
||||||
|
**/
|
||||||
|
GRilIoRequest *req = grilio_request_array_int32_new(1, on);
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
priv->next_state_valid = FALSE;
|
||||||
|
priv->next_state = on;
|
||||||
|
priv->state_changed_while_request_pending = 0;
|
||||||
|
ril_radio_cancel_retry(self);
|
||||||
|
|
||||||
|
GASSERT(!priv->pending_id);
|
||||||
|
grilio_request_set_blocking(req, TRUE);
|
||||||
|
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
|
||||||
|
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
|
||||||
|
NULL, self);
|
||||||
|
grilio_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||||
|
gboolean allow_repeat)
|
||||||
|
{
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
const char *on_off = on ? "on" : "off";
|
||||||
|
|
||||||
|
if (priv->pending_id) {
|
||||||
|
if (allow_repeat || priv->next_state != on) {
|
||||||
|
/* Wait for the pending request to complete */
|
||||||
|
priv->next_state_valid = TRUE;
|
||||||
|
priv->next_state = on;
|
||||||
|
DBG_(self, "%s (queued)", on_off);
|
||||||
|
} else {
|
||||||
|
DBG_(self, "%s (ignored)", on_off);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ril_radio_state_on(priv->last_known_state) == on) {
|
||||||
|
DBG_(self, "%s (already)", on_off);
|
||||||
|
ril_radio_check_state(self);
|
||||||
|
} else {
|
||||||
|
DBG_(self, "%s", on_off);
|
||||||
|
ril_radio_submit_power_request(self, on);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_confirm_power_on(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
|
||||||
|
ril_radio_power_request(self, TRUE, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_power_cycle(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (ril_radio_state_off(priv->last_known_state)) {
|
||||||
|
DBG_(self, "power is already off");
|
||||||
|
GASSERT(!priv->power_cycle);
|
||||||
|
} else if (priv->power_cycle) {
|
||||||
|
DBG_(self, "already in progress");
|
||||||
|
} else {
|
||||||
|
DBG_(self, "initiated");
|
||||||
|
priv->power_cycle = TRUE;
|
||||||
|
if (!priv->pending_id) {
|
||||||
|
ril_radio_submit_power_request(self, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (!g_hash_table_contains(priv->req_table, tag)) {
|
||||||
|
gboolean was_on = ril_radio_power_should_be_on(self);
|
||||||
|
|
||||||
|
DBG_(self, "%p", tag);
|
||||||
|
g_hash_table_insert(priv->req_table, tag, tag);
|
||||||
|
if (!was_on && ril_radio_power_should_be_on(self)) {
|
||||||
|
ril_radio_power_request(self, TRUE, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (g_hash_table_remove(priv->req_table, tag)) {
|
||||||
|
DBG_(self, "%p", tag);
|
||||||
|
if (!ril_radio_power_should_be_on(self)) {
|
||||||
|
/* The last one turns the lights off */
|
||||||
|
ril_radio_power_request(self, FALSE, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_set_online(struct ril_radio *self, gboolean online)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self) && self->online != online) {
|
||||||
|
gboolean on, was_on = ril_radio_power_should_be_on(self);
|
||||||
|
self->online = online;
|
||||||
|
on = ril_radio_power_should_be_on(self);
|
||||||
|
if (was_on != on) {
|
||||||
|
ril_radio_power_request(self, on, FALSE);
|
||||||
|
}
|
||||||
|
ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
|
||||||
|
ril_radio_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||||
|
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gulong ril_radio_add_online_changed_handler(struct ril_radio *self,
|
||||||
|
ril_radio_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||||
|
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||||
|
g_signal_handler_disconnect(self, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_remove_handlers(struct ril_radio *self, gulong *ids, int count)
|
||||||
|
{
|
||||||
|
gutil_disconnect_handlers(self, ids, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
|
||||||
|
{
|
||||||
|
GRilIoParser rilp;
|
||||||
|
int radio_state;
|
||||||
|
|
||||||
|
grilio_parser_init(&rilp, data, len);
|
||||||
|
if (grilio_parser_get_int32(&rilp, &radio_state)) {
|
||||||
|
return radio_state;
|
||||||
|
} else {
|
||||||
|
ofono_error("Error parsing radio state");
|
||||||
|
return RADIO_STATE_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||||
|
const void *data, guint len, void *user_data)
|
||||||
|
{
|
||||||
|
struct ril_radio *self = RIL_RADIO(user_data);
|
||||||
|
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
|
||||||
|
|
||||||
|
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
|
||||||
|
if (radio_state != RADIO_STATE_UNAVAILABLE) {
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
|
||||||
|
GASSERT(!priv->pending_id || !priv->retry_id);
|
||||||
|
|
||||||
|
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
|
||||||
|
DBG_(self, "switched off for power cycle");
|
||||||
|
priv->power_cycle = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->last_known_state = radio_state;
|
||||||
|
|
||||||
|
if (priv->pending_id) {
|
||||||
|
if (ril_radio_state_on(radio_state) ==
|
||||||
|
ril_radio_power_should_be_on(self)) {
|
||||||
|
DBG_(self, "dropping pending request");
|
||||||
|
/*
|
||||||
|
* All right, the modem has switched to the
|
||||||
|
* desired state, drop the request.
|
||||||
|
*/
|
||||||
|
grilio_queue_cancel_request(priv->q,
|
||||||
|
priv->pending_id, FALSE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This will zero pending_id and call
|
||||||
|
* ril_radio_check_state() if necesary:
|
||||||
|
*/
|
||||||
|
ril_radio_power_request_done(self);
|
||||||
|
|
||||||
|
/* We are done */
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* Something weird is going on */
|
||||||
|
priv->state_changed_while_request_pending++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ril_radio_check_state(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_radio *ril_radio_new(GRilIoChannel *io)
|
||||||
|
{
|
||||||
|
struct ril_radio *self = g_object_new(RIL_RADIO_TYPE, NULL);
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
priv->io = grilio_channel_ref(io);
|
||||||
|
priv->q = grilio_queue_new(priv->io);
|
||||||
|
priv->log_prefix =
|
||||||
|
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
|
||||||
|
g_strconcat(io->name, " ", NULL) : g_strdup("");
|
||||||
|
DBG_(self, "");
|
||||||
|
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||||
|
ril_radio_state_changed,
|
||||||
|
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
|
||||||
|
/*
|
||||||
|
* Some RILs like to receive power off request at startup even if
|
||||||
|
* radio is already off. Make those happy.
|
||||||
|
*/
|
||||||
|
ril_radio_submit_power_request(self, FALSE);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ril_radio *ril_radio_ref(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
g_object_ref(RIL_RADIO(self));
|
||||||
|
return self;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ril_radio_unref(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
g_object_unref(RIL_RADIO(self));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_init(struct ril_radio *self)
|
||||||
|
{
|
||||||
|
struct ril_radio_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||||
|
RIL_RADIO_TYPE, struct ril_radio_priv);
|
||||||
|
self->priv = priv;
|
||||||
|
priv->req_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_dispose(GObject *object)
|
||||||
|
{
|
||||||
|
struct ril_radio *self = RIL_RADIO(object);
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
if (priv->state_event_id) {
|
||||||
|
grilio_channel_remove_handler(priv->io, priv->state_event_id);
|
||||||
|
priv->state_event_id = 0;
|
||||||
|
}
|
||||||
|
if (priv->pending_id) {
|
||||||
|
grilio_queue_cancel_request(priv->q, priv->pending_id, FALSE);
|
||||||
|
priv->pending_id = 0;
|
||||||
|
}
|
||||||
|
priv->next_state_valid = FALSE;
|
||||||
|
ril_radio_cancel_retry(self);
|
||||||
|
grilio_queue_cancel_all(priv->q, FALSE);
|
||||||
|
G_OBJECT_CLASS(ril_radio_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_finalize(GObject *object)
|
||||||
|
{
|
||||||
|
struct ril_radio *self = RIL_RADIO(object);
|
||||||
|
struct ril_radio_priv *priv = self->priv;
|
||||||
|
|
||||||
|
DBG_(self, "");
|
||||||
|
g_free(priv->log_prefix);
|
||||||
|
grilio_channel_unref(priv->io);
|
||||||
|
grilio_queue_unref(priv->q);
|
||||||
|
g_hash_table_unref(priv->req_table);
|
||||||
|
G_OBJECT_CLASS(ril_radio_parent_class)->finalize(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ril_radio_class_init(RilRadioClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->dispose = ril_radio_dispose;
|
||||||
|
object_class->finalize = ril_radio_finalize;
|
||||||
|
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
|
||||||
|
NEW_SIGNAL(klass, STATE);
|
||||||
|
NEW_SIGNAL(klass, ONLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
60
ofono/drivers/ril/ril_radio.h
Normal file
60
ofono/drivers/ril/ril_radio.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* oFono - Open Source Telephony - RIL-based devices
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RIL_RADIO_H
|
||||||
|
#define RIL_RADIO_H
|
||||||
|
|
||||||
|
#include "ril_types.h"
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
struct ril_radio {
|
||||||
|
GObject object;
|
||||||
|
struct ril_radio_priv *priv;
|
||||||
|
enum ril_radio_state state;
|
||||||
|
gboolean online;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
|
||||||
|
|
||||||
|
struct ril_radio *ril_radio_new(GRilIoChannel *io);
|
||||||
|
struct ril_radio *ril_radio_ref(struct ril_radio *radio);
|
||||||
|
void ril_radio_unref(struct ril_radio *radio);
|
||||||
|
|
||||||
|
void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
|
||||||
|
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
|
||||||
|
void ril_radio_power_cycle(struct ril_radio *radio);
|
||||||
|
void ril_radio_confirm_power_on(struct ril_radio *radio);
|
||||||
|
void ril_radio_set_online(struct ril_radio *radio, gboolean online);
|
||||||
|
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
|
||||||
|
ril_radio_cb_t cb, void *arg);
|
||||||
|
gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
|
||||||
|
ril_radio_cb_t cb, void *arg);
|
||||||
|
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
|
||||||
|
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
|
||||||
|
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
|
||||||
|
|
||||||
|
#define ril_radio_remove_all_handlers(r,ids) \
|
||||||
|
ril_radio_remove_handlers(r, ids, G_N_ELEMENTS(ids))
|
||||||
|
|
||||||
|
#endif /* RIL_RADIO_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user