forked from sailfishos/ofono
Compare commits
1400 Commits
mer/1.16+g
...
upgrade-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
3860230644 | ||
|
|
063234a433 | ||
|
|
a5b040b781 | ||
|
|
97abe1751d | ||
|
|
2f75b13ecd | ||
|
|
73e517bcca | ||
|
|
dae225a0d6 | ||
|
|
97ac3f7c76 | ||
|
|
26a00f2f31 | ||
|
|
cede3700f7 | ||
|
|
318d313fc9 | ||
|
|
8e6ebab83b | ||
|
|
d8edd49535 | ||
|
|
8660527b11 | ||
|
|
d6bc91ebfc | ||
|
|
3d592d7d46 | ||
|
|
e2398b4dfa | ||
|
|
42deee76a1 | ||
|
|
2af3c733b7 | ||
|
|
604fa223f4 | ||
|
|
04218d3a86 | ||
|
|
41fadd3787 | ||
|
|
d539ed19f3 | ||
|
|
25f926c733 | ||
|
|
151b837428 |
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>
|
||||
39
ofono/.gitignore
vendored
39
ofono/.gitignore
vendored
@@ -32,6 +32,8 @@ src/ofono.service
|
||||
dundee/dundee
|
||||
dundee/dundee.service
|
||||
|
||||
test-driver
|
||||
test-suite.log
|
||||
unit/test-common
|
||||
unit/test-util
|
||||
unit/test-idmap
|
||||
@@ -42,6 +44,43 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-dbus-queue
|
||||
unit/test-gprs-filter
|
||||
unit/test-ril_config
|
||||
unit/test-ril_util
|
||||
unit/test-ril-transport
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
unit/test-rilmodem-sms
|
||||
unit/test-sailfish_cell_info
|
||||
unit/test-sailfish_cell_info_dbus
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sailfish_sim_info_dbus
|
||||
unit/test-sailfish_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/auto-enable
|
||||
|
||||
@@ -99,3 +99,30 @@ 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,77 @@
|
||||
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.
|
||||
|
||||
@@ -113,3 +113,5 @@ doc/coding-style.txt.
|
||||
a feature that touches files under 'include/', 'src/' and 'drivers/'
|
||||
directories, split in three separated patches, taking care not to
|
||||
break compilation.
|
||||
|
||||
4) Submit patches using git send-email to ofono@ofono.org
|
||||
|
||||
@@ -21,12 +21,22 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/cdma-connman.h include/gnss.h \
|
||||
include/private-network.h include/cdma-netreg.h \
|
||||
include/cdma-provision.h include/handsfree.h \
|
||||
include/handsfree-audio.h \
|
||||
include/sim-mnclength.h include/oemraw.h \
|
||||
include/siri.h
|
||||
include/sim-mnclength.h \
|
||||
include/handsfree-audio.h include/siri.h \
|
||||
include/sms-filter.h include/gprs-filter.h \
|
||||
include/voicecall-filter.h \
|
||||
include/ril-constants.h include/ril-transport.h \
|
||||
include/netmon.h include/lte.h \
|
||||
include/storage.h \
|
||||
gdbus/gdbus.h
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
|
||||
include/sailfish_manager.h include/sailfish_watch.h
|
||||
endif
|
||||
|
||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
||||
$(nodist_pkginclude_HEADERS), \
|
||||
include/ofono/$(notdir $(file)))
|
||||
@@ -97,20 +107,16 @@ gisi_sources = gisi/client.c gisi/client.h gisi/common.h \
|
||||
gisi/server.c gisi/server.h \
|
||||
gisi/socket.c gisi/socket.h
|
||||
|
||||
gril_sources = gril/gril.h gril/gril.c gril/grilio.h \
|
||||
gril/grilio.c gril/grilutil.h \
|
||||
gril/grilutil.c gril/ringbuffer.h \
|
||||
gril/gfunc.h gril/ril.h \
|
||||
gril_sources = gril/gril.h gril/gril.c \
|
||||
gril/grilio.h gril/grilio.c \
|
||||
gril/grilutil.h gril/grilutil.c \
|
||||
gril/gfunc.h gril/gril.h \
|
||||
gril/parcel.c gril/parcel.h \
|
||||
gril/grilreply.c gril/grilreply.h \
|
||||
gril/grilrequest.c gril/grilrequest.h \
|
||||
gril/grilunsol.c gril/grilunsol.h
|
||||
gril/ril_constants.h
|
||||
|
||||
btio_sources = btio/btio.h btio/btio.c
|
||||
|
||||
if UDEV
|
||||
builtin_modules += udev
|
||||
builtin_sources += plugins/udev.c
|
||||
builtin_cflags += @UDEV_CFLAGS@
|
||||
builtin_libadd += @UDEV_LIBS@
|
||||
|
||||
@@ -118,21 +124,84 @@ builtin_modules += udevng
|
||||
builtin_sources += plugins/udevng.c
|
||||
endif
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
builtin_modules += sailfish_manager
|
||||
builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_manager_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_watch.c
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_forward.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_netmon.c \
|
||||
drivers/ril/ril_netreg.c \
|
||||
drivers/ril/ril_network.c \
|
||||
drivers/ril/ril_oem_raw.c \
|
||||
drivers/ril/ril_phonebook.c \
|
||||
drivers/ril/ril_plugin.c \
|
||||
drivers/ril/ril_radio.c \
|
||||
drivers/ril/ril_radio_caps.c \
|
||||
drivers/ril/ril_radio_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_settings.c \
|
||||
drivers/ril/ril_sms.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
drivers/ril/ril_ussd.c \
|
||||
drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_vendor.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
# Vendor specific extensions
|
||||
builtin_sources += drivers/ril/ril_vendor_mtk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
builtin_modules += rildev
|
||||
builtin_sources += plugins/rildev.c
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += plugins/ril.c
|
||||
builtin_sources += plugins/ril.c plugins/ril.h
|
||||
|
||||
builtin_modules += infineon
|
||||
builtin_sources += plugins/infineon.c
|
||||
|
||||
builtin_modules += ril_intel
|
||||
builtin_sources += plugins/ril_intel.c
|
||||
|
||||
builtin_modules += rilmodem
|
||||
builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/vendor.h \
|
||||
drivers/rilmodem/rilmodem.c \
|
||||
drivers/rilmodem/devinfo.c \
|
||||
drivers/rilmodem/network-registration.c \
|
||||
drivers/rilmodem/voicecall.c \
|
||||
drivers/rilmodem/voicecall.h \
|
||||
drivers/rilmodem/call-volume.c \
|
||||
drivers/rilmodem/gprs.c \
|
||||
drivers/rilmodem/gprs-context.c \
|
||||
@@ -140,16 +209,17 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/sms.c \
|
||||
drivers/rilmodem/rilutil.c \
|
||||
drivers/rilmodem/rilutil.h \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/phonebook.c \
|
||||
drivers/rilmodem/ussd.c \
|
||||
drivers/rilmodem/call-settings.c \
|
||||
drivers/rilmodem/call-forwarding.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/rilmodem/oemraw-messages.c \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/call-barring.c \
|
||||
drivers/rilmodem/stk.c
|
||||
|
||||
drivers/rilmodem/netmon.c \
|
||||
drivers/rilmodem/stk.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/infineonmodem/infineon_constants.h \
|
||||
drivers/rilmodem/lte.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if ISIMODEM
|
||||
@@ -207,11 +277,13 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
|
||||
drivers/qmimodem/ctl.h \
|
||||
drivers/qmimodem/dms.h \
|
||||
drivers/qmimodem/nas.h \
|
||||
drivers/qmimodem/nas.c \
|
||||
drivers/qmimodem/uim.h \
|
||||
drivers/qmimodem/wms.h \
|
||||
drivers/qmimodem/wds.h \
|
||||
drivers/qmimodem/pds.h \
|
||||
drivers/qmimodem/common.h
|
||||
drivers/qmimodem/common.h \
|
||||
drivers/qmimodem/wda.h
|
||||
|
||||
builtin_modules += qmimodem
|
||||
builtin_sources += $(qmi_sources) \
|
||||
@@ -228,7 +300,8 @@ builtin_sources += $(qmi_sources) \
|
||||
drivers/qmimodem/gprs.c \
|
||||
drivers/qmimodem/gprs-context.c \
|
||||
drivers/qmimodem/radio-settings.c \
|
||||
drivers/qmimodem/location-reporting.c
|
||||
drivers/qmimodem/location-reporting.c \
|
||||
drivers/qmimodem/netmon.c
|
||||
|
||||
builtin_modules += gobi
|
||||
builtin_sources += plugins/gobi.c
|
||||
@@ -236,8 +309,7 @@ endif
|
||||
|
||||
if ATMODEM
|
||||
builtin_modules += atmodem
|
||||
builtin_sources += $(gatchat_sources) \
|
||||
drivers/atmodem/atmodem.h \
|
||||
builtin_sources += drivers/atmodem/atmodem.h \
|
||||
drivers/atmodem/atmodem.c \
|
||||
drivers/atmodem/call-settings.c \
|
||||
drivers/atmodem/sms.c \
|
||||
@@ -260,7 +332,8 @@ builtin_sources += $(gatchat_sources) \
|
||||
drivers/atmodem/gprs.c \
|
||||
drivers/atmodem/gprs-context.c \
|
||||
drivers/atmodem/sim-auth.c \
|
||||
drivers/atmodem/gnss.c
|
||||
drivers/atmodem/gnss.c \
|
||||
drivers/atmodem/lte.c
|
||||
|
||||
builtin_modules += nwmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
@@ -317,7 +390,8 @@ builtin_modules += telitmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/telitmodem/telitmodem.h \
|
||||
drivers/telitmodem/telitmodem.c \
|
||||
drivers/telitmodem/location-reporting.c
|
||||
drivers/telitmodem/location-reporting.c \
|
||||
drivers/telitmodem/gprs-context-ncm.c
|
||||
|
||||
builtin_modules += hsomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
@@ -375,15 +449,33 @@ builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/speedupmodem/speedupmodem.c \
|
||||
drivers/speedupmodem/ussd.c
|
||||
|
||||
builtin_modules += ubloxmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/ubloxmodem/ubloxmodem.h \
|
||||
drivers/ubloxmodem/ubloxmodem.c \
|
||||
drivers/ubloxmodem/gprs-context.c \
|
||||
drivers/ubloxmodem/netmon.c \
|
||||
drivers/ubloxmodem/lte.c
|
||||
|
||||
|
||||
builtin_modules += gemaltomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/gemaltomodem/gemaltomodem.h \
|
||||
drivers/gemaltomodem/gemaltomodem.c \
|
||||
drivers/gemaltomodem/location-reporting.c
|
||||
|
||||
builtin_modules += xmm7modem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/xmm7modem/xmm7modem.h \
|
||||
drivers/xmm7modem/xmm7modem.c \
|
||||
drivers/xmm7modem/radio-settings.c
|
||||
|
||||
if PHONESIM
|
||||
builtin_modules += phonesim
|
||||
builtin_sources += plugins/phonesim.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += plugins/phonesim.conf
|
||||
if RILMODEM
|
||||
dist_conf_DATA += gril/ril_subscription.conf
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -439,8 +531,11 @@ builtin_sources += plugins/stemgr.c
|
||||
builtin_modules += caif
|
||||
builtin_sources += plugins/caif.c
|
||||
|
||||
builtin_modules += tc65
|
||||
builtin_sources += plugins/tc65.c
|
||||
builtin_modules += cinterion
|
||||
builtin_sources += plugins/cinterion.c
|
||||
|
||||
builtin_modules += gemalto
|
||||
builtin_sources += plugins/gemalto.c
|
||||
|
||||
builtin_modules += nokia
|
||||
builtin_sources += plugins/nokia.c
|
||||
@@ -469,38 +564,55 @@ builtin_sources += plugins/samsung.c
|
||||
builtin_modules += sim900
|
||||
builtin_sources += plugins/sim900.c
|
||||
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c
|
||||
|
||||
builtin_modules += quectel
|
||||
builtin_sources += plugins/quectel.c
|
||||
|
||||
builtin_modules += ublox
|
||||
builtin_sources += plugins/ublox.c
|
||||
|
||||
builtin_modules += he910
|
||||
builtin_sources += plugins/he910.c
|
||||
builtin_modules += xmm7xxx
|
||||
builtin_sources += plugins/xmm7xxx.c
|
||||
endif
|
||||
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
|
||||
if BLUETOOTH
|
||||
if BLUEZ4
|
||||
builtin_modules += bluez4
|
||||
builtin_sources += plugins/bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += sap
|
||||
builtin_sources += plugins/sap.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_bluez4
|
||||
builtin_sources += plugins/hfp_hf_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez4
|
||||
builtin_sources += plugins/hfp_ag_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += dun_gw_bluez4
|
||||
builtin_sources += plugins/dun_gw_bluez4.c plugins/bluez4.h
|
||||
else
|
||||
builtin_modules += hfp_bluez5
|
||||
builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += dun_gw_bluez5
|
||||
builtin_sources += plugins/dun_gw_bluez5.c plugins/bluez5.h
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if BLUETOOTH
|
||||
if BLUEZ4
|
||||
builtin_modules += bluez4
|
||||
builtin_sources += plugins/bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez4
|
||||
builtin_sources += plugins/hfp_ag_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_sources += $(btio_sources)
|
||||
builtin_cflags += @BLUEZ_CFLAGS@
|
||||
@@ -509,16 +621,19 @@ else
|
||||
builtin_modules += bluez5
|
||||
builtin_sources += plugins/bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_bluez5
|
||||
builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez5
|
||||
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += dun_gw_bluez5
|
||||
builtin_sources += plugins/dun_gw_bluez5.c plugins/bluez5.h
|
||||
if SAILFISH_BT
|
||||
builtin_modules += sfos_bt
|
||||
builtin_sources += plugins/sailfish_bt.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if UPOWER
|
||||
builtin_modules += upower
|
||||
builtin_sources += plugins/upower.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if NETTIME
|
||||
@@ -526,17 +641,32 @@ builtin_modules += nettime
|
||||
builtin_sources += plugins/nettime.c
|
||||
endif
|
||||
|
||||
if SAILFISH_DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/sailfish_debuglog.c
|
||||
endif
|
||||
|
||||
if SAILFISH_PROVISION
|
||||
builtin_sources += plugins/sailfish_provision.c
|
||||
PROVISION = 1
|
||||
else
|
||||
if PROVISION
|
||||
builtin_sources += plugins/provision.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if PROVISION
|
||||
builtin_sources += plugins/mbpi.h plugins/mbpi.c
|
||||
|
||||
builtin_modules += provision
|
||||
builtin_sources += plugins/provision.h plugins/provision.c
|
||||
builtin_sources += plugins/provision.h
|
||||
|
||||
builtin_modules += cdma_provision
|
||||
builtin_sources += plugins/cdma-provision.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
builtin_modules += file_provision
|
||||
builtin_sources += plugins/file-provision.c
|
||||
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
@@ -568,19 +698,21 @@ builtin_sources += plugins/smart-messaging.c
|
||||
builtin_modules += push_notification
|
||||
builtin_sources += plugins/push-notification.c
|
||||
|
||||
if PUSHFORWARDER
|
||||
builtin_modules += push_forwarder
|
||||
builtin_sources += plugins/push-forwarder.c
|
||||
builtin_cflags += @WSPCODEC_CFLAGS@
|
||||
builtin_libadd += @WSPCODEC_LIBS@
|
||||
if SAILFISH_PUSHFORWARDER
|
||||
builtin_modules += pushforwarder
|
||||
builtin_sources += plugins/sailfish_pushforwarder.c
|
||||
endif
|
||||
|
||||
builtin_modules += sms_history
|
||||
builtin_sources += plugins/smshistory.c
|
||||
|
||||
builtin_modules += allowed_apns
|
||||
builtin_sources += plugins/allowed-apns.c
|
||||
|
||||
sbin_PROGRAMS = src/ofonod
|
||||
|
||||
src_ofonod_SOURCES = $(builtin_sources) src/ofono.ver \
|
||||
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/mtu-watch.c \
|
||||
src/main.c src/ofono.h src/log.c src/plugin.c \
|
||||
src/modem.c src/common.h src/common.c \
|
||||
src/manager.c src/dbus.c src/util.h src/util.c \
|
||||
@@ -605,8 +737,12 @@ src_ofonod_SOURCES = $(builtin_sources) src/ofono.ver \
|
||||
src/cdma-sms.c src/private-network.c src/cdma-netreg.c \
|
||||
src/cdma-provision.c src/handsfree.c \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/sim-mnclength.c src/oemraw.c src/voicecallagent.c \
|
||||
src/hfp.h src/siri.c
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/sms-filter.c src/gprs-filter.c src/dbus-queue.c \
|
||||
src/voicecall-filter.c src/ril-transport.c \
|
||||
src/hfp.h src/siri.c \
|
||||
src/netmon.c src/lte.c \
|
||||
src/netmonagent.c src/netmonagent.h
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -616,7 +752,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
|
||||
|
||||
BUILT_SOURCES = $(local_headers) src/builtin.h
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
|
||||
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
|
||||
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
|
||||
|
||||
plugindir = $(pkglibdir)/plugins
|
||||
|
||||
@@ -652,7 +789,11 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/location-reporting-api.txt \
|
||||
doc/smshistory-api.txt doc/oemraw-api.txt \
|
||||
doc/certification.txt doc/siri-api.txt \
|
||||
doc/telit-modem.txt
|
||||
doc/telit-modem.txt \
|
||||
doc/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt \
|
||||
doc/lte-api.txt \
|
||||
doc/cinterion-hardware-monitor-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -686,6 +827,7 @@ test_scripts = test/backtrace \
|
||||
test/receive-sms \
|
||||
test/remove-contexts \
|
||||
test/send-sms \
|
||||
test/cancel-sms \
|
||||
test/set-mic-volume \
|
||||
test/set-speaker-volume \
|
||||
test/test-stk-menu \
|
||||
@@ -750,7 +892,18 @@ test_scripts = test/backtrace \
|
||||
test/set-msisdn \
|
||||
test/test-voicecallagent \
|
||||
test/get-network-time \
|
||||
test/set-ddr
|
||||
test/set-ddr \
|
||||
test/register-auto \
|
||||
test/register-operator \
|
||||
test/set-sms-smsc \
|
||||
test/set-sms-bearer \
|
||||
test/get-serving-cell-info \
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling \
|
||||
test/set-lte-property \
|
||||
test/test-serving-cell-info
|
||||
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -762,35 +915,133 @@ EXTRA_DIST = src/genbuiltin plugins/ofono.rules plugins/ofono-speedup.rules \
|
||||
|
||||
dist_man_MANS = doc/ofonod.8
|
||||
|
||||
if TEST_COVERAGE
|
||||
COVERAGE_OPT = --coverage
|
||||
endif
|
||||
|
||||
unit_objects =
|
||||
|
||||
unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
||||
unit/test-simutil unit/test-stkutil \
|
||||
unit/test-sms unit/test-cdmasms \
|
||||
unit/test-grilrequest \
|
||||
unit/test-grilreply \
|
||||
unit/test-grilunsol \
|
||||
unit/test-sms unit/test-cdmasms \
|
||||
unit/test-provision
|
||||
unit/test-sms unit/test-cdmasms
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-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_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/watch.c src/log.c
|
||||
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info
|
||||
|
||||
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
|
||||
unit/test-dbus.c unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/storage.c src/watch.c src/log.c
|
||||
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_sailfish_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_sailfish_watch_SOURCES = unit/test-sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_watch.c \
|
||||
src/log.c src/watch.c
|
||||
unit_test_sailfish_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
unit_test_sailfish_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_watch_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_watch
|
||||
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
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) \
|
||||
unit/test-sms-root unit/test-mux unit/test-caif
|
||||
|
||||
unit_test_common_SOURCES = unit/test-common.c src/common.c src/util.c
|
||||
unit_test_common_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_common_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_common_OBJECTS)
|
||||
|
||||
unit_test_util_SOURCES = unit/test-util.c src/util.c
|
||||
unit_test_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_util_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_utils_OBJECTS)
|
||||
|
||||
unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
|
||||
unit_test_idmap_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_idmap_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_idmap_OBJECTS)
|
||||
|
||||
unit_test_simutil_SOURCES = unit/test-simutil.c src/util.c \
|
||||
src/simutil.c src/smsutil.c src/storage.c
|
||||
unit_test_simutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_simutil_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_simutil_OBJECTS)
|
||||
|
||||
@@ -798,19 +1049,23 @@ unit_test_stkutil_SOURCES = unit/test-stkutil.c unit/stk-test-data.h \
|
||||
src/util.c \
|
||||
src/storage.c src/smsutil.c \
|
||||
src/simutil.c src/stkutil.c
|
||||
unit_test_stkutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_stkutil_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_stkutil_OBJECTS)
|
||||
|
||||
unit_test_sms_SOURCES = unit/test-sms.c src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_OBJECTS)
|
||||
|
||||
unit_test_cdmasms_SOURCES = unit/test-cdmasms.c src/cdma-smsutil.c
|
||||
unit_test_cdmasms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_cdmasms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_cdmasms_OBJECTS)
|
||||
|
||||
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
|
||||
src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_root_CFLAGS = -DSTORAGEDIR='"/tmp/ofono"' $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_root_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_root_OBJECTS)
|
||||
|
||||
@@ -821,30 +1076,92 @@ unit_objects += $(unit_test_mux_OBJECTS)
|
||||
unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
|
||||
drivers/stemodem/caif_socket.h \
|
||||
drivers/stemodem/if_caif.h
|
||||
unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_grilrequest_SOURCES = unit/test-grilrequest.c $(gril_sources) \
|
||||
src/log.c gatchat/ringbuffer.c
|
||||
unit_test_grilrequest_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_grilrequest_OBJECTS)
|
||||
|
||||
unit_test_grilreply_SOURCES = unit/test-grilreply.c $(gril_sources) \
|
||||
src/log.c gatchat/ringbuffer.c
|
||||
unit_test_grilreply_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_grilreply_OBJECTS)
|
||||
|
||||
unit_test_grilunsol_SOURCES = unit/test-grilunsol.c $(gril_sources) \
|
||||
src/log.c gatchat/ringbuffer.c
|
||||
unit_test_grilunsol_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_grilunsol_OBJECTS)
|
||||
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||
src/dbus-queue.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_queue_OBJECTS)
|
||||
unit_tests += unit/test-dbus-queue
|
||||
|
||||
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
plugins/provision.h plugins/provision.c \
|
||||
plugins/mbpi.c src/gprs-provision.c \
|
||||
src/log.c
|
||||
plugins/provision.h plugins/mbpi.c \
|
||||
plugins/sailfish_provision.c \
|
||||
src/gprs-provision.c src/log.c
|
||||
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_provision_OBJECTS)
|
||||
unit_tests += unit/test-provision
|
||||
|
||||
unit_test_ril_transport_SOURCES = unit/test-ril-transport.c \
|
||||
src/ril-transport.c src/log.c
|
||||
unit_test_ril_transport_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_transport_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_transport_OBJECTS)
|
||||
unit_tests += unit/test-ril-transport
|
||||
|
||||
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
|
||||
src/sms-filter.c src/log.c
|
||||
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sms_filter_OBJECTS)
|
||||
unit_tests += unit/test-sms-filter
|
||||
|
||||
unit_test_gprs_filter_SOURCES = unit/test-gprs-filter.c \
|
||||
src/gprs-filter.c src/log.c
|
||||
unit_test_gprs_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_gprs_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_gprs_filter_OBJECTS)
|
||||
unit_tests += unit/test-gprs-filter
|
||||
|
||||
unit_test_voicecall_filter_SOURCES = unit/test-voicecall-filter.c \
|
||||
src/voicecall-filter.c src/log.c \
|
||||
src/common.c src/util.c
|
||||
unit_test_voicecall_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_voicecall_filter_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_voicecall_filter_OBJECTS)
|
||||
unit_tests += unit/test-voicecall-filter
|
||||
|
||||
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
|
||||
gatchat/ringbuffer.h gatchat/ringbuffer.c \
|
||||
unit/rilmodem-test-server.h \
|
||||
unit/rilmodem-test-server.c \
|
||||
unit/rilmodem-test-engine.h \
|
||||
unit/rilmodem-test-engine.c \
|
||||
src/simutil.c \
|
||||
drivers/rilmodem/rilutil.c
|
||||
|
||||
unit_test_rilmodem_cs_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-cs.c \
|
||||
drivers/rilmodem/call-settings.c
|
||||
unit_test_rilmodem_cs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_cs_OBJECTS)
|
||||
|
||||
unit_test_rilmodem_sms_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-sms.c \
|
||||
drivers/rilmodem/sms.c
|
||||
unit_test_rilmodem_sms_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_sms_OBJECTS)
|
||||
|
||||
unit_test_rilmodem_cb_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-cb.c \
|
||||
drivers/rilmodem/call-barring.c
|
||||
unit_test_rilmodem_cb_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_cb_OBJECTS)
|
||||
|
||||
unit_test_rilmodem_gprs_SOURCES = $(test_rilmodem_sources) \
|
||||
unit/test-rilmodem-gprs.c \
|
||||
drivers/rilmodem/gprs.c
|
||||
unit_test_rilmodem_gprs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_rilmodem_gprs_OBJECTS)
|
||||
|
||||
TESTS = $(unit_tests)
|
||||
|
||||
@@ -872,13 +1189,6 @@ tools_lookup_provider_name_LDADD = @GLIB_LIBS@
|
||||
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
||||
tools_tty_redirector_LDADD = @GLIB_LIBS@
|
||||
|
||||
if QMIMODEM
|
||||
noinst_PROGRAMS += tools/qmi
|
||||
|
||||
tools_qmi_SOURCES = $(qmi_sources) tools/qmi.c
|
||||
tools_qmi_LDADD = @GLIB_LIBS@
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
noinst_PROGRAMS += tools/stktest
|
||||
|
||||
@@ -947,6 +1257,10 @@ include/ofono/version.h: include/version.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
|
||||
|
||||
include/ofono/gdbus.h: $(abs_top_srcdir)/gdbus/gdbus.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $< $@
|
||||
|
||||
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
|
||||
$(AM_V_at)$(MKDIR_P) include/ofono
|
||||
$(AM_V_GEN)$(LN_S) $< $@
|
||||
|
||||
10
ofono/TODO
10
ofono/TODO
@@ -256,6 +256,16 @@ Voicecall
|
||||
Priority: Medium
|
||||
Complexity: C1
|
||||
|
||||
- DTMF Driver hints
|
||||
|
||||
Currently multiple DTMF tones are sent to the driver in batches of up to 8
|
||||
characters. For those drivers that can only accept a limited set of DTMF
|
||||
characters at a time (e.g. one), add a setting to the core that will change
|
||||
this batch size limit.
|
||||
|
||||
Priority: Medium
|
||||
Complexity: C1
|
||||
|
||||
|
||||
Sim Toolkit
|
||||
===========
|
||||
|
||||
@@ -22,6 +22,7 @@ AC_DEFUN([COMPILER_FLAGS], [
|
||||
CFLAGS="$CFLAGS -Wmissing-declarations"
|
||||
CFLAGS="$CFLAGS -Wredundant-decls"
|
||||
CFLAGS="$CFLAGS -Wcast-align"
|
||||
CFLAGS="$CFLAGS -Wno-format-truncation"
|
||||
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.16)
|
||||
AC_INIT(ofono, 1.21)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -42,6 +42,7 @@ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
|
||||
if (test "${enableval}" = "yes" &&
|
||||
test "${ac_cv_prog_cc_g}" = "yes"); then
|
||||
CFLAGS="$CFLAGS -g"
|
||||
CPPFLAGS="$CPPFLAGS -DDEBUG"
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -63,11 +64,21 @@ AC_CHECK_FUNC(signalfd, dummy=yes,
|
||||
AC_CHECK_LIB(dl, dlopen, dummy=yes,
|
||||
AC_MSG_ERROR(dynamic linking loader is required))
|
||||
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.28 is required))
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.32 is required))
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(GOBJECT, gobject-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GObject is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GOBJECT_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GOBJECT_LIBS"
|
||||
|
||||
PKG_CHECK_MODULES(GIO, gio-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GIO is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GIO_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GIO_LIBS"
|
||||
|
||||
if (test "${enable_threads}" = "yes"); then
|
||||
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
||||
@@ -166,6 +177,51 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
|
||||
[enable_rilmodem=${enableval}])
|
||||
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||
[enable Sailfish RIL modem]),
|
||||
[enable_sailfish_rilmodem=${enableval}],
|
||||
[enable_sailfish_rilmodem="no"])
|
||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||
|
||||
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],
|
||||
[disable Qualcomm QMI modem support]),
|
||||
[enable_qmimodem=${enableval}])
|
||||
@@ -189,6 +245,16 @@ fi
|
||||
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
|
||||
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-bt, AC_HELP_STRING([--enable-sailfish-bt],
|
||||
[enable Sailfish OS Bluetooth plugin]),
|
||||
[enable_sailfish_bt=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_BT, test "${enable_sailfish_bt}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
|
||||
[enable Sailfish OS provisioning plugin]),
|
||||
[enable_sailfish_provision=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
|
||||
[disable Nettime plugin]),
|
||||
[enable_nettime=${enableval}])
|
||||
@@ -201,7 +267,7 @@ AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE],
|
||||
[location of provision database]), [path_provisiondb=${withval}])
|
||||
|
||||
AC_ARG_ENABLE(provision, AC_HELP_STRING([--disable-provision],
|
||||
[disable provisioning suport]),
|
||||
[disable provisioning support]),
|
||||
[enable_provision=${enableval}])
|
||||
if (test "${enable_provision}" != "no"); then
|
||||
if (test -n "${path_provisiondb}"); then
|
||||
@@ -221,20 +287,46 @@ if (test "${enable_provision}" != "no"); then
|
||||
fi
|
||||
AM_CONDITIONAL(PROVISION, test "${enable_provision}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(upower, AC_HELP_STRING([--disable-upower],
|
||||
[disable UPower plugin]),
|
||||
[enable_upower=${enableval}])
|
||||
AM_CONDITIONAL(UPOWER, test "${enable_power}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
|
||||
[do not install configuration and data files]),
|
||||
[enable_datafiles=${enableval}])
|
||||
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
|
||||
[disable Push Forwarder plugin]),
|
||||
[enable_pushforwarder=${enableval}])
|
||||
AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
|
||||
if (test "${enable_pushforwarder}" != "no"); then
|
||||
AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforwarder],
|
||||
[enable Sailfish OS push forwarder plugin]),
|
||||
[enable_sailfish_pushforwarder=${enableval}],
|
||||
[enable_sailfish_pushforwarder="no"])
|
||||
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
|
||||
if (test "${enable_sailfish_pushforwarder}" != "no"); then
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.15, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.15 is required))
|
||||
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
|
||||
AC_MSG_ERROR(WSP decoder is required))
|
||||
AC_SUBST(WSPCODEC_CFLAGS)
|
||||
AC_SUBST(WSPCODEC_LIBS)
|
||||
AC_MSG_ERROR(WSP decoder is required))
|
||||
CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
|
||||
LIBS="$LIBS $WSPCODEC_LIBS"
|
||||
need_glibutil=yes
|
||||
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
|
||||
|
||||
if (test "${prefix}" = "NONE"); then
|
||||
@@ -251,7 +343,7 @@ if (test "$localstatedir" = '${prefix}/var'); then
|
||||
else
|
||||
storagedir="${localstatedir}/lib/ofono"
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_STORAGEDIR, "${storagedir}",
|
||||
[Directory for the storage files])
|
||||
|
||||
if (test "$sysconfdir" = '${prefix}/etc'); then
|
||||
|
||||
17
ofono/doc/allowed-apns-api.txt
Normal file
17
ofono/doc/allowed-apns-api.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Allowed APNs hierarchy
|
||||
=========================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.AllowedAccessPoints
|
||||
Object path [variable prefix]/{modem0,modem1,...}
|
||||
|
||||
Methods array{string} GetAllowedAccessPoints()
|
||||
|
||||
Get the list of allowed access points provided
|
||||
in the SIM card.
|
||||
|
||||
This method returns an array of strings which
|
||||
contains a list of Access Point Names supported
|
||||
by network provider. Returns with an error if
|
||||
SIM reading failed or an empty list if there
|
||||
are no access points listed on the SIM.
|
||||
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
16
ofono/doc/cinterion-hardware-monitor-api.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
HardwareMonitor hierarchy
|
||||
=========================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.cinterion.HardwareMonitor
|
||||
Object path /{device0,device1,...}
|
||||
|
||||
Methods array{string,variant} GetStatistics
|
||||
|
||||
Returns an array of dict entries representing the
|
||||
current temperature and supply voltage of the modem.
|
||||
|
||||
Units:
|
||||
Temperature: Celsius
|
||||
Voltage: mV
|
||||
@@ -19,7 +19,7 @@ Besides the kernel coding style above, oFono has special flavors for its own.
|
||||
Some of them are mandatory (marked as 'M'), while some others are optional
|
||||
(marked as 'O'), but generally preferred.
|
||||
|
||||
M1: Blank line before and after an if/while/do/for statement
|
||||
M1: Blank line before and after an if/while/do/for/switch statement
|
||||
============================================================
|
||||
There should be a blank line before if statement unless the if is nested and
|
||||
not preceded by an expression or variable declaration.
|
||||
@@ -306,6 +306,13 @@ Example:
|
||||
2)
|
||||
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
|
||||
====================
|
||||
Better to use abbreviation, rather than full name, to name a variable,
|
||||
|
||||
@@ -60,6 +60,16 @@ Methods dict GetProperties()
|
||||
[service].Error.NotFound
|
||||
[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)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
@@ -96,7 +106,7 @@ Properties boolean Attached [readonly]
|
||||
GPRS service registration (if known).
|
||||
|
||||
Possible values are:
|
||||
"none", "gsm", "edge", "umts", "hsdpa", "hsupa",
|
||||
"none", "gprs", "edge", "umts", "hsdpa", "hsupa",
|
||||
"hspa" (HSDPA and HSUPA at the same time) and
|
||||
"lte"
|
||||
|
||||
|
||||
@@ -76,6 +76,22 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
fd, byte Acquire()
|
||||
|
||||
Attempts to establish the SCO audio connection
|
||||
returning the filedescriptor of the connection and the
|
||||
codec in use.
|
||||
|
||||
Note: Contrary to Connect this does not call
|
||||
NewConnection so it can be called in a blocking
|
||||
manner.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.Failed
|
||||
[service].Error.NotAvailable
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
Signals PropertyChanged(string name, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
@@ -89,6 +105,10 @@ Properties string RemoteAddress [readonly]
|
||||
|
||||
Bluetooth address of the local adapter.
|
||||
|
||||
string Type [readonly]
|
||||
|
||||
Type of the card. Valid values are "gateway" or
|
||||
"handsfree".
|
||||
|
||||
Handsfree Audio Agent hierarchy [experimental]
|
||||
===============================
|
||||
|
||||
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
|
||||
Address of the remote device.
|
||||
|
||||
string SoftwareVersionNumber [readonly, optional]
|
||||
|
||||
String representing the software version number of the
|
||||
modem device.
|
||||
|
||||
array{string} Features [readonly]
|
||||
|
||||
List of currently enabled features. It uses simple
|
||||
|
||||
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.
|
||||
@@ -93,6 +93,11 @@ Properties boolean Present [readonly]
|
||||
|
||||
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]
|
||||
|
||||
Contains the Mobile Country Code (MCC) of the home
|
||||
|
||||
@@ -17,3 +17,30 @@ GPS:
|
||||
After setting the configuration, a power cycle is required.
|
||||
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
|
||||
can be checked using 'AT+CGMR'.
|
||||
|
||||
LE910 V2
|
||||
========
|
||||
|
||||
Default USB composition of LE910V2 uses PID 0x36 (AT#PORTCFG=0)
|
||||
and consists of 6 serial ports (CDC-ACM standard, /dev/ttyACMx)
|
||||
and 1 network adapter using CDC-NCM standard (wwanx or usbx).
|
||||
|
||||
NCM interface configuration follows Telit documentation
|
||||
(both documents available on Telit Download Zone - registration required)
|
||||
"GE/HE/UE910, UL865, LE910 V2 Linux USB Driver - User Guide r0"
|
||||
(document 1VV0301255 Rev.0 - 2016-01-22)
|
||||
and "Telit LE910-V2 NCM SETUP r3"
|
||||
(document 1VV0301246 Rev.3 - 2016-11-29).
|
||||
|
||||
After context is setup, NCM mode activated and PDP context activated
|
||||
connection configuration can be read using
|
||||
AT+CGPADDR=context_id and AT+CGCONTRDP=context_id commands.
|
||||
This is done automatically and results available via
|
||||
org.ofono.ConnectionContext.GetProperties DBus method.
|
||||
|
||||
Then Linux network interface needs to be configured:
|
||||
ifconfig <Interface> <Address> netmask <Netmask> up
|
||||
route add default gw <Gateway>
|
||||
arp -s <Gateway> 11:22:33:44:55:66
|
||||
|
||||
Only after these steps network interface is usable.
|
||||
|
||||
@@ -52,6 +52,7 @@ static int atmodem_init(void)
|
||||
at_gprs_context_init();
|
||||
at_sim_auth_init();
|
||||
at_gnss_init();
|
||||
at_lte_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -76,6 +77,7 @@ static void atmodem_exit(void)
|
||||
at_gprs_exit();
|
||||
at_gprs_context_exit();
|
||||
at_gnss_exit();
|
||||
at_lte_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,
|
||||
|
||||
@@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void);
|
||||
|
||||
extern void at_gnss_init(void);
|
||||
extern void at_gnss_exit(void);
|
||||
|
||||
extern void at_lte_init(void);
|
||||
extern void at_lte_exit(void);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gatchat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/log.h>
|
||||
@@ -614,3 +615,42 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req)
|
||||
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||
* of "a.b.c.d.m.m.m.m" for IPv4.
|
||||
* address/netmask must be able to hold
|
||||
* 255.255.255.255 + null = 16 characters
|
||||
*/
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask)
|
||||
{
|
||||
const char *s = addrnetmask;
|
||||
const char *net = NULL;
|
||||
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
/* Count 7 dots for ipv4, less or more means error. */
|
||||
for (i = 0; i < 9; i++, s++) {
|
||||
s = strchr(s, '.');
|
||||
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
if (i == 3) {
|
||||
/* set netmask ptr and break the string */
|
||||
net = s + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 7) {
|
||||
memcpy(address, addrnetmask, net - addrnetmask);
|
||||
address[net - addrnetmask - 1] = '\0';
|
||||
strcpy(netmask, net);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@ struct at_util_sim_state_query *at_util_sim_state_query_new(GAtChat *chat,
|
||||
GDestroyNotify destroy);
|
||||
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
|
||||
|
||||
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
|
||||
char *address, char *netmask);
|
||||
|
||||
struct cb_data {
|
||||
void *cb;
|
||||
void *data;
|
||||
|
||||
@@ -43,10 +43,11 @@
|
||||
#include "atmodem.h"
|
||||
#include "vendor.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
static const char *cgdata_prefix[] = { "+CGDATA:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
enum state {
|
||||
@@ -67,6 +68,7 @@ struct gprs_context_data {
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data; /* Callback data */
|
||||
unsigned int vendor;
|
||||
gboolean use_atd99;
|
||||
};
|
||||
|
||||
static void ppp_debug(const char *str, void *data)
|
||||
@@ -210,7 +212,7 @@ static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gcd->vendor == OFONO_VENDOR_SIMCOM_SIM900)
|
||||
if (gcd->use_atd99)
|
||||
sprintf(buf, "ATD*99***%u#", gcd->active_context);
|
||||
else
|
||||
sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
|
||||
@@ -247,6 +249,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
/* We only support CHAP and PAP */
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
|
||||
break;
|
||||
@@ -294,6 +298,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
* prefix, this is the least invasive place to set it.
|
||||
*/
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
snprintf(buf + len, sizeof(buf) - len - 3,
|
||||
",\"CHAP:%s\"", ctx->apn);
|
||||
@@ -378,6 +384,43 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
g_at_ppp_shutdown(gcd->ppp);
|
||||
}
|
||||
|
||||
static void at_cgdata_test_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
GAtResultIter iter;
|
||||
const char *data_type;
|
||||
gboolean found = FALSE;
|
||||
|
||||
gcd->use_atd99 = TRUE;
|
||||
|
||||
if (!ok) {
|
||||
DBG("not ok");
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
if (!g_at_result_iter_next(&iter, "+CGDATA:")) {
|
||||
DBG("no +CGDATA line");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!g_at_result_iter_open_list(&iter)) {
|
||||
DBG("no list found");
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (!found && g_at_result_iter_next_string(&iter, &data_type)) {
|
||||
if (g_str_equal(data_type, "PPP")) {
|
||||
found = TRUE;
|
||||
gcd->use_atd99 = FALSE;
|
||||
}
|
||||
}
|
||||
error:
|
||||
DBG("use_atd99:%d", gcd->use_atd99);
|
||||
}
|
||||
|
||||
static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
@@ -387,7 +430,7 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -405,6 +448,15 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
if (chat == NULL)
|
||||
return 0;
|
||||
|
||||
switch (vendor) {
|
||||
case OFONO_VENDOR_SIMCOM_SIM900:
|
||||
gcd->use_atd99 = FALSE;
|
||||
break;
|
||||
default:
|
||||
g_at_chat_send(chat, "AT+CGDATA=?", cgdata_prefix,
|
||||
at_cgdata_test_cb, gc, NULL);
|
||||
}
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -49,6 +49,9 @@ static const char *none_prefix[] = { NULL };
|
||||
struct gprs_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
unsigned int last_auto_context_id;
|
||||
gboolean telit_try_reattach;
|
||||
int attached;
|
||||
};
|
||||
|
||||
static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
@@ -72,8 +75,10 @@ static void at_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
|
||||
|
||||
if (g_at_chat_send(gd->chat, buf, none_prefix,
|
||||
at_cgatt_cb, cbd, g_free) > 0)
|
||||
at_cgatt_cb, cbd, g_free) > 0) {
|
||||
gd->attached = attached;
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
@@ -141,6 +146,48 @@ static void at_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void at_cgdcont_read_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
int activated_cid = gd->last_auto_context_id;
|
||||
const char *apn = NULL;
|
||||
GAtResultIter iter;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
ofono_warn("Can't read CGDCONT contexts.");
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CGDCONT:")) {
|
||||
int read_cid;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &read_cid))
|
||||
break;
|
||||
|
||||
if (read_cid != activated_cid)
|
||||
continue;
|
||||
|
||||
/* ignore protocol */
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
g_at_result_iter_next_string(&iter, &apn);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (apn)
|
||||
ofono_gprs_cid_activated(gprs, activated_cid, apn);
|
||||
else
|
||||
ofono_warn("cid %u: Received activated but no apn present",
|
||||
activated_cid);
|
||||
}
|
||||
|
||||
static void cgreg_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -151,12 +198,35 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
|
||||
NULL, NULL, NULL, gd->vendor) == FALSE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Telit AT modem firmware (tested with UE910-EUR) generates
|
||||
* +CGREG: 0\r\n\r\n+CGEV: NW DETACH
|
||||
* after a context is de-activated and ppp connection closed.
|
||||
* Then, after a random amount of time (observed from a few seconds
|
||||
* to a few hours), an unsolicited +CGREG: 1 arrives.
|
||||
* Attempt to fix the problem, by sending AT+CGATT=1 once.
|
||||
* This does not re-activate the context, but if a network connection
|
||||
* is still correct, will generate an immediate +CGREG: 1.
|
||||
*/
|
||||
if (gd->vendor == OFONO_VENDOR_TELIT) {
|
||||
if (gd->attached && !status && !gd->telit_try_reattach) {
|
||||
DBG("Trying to re-attach gprs network");
|
||||
gd->telit_try_reattach = TRUE;
|
||||
g_at_chat_send(gd->chat, "AT+CGATT=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
gd->telit_try_reattach = FALSE;
|
||||
}
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
|
||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
GAtResultIter iter;
|
||||
const char *event;
|
||||
|
||||
@@ -170,8 +240,18 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
if (g_str_equal(event, "NW DETACH") ||
|
||||
g_str_equal(event, "ME DETACH")) {
|
||||
if (gd->vendor == OFONO_VENDOR_TELIT &&
|
||||
gd->telit_try_reattach)
|
||||
return;
|
||||
|
||||
gd->attached = FALSE;
|
||||
ofono_gprs_detached_notify(gprs);
|
||||
return;
|
||||
} else if (g_str_has_prefix(event, "ME PDN ACT")) {
|
||||
sscanf(event, "%*s %*s %*s %u", &gd->last_auto_context_id);
|
||||
|
||||
g_at_chat_send(gd->chat, "AT+CGDCONT?", cgdcont_prefix,
|
||||
at_cgdcont_read_cb, gprs, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +327,26 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
|
||||
ofono_gprs_bearer_notify(gprs, bearer);
|
||||
}
|
||||
|
||||
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
GAtResultIter iter;
|
||||
const char *mode;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &mode))
|
||||
return;
|
||||
|
||||
if (!strcmp("LTE", mode))
|
||||
ofono_gprs_bearer_notify(gprs, 7); /* LTE */
|
||||
|
||||
/* in other modes, notification ^MODE is used */
|
||||
}
|
||||
|
||||
static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -274,6 +374,9 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||
case 3:
|
||||
bearer = 5; /* HSDPA */
|
||||
break;
|
||||
case 4:
|
||||
bearer = 7; /* LTE */
|
||||
break;
|
||||
default:
|
||||
bearer = 0;
|
||||
break;
|
||||
@@ -303,10 +406,6 @@ static void ublox_ureg_notify(GAtResult *result, gpointer user_data)
|
||||
case 5:
|
||||
bearer = 4;
|
||||
break;
|
||||
case 7:
|
||||
/* XXX: reserved - assume none. */
|
||||
bearer = 0;
|
||||
break;
|
||||
case 8:
|
||||
bearer = 1;
|
||||
break;
|
||||
@@ -353,8 +452,11 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
case OFONO_VENDOR_HUAWEI:
|
||||
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_register(gd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||
FALSE, gprs, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
g_at_chat_register(gd->chat, "+UREG:", ublox_ureg_notify,
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_send(gd->chat, "AT+UREG=1", none_prefix,
|
||||
@@ -365,6 +467,7 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
|
||||
FALSE, gprs, NULL);
|
||||
@@ -476,7 +579,7 @@ static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
|
||||
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
|
||||
continue;
|
||||
|
||||
if (!g_at_result_iter_close_list(&iter))
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
continue;
|
||||
|
||||
if (g_at_result_iter_open_list(&iter))
|
||||
|
||||
142
ofono/drivers/atmodem/lte.c
Normal file
142
ofono/drivers/atmodem/lte.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "atmodem.h"
|
||||
|
||||
struct lte_driver_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1];
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("LTE config with APN: %s", info->apn);
|
||||
|
||||
if (strlen(info->apn) > 0)
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"",
|
||||
info->apn);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\"");
|
||||
|
||||
/* We can't do much in case of failure so don't check response. */
|
||||
if (g_at_chat_send(ldd->chat, buf, NULL,
|
||||
at_lte_set_default_attach_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static gboolean lte_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
|
||||
ofono_lte_register(lte);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct lte_driver_data *ldd;
|
||||
|
||||
DBG("at lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_driver_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ldd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
g_idle_add(lte_delayed_register, lte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("at lte remove");
|
||||
|
||||
g_at_chat_unref(ldd->chat);
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "atmodem",
|
||||
.probe = at_lte_probe,
|
||||
.remove = at_lte_remove,
|
||||
.set_default_attach_info = at_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void at_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void at_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -838,6 +838,39 @@ static void telit_ciev_notify(GAtResult *result, gpointer user_data)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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,
|
||||
struct netreg_data *nd)
|
||||
{
|
||||
const char *mode;
|
||||
const char *ind;
|
||||
int len = sprintf(buf, "AT+CMER=");
|
||||
const char *mode;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (nd->vendor) {
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
/* UBX-13002752 R33: TOBY L2 doesn't support mode 2 and 3 */
|
||||
mode = "1";
|
||||
break;
|
||||
default:
|
||||
mode = "3";
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward unsolicited result codes directly to the TE;
|
||||
* TA‑TE link specific inband technique used to embed result codes and
|
||||
* data when TA is in on‑line data mode
|
||||
*/
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], "3", FALSE))
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], mode, FALSE))
|
||||
return FALSE;
|
||||
|
||||
/* No keypad event reporting */
|
||||
@@ -1574,14 +1639,14 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
* Telit does not support mode 1.
|
||||
* All indicator events shall be directed from TA to TE.
|
||||
*/
|
||||
mode = "2";
|
||||
ind = "2";
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Only those indicator events, which are not caused by +CIND
|
||||
* shall be indicated by the TA to the TE.
|
||||
*/
|
||||
mode = "1";
|
||||
ind = "1";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
* and <value> is the new value of indicator.
|
||||
*/
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[3], mode, TRUE))
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[3], ind, TRUE))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
@@ -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,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for 4G system mode reports */
|
||||
g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify,
|
||||
FALSE, netreg, NULL);
|
||||
|
||||
/* Register for network time reports */
|
||||
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
|
||||
FALSE, netreg, NULL);
|
||||
@@ -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,
|
||||
NULL, NULL, NULL);
|
||||
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_SAMSUNG:
|
||||
/* Signal strength reporting via CIND is not supported */
|
||||
|
||||
@@ -51,6 +51,7 @@ struct sim_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
guint ready_id;
|
||||
guint passwd_type_mask;
|
||||
struct at_util_sim_state_query *sim_state_query;
|
||||
};
|
||||
|
||||
@@ -827,7 +828,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if (!strcmp(name, at_sim_name[i].name)) {
|
||||
retries[i] = val;
|
||||
retries[at_sim_name[i].type] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1120,6 +1121,7 @@ static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
|
||||
upincnt_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
@@ -1292,14 +1294,15 @@ static void sim_state_cb(gboolean present, gpointer user_data)
|
||||
struct cb_data *cbd = user_data;
|
||||
struct sim_data *sd = cbd->user;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
void *data = cbd->data;
|
||||
|
||||
at_util_sim_state_query_free(sd->sim_state_query);
|
||||
sd->sim_state_query = NULL;
|
||||
|
||||
if (present == 1)
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
@@ -1350,6 +1353,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
case OFONO_VENDOR_ALCATEL:
|
||||
case OFONO_VENDOR_HUAWEI:
|
||||
case OFONO_VENDOR_SIMCOM:
|
||||
case OFONO_VENDOR_SIERRA:
|
||||
/*
|
||||
* On ZTE modems, after pin is entered, SIM state is checked
|
||||
* by polling CPIN as their modem doesn't provide unsolicited
|
||||
@@ -1456,9 +1460,8 @@ static void at_pin_enable(struct ofono_sim *sim,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
int ret;
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
||||
@@ -1487,10 +1490,8 @@ static void at_change_passwd(struct ofono_sim *sim,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
int ret;
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len ||
|
||||
at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
||||
@@ -1515,7 +1516,7 @@ static void at_lock_status_cb(gboolean ok, GAtResult *result,
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
GAtResultIter iter;
|
||||
ofono_sim_locked_cb_t cb = cbd->cb;
|
||||
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
int locked;
|
||||
|
||||
@@ -1540,16 +1541,15 @@ static void at_lock_status_cb(gboolean ok, GAtResult *result,
|
||||
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,
|
||||
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 cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[64];
|
||||
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
|
||||
|
||||
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
|
||||
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
||||
goto error;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
||||
@@ -1565,13 +1565,42 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static gboolean at_sim_register(gpointer user)
|
||||
static void at_clck_query_cb(gboolean ok, GAtResult *result, gpointer user)
|
||||
{
|
||||
struct ofono_sim *sim = user;
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
GAtResultIter iter;
|
||||
const char *fac;
|
||||
|
||||
if (!ok)
|
||||
goto done;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
/* e.g. +CLCK: ("SC","FD","PN","PU","PP","PC","PF") */
|
||||
if (!g_at_result_iter_next(&iter, "+CLCK:") ||
|
||||
!g_at_result_iter_open_list(&iter))
|
||||
goto done;
|
||||
|
||||
/* Clear the default mask */
|
||||
sd->passwd_type_mask = 0;
|
||||
|
||||
/* Set the bits for <fac>s that are actually supported */
|
||||
while (g_at_result_iter_next_string(&iter, &fac)) {
|
||||
unsigned int i;
|
||||
|
||||
/* Find it in the list of known <fac>s */
|
||||
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++) {
|
||||
if (!g_strcmp0(at_clck_cpwd_fac[i], fac)) {
|
||||
sd->passwd_type_mask |= (1 << i);
|
||||
DBG("found %s", fac);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ofono_sim_register(sim);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
@@ -1579,6 +1608,7 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct sim_data *sd;
|
||||
unsigned int i;
|
||||
|
||||
sd = g_new0(struct sim_data, 1);
|
||||
sd->chat = g_at_chat_clone(chat);
|
||||
@@ -1588,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);
|
||||
|
||||
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)
|
||||
@@ -1625,7 +1661,7 @@ static struct ofono_sim_driver driver = {
|
||||
.reset_passwd = at_pin_send_puk,
|
||||
.lock = at_pin_enable,
|
||||
.change_passwd = at_change_passwd,
|
||||
.query_locked = at_pin_query_enabled,
|
||||
.query_facility_lock = at_query_clck,
|
||||
};
|
||||
|
||||
static struct ofono_sim_driver driver_noef = {
|
||||
@@ -1639,7 +1675,7 @@ static struct ofono_sim_driver driver_noef = {
|
||||
.reset_passwd = at_pin_send_puk,
|
||||
.lock = at_pin_enable,
|
||||
.change_passwd = at_change_passwd,
|
||||
.query_locked = at_pin_query_enabled,
|
||||
.query_facility_lock = at_query_clck,
|
||||
};
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
static gboolean at_parse_cmt(GAtResult *result, const char **pdu, int *pdulen)
|
||||
{
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, pdulen))
|
||||
return FALSE;
|
||||
|
||||
*pdu = g_at_result_pdu(result);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||
{
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
@@ -347,11 +327,21 @@ static inline void at_ack_delivery(struct ofono_sms *sms)
|
||||
DBG("");
|
||||
|
||||
/* We must acknowledge the PDU using CNMA */
|
||||
if (data->cnma_ack_pdu)
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
||||
data->cnma_ack_pdu_len, data->cnma_ack_pdu);
|
||||
else /* Should be a safe fallback */
|
||||
if (data->cnma_ack_pdu) {
|
||||
switch (data->vendor) {
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1");
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
|
||||
data->cnma_ack_pdu_len,
|
||||
data->cnma_ack_pdu);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Should be a safe fallback */
|
||||
snprintf(buf, sizeof(buf), "AT+CNMA=0");
|
||||
}
|
||||
|
||||
g_at_chat_send(data->chat, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
||||
}
|
||||
@@ -409,16 +399,34 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_sms *sms = user_data;
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
GAtResultIter iter;
|
||||
const char *hexpdu;
|
||||
unsigned char pdu[176];
|
||||
long pdu_len;
|
||||
int tpdu_len;
|
||||
unsigned char pdu[176];
|
||||
|
||||
if (!at_parse_cmt(result, &hexpdu, &tpdu_len)) {
|
||||
ofono_error("Unable to parse CMT notification");
|
||||
return;
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMT:"))
|
||||
goto err;
|
||||
|
||||
switch (data->vendor) {
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
|
||||
goto err;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
hexpdu = g_at_result_pdu(result);
|
||||
|
||||
if (strlen(hexpdu) > sizeof(pdu) * 2) {
|
||||
ofono_error("Bad PDU length in CMT notification");
|
||||
return;
|
||||
@@ -431,6 +439,9 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
if (data->vendor != OFONO_VENDOR_SIMCOM)
|
||||
at_ack_delivery(sms);
|
||||
|
||||
err:
|
||||
ofono_error("Unable to parse CMT notification");
|
||||
}
|
||||
|
||||
static void at_cmgr_notify(GAtResult *result, gpointer user_data)
|
||||
@@ -742,7 +753,7 @@ static void at_sms_initialized(struct ofono_sms *sms)
|
||||
|
||||
static void at_sms_not_supported(struct ofono_sms *sms)
|
||||
{
|
||||
ofono_error("SMS not supported by this modem. If this is in error"
|
||||
ofono_error("SMS not supported by this modem. If this is an error"
|
||||
" please submit patches to support this hardware");
|
||||
|
||||
ofono_sms_remove(sms);
|
||||
|
||||
@@ -45,4 +45,7 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_ALCATEL,
|
||||
OFONO_VENDOR_QUECTEL,
|
||||
OFONO_VENDOR_UBLOX,
|
||||
OFONO_VENDOR_UBLOX_TOBY_L2,
|
||||
OFONO_VENDOR_CINTERION,
|
||||
OFONO_VENDOR_XMM,
|
||||
};
|
||||
|
||||
@@ -253,8 +253,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
|
||||
@@ -1147,8 +1146,7 @@ static void at_voicecall_remove(struct ofono_voicecall *vc)
|
||||
if (vd->vts_source)
|
||||
g_source_remove(vd->vts_source);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "cdmamodem.h"
|
||||
#include "drivers/atmodem/vendor.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
@@ -285,7 +285,7 @@ static int cdma_connman_probe(struct ofono_cdma_connman *cm,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* RIL library with GLib integration
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012-2013 Canonical Ltd.
|
||||
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,38 +19,31 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GRILREPLY_H
|
||||
#define __GRILREPLY_H
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <gatchat.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/types.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "gemaltomodem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
static int gemaltomodem_init(void)
|
||||
{
|
||||
gemalto_location_reporting_init();
|
||||
|
||||
struct reply_setup_data_call {
|
||||
guint version;
|
||||
guint status;
|
||||
gint cid;
|
||||
guint retry_time;
|
||||
guint active;
|
||||
guint protocol;
|
||||
gchar *ifname;
|
||||
gchar **dns_addresses;
|
||||
gchar **gateways;
|
||||
gchar **ip_addrs;
|
||||
};
|
||||
|
||||
void g_ril_reply_free_setup_data_call(struct reply_setup_data_call *reply);
|
||||
|
||||
struct reply_setup_data_call *g_ril_reply_parse_data_call(GRil *gril,
|
||||
struct ril_msg *message,
|
||||
struct ofono_error *error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GRILREPLY_H */
|
||||
static void gemaltomodem_exit(void)
|
||||
{
|
||||
gemalto_location_reporting_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
gemaltomodem_init, gemaltomodem_exit)
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -19,11 +19,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
extern void gemalto_location_reporting_init();
|
||||
extern void gemalto_location_reporting_exit();
|
||||
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
237
ofono/drivers/gemaltomodem/location-reporting.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
#include "gattty.h"
|
||||
|
||||
#include "gemaltomodem.h"
|
||||
|
||||
static const char *sgpsc_prefix[] = { "^SGPSC:", NULL };
|
||||
|
||||
struct gps_data {
|
||||
GAtChat *chat;
|
||||
};
|
||||
|
||||
static void gemalto_gps_disable_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_location_reporting *lr = cbd->user;
|
||||
ofono_location_reporting_disable_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("lr=%p, ok=%d", lr, ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
cb(&error, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_disable(
|
||||
struct ofono_location_reporting *lr,
|
||||
ofono_location_reporting_disable_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("lr=%p", lr);
|
||||
|
||||
cbd->user = lr;
|
||||
|
||||
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",0", sgpsc_prefix,
|
||||
gemalto_gps_disable_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static int enable_data_stream(struct ofono_location_reporting *lr)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
const char *gps_dev;
|
||||
GHashTable *options;
|
||||
GIOChannel *channel;
|
||||
int fd;
|
||||
|
||||
modem = ofono_location_reporting_get_modem(lr);
|
||||
gps_dev = ofono_modem_get_string(modem, "GPS");
|
||||
|
||||
options = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
if (options == NULL)
|
||||
return -1;
|
||||
|
||||
g_hash_table_insert(options, "Baud", "115200");
|
||||
|
||||
channel = g_at_tty_open(gps_dev, options);
|
||||
|
||||
g_hash_table_destroy(options);
|
||||
|
||||
if (channel == NULL)
|
||||
return -1;
|
||||
|
||||
fd = g_io_channel_unix_get_fd(channel);
|
||||
|
||||
g_io_channel_set_close_on_unref(channel, FALSE);
|
||||
g_io_channel_unref(channel);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void gemalto_sgpsc_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_location_reporting_enable_cb_t cb = cbd->cb;
|
||||
struct ofono_location_reporting *lr = cbd->user;
|
||||
struct ofono_error error;
|
||||
int fd;
|
||||
|
||||
DBG("lr=%p ok=%d", lr, ok);
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fd = enable_data_stream(lr);
|
||||
|
||||
if (fd < 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cb(&error, fd, cbd->data);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_enable(struct ofono_location_reporting *lr,
|
||||
ofono_location_reporting_enable_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
DBG("lr=%p", lr);
|
||||
|
||||
cbd->user = lr;
|
||||
|
||||
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",2", sgpsc_prefix,
|
||||
gemalto_sgpsc_cb, cbd, NULL) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_support_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_location_reporting *lr = user_data;
|
||||
|
||||
if (!ok) {
|
||||
ofono_location_reporting_remove(lr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_location_reporting_register(lr);
|
||||
}
|
||||
|
||||
static int gemalto_location_reporting_probe(struct ofono_location_reporting *lr,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct gps_data *gd;
|
||||
|
||||
gd = g_try_new0(struct gps_data, 1);
|
||||
if (gd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_location_reporting_set_data(lr, gd);
|
||||
|
||||
g_at_chat_send(gd->chat, "AT^SGPSC=?", sgpsc_prefix,
|
||||
gemalto_location_reporting_support_cb,
|
||||
lr, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gemalto_location_reporting_remove(struct ofono_location_reporting *lr)
|
||||
{
|
||||
struct gps_data *gd = ofono_location_reporting_get_data(lr);
|
||||
|
||||
ofono_location_reporting_set_data(lr, NULL);
|
||||
|
||||
g_at_chat_unref(gd->chat);
|
||||
g_free(gd);
|
||||
}
|
||||
|
||||
static struct ofono_location_reporting_driver driver = {
|
||||
.name = "gemaltomodem",
|
||||
.type = OFONO_LOCATION_REPORTING_TYPE_NMEA,
|
||||
.probe = gemalto_location_reporting_probe,
|
||||
.remove = gemalto_location_reporting_remove,
|
||||
.enable = gemalto_location_reporting_enable,
|
||||
.disable = gemalto_location_reporting_disable,
|
||||
};
|
||||
|
||||
void gemalto_location_reporting_init()
|
||||
{
|
||||
ofono_location_reporting_driver_register(&driver);
|
||||
}
|
||||
|
||||
void gemalto_location_reporting_exit()
|
||||
{
|
||||
ofono_location_reporting_driver_unregister(&driver);
|
||||
}
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
static const char *binp_prefix[] = { "+BINP:", NULL };
|
||||
static const char *bvra_prefix[] = { "+BVRA:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct hf_data {
|
||||
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 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)
|
||||
return;
|
||||
|
||||
@@ -382,8 +383,8 @@ static void hfp_disable_nrec(struct ofono_handsfree *hf,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
const char *buf = "AT+NREC=0";
|
||||
|
||||
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
|
||||
cbd, g_free) > 0)
|
||||
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||
hf_generic_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
@@ -401,8 +402,8 @@ static void hfp_hf_indicator(struct ofono_handsfree *hf,
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+BIEV=%u,%u", indicator, value);
|
||||
|
||||
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
|
||||
cbd, g_free) > 0)
|
||||
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||
hf_generic_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
static const char *cops_prefix[] = { "+COPS:", NULL };
|
||||
static const char *cind_prefix[] = { "+CIND:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct netreg_data {
|
||||
GAtChat *chat;
|
||||
@@ -263,7 +264,7 @@ static void hfp_current_operator(struct ofono_netreg *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);
|
||||
|
||||
if (ok)
|
||||
|
||||
@@ -113,7 +113,8 @@ static void slc_established(struct slc_establish_data *sed)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -434,8 +435,8 @@ static void brsf_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
sprintf(str, "AT+BAC=%d", HFP_CODEC_CVSD);
|
||||
|
||||
slc_establish_data_ref(sed);
|
||||
g_at_chat_send(info->chat, str, NULL, bac_cb, sed,
|
||||
slc_establish_data_unref);
|
||||
g_at_chat_send(info->chat, str, none_prefix, bac_cb,
|
||||
sed, slc_establish_data_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -286,8 +286,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
|
||||
@@ -333,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);
|
||||
}
|
||||
|
||||
@@ -705,12 +708,31 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
|
||||
int num_type, validity;
|
||||
struct ofono_call *call;
|
||||
|
||||
/* Waiting call notification makes no sense, when there are
|
||||
* no calls at all. This can happen when a phone already has
|
||||
* waiting and active calls and is being connected over HFP
|
||||
* but it first sends +CCWA before we manage to synchronize
|
||||
* calls with AT+CLCC.
|
||||
*/
|
||||
if (!vd->calls)
|
||||
return;
|
||||
|
||||
/* CCWA can repeat, ignore if we already have an waiting call */
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_WAITING),
|
||||
at_util_call_compare_by_status))
|
||||
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);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CCWA:"))
|
||||
@@ -1096,6 +1118,17 @@ static void ciev_callheld_notify(struct ofono_voicecall *vc,
|
||||
*/
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
||||
poll_clcc, vc);
|
||||
} else {
|
||||
if (vd->clcc_source)
|
||||
g_source_remove(vd->clcc_source);
|
||||
|
||||
/*
|
||||
* We got a notification that there is a held call
|
||||
* and no active call but we already are in such state.
|
||||
* Let's schedule a poll to see what happened.
|
||||
*/
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
||||
poll_clcc, vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1134,6 +1167,10 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
struct ofono_voicecall *vc = user_data;
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
unsigned int mpty_ids;
|
||||
GSList *n;
|
||||
struct ofono_call *nc;
|
||||
unsigned int num_active = 0;
|
||||
unsigned int num_held = 0;
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
@@ -1142,6 +1179,22 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
g_slist_foreach(vd->calls, voicecall_notify, vc);
|
||||
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,
|
||||
@@ -1183,8 +1236,8 @@ static int hfp_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
|
||||
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+CCWA=1", NULL,
|
||||
g_at_chat_send(vd->chat, "AT+CLIP=1", none_prefix, NULL, NULL, NULL);
|
||||
g_at_chat_send(vd->chat, "AT+CCWA=1", none_prefix,
|
||||
hfp_voicecall_initialized, vc, NULL);
|
||||
return 0;
|
||||
}
|
||||
@@ -1202,8 +1255,7 @@ static void hfp_voicecall_remove(struct ofono_voicecall *vc)
|
||||
if (vd->expect_release_source)
|
||||
g_source_remove(vd->expect_release_source);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ static gboolean get_next_addr(GAtResultIter *iter, char **addr)
|
||||
if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
|
||||
return FALSE;
|
||||
|
||||
val = strtol(str, NULL, 16);
|
||||
val = strtoul(str, NULL, 16);
|
||||
|
||||
if (addr)
|
||||
*addr = g_strdup_printf("%u.%u.%u.%u",
|
||||
|
||||
@@ -42,11 +42,13 @@
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
|
||||
static const char *syscfgex_prefix[] = { "^SYSCFGEX:", NULL };
|
||||
|
||||
#define HUAWEI_BAND_ANY 0x3FFFFFFF
|
||||
|
||||
struct radio_settings_data {
|
||||
GAtChat *chat;
|
||||
ofono_bool_t syscfgex_cap;
|
||||
};
|
||||
|
||||
static const struct huawei_band_gsm_table {
|
||||
@@ -176,20 +178,76 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void syscfgex_query_mode_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode;
|
||||
struct ofono_error error;
|
||||
GAtResultIter iter;
|
||||
const char *acqorder;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (g_at_result_iter_next(&iter, "^SYSCFGEX:") == FALSE)
|
||||
goto error;
|
||||
|
||||
if (g_at_result_iter_next_string(&iter, &acqorder) == FALSE)
|
||||
goto error;
|
||||
|
||||
if ((strcmp(acqorder, "00") == 0) ||
|
||||
(strstr(acqorder, "01") &&
|
||||
strstr(acqorder, "02") &&
|
||||
strstr(acqorder, "03")))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
else if (strstr(acqorder, "03"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
else if (strstr(acqorder, "02"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
else if (strstr(acqorder, "01"))
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
else
|
||||
goto error;
|
||||
|
||||
cb(&error, mode, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, "AT^SYSCFG?", syscfg_prefix,
|
||||
syscfg_query_mode_cb, cbd, g_free) == 0) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
if (rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFGEX?",
|
||||
syscfgex_prefix,
|
||||
syscfgex_query_mode_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
if (!rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFG?",
|
||||
syscfg_prefix,
|
||||
syscfg_query_mode_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
static void syscfgxx_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -200,12 +258,11 @@ static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
static void syscfg_set_rat_mode(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[40];
|
||||
unsigned int value = 2, acq_order = 0;
|
||||
@@ -231,7 +288,7 @@ static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
value, acq_order);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfg_modify_mode_cb, cbd, g_free) > 0)
|
||||
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -239,7 +296,55 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
static void syscfgex_set_rat_mode(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[50];
|
||||
char *atcmd = "AT^SYSCFGEX=\"%s\",40000000,2,4,40000000,,";
|
||||
char *acqorder = "030201";
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
acqorder = "00";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
acqorder = "01";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
acqorder = "02";
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
acqorder = "03";
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), atcmd, acqorder);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (rsd->syscfgex_cap)
|
||||
syscfgex_set_rat_mode(rsd, mode, cb, data);
|
||||
else
|
||||
syscfg_set_rat_mode(rsd, mode, cb, data);
|
||||
}
|
||||
|
||||
static void syscfgxx_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
@@ -250,13 +355,54 @@ static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
static void syscfgex_set_band(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[50];
|
||||
char *atcmd = "AT^SYSCFGEX=\"99\",%x,2,4,40000000,,";
|
||||
unsigned int huawei_band;
|
||||
|
||||
if (band_gsm == OFONO_RADIO_BAND_GSM_ANY
|
||||
&& band_umts == OFONO_RADIO_BAND_UMTS_ANY) {
|
||||
huawei_band = HUAWEI_BAND_ANY;
|
||||
} else {
|
||||
unsigned int huawei_band_gsm;
|
||||
unsigned int huawei_band_umts;
|
||||
|
||||
huawei_band_gsm = band_gsm_to_huawei(band_gsm);
|
||||
|
||||
if (!huawei_band_gsm)
|
||||
goto error;
|
||||
|
||||
huawei_band_umts = band_umts_to_huawei(band_umts);
|
||||
|
||||
if (!huawei_band_umts)
|
||||
goto error;
|
||||
|
||||
huawei_band = huawei_band_gsm | huawei_band_umts;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), atcmd, huawei_band);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void syscfg_set_band(struct radio_settings_data *rsd,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[40];
|
||||
unsigned int huawei_band;
|
||||
@@ -284,7 +430,7 @@ static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
|
||||
|
||||
if (g_at_chat_send(rsd->chat, buf, none_prefix,
|
||||
syscfg_modify_band_cb, cbd, g_free) > 0)
|
||||
syscfgxx_modify_band_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -292,6 +438,20 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void huawei_set_band(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (rsd->syscfgex_cap)
|
||||
syscfgex_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||
else
|
||||
syscfg_set_band(rsd, band_gsm, band_umts, cb, data);
|
||||
}
|
||||
|
||||
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
@@ -364,6 +524,21 @@ static void syscfg_support_cb(gboolean ok, GAtResult *result,
|
||||
ofono_radio_settings_register(rs);
|
||||
}
|
||||
|
||||
static void syscfgex_support_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
if (!ok) {
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||
syscfg_support_cb, rs, NULL);
|
||||
}
|
||||
|
||||
rsd->syscfgex_cap = 1;
|
||||
ofono_radio_settings_register(rs);
|
||||
}
|
||||
|
||||
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
@@ -378,8 +553,8 @@ static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
|
||||
syscfg_support_cb, rs, NULL);
|
||||
g_at_chat_send(rsd->chat, "AT^SYSCFGEX=?", syscfgex_prefix,
|
||||
syscfgex_support_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -400,8 +575,8 @@ static struct ofono_radio_settings_driver driver = {
|
||||
.remove = huawei_radio_settings_remove,
|
||||
.query_rat_mode = huawei_query_rat_mode,
|
||||
.set_rat_mode = huawei_set_rat_mode,
|
||||
.query_band = huawei_query_band,
|
||||
.set_band = huawei_set_band,
|
||||
.query_band = huawei_query_band,
|
||||
.set_band = huawei_set_band,
|
||||
};
|
||||
|
||||
void huawei_radio_settings_init(void)
|
||||
|
||||
@@ -42,13 +42,14 @@
|
||||
|
||||
#include "ifxmodem.h"
|
||||
|
||||
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
|
||||
#define TUN_DEV "/dev/net/tun"
|
||||
|
||||
#define STATIC_IP_NETMASK "255.255.255.255"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *xdns_prefix[] = { "+XDNS:", NULL };
|
||||
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
|
||||
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||
|
||||
enum state {
|
||||
STATE_IDLE,
|
||||
@@ -59,17 +60,20 @@ enum state {
|
||||
|
||||
struct gprs_context_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
unsigned int active_context;
|
||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||
GAtRawIP *rawip;
|
||||
enum state state;
|
||||
enum ofono_gprs_proto proto;
|
||||
char address[32];
|
||||
char dns1[32];
|
||||
char dns2[32];
|
||||
char address[64];
|
||||
char gateway[64];
|
||||
char netmask[64];
|
||||
char dns1[64];
|
||||
char dns2[64];
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data; /* Callback data */
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static void rawip_debug(const char *str, void *data)
|
||||
@@ -257,11 +261,136 @@ error:
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
GAtResultIter iter;
|
||||
|
||||
const char *laddrnetmask = NULL;
|
||||
const char *gw = NULL;
|
||||
const char *interface;
|
||||
const char *dns[3];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
gcd->cb(&error, gcd->cb_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
|
||||
/* skip cid, bearer_id, apn */
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &laddrnetmask))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[0]))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[1]))
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(gcd->dns1, dns[0], sizeof(gcd->dns1));
|
||||
strncpy(gcd->dns2, dns[1], sizeof(gcd->dns2));
|
||||
dns[2] = 0;
|
||||
|
||||
DBG("DNS: %s, %s\n", gcd->dns1, gcd->dns2);
|
||||
|
||||
if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
|
||||
gcd->address, gcd->netmask) < 0) {
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw)
|
||||
strncpy(gcd->gateway, gw, sizeof(gcd->gateway));
|
||||
|
||||
gcd->state = STATE_ACTIVE;
|
||||
|
||||
DBG("address: %s\n", gcd->address);
|
||||
DBG("netmask: %s\n", gcd->netmask);
|
||||
DBG("DNS1: %s\n", gcd->dns1);
|
||||
DBG("DNS2: %s\n", gcd->dns2);
|
||||
DBG("Gateway: %s\n", gcd->gateway);
|
||||
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
|
||||
|
||||
if (gcd->netmask[0])
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
|
||||
|
||||
if (gcd->gateway[0])
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void ifx_read_settings(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
gcd->address[0] = '\0';
|
||||
gcd->gateway[0] = '\0';
|
||||
gcd->netmask[0] = '\0';
|
||||
gcd->dns1[0] = '\0';
|
||||
gcd->dns2[0] = '\0';
|
||||
|
||||
/* read IP configuration info */
|
||||
if(gcd->vendor == OFONO_VENDOR_XMM) {
|
||||
snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%u",
|
||||
gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
|
||||
cgcontrdp_cb, gc, NULL) > 0)
|
||||
return;
|
||||
} else {
|
||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||
address_cb, gc, NULL) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void ifx_gprs_read_settings(struct ofono_gprs_context *gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
DBG("cid %u", cid);
|
||||
|
||||
gcd->active_context = cid;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
ifx_read_settings(gc);
|
||||
}
|
||||
|
||||
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
@@ -271,19 +400,14 @@ static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
|
||||
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
|
||||
address_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
failed_setup(gc, NULL, TRUE);
|
||||
ifx_read_settings(gc);
|
||||
}
|
||||
|
||||
static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[128];
|
||||
char buf[384];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
@@ -387,7 +511,8 @@ static void deactivate_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
g_at_chat_resume(gcd->chat);
|
||||
if (gcd->vendor != OFONO_VENDOR_XMM)
|
||||
g_at_chat_resume(gcd->chat);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
@@ -409,11 +534,25 @@ static void ifx_gprs_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
g_at_rawip_shutdown(gcd->rawip);
|
||||
|
||||
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
|
||||
if (g_at_chat_send(chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
if (gcd->vendor == OFONO_VENDOR_XMM) {
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
} else {
|
||||
if (g_at_chat_send(chat, buf, none_prefix,
|
||||
deactivate_cb, gc, NULL) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ifx_gprs_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
DBG("");
|
||||
ifx_gprs_deactivate_primary(gc, cid, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
@@ -451,14 +590,13 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
|
||||
g_at_rawip_unref(gcd->rawip);
|
||||
gcd->rawip = NULL;
|
||||
g_at_chat_resume(gcd->chat);
|
||||
}
|
||||
|
||||
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
||||
|
||||
gcd->active_context = 0;
|
||||
gcd->state = STATE_IDLE;
|
||||
|
||||
g_at_chat_resume(gcd->chat);
|
||||
}
|
||||
|
||||
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
@@ -470,23 +608,27 @@ static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (stat(TUN_SYSFS_DIR, &st) < 0) {
|
||||
if (stat(TUN_DEV, &st) < 0) {
|
||||
ofono_error("Missing support for TUN/TAP devices");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (g_at_chat_get_slave(chat) == NULL)
|
||||
return -EINVAL;
|
||||
if (vendor != OFONO_VENDOR_XMM) {
|
||||
if (g_at_chat_get_slave(chat) == NULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gcd = g_try_new0(struct gprs_context_data, 1);
|
||||
if (gcd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gcd->vendor = vendor;
|
||||
gcd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
|
||||
chat = g_at_chat_get_slave(gcd->chat);
|
||||
if (vendor != OFONO_VENDOR_XMM)
|
||||
chat = g_at_chat_get_slave(gcd->chat);
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
@@ -516,6 +658,8 @@ static struct ofono_gprs_context_driver driver = {
|
||||
.remove = ifx_gprs_context_remove,
|
||||
.activate_primary = ifx_gprs_activate_primary,
|
||||
.deactivate_primary = ifx_gprs_deactivate_primary,
|
||||
.read_settings = ifx_gprs_read_settings,
|
||||
.detach_shutdown = ifx_gprs_detach_shutdown
|
||||
};
|
||||
|
||||
void ifx_gprs_context_init(void)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
extern void ifx_voicecall_init(void);
|
||||
extern void ifx_voicecall_exit(void);
|
||||
|
||||
@@ -1009,8 +1009,7 @@ static void ifx_voicecall_remove(struct ofono_voicecall *vc)
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
g_strfreev(vd->en_list);
|
||||
|
||||
|
||||
77
ofono/drivers/infineonmodem/infineon_constants.h
Normal file
77
ofono/drivers/infineonmodem/infineon_constants.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
*
|
||||
* RIL constants for infineon modem
|
||||
*
|
||||
* Copyright (C) 2014 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INFINEON_CONSTANTS_H
|
||||
#define INFINEON_CONSTANTS_H
|
||||
|
||||
/* Messages encapsulated in RIL_REQUEST_OEM_HOOK_RAW requests */
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_SELECT_BAND 1
|
||||
#define INF_RIL_REQUEST_OEM_SET_SELECT_BAND 2
|
||||
#define INF_RIL_REQUEST_OEM_SET_CIRCUIT_SWITCHING_PAGING 3
|
||||
#define INF_RIL_REQUEST_OEM_GET_LAST_FAILURE_REPORT_FOR_CS_REGISTRATION 4
|
||||
#define INF_RIL_REQUEST_OEM_GET_SELECT_BEARER_SERVICE_TYPE 5
|
||||
#define INF_RIL_REQUEST_OEM_GET_XPROGRESS_STATUS 6
|
||||
#define INF_RIL_REQUEST_OEM_SET_SS_NOTIFY 7
|
||||
#define INF_RIL_REQUEST_OEM_GET_SS_NOTIFY 8
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTHENTICATION_TYPE 9
|
||||
#define INF_RIL_REQUEST_OEM_SWITCH_OFF_MS 10
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_TIMEZONE_UPDATE 11
|
||||
#define INF_RIL_REQUEST_OEM_SET_TIMEZONE_RESPORTING 12
|
||||
#define INF_RIL_REQUEST_OEM_SET_DISPLAY_SIM_AND_PB_STATUS 13
|
||||
#define INF_RIL_REQUEST_OEM_GET_REMAIN_SIM_PIN_ATTEMPTS 14
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_REDIAL 15
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_CALL_STATUS_REPORTING 16
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_ANSWER 17
|
||||
#define INF_RIL_REQUEST_OEM_SET_LINE 18
|
||||
#define INF_RIL_REQUEST_OEM_PDP_ACTIVATE_OR_DEACTIVATE 19
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_GPRS_MS_CLASS 20
|
||||
#define INF_RIL_REQUEST_OEM_SET_TRACE_AND_AT_INTERFACES 21
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_TRACE_AND_AT_INTERFACES_CONFIGURE 22
|
||||
#define INF_RIL_REQUEST_OEM_SWITCH_TRACE_ON_OR_OFF 23
|
||||
#define INF_RIL_REQUEST_OEM_READ_EXCEPTION_LOG 24
|
||||
#define INF_RIL_REQUEST_OEM_GET_PHONE_ACTIVITY_STATUS 25
|
||||
#define INF_RIL_REQUEST_OEM_INITIATE_RESEND_SMS_IF_GPRS_FAILS 26
|
||||
#define INF_RIL_REQUEST_OEM_GET_DEVICE_NUMBER 27
|
||||
#define INF_RIL_REQUEST_OEM_ENABLE_STK 28
|
||||
#define INF_RIL_REQUEST_OEM_GET_SUBSCRIBER_NUMBER 29
|
||||
#define INF_RIL_REQUEST_OEM_SELECT_PHONE_BOOK 30
|
||||
#define INF_RIL_REQUEST_OEM_READ_PHONE_BOOK 31
|
||||
#define INF_RIL_REQUEST_OEM_INSERT_RECORD_TO_PHONE_BOOK 32
|
||||
#define INF_RIL_REQUEST_OEM_DELECT_RECORD_IN_PHONE_BOOK 33
|
||||
#define INF_RIL_REQUEST_OEM_GET_RECORD_FIELDS_MAX_LEN 34
|
||||
#define INF_RIL_REQUEST_OEM_SET_SERIAL_PORT 35
|
||||
#define INF_RIL_REQUEST_OEM_SET_DATA_PREFERED 36
|
||||
#define INF_RIL_REQUEST_OEM_SET_MODEM_ROUTING 37
|
||||
#define INF_RIL_REQUEST_OEM_CLEAR_MISS_NUMBER 38
|
||||
#define INF_RIL_REQUEST_OEM_ATH 39
|
||||
#define INF_RIL_REQUEST_OEM_NOSIG_MODE_TEST 40
|
||||
#define INF_RIL_REQUEST_OEM_SELECT_3G_BAND 41
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_3G_BAND 42
|
||||
#define INF_RIL_REQUEST_OEM_HW_RESET_MODEM 43
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_DIRECT 44
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_QUERY 45
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_SET 46
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_DELTE 47
|
||||
#define INF_RIL_REQUEST_OEM_SET_USB_LOG 48
|
||||
#define INF_RIL_REQUEST_OEM_UPDATE_CSQ 49
|
||||
#define INF_RIL_REQUEST_OEM_DUMP_CELL_ENV 50
|
||||
|
||||
#endif /* INFINEON_CONSTANTS_H */
|
||||
@@ -646,13 +646,36 @@ error:
|
||||
/* ISI callback: PIN state (enabled/disabled) query */
|
||||
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
||||
{
|
||||
check_sec_response(msg, opaque, SEC_CODE_STATE_OK_RESP,
|
||||
SEC_CODE_STATE_FAIL_RESP);
|
||||
struct isi_cb_data *cbd = opaque;
|
||||
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
||||
int locked;
|
||||
uint8_t state;
|
||||
uint8_t status;
|
||||
|
||||
if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
|
||||
!g_isi_msg_data_get_byte(msg, 1, &status))
|
||||
goto error;
|
||||
|
||||
if (state != SEC_CODE_STATE_OK_RESP)
|
||||
goto error;
|
||||
|
||||
if (status == SEC_CODE_ENABLE)
|
||||
locked = 1;
|
||||
else if (status == SEC_CODE_DISABLE)
|
||||
locked = 0;
|
||||
else
|
||||
goto error;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, locked, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void isi_query_locked(struct ofono_sim *sim,
|
||||
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 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,
|
||||
.lock = isi_lock,
|
||||
.change_passwd = isi_change_passwd,
|
||||
.query_locked = isi_query_locked,
|
||||
.query_facility_lock = isi_query_locked,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
uint8_t *pin1, uint8_t *pin2)
|
||||
{
|
||||
@@ -1677,7 +1669,6 @@ static struct ofono_sim_driver driver = {
|
||||
.reset_passwd = uicc_reset_passwd,
|
||||
.change_passwd = uicc_change_passwd,
|
||||
.lock = uicc_lock,
|
||||
.query_locked = uicc_query_locked,
|
||||
};
|
||||
|
||||
void isi_uicc_init(void)
|
||||
|
||||
@@ -1715,7 +1715,7 @@ static void isi_release_specific(struct ofono_voicecall *ovc, int id,
|
||||
|
||||
if ((status->mode_info & CALL_MODE_ORIGINATOR))
|
||||
cause = CALL_CAUSE_BUSY_USER_REQUEST;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
isi_call_release_req(ovc, id, CALL_CAUSE_TYPE_CLIENT, cause, cb, data);
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/devinfo.h>
|
||||
@@ -125,7 +127,8 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
|
||||
}
|
||||
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
|
||||
if (!str) {
|
||||
/* Telit qmi modems return a "0" string when ESN is not available. */
|
||||
if (!str || strcmp(str, "0") == 0) {
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
@@ -24,18 +24,22 @@
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "wda.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_context_data {
|
||||
struct qmi_service *wds;
|
||||
struct qmi_service *wda;
|
||||
struct qmi_device *dev;
|
||||
unsigned int active_context;
|
||||
uint32_t pkt_handle;
|
||||
};
|
||||
@@ -61,8 +65,12 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
|
||||
|
||||
switch (status->status) {
|
||||
case QMI_WDS_CONN_STATUS_DISCONNECTED:
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
data->active_context = 0;
|
||||
if (data->pkt_handle) {
|
||||
/* The context has been disconnected by the network */
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
data->pkt_handle = 0;
|
||||
data->active_context = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -75,18 +83,68 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
|
||||
struct ofono_modem *modem;
|
||||
const char *interface;
|
||||
uint8_t pdp_type, ip_family;
|
||||
uint32_t ip_addr;
|
||||
struct in_addr addr;
|
||||
char* straddr;
|
||||
char* apn;
|
||||
const char *dns[3] = { NULL, NULL, NULL };
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
|
||||
apn = qmi_result_get_string(result, QMI_WDS_RESULT_APN);
|
||||
if (apn) {
|
||||
DBG("APN: %s", apn);
|
||||
g_free(apn);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_PDP_TYPE, &pdp_type))
|
||||
DBG("PDP type %d", pdp_type);
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
|
||||
DBG("IP family %d", ip_family);
|
||||
|
||||
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_IP_ADDRESS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("IP addr: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_address(gc, straddr, 1);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_GATEWAY, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("Gateway: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, straddr);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_GATEWAY_NETMASK, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
straddr = inet_ntoa(addr);
|
||||
DBG("Gateway netmask: %s", straddr);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, straddr);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_PRIMARY_DNS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
dns[0] = inet_ntoa(addr);
|
||||
DBG("Primary DNS: %s", dns[0]);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint32(result,
|
||||
QMI_WDS_RESULT_SECONDARY_DNS, &ip_addr)) {
|
||||
addr.s_addr = htonl(ip_addr);
|
||||
dns[1] = inet_ntoa(addr);
|
||||
DBG("Secondary DNS: %s", dns[1]);
|
||||
}
|
||||
|
||||
if (dns[0])
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
done:
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
@@ -94,8 +152,6 @@ done:
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
@@ -120,8 +176,12 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
data->pkt_handle = handle;
|
||||
|
||||
/* Duplicate cbd, the old one will be freed when this method returns */
|
||||
cbd = cb_data_new(cb, cbd->data);
|
||||
cbd->user = gc;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_GET_SETTINGS, NULL,
|
||||
get_settings_cb, cbd, NULL) > 0)
|
||||
get_settings_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
@@ -131,12 +191,39 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
data->active_context = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gets called for "automatic" contexts, those which are
|
||||
* not activated via activate_primary. For these, we will still need
|
||||
* to call start_net in order to get the packet handle for the context.
|
||||
* The process for automatic contexts is essentially identical to that
|
||||
* for others.
|
||||
*/
|
||||
static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("cid %u", cid);
|
||||
|
||||
data->active_context = cid;
|
||||
|
||||
cbd->user = gc;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_START_NET, NULL,
|
||||
start_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
data->active_context = 0;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
@@ -151,6 +238,7 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct qmi_param *param;
|
||||
uint8_t ip_family;
|
||||
uint8_t auth;
|
||||
|
||||
DBG("cid %u", ctx->cid);
|
||||
|
||||
@@ -178,8 +266,31 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
|
||||
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = QMI_WDS_AUTHENTICATION_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = QMI_WDS_AUTHENTICATION_PAP;
|
||||
break;
|
||||
default:
|
||||
auth = QMI_WDS_AUTHENTICATION_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
qmi_param_append_uint8(param, QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE,
|
||||
auth);
|
||||
|
||||
if (ctx->username[0] != '\0')
|
||||
qmi_param_append(param, QMI_WDS_PARAM_USERNAME,
|
||||
strlen(ctx->username), ctx->username);
|
||||
|
||||
if (ctx->password[0] != '\0')
|
||||
qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
|
||||
strlen(ctx->password), ctx->password);
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_START_NET, param,
|
||||
start_net_cb, cbd, NULL) > 0)
|
||||
start_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
@@ -202,17 +313,19 @@ static void stop_net_cb(struct qmi_result *result, void *user_data)
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
data->active_context = 0;
|
||||
|
||||
data->pkt_handle = 0;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else
|
||||
ofono_gprs_context_deactivated(gc, data->active_context);
|
||||
|
||||
g_free(cbd);
|
||||
data->active_context = 0;
|
||||
}
|
||||
|
||||
static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
@@ -233,17 +346,26 @@ static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(data->wds, QMI_WDS_STOP_NET, param,
|
||||
stop_net_cb, cbd, NULL) > 0)
|
||||
stop_net_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
qmi_deactivate_primary(gc, cid, NULL, NULL);
|
||||
}
|
||||
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
@@ -263,6 +385,69 @@ static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
pkt_status_notify, gc, NULL);
|
||||
}
|
||||
|
||||
static void get_data_format_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
uint32_t llproto;
|
||||
enum qmi_device_expected_data_format expected_llproto;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
|
||||
if (!qmi_result_get_uint32(result, QMI_WDA_LL_PROTOCOL, &llproto))
|
||||
goto done;
|
||||
|
||||
expected_llproto = qmi_device_get_expected_data_format(data->dev);
|
||||
|
||||
if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_802_3) &&
|
||||
(expected_llproto ==
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP)) {
|
||||
if (!qmi_device_set_expected_data_format(data->dev,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3))
|
||||
DBG("Fail to set expected data to 802.3");
|
||||
else
|
||||
DBG("expected data set to 802.3");
|
||||
} else if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP) &&
|
||||
(expected_llproto ==
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3)) {
|
||||
if (!qmi_device_set_expected_data_format(data->dev,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP))
|
||||
DBG("Fail to set expected data to raw-ip");
|
||||
else
|
||||
DBG("expected data set to raw-ip");
|
||||
}
|
||||
|
||||
done:
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void create_wda_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
DBG("Failed to request WDA service, continue initialization");
|
||||
goto error;
|
||||
}
|
||||
|
||||
data->wda = qmi_service_ref(service);
|
||||
|
||||
if (qmi_service_send(data->wda, QMI_WDA_GET_DATA_FORMAT, NULL,
|
||||
get_data_format_cb, gc, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
@@ -274,8 +459,9 @@ static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
data = g_new0(struct gprs_context_data, 1);
|
||||
|
||||
ofono_gprs_context_set_data(gc, data);
|
||||
data->dev = device;
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_WDS, create_wds_cb, gc, NULL);
|
||||
qmi_service_create(device, QMI_SERVICE_WDA, create_wda_cb, gc, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -288,9 +474,15 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->wds);
|
||||
if (data->wds) {
|
||||
qmi_service_unregister_all(data->wds);
|
||||
qmi_service_unref(data->wds);
|
||||
}
|
||||
|
||||
qmi_service_unref(data->wds);
|
||||
if (data->wda) {
|
||||
qmi_service_unregister_all(data->wda);
|
||||
qmi_service_unref(data->wda);
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
@@ -301,6 +493,8 @@ static struct ofono_gprs_context_driver driver = {
|
||||
.remove = qmi_gprs_context_remove,
|
||||
.activate_primary = qmi_activate_primary,
|
||||
.deactivate_primary = qmi_deactivate_primary,
|
||||
.read_settings = qmi_gprs_read_settings,
|
||||
.detach_shutdown = qmi_gprs_context_detach_shutdown,
|
||||
};
|
||||
|
||||
void qmi_gprs_context_init(void)
|
||||
|
||||
@@ -30,16 +30,18 @@
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
|
||||
#include "src/common.h"
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_data {
|
||||
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;
|
||||
uint16_t len;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
@@ -47,14 +49,46 @@ static bool extract_ss_info(struct qmi_result *result, int *status)
|
||||
if (!ss)
|
||||
return false;
|
||||
|
||||
if (ss->ps_state == QMI_NAS_ATTACH_STATUS_ATTACHED)
|
||||
*status = 0x01;
|
||||
if (ss->ps_state == QMI_NAS_ATTACH_STATE_ATTACHED)
|
||||
*status = NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
else
|
||||
*status = 0x00;
|
||||
*status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
|
||||
*tech = -1;
|
||||
for (i = 0; i < ss->radio_if_count; i++) {
|
||||
DBG("radio in use %d", ss->radio_if[i]);
|
||||
|
||||
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static 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)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -62,10 +96,10 @@ static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!extract_ss_info(result, &status))
|
||||
return;
|
||||
status = handle_ss_info(result, gprs);
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
if (status >= 0)
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
|
||||
static void attach_detach_cb(struct qmi_result *result, void *user_data)
|
||||
@@ -124,22 +158,26 @@ error:
|
||||
static void get_ss_info_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_gprs *gprs = cbd->user;
|
||||
ofono_gprs_status_cb_t cb = cbd->cb;
|
||||
int status;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto error;
|
||||
|
||||
if (!extract_ss_info(result, &status)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
status = handle_ss_info(result, gprs);
|
||||
|
||||
if (status < 0)
|
||||
goto error;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
@@ -150,6 +188,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = gprs;
|
||||
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
|
||||
get_ss_info_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
@@ -174,6 +213,13 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
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,
|
||||
ss_info_notify, gprs, NULL);
|
||||
|
||||
@@ -194,7 +240,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
|
||||
ofono_gprs_set_data(gprs, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, gprs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, gprs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* RIL chat library with GLib integration
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012 Canonical Ltd.
|
||||
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,27 +19,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GRIL_RESPONSE_H
|
||||
#define __GRIL_RESPONSE_H
|
||||
#include "nas.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "src/common.h"
|
||||
|
||||
struct _GRilResponse {
|
||||
GSList *lines;
|
||||
char *final_or_pdu;
|
||||
};
|
||||
int qmi_nas_rat_to_tech(uint8_t rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
}
|
||||
|
||||
typedef struct _GRilResponse GRilResponse;
|
||||
|
||||
#define G_RIL_RESPONSE_LINE_LENGTH_MAX 2048
|
||||
|
||||
const char *g_ril_final_response(GRilResponse *response);
|
||||
const char *g_ril_response_pdu(GRilResponse *response);
|
||||
|
||||
#ifdef __cplusplus
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GRIL_RESPONSE_H */
|
||||
@@ -19,6 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define QMI_NAS_RESET 0 /* Reset NAS service state variables */
|
||||
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
|
||||
#define QMI_NAS_EVENT 2 /* Connection state report indication */
|
||||
@@ -33,6 +35,8 @@
|
||||
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
|
||||
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
|
||||
|
||||
#define QMI_NAS_SET_SYSTEM_SELECTION_PREF 51
|
||||
#define QMI_NAS_GET_SYSTEM_SELECTION_PREF 52
|
||||
|
||||
/* Set NAS state report conditions */
|
||||
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
|
||||
@@ -63,7 +67,7 @@ struct qmi_nas_rf_info {
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Get the signal strength */
|
||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x10
|
||||
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x01
|
||||
|
||||
/* Scan for visible network */
|
||||
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
|
||||
@@ -95,6 +99,7 @@ struct qmi_nas_network_rat {
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define QMI_NAS_NETWORK_RAT_NONE 0x00
|
||||
#define QMI_NAS_NETWORK_RAT_GSM 0x04
|
||||
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
|
||||
#define QMI_NAS_NETWORK_RAT_LTE 0x08
|
||||
@@ -140,9 +145,29 @@ struct qmi_nas_current_plmn {
|
||||
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
|
||||
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
|
||||
|
||||
#define QMI_NAS_ATTACH_STATUS_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATUS_ATTACHED 0x01
|
||||
#define QMI_NAS_ATTACH_STATUS_DETACHED 0x02
|
||||
/* qmi_nas_serving_system.status */
|
||||
#define QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED 0x00
|
||||
#define QMI_NAS_REGISTRATION_STATE_REGISTERED 0x01
|
||||
#define QMI_NAS_REGISTRATION_STATE_SEARCHING 0x02
|
||||
#define QMI_NAS_REGISTRATION_STATE_DENIED 0x03
|
||||
#define QMI_NAS_REGISTRATION_STATE_UNKNOWN 0x04
|
||||
|
||||
#define QMI_NAS_RESULT_3GGP_DST 0x1b
|
||||
#define QMI_NAS_RESULT_3GPP_TIME 0x1c
|
||||
struct qmi_nas_3gpp_time {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t timezone;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* cs_state/ps_state */
|
||||
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
|
||||
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
|
||||
#define QMI_NAS_ATTACH_STATE_DETACHED 0x02
|
||||
|
||||
/* Get info about home network */
|
||||
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
|
||||
@@ -152,3 +177,14 @@ struct qmi_nas_home_network {
|
||||
uint8_t desc_len;
|
||||
char desc[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define QMI_NAS_RAT_MODE_PREF_ANY (-1)
|
||||
#define QMI_NAS_RAT_MODE_PREF_GSM (1 << 2)
|
||||
#define QMI_NAS_RAT_MODE_PREF_UMTS (1 << 3)
|
||||
#define QMI_NAS_RAT_MODE_PREF_LTE (1 << 4)
|
||||
|
||||
#define QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||
|
||||
#define QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE 0x11
|
||||
|
||||
int qmi_nas_rat_to_tech(uint8_t rat);
|
||||
|
||||
286
ofono/drivers/qmimodem/netmon.c
Normal file
286
ofono/drivers/qmimodem/netmon.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
#include "src/common.h"
|
||||
|
||||
struct netmon_data {
|
||||
struct qmi_service *nas;
|
||||
};
|
||||
|
||||
static void get_rssi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_netmon *netmon = cbd->user;
|
||||
ofono_netmon_cb_t cb = cbd->cb;
|
||||
struct {
|
||||
enum ofono_netmon_cell_type type;
|
||||
int rssi;
|
||||
int ber;
|
||||
int rsrq;
|
||||
int rsrp;
|
||||
} props;
|
||||
uint16_t len;
|
||||
int16_t rsrp;
|
||||
const struct {
|
||||
int8_t value;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) *rsrq;
|
||||
const struct {
|
||||
uint16_t count;
|
||||
struct {
|
||||
uint8_t rssi;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__)) *rssi;
|
||||
const struct {
|
||||
uint16_t count;
|
||||
struct {
|
||||
uint16_t rate;
|
||||
int8_t rat;
|
||||
} __attribute__((__packed__)) info[0];
|
||||
} __attribute__((__packed__)) *ber;
|
||||
int i;
|
||||
uint16_t num;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* RSSI */
|
||||
rssi = qmi_result_get(result, 0x11, &len);
|
||||
num = GUINT16_FROM_LE(rssi->count);
|
||||
if (rssi) {
|
||||
for (i = 0; i < num; i++) {
|
||||
DBG("RSSI: %hhu on RAT %hhd",
|
||||
rssi->info[i].rssi,
|
||||
rssi->info[i].rat);
|
||||
}
|
||||
|
||||
/* Get cell type from RSSI info... it will be the same
|
||||
* for all the other entries
|
||||
*/
|
||||
props.type = qmi_nas_rat_to_tech(rssi->info[0].rat);
|
||||
switch (rssi->info[0].rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||
break;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_UMTS;
|
||||
break;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_LTE;
|
||||
break;
|
||||
default:
|
||||
props.type = OFONO_NETMON_CELL_TYPE_GSM;
|
||||
break;
|
||||
}
|
||||
|
||||
props.rssi = (rssi->info[0].rssi + 113) / 2;
|
||||
if (props.rssi > 31) props.rssi = 31;
|
||||
if (props.rssi < 0) props.rssi = 0;
|
||||
} else {
|
||||
props.type = QMI_NAS_NETWORK_RAT_GSM;
|
||||
props.rssi = -1;
|
||||
}
|
||||
|
||||
/* Bit error rate */
|
||||
ber = qmi_result_get(result, 0x15, &len);
|
||||
num = GUINT16_FROM_LE(ber->count);
|
||||
if (ber) {
|
||||
for (i = 0; i < ber->count; i++) {
|
||||
DBG("Bit error rate: %hu on RAT %hhd",
|
||||
GUINT16_FROM_LE(ber->info[i].rate),
|
||||
ber->info[i].rat);
|
||||
}
|
||||
|
||||
props.ber = GUINT16_FROM_LE(ber->info[0].rate);
|
||||
if (props.ber > 7)
|
||||
props.ber = -1;
|
||||
} else {
|
||||
props.ber = -1;
|
||||
}
|
||||
|
||||
/* LTE RSRQ */
|
||||
rsrq = qmi_result_get(result, 0x16, &len);
|
||||
if (rsrq) {
|
||||
DBG("RSRQ: %hhd on RAT %hhd",
|
||||
rsrq->value,
|
||||
rsrq->rat);
|
||||
|
||||
if (rsrq->value == 0) {
|
||||
props.rsrq = -1;
|
||||
} else {
|
||||
props.rsrq = (rsrq->value + 19) * 2;
|
||||
if (props.rsrq > 34) props.rsrq = 34;
|
||||
if (props.rsrq < 0) props.rsrq = 0;
|
||||
}
|
||||
} else {
|
||||
props.rsrq = -1;
|
||||
}
|
||||
|
||||
/* LTE RSRP */
|
||||
if (qmi_result_get_int16(result, 0x18, &rsrp)) {
|
||||
DBG("Got LTE RSRP: %hd", rsrp);
|
||||
|
||||
if (rsrp == 0) {
|
||||
props.rsrp = -1;
|
||||
} else {
|
||||
props.rsrp = rsrp + 140;
|
||||
if (props.rsrp > 97) props.rsrp = 97;
|
||||
if (props.rsrp < 0) props.rsrp = 0;
|
||||
}
|
||||
} else {
|
||||
props.rsrp = -1;
|
||||
}
|
||||
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
props.type,
|
||||
OFONO_NETMON_INFO_RSSI, props.rssi,
|
||||
OFONO_NETMON_INFO_BER, props.ber,
|
||||
OFONO_NETMON_INFO_RSRQ, props.rsrq,
|
||||
OFONO_NETMON_INFO_RSRP, props.rsrp,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct netmon_data *data = ofono_netmon_get_data(netmon);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = netmon;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto out;
|
||||
|
||||
/* Request all signal strength items: mask=0xff */
|
||||
qmi_param_append_uint16(param, 0x10, 255);
|
||||
|
||||
if (qmi_service_send(data->nas, QMI_NAS_GET_RSSI, param,
|
||||
get_rssi_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
out:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_netmon *netmon = user_data;
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_netmon_remove(netmon);
|
||||
return;
|
||||
}
|
||||
|
||||
nmd->nas = qmi_service_ref(service);
|
||||
|
||||
ofono_netmon_register(netmon);
|
||||
}
|
||||
|
||||
static int qmi_netmon_probe(struct ofono_netmon *netmon,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
struct qmi_device *device = user_data;
|
||||
struct netmon_data *nmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
nmd = g_new0(struct netmon_data, 1);
|
||||
|
||||
ofono_netmon_set_data(netmon, nmd);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, netmon, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmi_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
|
||||
qmi_service_unregister_all(nmd->nas);
|
||||
|
||||
qmi_service_unref(nmd->nas);
|
||||
|
||||
g_free(nmd);
|
||||
}
|
||||
|
||||
static struct ofono_netmon_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_netmon_probe,
|
||||
.remove = qmi_netmon_remove,
|
||||
.request_update = qmi_netmon_request_update,
|
||||
};
|
||||
|
||||
void qmi_netmon_init(void)
|
||||
{
|
||||
ofono_netmon_driver_register(&driver);
|
||||
}
|
||||
|
||||
void qmi_netmon_exit(void)
|
||||
{
|
||||
ofono_netmon_driver_unregister(&driver);
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -43,18 +44,36 @@ struct netreg_data {
|
||||
uint8_t current_rat;
|
||||
};
|
||||
|
||||
static int rat_to_tech(uint8_t rat)
|
||||
static bool extract_ss_info_time(
|
||||
struct qmi_result *result,
|
||||
struct ofono_network_time *time)
|
||||
{
|
||||
switch (rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
const struct qmi_nas_3gpp_time *time_3gpp = NULL;
|
||||
uint8_t dst_3gpp;
|
||||
bool dst_3gpp_valid;
|
||||
uint16_t len;
|
||||
|
||||
/* parse 3gpp time & dst */
|
||||
dst_3gpp_valid = qmi_result_get_uint8(result, QMI_NAS_RESULT_3GGP_DST,
|
||||
&dst_3gpp);
|
||||
|
||||
time_3gpp = qmi_result_get(result, QMI_NAS_RESULT_3GPP_TIME, &len);
|
||||
if (time_3gpp && len == sizeof(struct qmi_nas_3gpp_time) &&
|
||||
dst_3gpp_valid) {
|
||||
time->year = le16toh(time_3gpp->year);
|
||||
time->mon = time_3gpp->month;
|
||||
time->mday = time_3gpp->day;
|
||||
time->hour = time_3gpp->hour;
|
||||
time->min = time_3gpp->minute;
|
||||
time->sec = time_3gpp->second;
|
||||
time->utcoff = time_3gpp->timezone * 15 * 60;
|
||||
time->dst = dst_3gpp;
|
||||
return true;
|
||||
}
|
||||
|
||||
return -1;
|
||||
/* TODO: 3gpp2 */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
@@ -64,7 +83,7 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
const struct qmi_nas_serving_system *ss;
|
||||
const struct qmi_nas_current_plmn *plmn;
|
||||
uint8_t i, roaming;
|
||||
uint16_t value16, len;
|
||||
uint16_t value16, len, opname_len;
|
||||
uint32_t value32;
|
||||
|
||||
DBG("");
|
||||
@@ -82,13 +101,13 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
for (i = 0; i < ss->radio_if_count; i++) {
|
||||
DBG("radio in use %d", ss->radio_if[i]);
|
||||
|
||||
*tech = rat_to_tech(ss->radio_if[i]);
|
||||
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, QMI_NAS_RESULT_ROAMING_STATUS,
|
||||
&roaming)) {
|
||||
if (ss->status == 1 && roaming == 0)
|
||||
*status = 5;
|
||||
*status = NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||
}
|
||||
|
||||
if (!operator)
|
||||
@@ -100,8 +119,21 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
GUINT16_FROM_LE(plmn->mcc));
|
||||
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
|
||||
GUINT16_FROM_LE(plmn->mnc));
|
||||
strncpy(operator->name, plmn->desc, plmn->desc_len);
|
||||
operator->name[plmn->desc_len] = '\0';
|
||||
opname_len = plmn->desc_len;
|
||||
if (opname_len > OFONO_MAX_OPERATOR_NAME_LENGTH)
|
||||
opname_len = OFONO_MAX_OPERATOR_NAME_LENGTH;
|
||||
|
||||
/*
|
||||
* Telit QMI modems can return non-utf-8 characters in
|
||||
* plmn-desc. When that happens, libdbus will abort ofono.
|
||||
* If non-utf-8 characters are detected, use mccmnc string.
|
||||
*/
|
||||
if (g_utf8_validate(plmn->desc, opname_len, NULL)) {
|
||||
strncpy(operator->name, plmn->desc, opname_len);
|
||||
operator->name[opname_len] = '\0';
|
||||
} else
|
||||
snprintf(operator->name, OFONO_MAX_OPERATOR_NAME_LENGTH,
|
||||
"%s%s", operator->mcc, operator->mnc);
|
||||
|
||||
DBG("%s (%s:%s)", operator->name, operator->mcc, operator->mnc);
|
||||
}
|
||||
@@ -125,11 +157,15 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
static void ss_info_notify(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct ofono_network_time net_time;
|
||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||
int status, lac, cellid, tech;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (extract_ss_info_time(result, &net_time))
|
||||
ofono_netreg_time_notify(netreg, &net_time);
|
||||
|
||||
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
|
||||
&data->operator))
|
||||
return;
|
||||
@@ -265,7 +301,7 @@ static void scan_nets_cb(struct qmi_result *result, void *user_data)
|
||||
DBG("%03d:%02d %d", netrat->info[i].mcc, netrat->info[i].mnc,
|
||||
netrat->info[i].rat);
|
||||
|
||||
list[i].tech = rat_to_tech(netrat->info[i].rat);
|
||||
list[i].tech = qmi_nas_rat_to_tech(netrat->info[i].rat);
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -357,7 +393,7 @@ static void qmi_register_manual(struct ofono_netreg *netreg,
|
||||
|
||||
info.mcc = atoi(mcc);
|
||||
info.mnc = atoi(mnc);
|
||||
info.rat = data->current_rat;
|
||||
info.rat = QMI_NAS_NETWORK_RAT_NO_CHANGE;
|
||||
|
||||
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
|
||||
sizeof(info), &info);
|
||||
@@ -451,10 +487,11 @@ static void event_notify(struct qmi_result *result, void *user_data)
|
||||
if (ss) {
|
||||
int strength;
|
||||
|
||||
DBG("signal with %d dBm on %d", ss->dbm, ss->rat);
|
||||
|
||||
strength = dbm_to_strength(ss->dbm);
|
||||
|
||||
DBG("signal with %d%%(%d dBm) on %d",
|
||||
strength, ss->dbm, ss->rat);
|
||||
|
||||
ofono_netreg_strength_notify(netreg, strength);
|
||||
}
|
||||
|
||||
@@ -474,10 +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)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *data = ofono_netreg_get_data(netreg);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_netreg_register(netreg);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||
event_notify, netreg, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, netreg, NULL);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
@@ -499,12 +543,6 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_EVENT,
|
||||
event_notify, netreg, NULL);
|
||||
|
||||
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
|
||||
ss_info_notify, netreg, NULL);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto done;
|
||||
@@ -543,7 +581,7 @@ static int qmi_netreg_probe(struct ofono_netreg *netreg,
|
||||
|
||||
ofono_netreg_set_data(netreg, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS,
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, netreg, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
@@ -33,12 +35,18 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "ctl.h"
|
||||
|
||||
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data);
|
||||
|
||||
struct discovery {
|
||||
qmi_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
struct qmi_device {
|
||||
int ref_count;
|
||||
int fd;
|
||||
@@ -49,6 +57,7 @@ struct qmi_device {
|
||||
GQueue *req_queue;
|
||||
GQueue *control_queue;
|
||||
GQueue *service_queue;
|
||||
GQueue *discovery_queue;
|
||||
uint8_t next_control_tid;
|
||||
uint16_t next_service_tid;
|
||||
qmi_debug_func_t debug_func;
|
||||
@@ -60,6 +69,12 @@ struct qmi_device {
|
||||
uint8_t version_count;
|
||||
GHashTable *service_list;
|
||||
unsigned int release_users;
|
||||
qmi_shutdown_func_t shutdown_func;
|
||||
void *shutdown_user_data;
|
||||
qmi_destroy_func_t shutdown_destroy;
|
||||
guint shutdown_source;
|
||||
bool shutting_down : 1;
|
||||
bool destroyed : 1;
|
||||
};
|
||||
|
||||
struct qmi_service {
|
||||
@@ -209,6 +224,14 @@ static gint __request_compare(gconstpointer a, gconstpointer b)
|
||||
return req->tid - tid;
|
||||
}
|
||||
|
||||
static void __discovery_free(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct discovery *d = data;
|
||||
qmi_destroy_func_t destroy = d->destroy;
|
||||
|
||||
destroy(d);
|
||||
}
|
||||
|
||||
static void __notify_free(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct qmi_notify *notify = data;
|
||||
@@ -313,8 +336,12 @@ static const char *__service_type_to_string(uint8_t type)
|
||||
return "UIM";
|
||||
case QMI_SERVICE_PBM:
|
||||
return "PBM";
|
||||
case QMI_SERVICE_QCHAT:
|
||||
return "QCHAT";
|
||||
case QMI_SERVICE_RMTFS:
|
||||
return "RMTFS";
|
||||
case QMI_SERVICE_TEST:
|
||||
return "TEST";
|
||||
case QMI_SERVICE_LOC:
|
||||
return "LOC";
|
||||
case QMI_SERVICE_SAR:
|
||||
@@ -326,9 +353,21 @@ static const char *__service_type_to_string(uint8_t type)
|
||||
case QMI_SERVICE_TS:
|
||||
return "TS";
|
||||
case QMI_SERVICE_TMD:
|
||||
return "TMS";
|
||||
return "TMD";
|
||||
case QMI_SERVICE_WDA:
|
||||
return "WDA";
|
||||
case QMI_SERVICE_CSVT:
|
||||
return "CSVT";
|
||||
case QMI_SERVICE_COEX:
|
||||
return "COEX";
|
||||
case QMI_SERVICE_PDC:
|
||||
return "PDC";
|
||||
case QMI_SERVICE_RFRPE:
|
||||
return "RFRPE";
|
||||
case QMI_SERVICE_DSD:
|
||||
return "DSD";
|
||||
case QMI_SERVICE_SSCTL:
|
||||
return "SSCTL";
|
||||
case QMI_SERVICE_CAT_OLD:
|
||||
return "CAT";
|
||||
case QMI_SERVICE_RMS:
|
||||
@@ -758,7 +797,7 @@ static void handle_packet(struct qmi_device *device,
|
||||
|
||||
tid = GUINT16_FROM_LE(service->transaction);
|
||||
|
||||
if (service->type == 0x04 && tid == 0x0000) {
|
||||
if (service->type == 0x04) {
|
||||
handle_indication(device, hdr->service, hdr->client,
|
||||
message, length, data);
|
||||
return;
|
||||
@@ -838,6 +877,21 @@ static void read_watch_destroy(gpointer user_data)
|
||||
device->read_watch = 0;
|
||||
}
|
||||
|
||||
static void __qmi_device_discovery_started(struct qmi_device *device,
|
||||
struct discovery *d)
|
||||
{
|
||||
g_queue_push_tail(device->discovery_queue, d);
|
||||
}
|
||||
|
||||
static void __qmi_device_discovery_complete(struct qmi_device *device,
|
||||
struct discovery *d)
|
||||
{
|
||||
if (g_queue_remove(device->discovery_queue, d) != TRUE)
|
||||
return;
|
||||
|
||||
__discovery_free(d, NULL);
|
||||
}
|
||||
|
||||
static void service_destroy(gpointer data)
|
||||
{
|
||||
struct qmi_service *service = data;
|
||||
@@ -891,6 +945,7 @@ struct qmi_device *qmi_device_new(int fd)
|
||||
device->req_queue = g_queue_new();
|
||||
device->control_queue = g_queue_new();
|
||||
device->service_queue = g_queue_new();
|
||||
device->discovery_queue = g_queue_new();
|
||||
|
||||
device->service_list = g_hash_table_new_full(g_direct_hash,
|
||||
g_direct_equal, NULL, service_destroy);
|
||||
@@ -927,6 +982,9 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
g_queue_foreach(device->req_queue, __request_free, NULL);
|
||||
g_queue_free(device->req_queue);
|
||||
|
||||
g_queue_foreach(device->discovery_queue, __discovery_free, NULL);
|
||||
g_queue_free(device->discovery_queue);
|
||||
|
||||
if (device->write_watch > 0)
|
||||
g_source_remove(device->write_watch);
|
||||
|
||||
@@ -936,12 +994,18 @@ void qmi_device_unref(struct qmi_device *device)
|
||||
if (device->close_on_unref)
|
||||
close(device->fd);
|
||||
|
||||
if (device->shutdown_source)
|
||||
g_source_remove(device->shutdown_source);
|
||||
|
||||
g_hash_table_destroy(device->service_list);
|
||||
|
||||
g_free(device->version_str);
|
||||
g_free(device->version_list);
|
||||
|
||||
g_free(device);
|
||||
if (device->shutting_down)
|
||||
device->destroyed = true;
|
||||
else
|
||||
g_free(device);
|
||||
}
|
||||
|
||||
void qmi_device_set_debug(struct qmi_device *device,
|
||||
@@ -962,6 +1026,23 @@ void qmi_device_set_close_on_unref(struct qmi_device *device, bool do_close)
|
||||
device->close_on_unref = do_close;
|
||||
}
|
||||
|
||||
void qmi_result_print_tlvs(struct qmi_result *result)
|
||||
{
|
||||
const void *ptr = result->data;
|
||||
uint16_t len = result->length;
|
||||
|
||||
while (len > QMI_TLV_HDR_SIZE) {
|
||||
const struct qmi_tlv_hdr *tlv = ptr;
|
||||
uint16_t tlv_length = GUINT16_FROM_LE(tlv->length);
|
||||
|
||||
DBG("tlv: 0x%02x len 0x%04x", tlv->type, tlv->length);
|
||||
|
||||
ptr += QMI_TLV_HDR_SIZE + tlv_length;
|
||||
len -= QMI_TLV_HDR_SIZE + tlv_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const void *tlv_get(const void *data, uint16_t size,
|
||||
uint8_t type, uint16_t *length)
|
||||
{
|
||||
@@ -987,6 +1068,7 @@ static const void *tlv_get(const void *data, uint16_t size,
|
||||
}
|
||||
|
||||
struct discover_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
qmi_discover_func_t func;
|
||||
void *user_data;
|
||||
@@ -994,6 +1076,21 @@ struct discover_data {
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static void discover_data_free(gpointer user_data)
|
||||
{
|
||||
struct discover_data *data = user_data;
|
||||
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void discover_callback(uint16_t message, uint16_t length,
|
||||
const void *buffer, void *user_data)
|
||||
{
|
||||
@@ -1007,8 +1104,6 @@ static void discover_callback(uint16_t message, uint16_t length,
|
||||
uint8_t count;
|
||||
unsigned int i;
|
||||
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
count = 0;
|
||||
list = NULL;
|
||||
|
||||
@@ -1079,10 +1174,7 @@ done:
|
||||
if (data->func)
|
||||
data->func(count, list, data->user_data);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
|
||||
static gboolean discover_reply(gpointer user_data)
|
||||
@@ -1096,10 +1188,7 @@ static gboolean discover_reply(gpointer user_data)
|
||||
data->func(device->version_count,
|
||||
device->version_list, data->user_data);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1120,13 +1209,15 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = discover_data_free;
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
if (device->version_list) {
|
||||
g_timeout_add_seconds(0, discover_reply, data);
|
||||
data->timeout = g_timeout_add_seconds(0, discover_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1147,6 +1238,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
|
||||
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1177,63 +1269,256 @@ static void release_client(struct qmi_device *device,
|
||||
__request_submit(device, req, hdr->transaction);
|
||||
}
|
||||
|
||||
struct shutdown_data {
|
||||
struct qmi_device *device;
|
||||
qmi_shutdown_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
static gboolean shutdown_reply(gpointer user_data)
|
||||
static void shutdown_destroy(gpointer user_data)
|
||||
{
|
||||
struct shutdown_data *data = user_data;
|
||||
struct qmi_device *device = user_data;
|
||||
|
||||
if (data->func)
|
||||
data->func(data->user_data);
|
||||
if (device->shutdown_destroy)
|
||||
device->shutdown_destroy(device->shutdown_user_data);
|
||||
|
||||
g_free(data);
|
||||
device->shutdown_source = 0;
|
||||
|
||||
return FALSE;
|
||||
if (device->destroyed)
|
||||
g_free(device);
|
||||
}
|
||||
|
||||
static gboolean shutdown_timeout(gpointer user_data)
|
||||
static gboolean shutdown_callback(gpointer user_data)
|
||||
{
|
||||
struct shutdown_data *data = user_data;
|
||||
struct qmi_device *device = data->device;
|
||||
struct qmi_device *device = user_data;
|
||||
|
||||
if (device->release_users > 0)
|
||||
return TRUE;
|
||||
|
||||
return shutdown_reply(data);
|
||||
device->shutting_down = true;
|
||||
|
||||
if (device->shutdown_func)
|
||||
device->shutdown_func(device->shutdown_user_data);
|
||||
|
||||
device->shutting_down = true;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
|
||||
void *user_data, qmi_destroy_func_t destroy)
|
||||
{
|
||||
struct shutdown_data *data;
|
||||
|
||||
if (!device)
|
||||
return false;
|
||||
|
||||
if (device->shutdown_source > 0)
|
||||
return false;
|
||||
|
||||
__debug_device(device, "device %p shutdown", device);
|
||||
|
||||
data = g_try_new0(struct shutdown_data, 1);
|
||||
if (!data)
|
||||
device->shutdown_source = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
|
||||
0, shutdown_callback, device,
|
||||
shutdown_destroy);
|
||||
if (device->shutdown_source == 0)
|
||||
return false;
|
||||
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
if (device->release_users > 0)
|
||||
g_timeout_add_seconds(0, shutdown_timeout, data);
|
||||
else
|
||||
g_timeout_add_seconds(0, shutdown_reply, data);
|
||||
device->shutdown_func = func;
|
||||
device->shutdown_user_data = user_data;
|
||||
device->shutdown_destroy = destroy;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_device_file_name(struct qmi_device *device,
|
||||
char *file_name, int size)
|
||||
{
|
||||
pid_t pid;
|
||||
char temp[100];
|
||||
ssize_t result;
|
||||
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
pid = getpid();
|
||||
|
||||
snprintf(temp, 100, "/proc/%d/fd/%d", (int) pid, device->fd);
|
||||
temp[99] = 0;
|
||||
|
||||
result = readlink(temp, file_name, size - 1);
|
||||
|
||||
if (result == -1 || result >= size - 1) {
|
||||
DBG("Error %d in readlink", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
file_name[result] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *get_first_dir_in_directory(char *dir_path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dir_entry;
|
||||
char *dir_name = NULL;
|
||||
|
||||
dir = opendir(dir_path);
|
||||
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
dir_entry = readdir(dir);
|
||||
|
||||
while ((dir_entry != NULL)) {
|
||||
if (dir_entry->d_type == DT_DIR &&
|
||||
strcmp(dir_entry->d_name, ".") != 0 &&
|
||||
strcmp(dir_entry->d_name, "..") != 0) {
|
||||
dir_name = g_strdup(dir_entry->d_name);
|
||||
break;
|
||||
}
|
||||
|
||||
dir_entry = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return dir_name;
|
||||
}
|
||||
|
||||
static char *get_device_interface(struct qmi_device *device)
|
||||
{
|
||||
char * const driver_names[] = { "usbmisc", "usb" };
|
||||
unsigned int i;
|
||||
char file_path[PATH_MAX];
|
||||
char *file_name;
|
||||
char *interface = NULL;
|
||||
|
||||
if (!get_device_file_name(device, file_path, sizeof(file_path)))
|
||||
return NULL;
|
||||
|
||||
file_name = basename(file_path);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(driver_names) && !interface; i++) {
|
||||
gchar *sysfs_path;
|
||||
|
||||
sysfs_path = g_strdup_printf("/sys/class/%s/%s/device/net/",
|
||||
driver_names[i], file_name);
|
||||
interface = get_first_dir_in_directory(sysfs_path);
|
||||
g_free(sysfs_path);
|
||||
}
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
|
||||
struct qmi_device *device)
|
||||
{
|
||||
char *sysfs_path = NULL;
|
||||
char *interface = NULL;
|
||||
int fd = -1;
|
||||
char value;
|
||||
enum qmi_device_expected_data_format expected =
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
|
||||
|
||||
if (!device)
|
||||
goto done;
|
||||
|
||||
interface = get_device_interface(device);
|
||||
|
||||
if (!interface) {
|
||||
DBG("Error while getting interface name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Build sysfs file path and open it */
|
||||
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||
|
||||
fd = open(sysfs_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
/* maybe not supported by kernel */
|
||||
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (read(fd, &value, 1) != 1) {
|
||||
DBG("Error %d in read(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (value == 'Y')
|
||||
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP;
|
||||
else if (value == 'N')
|
||||
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3;
|
||||
else
|
||||
DBG("Unexpected sysfs file contents");
|
||||
|
||||
done:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (sysfs_path)
|
||||
g_free(sysfs_path);
|
||||
|
||||
if (interface)
|
||||
g_free(interface);
|
||||
|
||||
return expected;
|
||||
}
|
||||
|
||||
bool qmi_device_set_expected_data_format(struct qmi_device *device,
|
||||
enum qmi_device_expected_data_format format)
|
||||
{
|
||||
bool res = false;
|
||||
char *sysfs_path = NULL;
|
||||
char *interface = NULL;
|
||||
int fd = -1;
|
||||
char value;
|
||||
|
||||
if (!device)
|
||||
goto done;
|
||||
|
||||
switch (format) {
|
||||
case QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3:
|
||||
value = 'N';
|
||||
break;
|
||||
case QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP:
|
||||
value = 'Y';
|
||||
break;
|
||||
default:
|
||||
DBG("Unhandled format: %d", (int) format);
|
||||
goto done;
|
||||
}
|
||||
|
||||
interface = get_device_interface(device);
|
||||
|
||||
if (!interface) {
|
||||
DBG("Error while getting interface name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Build sysfs file path and open it */
|
||||
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
|
||||
|
||||
fd = open(sysfs_path, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
/* maybe not supported by kernel */
|
||||
DBG("Error %d in open(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (write(fd, &value, 1) != 1) {
|
||||
DBG("Error %d in write(%s)", errno, sysfs_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
res = true;
|
||||
|
||||
done:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (sysfs_path)
|
||||
g_free(sysfs_path);
|
||||
|
||||
if (interface)
|
||||
g_free(interface);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct qmi_param *qmi_param_new(void)
|
||||
{
|
||||
struct qmi_param *param;
|
||||
@@ -1435,6 +1720,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
uint16_t len, tmp;
|
||||
|
||||
if (!result || !type)
|
||||
return false;
|
||||
|
||||
ptr = tlv_get(result->data, result->length, type, &len);
|
||||
if (!ptr)
|
||||
return false;
|
||||
|
||||
memcpy(&tmp, ptr, 2);
|
||||
|
||||
if (value)
|
||||
*value = GINT16_FROM_LE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value)
|
||||
{
|
||||
@@ -1501,6 +1807,7 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
}
|
||||
|
||||
struct service_create_data {
|
||||
struct discovery super;
|
||||
struct qmi_device *device;
|
||||
bool shared;
|
||||
uint8_t type;
|
||||
@@ -1512,16 +1819,29 @@ struct service_create_data {
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static gboolean service_create_reply(gpointer user_data)
|
||||
static void service_create_data_free(gpointer user_data)
|
||||
{
|
||||
struct service_create_data *data = user_data;
|
||||
|
||||
data->func(NULL, data->user_data);
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static gboolean service_create_reply(gpointer user_data)
|
||||
{
|
||||
struct service_create_data *data = user_data;
|
||||
|
||||
data->timeout = 0;
|
||||
data->func(NULL, data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1537,8 +1857,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
||||
uint16_t len;
|
||||
unsigned int hash_id;
|
||||
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
result_code = tlv_get(buffer, length, 0x02, &len);
|
||||
if (!result_code)
|
||||
goto done;
|
||||
@@ -1580,13 +1898,9 @@ static void service_create_callback(uint16_t message, uint16_t length,
|
||||
|
||||
done:
|
||||
data->func(service, data->user_data);
|
||||
|
||||
qmi_service_unref(service);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
}
|
||||
|
||||
static void service_create_discover(uint8_t count,
|
||||
@@ -1617,7 +1931,9 @@ static void service_create_discover(uint8_t count,
|
||||
if (data->timeout > 0)
|
||||
g_source_remove(data->timeout);
|
||||
|
||||
g_timeout_add_seconds(0, service_create_reply, data);
|
||||
data->timeout = g_timeout_add_seconds(0,
|
||||
service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1640,6 +1956,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = service_create_data_free;
|
||||
data->device = device;
|
||||
data->shared = shared;
|
||||
data->type = type;
|
||||
@@ -1662,6 +1979,7 @@ static bool service_create(struct qmi_device *device, bool shared,
|
||||
|
||||
done:
|
||||
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1680,17 +1998,23 @@ bool qmi_service_create(struct qmi_device *device,
|
||||
}
|
||||
|
||||
struct service_create_shared_data {
|
||||
struct discovery super;
|
||||
struct qmi_service *service;
|
||||
struct qmi_device *device;
|
||||
qmi_create_func_t func;
|
||||
void *user_data;
|
||||
qmi_destroy_func_t destroy;
|
||||
guint timeout;
|
||||
};
|
||||
|
||||
static gboolean service_create_shared_reply(gpointer user_data)
|
||||
static void service_create_shared_data_free(gpointer user_data)
|
||||
{
|
||||
struct service_create_shared_data *data = user_data;
|
||||
|
||||
data->func(data->service, data->user_data);
|
||||
if (data->timeout) {
|
||||
g_source_remove(data->timeout);
|
||||
data->timeout = 0;
|
||||
}
|
||||
|
||||
qmi_service_unref(data->service);
|
||||
|
||||
@@ -1698,6 +2022,16 @@ static gboolean service_create_shared_reply(gpointer user_data)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static gboolean service_create_shared_reply(gpointer user_data)
|
||||
{
|
||||
struct service_create_shared_data *data = user_data;
|
||||
|
||||
data->timeout = 0;
|
||||
data->func(data->service, data->user_data);
|
||||
|
||||
__qmi_device_discovery_complete(data->device, &data->super);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1724,13 +2058,16 @@ bool qmi_service_create_shared(struct qmi_device *device,
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
data->super.destroy = service_create_shared_data_free;
|
||||
data->service = qmi_service_ref(service);
|
||||
|
||||
data->device = device;
|
||||
data->func = func;
|
||||
data->user_data = user_data;
|
||||
data->destroy = destroy;
|
||||
|
||||
g_timeout_add(0, service_create_shared_reply, data);
|
||||
data->timeout = g_timeout_add(0,
|
||||
service_create_shared_reply, data);
|
||||
__qmi_device_discovery_started(device, &data->super);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,18 +35,32 @@
|
||||
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
|
||||
#define QMI_SERVICE_UIM 11 /* UIM service */
|
||||
#define QMI_SERVICE_PBM 12 /* Phonebook service */
|
||||
#define QMI_SERVICE_QCHAT 13
|
||||
#define QMI_SERVICE_RMTFS 14 /* Remote file system service */
|
||||
#define QMI_SERVICE_TEST 15
|
||||
#define QMI_SERVICE_LOC 16 /* Location service */
|
||||
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
|
||||
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
|
||||
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
|
||||
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
|
||||
#define QMI_SERVICE_TMD 24 /* Thermal mitigation device service */
|
||||
#define QMI_SERVICE_WDA 26 /* Wireless data administrative service */
|
||||
#define QMI_SERVICE_CSVT 29
|
||||
#define QMI_SERVICE_COEX 34
|
||||
#define QMI_SERVICE_PDC 36 /* Persistent device configuration service */
|
||||
#define QMI_SERVICE_RFRPE 41
|
||||
#define QMI_SERVICE_DSD 42
|
||||
#define QMI_SERVICE_SSCTL 43
|
||||
#define QMI_SERVICE_CAT_OLD 224 /* Card application toolkit service */
|
||||
#define QMI_SERVICE_RMS 225 /* Remote management service */
|
||||
#define QMI_SERVICE_OMA 226 /* OMA device management service */
|
||||
|
||||
enum qmi_device_expected_data_format {
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3,
|
||||
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
|
||||
};
|
||||
|
||||
struct qmi_version {
|
||||
uint8_t type;
|
||||
uint16_t major;
|
||||
@@ -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,
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
|
||||
uint8_t *value);
|
||||
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
|
||||
int16_t *value);
|
||||
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
|
||||
uint16_t *value);
|
||||
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
|
||||
uint32_t *value);
|
||||
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
|
||||
uint64_t *value);
|
||||
|
||||
void qmi_result_print_tlvs(struct qmi_result *result);
|
||||
|
||||
struct qmi_service;
|
||||
|
||||
|
||||
@@ -41,12 +41,14 @@ static int qmimodem_init(void)
|
||||
qmi_gprs_context_init();
|
||||
qmi_radio_settings_init();
|
||||
qmi_location_reporting_init();
|
||||
qmi_netmon_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmimodem_exit(void)
|
||||
{
|
||||
qmi_netmon_exit();
|
||||
qmi_location_reporting_exit();
|
||||
qmi_radio_settings_exit();
|
||||
qmi_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_exit(void);
|
||||
|
||||
extern void qmi_netmon_init(void);
|
||||
extern void qmi_netmon_exit(void);
|
||||
|
||||
@@ -29,15 +29,202 @@
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
#include "dms.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct settings_data {
|
||||
struct qmi_service *nas;
|
||||
struct qmi_service *dms;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
static void get_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
uint16_t pref;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_result_get_uint16(result,
|
||||
QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref);
|
||||
|
||||
switch (pref) {
|
||||
case QMI_NAS_RAT_MODE_PREF_GSM:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_UMTS:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_NAS_RAT_MODE_PREF_LTE:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL,
|
||||
get_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void set_system_selection_pref_cb(struct qmi_result *result,
|
||||
void* user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_ANY;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_GSM;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_UMTS;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
pref = QMI_NAS_RAT_MODE_PREF_LTE;
|
||||
break;
|
||||
}
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param) {
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE,
|
||||
pref);
|
||||
|
||||
if (qmi_service_send(data->nas,
|
||||
QMI_NAS_SET_SYSTEM_SELECTION_PREF, param,
|
||||
set_system_selection_pref_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void get_caps_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
|
||||
const struct qmi_dms_device_caps *caps;
|
||||
unsigned int available_rats;
|
||||
uint16_t len;
|
||||
uint8_t i;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto error;
|
||||
|
||||
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
|
||||
if (!caps)
|
||||
goto error;
|
||||
|
||||
available_rats = 0;
|
||||
for (i = 0; i < caps->radio_if_count; i++) {
|
||||
switch (caps->radio_if[i]) {
|
||||
case QMI_DMS_RADIO_IF_GSM:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_UMTS:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case QMI_DMS_RADIO_IF_LTE:
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_available_rats(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct settings_data *rsd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (!rsd->dms)
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL,
|
||||
get_caps_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct settings_data *data = ofono_radio_settings_get_data(rs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service)
|
||||
return;
|
||||
|
||||
data->dms = qmi_service_ref(service);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
@@ -74,10 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
|
||||
ofono_radio_settings_set_data(rs, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, rs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||
create_dms_cb, rs, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
@@ -99,6 +288,9 @@ static struct ofono_radio_settings_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmi_radio_settings_probe,
|
||||
.remove = qmi_radio_settings_remove,
|
||||
.set_rat_mode = qmi_set_rat_mode,
|
||||
.query_rat_mode = qmi_query_rat_mode,
|
||||
.query_available_rats = qmi_query_available_rats,
|
||||
};
|
||||
|
||||
void qmi_radio_settings_init(void)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "dms.h"
|
||||
#include "uim.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
@@ -38,15 +39,36 @@
|
||||
#define EF_STATUS_INVALIDATED 0
|
||||
#define EF_STATUS_VALID 1
|
||||
|
||||
struct sim_data {
|
||||
struct qmi_service *uim;
|
||||
uint32_t event_mask;
|
||||
/* max number of retry of commands that can temporary fail */
|
||||
#define MAX_RETRY_COUNT 100
|
||||
|
||||
enum get_card_status_result {
|
||||
GET_CARD_STATUS_RESULT_OK, /* No error */
|
||||
GET_CARD_STATUS_RESULT_ERROR, /* Definitive error */
|
||||
GET_CARD_STATUS_RESULT_TEMP_ERROR, /* error, a retry could work */
|
||||
};
|
||||
|
||||
/* information from QMI_UIM_GET_CARD_STATUS command */
|
||||
struct sim_status {
|
||||
uint8_t card_state;
|
||||
uint8_t app_type;
|
||||
uint8_t passwd_state;
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
};
|
||||
|
||||
struct sim_data {
|
||||
struct qmi_device *qmi_dev;
|
||||
struct qmi_service *dms;
|
||||
struct qmi_service *uim;
|
||||
uint32_t event_mask;
|
||||
uint8_t app_type;
|
||||
uint32_t retry_count;
|
||||
guint poll_source;
|
||||
};
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data);
|
||||
|
||||
static int create_fileid_data(uint8_t app_type, int fileid,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
@@ -146,7 +168,7 @@ static void qmi_read_attributes(struct ofono_sim *sim, int fileid,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
struct qmi_param *param;
|
||||
@@ -211,7 +233,7 @@ static void qmi_read_transparent(struct ofono_sim *sim,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char read_data[4];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
@@ -257,7 +279,7 @@ static void qmi_read_record(struct ofono_sim *sim,
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x06, 0x00 };
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char read_data[4];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
@@ -295,76 +317,214 @@ error:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
||||
static void write_generic_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_write_cb_t cb = cbd->cb;
|
||||
uint16_t len;
|
||||
const uint8_t *card_result;
|
||||
uint8_t sw1, sw2;
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
card_result = qmi_result_get(result, 0x10, &len);
|
||||
if (card_result == NULL || len != 2) {
|
||||
DBG("card_result: %p, len: %d", card_result, (int) len);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_data);
|
||||
}
|
||||
sw1 = card_result[0];
|
||||
sw2 = card_result[1];
|
||||
|
||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
DBG("%02x, %02x", sw1, sw2);
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
||||
(sw1 == 0x90 && sw2 != 0x00)) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
||||
ofono_error("%s: error sw1 %02x sw2 %02x", __func__, sw1, sw2);
|
||||
|
||||
error.type = OFONO_ERROR_TYPE_SIM;
|
||||
error.error = (sw1 << 8) | sw2;
|
||||
|
||||
cb(&error, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data->retries, user_data);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void card_setup(const struct qmi_uim_slot_info *slot,
|
||||
static void write_generic(struct ofono_sim *sim,
|
||||
uint16_t qmi_message, int fileid,
|
||||
int start_or_recordnum,
|
||||
int length, const unsigned char *value,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
unsigned char aid_data[2] = { 0x00, 0x00 };
|
||||
unsigned char write_data[4 + length];
|
||||
unsigned char fileid_data[9];
|
||||
int fileid_len;
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("file id 0x%04x path len %d", fileid, path_len);
|
||||
|
||||
fileid_len = create_fileid_data(data->app_type, fileid,
|
||||
path, path_len, fileid_data);
|
||||
|
||||
if (fileid_len < 0)
|
||||
goto error;
|
||||
|
||||
write_data[0] = start_or_recordnum & 0xff;
|
||||
write_data[1] = (start_or_recordnum & 0xff00) >> 8;
|
||||
write_data[2] = length & 0xff;
|
||||
write_data[3] = (length & 0xff00) >> 8;
|
||||
memcpy(&write_data[4], value, length);
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
|
||||
qmi_param_append(param, 0x02, fileid_len, fileid_data);
|
||||
qmi_param_append(param, 0x03, 4 + length, write_data);
|
||||
|
||||
if (qmi_service_send(data->uim, qmi_message, param,
|
||||
write_generic_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void qmi_write_transparent(struct ofono_sim *sim,
|
||||
int fileid, int start, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_TRANSPARENT, fileid, start,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_linear(struct ofono_sim *sim,
|
||||
int fileid, int record, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, record,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void qmi_write_cyclic(struct ofono_sim *sim,
|
||||
int fileid, int length,
|
||||
const unsigned char *value,
|
||||
const unsigned char *path,
|
||||
unsigned int path_len,
|
||||
ofono_sim_write_cb_t cb, void *user_data)
|
||||
{
|
||||
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, 0,
|
||||
length, value, path, path_len, cb, user_data);
|
||||
}
|
||||
|
||||
static void get_imsi_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_imsi_cb_t cb = cbd->cb;
|
||||
char *str;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMSI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
|
||||
|
||||
qmi_free(str);
|
||||
}
|
||||
|
||||
static void qmi_read_imsi(struct ofono_sim *sim,
|
||||
ofono_sim_imsi_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->dms, QMI_DMS_GET_IMSI, NULL,
|
||||
get_imsi_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
/* Return true if a retry could give another (better) result */
|
||||
static bool get_card_status(const struct qmi_uim_slot_info *slot,
|
||||
const struct qmi_uim_app_info1 *info1,
|
||||
const struct qmi_uim_app_info2 *info2,
|
||||
struct sim_data *data)
|
||||
struct sim_status *sim_stat)
|
||||
{
|
||||
data->card_state = slot->card_state;
|
||||
data->app_type = info1->app_type;
|
||||
bool need_retry = false;
|
||||
sim_stat->card_state = slot->card_state;
|
||||
sim_stat->app_type = info1->app_type;
|
||||
|
||||
switch (info1->app_state) {
|
||||
case 0x02: /* PIN1 or UPIN is required */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
|
||||
break;
|
||||
case 0x03: /* PUK1 or PUK for UPIN is required */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
|
||||
break;
|
||||
case 0x04: /* Personalization state must be checked. */
|
||||
/* This is temporary, we could retry and get another result */
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
need_retry = true;
|
||||
break;
|
||||
case 0x07: /* Ready */
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_NONE;
|
||||
break;
|
||||
default:
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
DBG("info1->app_state:0x%x: OFONO_SIM_PASSWORD_INVALID",
|
||||
info1->app_state);
|
||||
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
|
||||
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
||||
data->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
|
||||
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
|
||||
|
||||
return need_retry;
|
||||
}
|
||||
|
||||
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
static enum get_card_status_result handle_get_card_status_result(
|
||||
struct qmi_result *result, struct sim_status *sim_stat)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
const void *ptr;
|
||||
const struct qmi_uim_card_status *status;
|
||||
uint16_t len, offset;
|
||||
uint8_t i;
|
||||
|
||||
DBG("");
|
||||
enum get_card_status_result res = GET_CARD_STATUS_RESULT_ERROR;
|
||||
|
||||
if (qmi_result_set_error(result, NULL))
|
||||
goto done;
|
||||
@@ -397,15 +557,211 @@ static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
|
||||
index = GUINT16_FROM_LE(status->index_gw_pri);
|
||||
|
||||
if ((index & 0xff) == i && (index >> 8) == n)
|
||||
card_setup(slot, info1, info2, data);
|
||||
if ((index & 0xff) == i && (index >> 8) == n) {
|
||||
if (get_card_status(slot, info1, info2,
|
||||
sim_stat))
|
||||
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
|
||||
else
|
||||
res = GET_CARD_STATUS_RESULT_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean query_passwd_state_retry(gpointer userdata)
|
||||
{
|
||||
struct cb_data *cbd = userdata;
|
||||
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
|
||||
data->poll_source = 0;
|
||||
|
||||
qmi_query_passwd_state(sim, cb, cbd->data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void query_passwd_state_cb(struct qmi_result *result,
|
||||
void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_passwd_cb_t cb = cbd->cb;
|
||||
struct ofono_sim *sim = cbd->user;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct sim_status sim_stat;
|
||||
enum get_card_status_result res;
|
||||
struct cb_data *retry_cbd;
|
||||
|
||||
res = handle_get_card_status_result(result, &sim_stat);
|
||||
switch (res) {
|
||||
case GET_CARD_STATUS_RESULT_OK:
|
||||
DBG("passwd state %d", sim_stat.passwd_state);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
|
||||
break;
|
||||
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
|
||||
data->retry_count++;
|
||||
if (data->retry_count > MAX_RETRY_COUNT) {
|
||||
DBG("Failed after %d attempts", data->retry_count);
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
} else {
|
||||
DBG("Retry command");
|
||||
retry_cbd = cb_data_new(cb, cbd->data);
|
||||
retry_cbd->user = sim;
|
||||
data->poll_source = g_timeout_add(20,
|
||||
query_passwd_state_retry,
|
||||
retry_cbd);
|
||||
}
|
||||
break;
|
||||
case GET_CARD_STATUS_RESULT_ERROR:
|
||||
DBG("Command failed");
|
||||
data->retry_count = 0;
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void qmi_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
cbd->user = sim;
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||
query_passwd_state_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
struct sim_status sim_stat;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||
GET_CARD_STATUS_RESULT_OK) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, sim_stat.retries, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_query_pin_retries(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
|
||||
query_pin_retries_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void pin_send_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmi_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
int passwd_len;
|
||||
struct qmi_param *param;
|
||||
struct qmi_uim_param_message_info *info_data;
|
||||
unsigned char session_info_data[2];
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!passwd)
|
||||
goto error;
|
||||
|
||||
passwd_len = strlen(passwd);
|
||||
|
||||
if (passwd_len <= 0 || passwd_len > 0xFF)
|
||||
goto error;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* param info */
|
||||
info_data = alloca(2 + passwd_len);
|
||||
info_data->pin_id = 0x01; /* PIN 1 */
|
||||
info_data->length = (uint8_t) passwd_len;
|
||||
memcpy(info_data->pin_value, passwd, passwd_len);
|
||||
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_INFO, 2 + passwd_len,
|
||||
info_data);
|
||||
/* param Session Information */
|
||||
session_info_data[0] = 0x6;
|
||||
session_info_data[1] = 0x0;
|
||||
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_SESSION_INFO, 2,
|
||||
session_info_data);
|
||||
|
||||
if (qmi_service_send(data->uim, QMI_UIM_VERIFY_PIN, param,
|
||||
pin_send_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void get_card_status_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
struct sim_status sim_stat;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (handle_get_card_status_result(result, &sim_stat) !=
|
||||
GET_CARD_STATUS_RESULT_OK) {
|
||||
data->app_type = 0; /* Unknown */
|
||||
sim_stat.card_state = 0x00; /* Absent */
|
||||
} else {
|
||||
data->app_type = sim_stat.app_type;
|
||||
}
|
||||
|
||||
ofono_sim_register(sim);
|
||||
|
||||
switch (data->card_state) {
|
||||
switch (sim_stat.card_state) {
|
||||
case 0x00: /* Absent */
|
||||
case 0x02: /* Error */
|
||||
break;
|
||||
@@ -465,30 +821,44 @@ static void create_uim_cb(struct qmi_service *service, void *user_data)
|
||||
return;
|
||||
|
||||
error:
|
||||
qmi_service_unref(data->uim);
|
||||
|
||||
ofono_sim_remove(sim);
|
||||
}
|
||||
|
||||
static void create_dms_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_sim *sim = user_data;
|
||||
struct sim_data *data = ofono_sim_get_data(sim);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request DMS service");
|
||||
ofono_sim_remove(sim);
|
||||
return;
|
||||
}
|
||||
|
||||
data->dms = qmi_service_ref(service);
|
||||
|
||||
qmi_service_create(data->qmi_dev, QMI_SERVICE_UIM, create_uim_cb, sim,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int qmi_sim_probe(struct ofono_sim *sim,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
struct qmi_device *device = user_data;
|
||||
struct sim_data *data;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
data = g_new0(struct sim_data, 1);
|
||||
|
||||
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
data->retries[i] = -1;
|
||||
data->qmi_dev = device;
|
||||
|
||||
ofono_sim_set_data(sim, data);
|
||||
|
||||
qmi_service_create(device, QMI_SERVICE_UIM, create_uim_cb, sim, NULL);
|
||||
qmi_service_create_shared(device, QMI_SERVICE_DMS,
|
||||
create_dms_cb, sim, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -501,9 +871,18 @@ static void qmi_sim_remove(struct ofono_sim *sim)
|
||||
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->uim);
|
||||
if (data->poll_source > 0)
|
||||
g_source_remove(data->poll_source);
|
||||
|
||||
qmi_service_unref(data->uim);
|
||||
if (data->uim) {
|
||||
qmi_service_unregister_all(data->uim);
|
||||
qmi_service_unref(data->uim);
|
||||
data->uim = NULL;
|
||||
}
|
||||
if (data->dms) {
|
||||
qmi_service_unregister_all(data->dms);
|
||||
qmi_service_unref(data->dms);
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
@@ -516,8 +895,13 @@ static struct ofono_sim_driver driver = {
|
||||
.read_file_transparent = qmi_read_transparent,
|
||||
.read_file_linear = qmi_read_record,
|
||||
.read_file_cyclic = qmi_read_record,
|
||||
.write_file_transparent = qmi_write_transparent,
|
||||
.write_file_linear = qmi_write_linear,
|
||||
.write_file_cyclic = qmi_write_cyclic,
|
||||
.read_imsi = qmi_read_imsi,
|
||||
.query_passwd_state = qmi_query_passwd_state,
|
||||
.query_pin_retries = qmi_query_pin_retries,
|
||||
.send_passwd = qmi_pin_send,
|
||||
};
|
||||
|
||||
void qmi_sim_init(void)
|
||||
|
||||
@@ -277,7 +277,7 @@ static void qmi_bearer_query(struct ofono_sms *sms,
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->major < 1 && data->minor < 2)
|
||||
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||
goto error;
|
||||
|
||||
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
|
||||
@@ -315,7 +315,7 @@ static void qmi_bearer_set(struct ofono_sms *sms, int bearer,
|
||||
|
||||
DBG("bearer %d", bearer);
|
||||
|
||||
if (data->major < 1 && data->minor < 2)
|
||||
if (data->major < 1 || (data->major == 1 && data->minor < 2))
|
||||
goto error;
|
||||
|
||||
domain = bearer_to_domain(bearer);
|
||||
@@ -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->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
|
||||
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
|
||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NV;
|
||||
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NONE;
|
||||
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
|
||||
|
||||
param = qmi_param_new();
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
|
||||
#define QMI_UIM_GET_FILE_ATTRIBUTES 36 /* Get file attributes */
|
||||
|
||||
#define QMI_UIM_VERIFY_PIN 38 /* Verify PIN */
|
||||
|
||||
#define QMI_UIM_EVENT_REGISTRATION 46 /* Register for indications */
|
||||
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
|
||||
|
||||
@@ -91,3 +93,12 @@ struct qmi_uim_file_attributes {
|
||||
uint16_t raw_len;
|
||||
uint8_t raw_value[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Verify PIN parameter */
|
||||
#define QMI_UIM_PARAM_MESSAGE_SESSION_INFO 0x01
|
||||
#define QMI_UIM_PARAM_MESSAGE_INFO 0x02
|
||||
struct qmi_uim_param_message_info {
|
||||
uint8_t pin_id;
|
||||
uint8_t length;
|
||||
uint8_t pin_value[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
25
ofono/drivers/qmimodem/wda.h
Normal file
25
ofono/drivers/qmimodem/wda.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Kerlink SA. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define QMI_WDA_SET_DATA_FORMAT 32 /* Set data format */
|
||||
#define QMI_WDA_GET_DATA_FORMAT 33 /* Get data format */
|
||||
|
||||
/* Get and set data format interface */
|
||||
#define QMI_WDA_LL_PROTOCOL 0x11 /* uint32_t */
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_UNKNOWN 0
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_802_3 1
|
||||
#define QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP 2
|
||||
@@ -30,6 +30,13 @@
|
||||
/* Start WDS network interface */
|
||||
#define QMI_WDS_PARAM_APN 0x14 /* string */
|
||||
#define QMI_WDS_PARAM_IP_FAMILY 0x19 /* uint8 */
|
||||
#define QMI_WDS_PARAM_USERNAME 0x17 /* string */
|
||||
#define QMI_WDS_PARAM_PASSWORD 0x18 /* string */
|
||||
#define QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE 0x16 /* uint8 */
|
||||
|
||||
#define QMI_WDS_AUTHENTICATION_NONE 0x0
|
||||
#define QMI_WDS_AUTHENTICATION_PAP 0x1
|
||||
#define QMI_WDS_AUTHENTICATION_CHAP 0x2
|
||||
|
||||
#define QMI_WDS_RESULT_PKT_HANDLE 0x01 /* uint32 */
|
||||
|
||||
@@ -51,10 +58,12 @@ struct qmi_wds_notify_conn_status {
|
||||
|
||||
/* Get the runtime data session settings */
|
||||
#define QMI_WDS_RESULT_PDP_TYPE 0x11 /* uint8 */
|
||||
#define QMI_WDS_RESULT_APN 0x14 /* string */
|
||||
#define QMI_WDS_RESULT_PRIMARY_DNS 0x15 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_GATEWAY 0x20 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_GATEWAY_NETMASK 0x21 /* uint32 IPv4 */
|
||||
#define QMI_WDS_RESULT_IP_FAMILY 0x2b /* uint8 */
|
||||
|
||||
#define QMI_WDS_PDP_TYPE_IPV4 0x00
|
||||
|
||||
@@ -62,6 +62,7 @@ struct qmi_wms_param_message {
|
||||
#define QMI_WMS_STORAGE_TYPE_UIM 0
|
||||
#define QMI_WMS_STORAGE_TYPE_NV 1
|
||||
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
|
||||
#define QMI_WMS_STORAGE_TYPE_NONE 255
|
||||
|
||||
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
|
||||
|
||||
|
||||
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:
|
||||
*/
|
||||
346
ofono/drivers/ril/ril_constants.h
Normal file
346
ofono/drivers/ril/ril_constants.h
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-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_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
|
||||
};
|
||||
|
||||
/* 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:
|
||||
*/
|
||||
1799
ofono/drivers/ril/ril_data.c
Normal file
1799
ofono/drivers/ril/ril_data.c
Normal file
File diff suppressed because it is too large
Load Diff
149
ofono/drivers/ril/ril_data.h
Normal file
149
ofono/drivers/ril/ril_data.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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_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_hook *vendor_hook);
|
||||
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);
|
||||
|
||||
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto);
|
||||
int ril_data_protocol_to_ofono(const gchar *str);
|
||||
|
||||
/* Constructors of various kinds of RIL requests */
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||
|
||||
#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:
|
||||
*/
|
||||
602
ofono/drivers/ril/ril_gprs_context.c
Normal file
602
ofono/drivers/ril/ril_gprs_context.c
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* 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) {
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
|
||||
gpointer cb_data = gcd->deactivate.data;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
GASSERT(gcd->active_call);
|
||||
ril_error_init_ok(&error);
|
||||
ofono_info("Deactivated data call");
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
ofono_error("Deactivate failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
if (cb) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(&error, cb_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure we are in the disconnected state */
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
unsigned int id, ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
gcd->deactivate.cb = cb;
|
||||
gcd->deactivate.data = data;
|
||||
gcd->deactivate.req = ril_data_call_deactivate(gcd->data,
|
||||
gcd->active_call->cid,
|
||||
ril_gprs_context_deactivate_primary_cb, gcd);
|
||||
} else if (cb) {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int id)
|
||||
{
|
||||
DBG("%u", id);
|
||||
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||
}
|
||||
|
||||
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_gprs_context *gcd = g_new0(struct ril_gprs_context, 1);
|
||||
|
||||
DBG("");
|
||||
gcd->gc = gc;
|
||||
gcd->modem = modem;
|
||||
gcd->network = ril_network_ref(modem->network);
|
||||
gcd->data = ril_data_ref(modem->data);
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
if (gcd->activate.req) {
|
||||
/*
|
||||
* The core has already completed its pending D-Bus
|
||||
* request, invoking the completion callback will
|
||||
* cause libdbus to panic.
|
||||
*/
|
||||
ril_data_request_detach(gcd->activate.req);
|
||||
ril_data_request_cancel(gcd->activate.req);
|
||||
}
|
||||
|
||||
if (gcd->deactivate.req) {
|
||||
/* Let it complete but we won't be around to be notified. */
|
||||
ril_data_request_detach(gcd->deactivate.req);
|
||||
} else if (gcd->active_call) {
|
||||
ril_data_call_deactivate(gcd->data, gcd->active_call->cid,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
ril_data_unref(gcd->data);
|
||||
ril_network_unref(gcd->network);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
mtu_watch_free(gcd->mtu_watch);
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
const struct ofono_gprs_context_driver ril_gprs_context_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_gprs_context_probe,
|
||||
.remove = ril_gprs_context_remove,
|
||||
.activate_primary = ril_gprs_context_activate_primary,
|
||||
.deactivate_primary = ril_gprs_context_deactivate_primary,
|
||||
.detach_shutdown = ril_gprs_context_detach_shutdown,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
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:
|
||||
*/
|
||||
518
ofono/drivers/ril/ril_modem.c
Normal file
518
ofono/drivers/ril/ril_modem.c
Normal file
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
* 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_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#define MAX_PDP_CONTEXTS (2)
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
enum ril_modem_power_state {
|
||||
POWERED_OFF,
|
||||
POWERED_ON,
|
||||
POWERING_OFF
|
||||
};
|
||||
|
||||
enum ril_modem_online_state {
|
||||
OFFLINE,
|
||||
GOING_ONLINE,
|
||||
ONLINE,
|
||||
GOING_OFFLINE
|
||||
};
|
||||
|
||||
struct ril_modem_online_request {
|
||||
ofono_modem_online_cb_t cb;
|
||||
struct ril_modem_data *md;
|
||||
void *data;
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
struct sailfish_watch *watch;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gulong imsi_event_id;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
gulong radio_state_event_id;
|
||||
|
||||
struct ril_modem_online_request set_online;
|
||||
struct ril_modem_online_request set_offline;
|
||||
};
|
||||
|
||||
#define RADIO_POWER_TAG(md) (md)
|
||||
|
||||
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
|
||||
|
||||
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||
{
|
||||
struct ril_modem_data *md = ofono_modem_get_data(o);
|
||||
GASSERT(md->modem.ofono == o);
|
||||
return md;
|
||||
}
|
||||
|
||||
static void *ril_modem_get_atom_data(struct ril_modem *modem,
|
||||
enum ofono_atom_type type)
|
||||
{
|
||||
if (modem && modem->ofono) {
|
||||
struct ofono_atom *atom =
|
||||
__ofono_modem_find_atom(modem->ofono, type);
|
||||
|
||||
if (atom) {
|
||||
return __ofono_atom_get_data(atom);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
|
||||
}
|
||||
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
|
||||
}
|
||||
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
|
||||
}
|
||||
|
||||
static inline struct ofono_radio_settings *ril_modem_radio_settings(
|
||||
struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
|
||||
}
|
||||
|
||||
void ril_modem_delete(struct ril_modem *md)
|
||||
{
|
||||
if (md && md->ofono) {
|
||||
ofono_modem_remove(md->ofono);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
req->timeout_id = 0;
|
||||
}
|
||||
|
||||
if (req->cb) {
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *data = req->data;
|
||||
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||
{
|
||||
switch (md->modem.radio->state) {
|
||||
case RADIO_STATE_ON:
|
||||
DBG("online");
|
||||
ril_modem_online_request_ok(&md->set_online);
|
||||
break;
|
||||
|
||||
case RADIO_STATE_OFF:
|
||||
case RADIO_STATE_UNAVAILABLE:
|
||||
DBG("offline");
|
||||
ril_modem_online_request_ok(&md->set_offline);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
|
||||
md->power_state == POWERING_OFF) {
|
||||
md->power_state = POWERED_OFF;
|
||||
if (md->modem.ofono) {
|
||||
ofono_modem_set_powered(md->modem.ofono, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_request_timeout(gpointer data)
|
||||
{
|
||||
struct ril_modem_online_request *req = data;
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *cb_data = req->data;
|
||||
|
||||
GASSERT(req->timeout_id);
|
||||
GASSERT(cb);
|
||||
|
||||
req->timeout_id = 0;
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_failure(&error), cb_data);
|
||||
ril_modem_update_online_state(req->md);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_check(gpointer data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->online_check_id);
|
||||
md->online_check_id = 0;
|
||||
ril_modem_update_online_state(md);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
{
|
||||
if (!md->online_check_id) {
|
||||
md->online_check_id = g_idle_add(ril_modem_online_check, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
struct ril_modem *m = &md->modem;
|
||||
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!ril_modem_radio_settings(m)) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
ofono_radio_settings_create(m->ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
} else {
|
||||
/* ofono core may remove radio settings atom internally */
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.radio == radio);
|
||||
ril_modem_update_radio_settings(md);
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
ril_modem_update_radio_settings(md);
|
||||
}
|
||||
|
||||
static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (md->modem.config.enable_voicecall) {
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
if (!md->radio_state_event_id) {
|
||||
md->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||
ril_modem_radio_state_cb, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (gprs) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
|
||||
struct ofono_gprs_context *gc =
|
||||
ofono_gprs_context_create(modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
if (gc == NULL)
|
||||
break;
|
||||
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
}
|
||||
|
||||
ofono_phonebook_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||
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);
|
||||
|
||||
sailfish_watch_remove_handler(md->watch, md->imsi_event_id);
|
||||
sailfish_watch_unref(md->watch);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
}
|
||||
|
||||
if (md->set_online.timeout_id) {
|
||||
g_source_remove(md->set_online.timeout_id);
|
||||
}
|
||||
|
||||
if (md->set_offline.timeout_id) {
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_data_unref(modem->data);
|
||||
sailfish_cell_info_unref(modem->cell_info);
|
||||
grilio_channel_unref(modem->io);
|
||||
grilio_queue_cancel_all(md->q, FALSE);
|
||||
grilio_queue_unref(md->q);
|
||||
g_free(md->ecclist_file);
|
||||
g_free(md->log_prefix);
|
||||
g_free(md->imeisv);
|
||||
g_free(md->imei);
|
||||
g_free(md);
|
||||
}
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
struct ofono_modem *ofono = ofono_modem_create(path + 1,
|
||||
RILMODEM_DRIVER);
|
||||
if (ofono) {
|
||||
int err;
|
||||
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
/*
|
||||
* ril_plugin.c must wait until IMEI becomes known before
|
||||
* creating the modem
|
||||
*/
|
||||
GASSERT(imei);
|
||||
|
||||
/* Copy config */
|
||||
modem->config = *config;
|
||||
modem->imei = md->imei = g_strdup(imei);
|
||||
modem->imeisv = md->imeisv = g_strdup(imeisv);
|
||||
modem->log_prefix = log_prefix; /* No need to strdup */
|
||||
modem->ecclist_file = ecclist_file; /* No need to strdup */
|
||||
md->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
modem->ofono = ofono;
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
modem->sim_settings = ril_sim_settings_ref(settings);
|
||||
modem->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
md->watch = sailfish_watch_new(path);
|
||||
|
||||
md->imsi_event_id =
|
||||
sailfish_watch_add_imsi_changed_handler(md->watch,
|
||||
ril_modem_imsi_cb, md);
|
||||
|
||||
md->set_online.md = md;
|
||||
md->set_offline.md = md;
|
||||
ofono_modem_set_data(ofono, md);
|
||||
err = ofono_modem_register(ofono);
|
||||
if (!err) {
|
||||
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:
|
||||
*/
|
||||
580
ofono/drivers/ril/ril_netreg.c
Normal file
580
ofono/drivers/ril/ril_netreg.c
Normal file
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
* 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_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "simutil.h"
|
||||
|
||||
enum ril_netreg_events {
|
||||
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||
NETREG_RIL_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_netreg_network_events {
|
||||
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
|
||||
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
|
||||
NETREG_NETWORK_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_netreg *netreg;
|
||||
struct ril_network *network;
|
||||
char *log_prefix;
|
||||
guint timer_id;
|
||||
guint notify_id;
|
||||
guint current_operator_id;
|
||||
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
|
||||
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
|
||||
};
|
||||
|
||||
struct ril_netreg_cbd {
|
||||
struct ril_netreg *nd;
|
||||
union {
|
||||
ofono_netreg_status_cb_t status;
|
||||
ofono_netreg_operator_cb_t operator;
|
||||
ofono_netreg_operator_list_cb_t operator_list;
|
||||
ofono_netreg_register_cb_t reg;
|
||||
ofono_netreg_strength_cb_t strength;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_netreg_cbd_free g_free
|
||||
|
||||
#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);
|
||||
|
||||
ofono_info("nw select automatic");
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
const char *mcc, const char *mnc,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("nw select manual: %s%s", mcc, mnc);
|
||||
grilio_request_append_format(req, "%s%s+0", mcc, mnc);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||
int rsrp = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* RIL_SignalStrength_v6 */
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &gw_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &cdma_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &evdo_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, <e_signal);
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
/* The rest is ignored */
|
||||
|
||||
if (rsrp == INT_MAX) {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal,
|
||||
cdma_dbm, evdo_dbm, lte_signal);
|
||||
} else {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d", gw_signal,
|
||||
cdma_dbm, evdo_dbm, lte_signal, rsrp);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
|
||||
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
return 140 - 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);
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
*/
|
||||
984
ofono/drivers/ril/ril_network.c
Normal file
984
ofono/drivers/ril/ril_network.c
Normal file
@@ -0,0 +1,984 @@
|
||||
/*
|
||||
* 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_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SET_PREF_MODE_HOLDOFF_SEC RIL_RETRY_SECS
|
||||
|
||||
typedef GObjectClass RilNetworkClass;
|
||||
typedef struct ril_network RilNetwork;
|
||||
|
||||
enum ril_network_timer {
|
||||
TIMER_SET_RAT_HOLDOFF,
|
||||
TIMER_FORCE_CHECK_PREF_MODE,
|
||||
TIMER_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_radio_event {
|
||||
RADIO_EVENT_STATE_CHANGED,
|
||||
RADIO_EVENT_ONLINE_CHANGED,
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_sim_events {
|
||||
SIM_EVENT_STATUS_CHANGED,
|
||||
SIM_EVENT_IO_ACTIVE_CHANGED,
|
||||
SIM_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_unsol_event {
|
||||
UNSOL_EVENT_NETWORK_STATE,
|
||||
UNSOL_EVENT_RADIO_CAPABILITY,
|
||||
UNSOL_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *simcard;
|
||||
int rat;
|
||||
int lte_network_mode;
|
||||
int network_mode_timeout;
|
||||
char *log_prefix;
|
||||
guint operator_poll_id;
|
||||
guint voice_poll_id;
|
||||
guint data_poll_id;
|
||||
guint timer[TIMER_COUNT];
|
||||
gulong query_rat_id;
|
||||
gulong set_rat_id;
|
||||
gulong unsol_event_id[UNSOL_EVENT_COUNT];
|
||||
gulong settings_event_id;
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
gulong simcard_event_id[SIM_EVENT_COUNT];
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
};
|
||||
|
||||
enum ril_network_signal {
|
||||
SIGNAL_OPERATOR_CHANGED,
|
||||
SIGNAL_VOICE_STATE_CHANGED,
|
||||
SIGNAL_DATA_STATE_CHANGED,
|
||||
SIGNAL_PREF_MODE_CHANGED,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
|
||||
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
|
||||
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
|
||||
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
|
||||
#define SIGNAL_MAX_PREF_MODE_CHANGED_NAME "ril-network-max-pref-mode-changed"
|
||||
|
||||
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilNetwork, ril_network, G_TYPE_OBJECT)
|
||||
#define RIL_NETWORK_TYPE (ril_network_get_type())
|
||||
#define RIL_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,\
|
||||
RIL_NETWORK_TYPE,RilNetwork))
|
||||
|
||||
#define RIL_NETWORK_SIGNAL(klass,name) \
|
||||
ril_network_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
/* Some assumptions: */
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_ANY == 0);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_GSM > OFONO_RADIO_ACCESS_MODE_ANY);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self);
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean immediate);
|
||||
|
||||
static void ril_network_emit(struct ril_network *self,
|
||||
enum ril_network_signal sig)
|
||||
{
|
||||
g_signal_emit(self, ril_network_signals[sig], 0);
|
||||
}
|
||||
|
||||
static void ril_network_stop_timer(struct ril_network *self,
|
||||
enum ril_network_timer tid)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->timer[tid]) {
|
||||
g_source_remove(priv->timer[tid]);
|
||||
priv->timer[tid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_reset_state(struct ril_registration_state *reg)
|
||||
{
|
||||
memset(reg, 0, sizeof(*reg));
|
||||
reg->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
reg->access_tech = -1;
|
||||
reg->ril_tech = -1;
|
||||
reg->lac = -1;
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
const void *data, guint len, struct ril_registration_state *reg)
|
||||
{
|
||||
int nparams, ril_status;
|
||||
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
|
||||
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
ril_network_reset_state(reg);
|
||||
|
||||
/* Size of response string array. The minimum seen in the wild is 3 */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (!grilio_parser_get_int32(&rilp, &nparams) || nparams < 3) {
|
||||
DBG_(self, "broken response");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sstatus = grilio_parser_get_utf8(&rilp); /* response[0] */
|
||||
if (!sstatus) {
|
||||
DBG_(self, "No sstatus value returned!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
slac = grilio_parser_get_utf8(&rilp); /* response[1] */
|
||||
sci = grilio_parser_get_utf8(&rilp); /* response[2] */
|
||||
|
||||
if (nparams > 3) {
|
||||
stech = grilio_parser_get_utf8(&rilp); /* response[3] */
|
||||
}
|
||||
|
||||
ril_status = atoi(sstatus);
|
||||
if (ril_status > 10) {
|
||||
reg->status = ril_status - 10;
|
||||
} else {
|
||||
reg->status = ril_status;
|
||||
}
|
||||
|
||||
/* FIXME: need to review VOICE_REGISTRATION response
|
||||
* as it returns up to 15 parameters ( vs. 6 for DATA ).
|
||||
*
|
||||
* The first four parameters are the same for both
|
||||
* responses ( although status includes values for
|
||||
* emergency calls for VOICE response ).
|
||||
*
|
||||
* Parameters 5 & 6 have different meanings for
|
||||
* voice & data response.
|
||||
*/
|
||||
if (nparams > 4) {
|
||||
/* TODO: different use for CDMA */
|
||||
sreason = grilio_parser_get_utf8(&rilp); /* response[4] */
|
||||
if (nparams > 5) {
|
||||
/* TODO: different use for CDMA */
|
||||
smax = grilio_parser_get_utf8(&rilp); /* response[5] */
|
||||
if (smax) {
|
||||
reg->max_calls = atoi(smax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some older RILs don't provide max calls, in that case let's
|
||||
* supply some reasonable default. We don't need more than 2
|
||||
* simultaneous data calls anyway.
|
||||
*/
|
||||
if (reg->max_calls < 1) {
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
if (!gutil_parse_int(slac, 16, ®->lac)) {
|
||||
reg->lac = -1;
|
||||
}
|
||||
|
||||
if (!gutil_parse_int(sci, 16, ®->ci)) {
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
||||
registration_status_to_string(reg->status),
|
||||
slac, sci, reg->ril_tech,
|
||||
registration_tech_to_string(reg->access_tech),
|
||||
sreason, smax);
|
||||
|
||||
g_free(sstatus);
|
||||
g_free(slac);
|
||||
g_free(sci);
|
||||
g_free(stech);
|
||||
g_free(sreason);
|
||||
g_free(smax);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ril_network_op_copy(struct ofono_network_operator *dest,
|
||||
const struct ofono_network_operator *src)
|
||||
{
|
||||
strncpy(dest->mcc, src->mcc, sizeof(dest->mcc));
|
||||
strncpy(dest->mnc, src->mnc, sizeof(dest->mnc));
|
||||
strncpy(dest->name, src->name, sizeof(dest->name));
|
||||
dest->mcc[sizeof(dest->mcc)-1] = 0;
|
||||
dest->mnc[sizeof(dest->mnc)-1] = 0;
|
||||
dest->name[sizeof(dest->name)-1] = 0;
|
||||
dest->status = src->status;
|
||||
dest->tech = src->tech;
|
||||
}
|
||||
|
||||
static gboolean ril_network_op_equal(const struct ofono_network_operator *op1,
|
||||
const struct ofono_network_operator *op2)
|
||||
{
|
||||
if (op1 == op2) {
|
||||
return TRUE;
|
||||
} else if (!op1 || !op2) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return op1->status == op2->status &&
|
||||
op1->tech == op2->tech &&
|
||||
!strncmp(op1->mcc, op2->mcc, sizeof(op2->mcc)) &&
|
||||
!strncmp(op1->mnc, op2->mnc, sizeof(op2->mnc)) &&
|
||||
!strncmp(op1->name, op2->name, sizeof(op2->name));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->operator_poll_id);
|
||||
priv->operator_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ofono_network_operator op;
|
||||
gboolean changed = FALSE;
|
||||
gchar *lalpha;
|
||||
char *salpha;
|
||||
char *numeric;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
lalpha = grilio_parser_get_utf8(&rilp);
|
||||
salpha = grilio_parser_get_utf8(&rilp);
|
||||
numeric = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
op.tech = -1;
|
||||
if (ril_parse_mcc_mnc(numeric, &op)) {
|
||||
if (op.tech < 0) op.tech = self->voice.access_tech;
|
||||
op.status = OPERATOR_STATUS_CURRENT;
|
||||
op.name[0] = 0;
|
||||
if (lalpha) {
|
||||
strncpy(op.name, lalpha, sizeof(op.name));
|
||||
} else if (salpha) {
|
||||
strncpy(op.name, salpha, sizeof(op.name));
|
||||
} else {
|
||||
strncpy(op.name, numeric, sizeof(op.name));
|
||||
}
|
||||
op.name[sizeof(op.name)-1] = 0;
|
||||
if (!self->operator) {
|
||||
self->operator = &priv->operator;
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
} else if (!ril_network_op_equal(&op, &priv->operator)) {
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
}
|
||||
} else if (self->operator) {
|
||||
self->operator = NULL;
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (self->operator) {
|
||||
DBG_(self, "lalpha=%s, salpha=%s, numeric=%s, "
|
||||
"%s, mcc=%s, mnc=%s, %s",
|
||||
lalpha, salpha, numeric,
|
||||
op.name, op.mcc, op.mnc,
|
||||
registration_tech_to_string(op.tech));
|
||||
} else {
|
||||
DBG_(self, "no operator");
|
||||
}
|
||||
ril_network_emit(self, SIGNAL_OPERATOR_CHANGED);
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_voice_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->voice_poll_id);
|
||||
priv->voice_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->voice, sizeof(state))) {
|
||||
DBG_(self, "voice registration changed");
|
||||
self->voice = state;
|
||||
ril_network_emit(self, SIGNAL_VOICE_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->data_poll_id);
|
||||
priv->data_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->data, sizeof(state))) {
|
||||
DBG_(self, "data registration changed");
|
||||
self->data = state;
|
||||
ril_network_emit(self, SIGNAL_DATA_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
|
||||
int code, GRilIoChannelResponseFunc fn)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, id);
|
||||
} else {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
id = grilio_queue_send_request_full(priv->q, req, code, fn,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_network_poll_state(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
||||
ril_network_poll_operator_cb);
|
||||
|
||||
ril_network_query_registration_state(self);
|
||||
}
|
||||
|
||||
void ril_network_query_registration_state(struct ril_network *self)
|
||||
{
|
||||
if (self) {
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->voice_poll_id,
|
||||
RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||
ril_network_poll_voice_state_cb);
|
||||
priv->data_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->data_poll_id,
|
||||
RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_network_poll_data_state_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case PREF_NET_TYPE_LTE_CDMA_EVDO:
|
||||
case PREF_NET_TYPE_LTE_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_LTE_ONLY:
|
||||
case PREF_NET_TYPE_LTE_WCDMA:
|
||||
return OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
case PREF_NET_TYPE_GSM_WCDMA_AUTO:
|
||||
case PREF_NET_TYPE_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA:
|
||||
return OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
default:
|
||||
DBG("unexpected rat mode %d", rat);
|
||||
case PREF_NET_TYPE_GSM_ONLY:
|
||||
return OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
return self->priv->lte_network_mode;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
|
||||
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
}
|
||||
/* no break */
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
return PREF_NET_TYPE_GSM_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_pref_mode_expected(struct ril_network *self)
|
||||
{
|
||||
struct ril_sim_settings *settings = self->settings;
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* On dual-SIM phones such as Jolla C only one slot at a time
|
||||
* is allowed to use LTE. Even if the slot which has been using
|
||||
* LTE gets powered off, we still need to explicitely set its
|
||||
* preferred mode to GSM, to make LTE machinery available to
|
||||
* the other slot. This sort of behaviour might not be necessary
|
||||
* on some hardware and can (should) be made configurable when
|
||||
* it becomes necessary.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
|
||||
/*
|
||||
* OFONO_RADIO_ACCESS_MODE_ANY is zero. If both pref_mode
|
||||
* and max_pref_mode are not ANY, we pick the smallest value.
|
||||
* Otherwise we take any non-zero value if there is one.
|
||||
*/
|
||||
const enum ofono_radio_access_mode pref_mode =
|
||||
(settings->pref_mode && max_pref_mode) ?
|
||||
MIN(settings->pref_mode, max_pref_mode) :
|
||||
settings->pref_mode ? settings->pref_mode :
|
||||
max_pref_mode;
|
||||
return ril_network_mode_to_rat(self, pref_mode);
|
||||
}
|
||||
|
||||
static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* With some modems an attempt to set rat significantly slows
|
||||
* down SIM I/O, let's avoid that.
|
||||
*/
|
||||
return priv->radio->online && ril_sim_card_ready(priv->simcard) &&
|
||||
!priv->simcard->sim_io_active &&
|
||||
!priv->timer[TIMER_SET_RAT_HOLDOFF] ;
|
||||
}
|
||||
|
||||
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_set_rat_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->set_rat_id);
|
||||
priv->set_rat_id = 0;
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("failed to set rat mode");
|
||||
}
|
||||
|
||||
ril_network_query_pref_mode(self);
|
||||
}
|
||||
|
||||
static void ril_network_set_rat(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (!priv->set_rat_id && priv->radio->online &&
|
||||
ril_sim_card_ready(priv->simcard) &&
|
||||
/*
|
||||
* With some modems an attempt to set rat significantly
|
||||
* slows down SIM I/O, let's avoid that.
|
||||
*/
|
||||
!priv->simcard->sim_io_active &&
|
||||
!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG_(self, "setting rat mode %d", rat);
|
||||
grilio_request_append_int32(req, 1); /* count */
|
||||
grilio_request_append_int32(req, rat);
|
||||
|
||||
grilio_request_set_timeout(req, priv->network_mode_timeout);
|
||||
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_set_rat_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* And don't do it too often */
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
|
||||
ril_network_set_rat_holdoff_cb, self);
|
||||
} else {
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
ril_network_set_rat(self, rat);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
immediate = TRUE;
|
||||
}
|
||||
|
||||
if (priv->rat != rat) {
|
||||
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_parse_pref_resp(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int pref = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &pref);
|
||||
return pref;
|
||||
}
|
||||
|
||||
static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
|
||||
int status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike ril_network_query_pref_mode_cb, this one always
|
||||
* checks the preferred mode.
|
||||
*/
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
/* This request never fails because in case of error it gets retried */
|
||||
GASSERT(status == RIL_E_SUCCESS);
|
||||
GASSERT(priv->query_rat_id);
|
||||
|
||||
priv->query_rat_id = 0;
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE);
|
||||
priv->query_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_query_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
void ril_network_set_max_pref_mode(struct ril_network *self,
|
||||
enum ofono_radio_access_mode max_mode,
|
||||
gboolean force_check)
|
||||
{
|
||||
if (self && (self->max_pref_mode != max_mode || force_check)) {
|
||||
if (self->max_pref_mode != max_mode) {
|
||||
DBG_(self, "rat mode %d (%s)", max_mode,
|
||||
ofono_radio_access_mode_to_string(max_mode));
|
||||
self->max_pref_mode = max_mode;
|
||||
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
|
||||
}
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
priv->assert_rat = TRUE;
|
||||
ril_network_check_pref_mode(self, immediate);
|
||||
}
|
||||
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_OPERATOR_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_VOICE_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_data_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_DATA_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_network_remove_handler(struct ril_network *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, n);
|
||||
}
|
||||
|
||||
static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
|
||||
guint code, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
|
||||
ril_network_assert_pref_mode(self, FALSE);
|
||||
}
|
||||
|
||||
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_radio_online_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_network_check_pref_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->timer[TIMER_FORCE_CHECK_PREF_MODE]);
|
||||
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] = 0;
|
||||
|
||||
DBG_(self, "checking pref mode");
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_pref_mode_changed_cb(struct ril_sim_settings *settings,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* Postpone ril_network_check_pref_mode because other pref_mode
|
||||
* listeners (namely, ril_data) may want to tweak max_pref_mode
|
||||
*/
|
||||
if (!priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
DBG_(self, "scheduling pref mode check");
|
||||
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] =
|
||||
g_idle_add(ril_network_check_pref_mode_cb, self);
|
||||
} else {
|
||||
DBG_(self, "pref mode check already scheduled");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *simcard,
|
||||
struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
self->settings = ril_sim_settings_ref(settings);
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->simcard = ril_sim_card_ref(simcard);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
|
||||
/* Copy relevant config values */
|
||||
priv->lte_network_mode = config->lte_network_mode;
|
||||
priv->network_mode_timeout = config->network_mode_timeout;
|
||||
|
||||
/* Register listeners */
|
||||
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_state_changed_cb,
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
|
||||
priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_radio_capability_changed_cb,
|
||||
RIL_UNSOL_RADIO_CAPABILITY, self);
|
||||
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
|
||||
ril_radio_add_state_changed_handler(priv->radio,
|
||||
ril_network_radio_state_cb, self);
|
||||
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
|
||||
ril_radio_add_online_changed_handler(priv->radio,
|
||||
ril_network_radio_online_cb, self);
|
||||
priv->simcard_event_id[SIM_EVENT_STATUS_CHANGED] =
|
||||
ril_sim_card_add_status_changed_handler(priv->simcard,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
priv->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
|
||||
ril_sim_card_add_sim_io_active_changed_handler(priv->simcard,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
priv->settings_event_id =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(settings,
|
||||
ril_network_pref_mode_changed_cb, self);
|
||||
|
||||
/*
|
||||
* Query the initial state. Querying network state before the radio
|
||||
* has been turned on makes RIL unhappy.
|
||||
*/
|
||||
grilio_queue_send_request_full(priv->q, NULL,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_startup_query_pref_mode_cb, NULL, self);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_ref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_NETWORK(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_unref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_NETWORK(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_init(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_NETWORK_TYPE, struct ril_network_priv);
|
||||
|
||||
self->priv = priv;
|
||||
ril_network_reset_state(&self->voice);
|
||||
ril_network_reset_state(&self->data);
|
||||
priv->rat = -1;
|
||||
}
|
||||
|
||||
static void ril_network_finalize(GObject *object)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
enum ril_network_timer tid;
|
||||
|
||||
DBG_(self, "");
|
||||
|
||||
for (tid=0; tid<TIMER_COUNT; tid++) {
|
||||
ril_network_stop_timer(self, tid);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->unsol_event_id);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id);
|
||||
ril_sim_card_unref(priv->simcard);
|
||||
ril_sim_settings_remove_handler(self->settings,
|
||||
priv->settings_event_id);
|
||||
ril_sim_settings_unref(self->settings);
|
||||
g_free(priv->log_prefix);
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_network_class_init(RilNetworkClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_network_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_network_priv));
|
||||
RIL_NETWORK_SIGNAL(klass, OPERATOR);
|
||||
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
|
||||
RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
85
ofono/drivers/ril/ril_network.h
Normal file
85
ofono/drivers/ril/ril_network.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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_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_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
2218
ofono/drivers/ril/ril_plugin.c
Normal file
2218
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:
|
||||
*/
|
||||
492
ofono/drivers/ril/ril_radio.c
Normal file
492
ofono/drivers/ril/ril_radio.c
Normal file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
typedef GObjectClass RilRadioClass;
|
||||
typedef struct ril_radio RilRadio;
|
||||
|
||||
/*
|
||||
* Object states:
|
||||
*
|
||||
* 1. Idle (!pending && !retry)
|
||||
* 2. Power on/off request pending (pending)
|
||||
* 3. Power on retry has been scheduled (retry)
|
||||
*/
|
||||
struct ril_radio_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gulong state_event_id;
|
||||
char *log_prefix;
|
||||
GHashTable *req_table;
|
||||
guint pending_id;
|
||||
guint retry_id;
|
||||
guint state_changed_while_request_pending;
|
||||
enum ril_radio_state last_known_state;
|
||||
gboolean power_cycle;
|
||||
gboolean next_state_valid;
|
||||
gboolean next_state;
|
||||
};
|
||||
|
||||
enum ril_radio_signal {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_ONLINE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define POWER_RETRY_SECS (1)
|
||||
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
|
||||
#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
|
||||
|
||||
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_radio_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
|
||||
#define RIL_RADIO_TYPE (ril_radio_get_type())
|
||||
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
|
||||
|
||||
#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);
|
||||
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:
|
||||
*/
|
||||
1463
ofono/drivers/ril/ril_radio_caps.c
Normal file
1463
ofono/drivers/ril/ril_radio_caps.c
Normal file
File diff suppressed because it is too large
Load Diff
66
ofono/drivers/ril/ril_radio_caps.h
Normal file
66
ofono/drivers/ril/ril_radio_caps.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_RADIO_CAPS_H
|
||||
#define RIL_RADIO_CAPS_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_radio_caps;
|
||||
struct ril_radio_caps_manager;
|
||||
struct ril_radio_capability;
|
||||
|
||||
typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
|
||||
void *user_data);
|
||||
/* ril_radio_capability pointer is NULL if functionality is unsupported */
|
||||
typedef void (*ril_radio_caps_check_cb_t)
|
||||
(const struct ril_radio_capability *cap, void *user_data);
|
||||
|
||||
/* The check can be cancelled with grilio_channel_cancel_request */
|
||||
guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb_t cb,
|
||||
void *user_data);
|
||||
|
||||
/* There should be a single ril_radio_caps_manager shared by all all modems */
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_new
|
||||
(struct ril_data_manager *dm);
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
|
||||
(struct ril_radio_caps_manager *mgr);
|
||||
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
|
||||
gulong ril_radio_caps_manager_add_aborted_handler
|
||||
(struct ril_radio_caps_manager *mgr,
|
||||
ril_radio_caps_manager_cb_t cb, void *arg);
|
||||
void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
|
||||
gulong id);
|
||||
|
||||
/* And one ril_radio_caps object per modem */
|
||||
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
const char *log_prefix, GRilIoChannel *io,
|
||||
struct ril_data *data, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim, struct ril_network *net,
|
||||
const struct ril_slot_config *config,
|
||||
const struct ril_radio_capability *cap);
|
||||
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
|
||||
void ril_radio_caps_unref(struct ril_radio_caps *caps);
|
||||
|
||||
#endif /* RIL_RADIO_CAPS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
194
ofono/drivers/ril/ril_radio_settings.c
Normal file
194
ofono/drivers/ril/ril_radio_settings.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
struct ril_radio_settings {
|
||||
struct ofono_radio_settings *rs;
|
||||
struct ril_sim_settings *settings;
|
||||
const char *log_prefix;
|
||||
char *allocated_log_prefix;
|
||||
guint source_id;
|
||||
};
|
||||
|
||||
struct ril_radio_settings_cbd {
|
||||
struct ril_radio_settings *rsd;
|
||||
union _ofono_radio_settings_cb {
|
||||
ofono_radio_settings_rat_mode_set_cb_t rat_mode_set;
|
||||
ofono_radio_settings_rat_mode_query_cb_t rat_mode_query;
|
||||
ofono_radio_settings_available_rats_query_cb_t available_rats;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define DBG_(rsd,fmt,args...) DBG("%s" fmt, (rsd)->log_prefix, ##args)
|
||||
|
||||
static inline struct ril_radio_settings *ril_radio_settings_get_data(
|
||||
struct ofono_radio_settings *rs)
|
||||
{
|
||||
return ofono_radio_settings_get_data(rs);
|
||||
}
|
||||
|
||||
static void ril_radio_settings_later(struct ril_radio_settings *rsd,
|
||||
GSourceFunc fn, void *cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_radio_settings_cbd, 1);
|
||||
cbd->rsd = rsd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
|
||||
GASSERT(!rsd->source_id);
|
||||
rsd->source_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
fn, cbd, g_free);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_set_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_set(ril_error_ok(&error), cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
DBG_(rsd, "%s", ofono_radio_access_mode_to_string(mode));
|
||||
ril_sim_settings_set_pref_mode(rsd->settings, mode);
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_set_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
enum ofono_radio_access_mode mode = rsd->settings->pref_mode;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(rsd, "rat mode %s", ofono_radio_access_mode_to_string(mode));
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_query(ril_error_ok(&error), mode, cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_query_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rsd->settings->techs,
|
||||
cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_available_rats(
|
||||
struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd,
|
||||
ril_radio_settings_query_available_rats_cb, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = user_data;
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
ofono_radio_settings_register(rsd->rs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
|
||||
|
||||
DBG("%s", modem->log_prefix);
|
||||
rsd->rs = rs;
|
||||
rsd->settings = ril_sim_settings_ref(modem->sim_settings);
|
||||
rsd->source_id = g_idle_add(ril_radio_settings_register, rsd);
|
||||
|
||||
if (modem->log_prefix && modem->log_prefix[0]) {
|
||||
rsd->log_prefix = rsd->allocated_log_prefix =
|
||||
g_strconcat(modem->log_prefix, " ", NULL);
|
||||
} else {
|
||||
rsd->log_prefix = "";
|
||||
}
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
if (rsd->source_id) {
|
||||
g_source_remove(rsd->source_id);
|
||||
}
|
||||
ril_sim_settings_unref(rsd->settings);
|
||||
g_free(rsd->allocated_log_prefix);
|
||||
g_free(rsd);
|
||||
}
|
||||
|
||||
const struct ofono_radio_settings_driver ril_radio_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.query_rat_mode = ril_radio_settings_query_rat_mode,
|
||||
.set_rat_mode = ril_radio_settings_set_rat_mode,
|
||||
.query_available_rats = ril_radio_settings_query_available_rats
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
1551
ofono/drivers/ril/ril_sim.c
Normal file
1551
ofono/drivers/ril/ril_sim.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user