mirror of
https://github.com/sailfishos/ofono
synced 2025-11-25 03:49:44 +08:00
Compare commits
863 Commits
upgrade-2.
...
mer/1.20+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
30
ofono/.gitignore
vendored
30
ofono/.gitignore
vendored
@@ -42,6 +42,36 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-ril_util
|
||||
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-sms-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
|
||||
|
||||
@@ -104,3 +104,22 @@ 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>
|
||||
|
||||
@@ -1,3 +1,54 @@
|
||||
ver 1.20:
|
||||
Fix issue with context removal before activation.
|
||||
Fix issue with update during GPRS context activation.
|
||||
Fix issue with receiving UTF-16 encoded messages.
|
||||
Fix issue with invalid access in CBS decoding.
|
||||
Fix issue with signal strength on QMI modems.
|
||||
Fix issue with PIN handling with QMI modems.
|
||||
Fix issue with QMI notification message handling.
|
||||
Fix issue with facility lock query on SIM removal.
|
||||
Fix issue with parsing +CLCC and +CCWA fields.
|
||||
Add support for obtaining IMSI via EF reading.
|
||||
Add support for additional netmon info types.
|
||||
Add support for provisioning via configuration files.
|
||||
Add support for Gemalto P-family series of modems.
|
||||
Add support for Telit HE910 and UE910 variants.
|
||||
Add support for Intel SoFIA SIM Toolkit interfaces.
|
||||
Add support for Intel SoFIA LTE features.
|
||||
Add support for U-Blox TOBY-L2 LTE feature.
|
||||
Add support for dedicated LTE atom.
|
||||
|
||||
ver 1.19:
|
||||
Fix issue with DHCP parsing and Huawei modems.
|
||||
Fix issue with detecting Huawei E3372 modem.
|
||||
Fix issue with handling serving cell info.
|
||||
Fix issue with handling SIM SC facility lock.
|
||||
Fix issue with Android RIL PIN retry logic.
|
||||
Fix issue with Android RIL and RAT handling.
|
||||
Add support for Android RIL cell broadcast.
|
||||
Add support for SoFIA 3GR thermal management.
|
||||
|
||||
ver 1.18:
|
||||
Fix issue with cell broadcast and use-after-fee.
|
||||
Fix issue with repeated held call indicator.
|
||||
Fix issue with +CCWA and connection setup.
|
||||
Fix issue with empty operator scan results.
|
||||
Fix issue with persistent RAT mode handling.
|
||||
Fix issue with multiparty call introspection.
|
||||
Fix issue with GRPS context introspection.
|
||||
Fix issue with stale context deactivation.
|
||||
Add support for automatic context activation.
|
||||
Add support for SIM service provider names.
|
||||
Add support for handling allowed APN lists.
|
||||
Add support for network monitoring interface.
|
||||
Add support for U-Blox TOBY-L2 modem series.
|
||||
Add support for Sierra MC73xx QMI modems.
|
||||
Add support for SoFIA 3GR modem series.
|
||||
Add support for upower battery monitoring.
|
||||
Add support for gateway audio card types.
|
||||
Add support for Handsfree audio driver.
|
||||
Add support for Android RIL integration.
|
||||
|
||||
ver 1.17:
|
||||
Fix issue with alphanumeric TP-OA handling.
|
||||
Fix issue with push notification origin port.
|
||||
|
||||
@@ -113,3 +113,5 @@ doc/coding-style.txt.
|
||||
a feature that touches files under 'include/', 'src/' and 'drivers/'
|
||||
directories, split in three separated patches, taking care not to
|
||||
break compilation.
|
||||
|
||||
4) Submit patches using git send-email to ofono@ofono.org
|
||||
|
||||
@@ -21,12 +21,20 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/cdma-connman.h include/gnss.h \
|
||||
include/private-network.h include/cdma-netreg.h \
|
||||
include/cdma-provision.h include/handsfree.h \
|
||||
include/handsfree-audio.h \
|
||||
include/sim-mnclength.h \
|
||||
include/siri.h
|
||||
include/handsfree-audio.h include/siri.h \
|
||||
include/sms-filter.h \
|
||||
include/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 +105,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,15 +122,26 @@ 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 JOLLA_RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_forward.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_cell_info_dbus.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
@@ -134,21 +149,18 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
drivers/ril/ril_mce.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_mtu.c \
|
||||
drivers/ril/ril_netmon.c \
|
||||
drivers/ril/ril_netreg.c \
|
||||
drivers/ril/ril_network.c \
|
||||
drivers/ril/ril_oem_raw.c \
|
||||
drivers/ril/ril_phonebook.c \
|
||||
drivers/ril/ril_plugin.c \
|
||||
drivers/ril/ril_plugin_dbus.c \
|
||||
drivers/ril/ril_radio.c \
|
||||
drivers/ril/ril_radio_caps.c \
|
||||
drivers/ril/ril_radio_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_info.c \
|
||||
drivers/ril/ril_sim_info_dbus.c \
|
||||
drivers/ril/ril_sim_settings.c \
|
||||
drivers/ril/ril_sms.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
@@ -161,20 +173,29 @@ dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
builtin_modules += rildev
|
||||
builtin_sources += plugins/rildev.c
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += plugins/ril.c
|
||||
builtin_sources += plugins/ril.c plugins/ril.h
|
||||
|
||||
builtin_modules += infineon
|
||||
builtin_sources += plugins/infineon.c
|
||||
|
||||
builtin_modules += ril_intel
|
||||
builtin_sources += plugins/ril_intel.c
|
||||
|
||||
builtin_modules += rilmodem
|
||||
builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/vendor.h \
|
||||
drivers/rilmodem/rilmodem.c \
|
||||
drivers/rilmodem/devinfo.c \
|
||||
drivers/rilmodem/network-registration.c \
|
||||
drivers/rilmodem/voicecall.c \
|
||||
drivers/rilmodem/voicecall.h \
|
||||
drivers/rilmodem/call-volume.c \
|
||||
drivers/rilmodem/gprs.c \
|
||||
drivers/rilmodem/gprs-context.c \
|
||||
@@ -182,20 +203,16 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/sms.c \
|
||||
drivers/rilmodem/rilutil.c \
|
||||
drivers/rilmodem/rilutil.h \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/phonebook.c \
|
||||
drivers/rilmodem/ussd.c \
|
||||
drivers/rilmodem/call-settings.c \
|
||||
drivers/rilmodem/call-forwarding.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/rilmodem/oemraw-messages.c \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/call-barring.c \
|
||||
drivers/rilmodem/stk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += gril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
drivers/rilmodem/netmon.c \
|
||||
drivers/rilmodem/stk.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/infineonmodem/infineon_constants.h \
|
||||
drivers/rilmodem/lte.c
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -254,11 +271,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) \
|
||||
@@ -283,8 +302,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 \
|
||||
@@ -364,7 +382,8 @@ builtin_modules += telitmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/telitmodem/telitmodem.h \
|
||||
drivers/telitmodem/telitmodem.c \
|
||||
drivers/telitmodem/location-reporting.c
|
||||
drivers/telitmodem/location-reporting.c \
|
||||
drivers/telitmodem/gprs-context-ncm.c
|
||||
|
||||
builtin_modules += hsomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
@@ -422,6 +441,22 @@ 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
|
||||
|
||||
|
||||
if PHONESIM
|
||||
builtin_modules += phonesim
|
||||
builtin_sources += plugins/phonesim.c
|
||||
@@ -486,6 +521,9 @@ builtin_sources += plugins/caif.c
|
||||
builtin_modules += cinterion
|
||||
builtin_sources += plugins/cinterion.c
|
||||
|
||||
builtin_modules += gemalto
|
||||
builtin_sources += plugins/gemalto.c
|
||||
|
||||
builtin_modules += nokia
|
||||
builtin_sources += plugins/nokia.c
|
||||
|
||||
@@ -513,6 +551,12 @@ 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
|
||||
|
||||
@@ -526,25 +570,36 @@ endif
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
|
||||
if BLUETOOTH
|
||||
if BLUEZ4
|
||||
builtin_modules += bluez4
|
||||
builtin_sources += plugins/bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += sap
|
||||
builtin_sources += plugins/sap.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_bluez4
|
||||
builtin_sources += plugins/hfp_hf_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez4
|
||||
builtin_sources += plugins/hfp_ag_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += dun_gw_bluez4
|
||||
builtin_sources += plugins/dun_gw_bluez4.c plugins/bluez4.h
|
||||
else
|
||||
builtin_modules += hfp_bluez5
|
||||
builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += dun_gw_bluez5
|
||||
builtin_sources += plugins/dun_gw_bluez5.c plugins/bluez5.h
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if BLUETOOTH
|
||||
if BLUEZ4
|
||||
builtin_modules += bluez4
|
||||
builtin_sources += plugins/bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez4
|
||||
builtin_sources += plugins/hfp_ag_bluez4.c plugins/bluez4.h
|
||||
|
||||
builtin_sources += $(btio_sources)
|
||||
builtin_cflags += @BLUEZ_CFLAGS@
|
||||
@@ -553,16 +608,19 @@ else
|
||||
builtin_modules += bluez5
|
||||
builtin_sources += plugins/bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_bluez5
|
||||
builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez5
|
||||
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += dun_gw_bluez5
|
||||
builtin_sources += plugins/dun_gw_bluez5.c plugins/bluez5.h
|
||||
if SAILFISH_BT
|
||||
builtin_modules += sfos_bt
|
||||
builtin_sources += plugins/sailfish_bt.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if UPOWER
|
||||
builtin_modules += upower
|
||||
builtin_sources += plugins/upower.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if NETTIME
|
||||
@@ -570,17 +628,32 @@ builtin_modules += nettime
|
||||
builtin_sources += plugins/nettime.c
|
||||
endif
|
||||
|
||||
if SAILFISH_DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/sailfish_debuglog.c
|
||||
endif
|
||||
|
||||
if SAILFISH_PROVISION
|
||||
builtin_sources += plugins/sailfish_provision.c
|
||||
PROVISION = 1
|
||||
else
|
||||
if PROVISION
|
||||
builtin_sources += plugins/provision.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if PROVISION
|
||||
builtin_sources += plugins/mbpi.h plugins/mbpi.c
|
||||
|
||||
builtin_modules += provision
|
||||
builtin_sources += plugins/provision.h plugins/provision.c
|
||||
builtin_sources += plugins/provision.h
|
||||
|
||||
builtin_modules += cdma_provision
|
||||
builtin_sources += plugins/cdma-provision.c
|
||||
|
||||
builtin_modules += mnclength
|
||||
builtin_sources += plugins/mnclength.c
|
||||
builtin_modules += file_provision
|
||||
builtin_sources += plugins/file-provision.c
|
||||
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
@@ -612,24 +685,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@
|
||||
endif
|
||||
|
||||
if DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/debuglog.c
|
||||
if SAILFISH_PUSHFORWARDER
|
||||
builtin_modules += pushforwarder
|
||||
builtin_sources += plugins/sailfish_pushforwarder.c
|
||||
endif
|
||||
|
||||
builtin_modules += sms_history
|
||||
builtin_sources += plugins/smshistory.c
|
||||
|
||||
builtin_modules += allowed_apns
|
||||
builtin_sources += plugins/allowed-apns.c
|
||||
|
||||
sbin_PROGRAMS = src/ofonod
|
||||
|
||||
src_ofonod_SOURCES = $(builtin_sources) src/ofono.ver \
|
||||
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/mtu-watch.c \
|
||||
src/main.c src/ofono.h src/log.c src/plugin.c \
|
||||
src/modem.c src/common.h src/common.c \
|
||||
src/manager.c src/dbus.c src/util.h src/util.c \
|
||||
@@ -655,7 +725,9 @@ src_ofonod_SOURCES = $(builtin_sources) src/ofono.ver \
|
||||
src/cdma-provision.c src/handsfree.c \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/hfp.h src/siri.c
|
||||
src/sms-filter.c src/dbus-queue.c \
|
||||
src/hfp.h src/siri.c \
|
||||
src/netmon.c src/lte.c
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -701,7 +773,10 @@ 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
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -735,6 +810,7 @@ test_scripts = test/backtrace \
|
||||
test/receive-sms \
|
||||
test/remove-contexts \
|
||||
test/send-sms \
|
||||
test/cancel-sms \
|
||||
test/set-mic-volume \
|
||||
test/set-speaker-volume \
|
||||
test/test-stk-menu \
|
||||
@@ -799,7 +875,16 @@ 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
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -811,35 +896,105 @@ 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-provision unit/test-sms-filter
|
||||
|
||||
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_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
|
||||
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_util_OBJECTS)
|
||||
unit_tests += unit/test-ril_util
|
||||
|
||||
else
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-sms \
|
||||
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)
|
||||
|
||||
@@ -847,19 +1002,23 @@ unit_test_stkutil_SOURCES = unit/test-stkutil.c unit/stk-test-data.h \
|
||||
src/util.c \
|
||||
src/storage.c src/smsutil.c \
|
||||
src/simutil.c src/stkutil.c
|
||||
unit_test_stkutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_stkutil_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_stkutil_OBJECTS)
|
||||
|
||||
unit_test_sms_SOURCES = unit/test-sms.c src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_OBJECTS)
|
||||
|
||||
unit_test_cdmasms_SOURCES = unit/test-cdmasms.c src/cdma-smsutil.c
|
||||
unit_test_cdmasms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_cdmasms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_cdmasms_OBJECTS)
|
||||
|
||||
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
|
||||
src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_root_CFLAGS = -DSTORAGEDIR='"/tmp/ofono"' $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_root_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_root_OBJECTS)
|
||||
|
||||
@@ -870,31 +1029,61 @@ 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_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_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)
|
||||
|
||||
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)
|
||||
|
||||
if TOOLS
|
||||
@@ -921,13 +1110,6 @@ tools_lookup_provider_name_LDADD = @GLIB_LIBS@
|
||||
tools_tty_redirector_SOURCES = tools/tty-redirector.c
|
||||
tools_tty_redirector_LDADD = @GLIB_LIBS@
|
||||
|
||||
if QMIMODEM
|
||||
noinst_PROGRAMS += tools/qmi
|
||||
|
||||
tools_qmi_SOURCES = $(qmi_sources) tools/qmi.c
|
||||
tools_qmi_LDADD = @GLIB_LIBS@
|
||||
endif
|
||||
|
||||
if MAINTAINER_MODE
|
||||
noinst_PROGRAMS += tools/stktest
|
||||
|
||||
@@ -996,6 +1178,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
|
||||
===========
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.17)
|
||||
AC_INIT(ofono, 1.20)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -64,11 +64,21 @@ AC_CHECK_FUNC(signalfd, dummy=yes,
|
||||
AC_CHECK_LIB(dl, dlopen, dummy=yes,
|
||||
AC_MSG_ERROR(dynamic linking loader is required))
|
||||
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.28 is required))
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.32 is required))
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(GOBJECT, gobject-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GObject is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GOBJECT_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GOBJECT_LIBS"
|
||||
|
||||
PKG_CHECK_MODULES(GIO, gio-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GIO is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GIO_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GIO_LIBS"
|
||||
|
||||
if (test "${enable_threads}" = "yes"); then
|
||||
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
||||
@@ -167,20 +177,51 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
|
||||
[enable_rilmodem=${enableval}])
|
||||
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(jolla-rilmodem,
|
||||
AC_HELP_STRING([--enable-jolla-rilmodem], [enable Jolla RIL modem]),
|
||||
[enable_jolla_rilmodem=${enableval}], [enable_jolla_rilmodem="no"])
|
||||
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
|
||||
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||
[enable Sailfish RIL modem]),
|
||||
[enable_sailfish_rilmodem=${enableval}],
|
||||
[enable_sailfish_rilmodem="no"])
|
||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||
|
||||
if (test "${enable_jolla_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS"
|
||||
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.18, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.18 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||
enable_sailfish_manager=yes
|
||||
need_glibutil=yes
|
||||
fi
|
||||
|
||||
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}])
|
||||
@@ -204,6 +245,16 @@ fi
|
||||
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
|
||||
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-bt, AC_HELP_STRING([--enable-sailfish-bt],
|
||||
[enable Sailfish OS Bluetooth plugin]),
|
||||
[enable_sailfish_bt=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_BT, test "${enable_sailfish_bt}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
|
||||
[enable Sailfish OS provisioning plugin]),
|
||||
[enable_sailfish_provision=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
|
||||
[disable Nettime plugin]),
|
||||
[enable_nettime=${enableval}])
|
||||
@@ -236,33 +287,48 @@ 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(debuglog,
|
||||
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
|
||||
[enable_debuglog=${enableval}], [enable_debuglog="no"])
|
||||
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
|
||||
if (test "${enable_debuglog}" = "yes"); then
|
||||
AC_ARG_ENABLE(sailfish-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
|
||||
dnl no prefix and no localstatedir, so default to /var
|
||||
if (test "$localstatedir" = '${prefix}/var'); then
|
||||
@@ -277,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.
|
||||
@@ -19,7 +19,7 @@ Besides the kernel coding style above, oFono has special flavors for its own.
|
||||
Some of them are mandatory (marked as 'M'), while some others are optional
|
||||
(marked as 'O'), but generally preferred.
|
||||
|
||||
M1: Blank line before and after an if/while/do/for statement
|
||||
M1: Blank line before and after an if/while/do/for/switch statement
|
||||
============================================================
|
||||
There should be a blank line before if statement unless the if is nested and
|
||||
not preceded by an expression or variable declaration.
|
||||
|
||||
@@ -106,7 +106,7 @@ Properties boolean Attached [readonly]
|
||||
GPRS service registration (if known).
|
||||
|
||||
Possible values are:
|
||||
"none", "gsm", "edge", "umts", "hsdpa", "hsupa",
|
||||
"none", "gprs", "edge", "umts", "hsdpa", "hsupa",
|
||||
"hspa" (HSDPA and HSUPA at the same time) and
|
||||
"lte"
|
||||
|
||||
|
||||
@@ -76,6 +76,22 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
fd, byte Acquire()
|
||||
|
||||
Attempts to establish the SCO audio connection
|
||||
returning the filedescriptor of the connection and the
|
||||
codec in use.
|
||||
|
||||
Note: Contrary to Connect this does not call
|
||||
NewConnection so it can be called in a blocking
|
||||
manner.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.Failed
|
||||
[service].Error.NotAvailable
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotAllowed
|
||||
|
||||
Signals PropertyChanged(string name, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
@@ -89,6 +105,10 @@ Properties string RemoteAddress [readonly]
|
||||
|
||||
Bluetooth address of the local adapter.
|
||||
|
||||
string Type [readonly]
|
||||
|
||||
Type of the card. Valid values are "gateway" or
|
||||
"handsfree".
|
||||
|
||||
Handsfree Audio Agent hierarchy [experimental]
|
||||
===============================
|
||||
|
||||
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
|
||||
|
||||
122
ofono/doc/networkmonitor-api.txt
Normal file
122
ofono/doc/networkmonitor-api.txt
Normal file
@@ -0,0 +1,122 @@
|
||||
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.
|
||||
|
||||
|
||||
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]
|
||||
|
||||
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.
|
||||
@@ -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.
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +354,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 +386,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;
|
||||
@@ -355,6 +434,7 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
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,
|
||||
@@ -476,7 +556,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))
|
||||
|
||||
@@ -1580,17 +1580,28 @@ static inline ofono_bool_t append_cmer_element(char *buf, int *len, int cap,
|
||||
static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
struct netreg_data *nd)
|
||||
{
|
||||
const char *mode;
|
||||
const char *ind;
|
||||
int len = sprintf(buf, "AT+CMER=");
|
||||
const char *mode;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (nd->vendor) {
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
/* UBX-13002752 R33: TOBY L2 doesn't support mode 2 and 3 */
|
||||
mode = "1";
|
||||
break;
|
||||
default:
|
||||
mode = "3";
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward unsolicited result codes directly to the TE;
|
||||
* TA‑TE link specific inband technique used to embed result codes and
|
||||
* data when TA is in on‑line data mode
|
||||
*/
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], "3", FALSE))
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], mode, FALSE))
|
||||
return FALSE;
|
||||
|
||||
/* No keypad event reporting */
|
||||
@@ -1607,14 +1618,14 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
* Telit does not support mode 1.
|
||||
* All indicator events shall be directed from TA to TE.
|
||||
*/
|
||||
mode = "2";
|
||||
ind = "2";
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Only those indicator events, which are not caused by +CIND
|
||||
* shall be indicated by the TA to the TE.
|
||||
*/
|
||||
mode = "1";
|
||||
ind = "1";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1623,7 +1634,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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
@@ -1457,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\"",
|
||||
@@ -1488,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\"",
|
||||
@@ -1516,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;
|
||||
|
||||
@@ -1541,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",
|
||||
@@ -1566,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,
|
||||
@@ -1580,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);
|
||||
@@ -1589,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)
|
||||
@@ -1626,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 = {
|
||||
@@ -1640,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,5 +45,6 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_ALCATEL,
|
||||
OFONO_VENDOR_QUECTEL,
|
||||
OFONO_VENDOR_UBLOX,
|
||||
OFONO_VENDOR_UBLOX_TOBY_L2,
|
||||
OFONO_VENDOR_CINTERION,
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -709,6 +708,15 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
|
||||
int num_type, validity;
|
||||
struct ofono_call *call;
|
||||
|
||||
/* Waiting call notification makes no sense, when there are
|
||||
* no calls at all. This can happen when a phone already has
|
||||
* waiting and active calls and is being connected over HFP
|
||||
* but it first sends +CCWA before we manage to synchronize
|
||||
* calls with AT+CLCC.
|
||||
*/
|
||||
if (!vd->calls)
|
||||
return;
|
||||
|
||||
/* CCWA can repeat, ignore if we already have an waiting call */
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_WAITING),
|
||||
@@ -1110,6 +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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,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",
|
||||
|
||||
@@ -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 */
|
||||
@@ -652,7 +652,7 @@ static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
||||
|
||||
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 +963,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 */
|
||||
@@ -63,7 +65,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 */
|
||||
@@ -140,9 +142,17 @@ 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
|
||||
|
||||
/* 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 +162,5 @@ struct qmi_nas_home_network {
|
||||
uint8_t desc_len;
|
||||
char desc[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
int qmi_nas_rat_to_tech(uint8_t rat);
|
||||
|
||||
@@ -43,20 +43,6 @@ struct netreg_data {
|
||||
uint8_t current_rat;
|
||||
};
|
||||
|
||||
static int rat_to_tech(uint8_t rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case QMI_NAS_NETWORK_RAT_GSM:
|
||||
return ACCESS_TECHNOLOGY_GSM;
|
||||
case QMI_NAS_NETWORK_RAT_UMTS:
|
||||
return ACCESS_TECHNOLOGY_UTRAN;
|
||||
case QMI_NAS_NETWORK_RAT_LTE:
|
||||
return ACCESS_TECHNOLOGY_EUTRAN;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status,
|
||||
int *lac, int *cellid, int *tech,
|
||||
struct ofono_network_operator *operator)
|
||||
@@ -64,7 +50,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 +68,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 +86,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);
|
||||
}
|
||||
@@ -265,7 +264,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:
|
||||
@@ -543,7 +542,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,10 @@ 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;
|
||||
};
|
||||
|
||||
struct qmi_service {
|
||||
@@ -209,6 +222,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 +334,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 +351,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 +795,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 +875,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 +943,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 +980,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,6 +992,9 @@ 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);
|
||||
@@ -987,6 +1046,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 +1054,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 +1082,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 +1152,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 +1166,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 +1187,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 +1216,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 +1247,249 @@ 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);
|
||||
|
||||
return FALSE;
|
||||
device->shutdown_source = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
if (device->shutdown_func)
|
||||
device->shutdown_func(device->shutdown_user_data);
|
||||
|
||||
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;
|
||||
@@ -1501,6 +1757,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 +1769,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 +1807,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 +1848,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 +1881,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 +1906,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 +1929,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 +1948,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 +1972,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 +2008,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;
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@ 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_NAS,
|
||||
create_nas_cb, rs, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -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,96 @@ 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 get_imsi_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_imsi_cb_t cb = cbd->cb;
|
||||
char *str;
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
DBG("");
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
if (qmi_result_set_error(result, NULL)) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_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);
|
||||
|
||||
DBG("passwd state %d", data->passwd_state);
|
||||
|
||||
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
||||
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMSI);
|
||||
if (!str) {
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, data->retries, user_data);
|
||||
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
|
||||
|
||||
qmi_free(str);
|
||||
}
|
||||
|
||||
static void card_setup(const struct qmi_uim_slot_info *slot,
|
||||
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 +439,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 +703,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 +753,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 +777,10 @@ static struct ofono_sim_driver driver = {
|
||||
.read_file_transparent = qmi_read_transparent,
|
||||
.read_file_linear = qmi_read_record,
|
||||
.read_file_cyclic = qmi_read_record,
|
||||
.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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -25,14 +24,16 @@ struct ril_call_forward {
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
enum ril_call_forward_cmd {
|
||||
enum ril_call_forward_action {
|
||||
CF_ACTION_DISABLE,
|
||||
CF_ACTION_ENABLE,
|
||||
CF_ACTION_UNUSED,
|
||||
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 {
|
||||
@@ -43,35 +44,57 @@ struct ril_call_forward_cbd {
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_forward_cbd_free g_free
|
||||
|
||||
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_new0(struct ril_call_forward_cbd, 1);
|
||||
cbd = g_slice_new0(struct ril_call_forward_cbd);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_forward_submit_request(struct ril_call_forward *fd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
|
||||
int type, int cls, const struct ofono_phone_number *number, int time)
|
||||
{
|
||||
grilio_queue_send_request_full(fd->q, req, code, response,
|
||||
ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
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_forward_set_cb(GRilIoChannel *io, int status,
|
||||
static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
@@ -86,93 +109,51 @@ static void ril_forward_set_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("cf registration");
|
||||
grilio_request_append_int32(req, CF_ACTION_REGISTRATION);
|
||||
grilio_request_append_int32(req, type);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* BEARER_CLASS_VOICE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls);
|
||||
grilio_request_append_int32(req, number->type);
|
||||
grilio_request_append_utf8(req, number->number);
|
||||
grilio_request_append_int32(req, time);
|
||||
|
||||
ril_call_forward_submit_request(fd, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_forward_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_forward_send_cmd(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb,
|
||||
void *data, int action)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, action);
|
||||
grilio_request_append_int32(req, type);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* BEARER_CLASS_VOICE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
|
||||
/* Following 3 values have no real meaning in erasure
|
||||
* but apparently RIL expects them so fields need to
|
||||
* be filled. Otherwise there is no response
|
||||
*/
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, "1234567890");
|
||||
grilio_request_append_int32(req, 60);
|
||||
|
||||
ril_call_forward_submit_request(fd, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_forward_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
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_ACTION_ERASURE");
|
||||
ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_ERASURE);
|
||||
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_ACTION_DISABLE");
|
||||
ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_DISABLE);
|
||||
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_ACTION_ENABLE");
|
||||
ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_ENABLE);
|
||||
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,
|
||||
@@ -223,36 +204,14 @@ 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 = grilio_request_new();
|
||||
GRilIoRequest *req = ril_call_forward_req(CF_ACTION_INTERROGATE,
|
||||
type, cls, NULL, CF_TIME_DEFAULT);
|
||||
|
||||
ofono_info("cf query");
|
||||
grilio_request_append_int32(req, 2);
|
||||
grilio_request_append_int32(req, type);
|
||||
|
||||
/*
|
||||
* 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_NONE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls);
|
||||
|
||||
/* Following 3 values have no real meaning in query
|
||||
* but apparently RIL expects them so fields need to
|
||||
* be filled. Otherwise there is no response
|
||||
*/
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, "1234567890");
|
||||
grilio_request_append_int32(req, 0);
|
||||
|
||||
ril_call_forward_submit_request(fd, req,
|
||||
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
ril_call_forward_query_cb, cb, data);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -286,7 +245,7 @@ static void ril_call_forward_remove(struct ofono_call_forwarding *cf)
|
||||
DBG("");
|
||||
ofono_call_forwarding_set_data(cf, NULL);
|
||||
|
||||
if (fd->timer_id > 0) {
|
||||
if (fd->timer_id) {
|
||||
g_source_remove(fd->timer_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ril_call_volume {
|
||||
struct ofono_call_volume *v;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,60 +16,155 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct ril_cbs {
|
||||
struct ofono_cbs *cbs;
|
||||
GRilIoChannel *io;
|
||||
guint timer_id;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
struct ril_cbs_cbd {
|
||||
struct ril_cbs *cd;
|
||||
ofono_cbs_set_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define RIL_CBS_CHECK_RETRY_MS 1000
|
||||
#define RIL_CBS_CHECK_RETRY_COUNT 30
|
||||
|
||||
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
|
||||
|
||||
#define ril_cbs_cbd_free g_free
|
||||
|
||||
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
|
||||
|
||||
cbd->cd = cd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_clear_topics(struct ofono_cbs *cbs,
|
||||
static 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 ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "%s", topics);
|
||||
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char* pdu;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
pdu = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", pdu);
|
||||
if (pdu) {
|
||||
ofono_cbs_notify(cd->cbs, (const guchar *)pdu, strlen(pdu));
|
||||
g_free(pdu);
|
||||
}
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
DBG_(cd, "%u bytes", len);
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_register(gpointer user_data)
|
||||
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;
|
||||
|
||||
DBG("");
|
||||
GASSERT(cd->timer_id);
|
||||
cd->timer_id = 0;
|
||||
ofono_cbs_register(cd->cbs);
|
||||
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
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,
|
||||
@@ -77,12 +172,30 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
DBG("");
|
||||
cd->cbs = cbs;
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->timer_id = g_idle_add(ril_cbs_register, cd);
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
cd->cbs = cbs;
|
||||
|
||||
DBG_(cd, "");
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -90,15 +203,13 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG("");
|
||||
DBG_(cd, "");
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
|
||||
if (cd->timer_id > 0) {
|
||||
g_source_remove(cd->timer_id);
|
||||
}
|
||||
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
grilio_queue_cancel_all(cd->q, FALSE);
|
||||
grilio_queue_unref(cd->q);
|
||||
g_free(cd->log_prefix);
|
||||
g_free(cd);
|
||||
}
|
||||
|
||||
@@ -106,8 +217,8 @@ const struct ofono_cbs_driver ril_cbs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_set_topics,
|
||||
.clear_topics = ril_clear_topics
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,22 +17,26 @@
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_mce.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#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_priv {
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct sailfish_cell_info info;
|
||||
GRilIoChannel *io;
|
||||
struct ril_mce *mce;
|
||||
MceDisplay *display;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
gulong display_state_event_id;
|
||||
@@ -59,63 +63,22 @@ G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
static inline void ril_cell_free(struct sailfish_cell *cell)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
if (c1->type != c2->type) {
|
||||
return c1->type - c2->type;
|
||||
} else if (c1->type == RIL_CELL_INFO_TYPE_GSM) {
|
||||
const struct ril_cell_info_gsm *g1 = &c1->info.gsm;
|
||||
const struct ril_cell_info_gsm *g2 = &c2->info.gsm;
|
||||
|
||||
if (g1->lac != g2->lac) {
|
||||
return g1->lac - g2->lac;
|
||||
} else {
|
||||
return g1->cid - g2->cid;
|
||||
}
|
||||
} else if (c2->type == RIL_CELL_INFO_TYPE_WCDMA) {
|
||||
const struct ril_cell_info_wcdma *w1 = &c1->info.wcdma;
|
||||
const struct ril_cell_info_wcdma *w2 = &c2->info.wcdma;
|
||||
|
||||
if (w1->lac != w2->lac) {
|
||||
return w1->lac - w2->lac;
|
||||
} else {
|
||||
return w1->cid - w2->cid;
|
||||
}
|
||||
} else {
|
||||
const struct ril_cell_info_lte *l1 = &c1->info.lte;
|
||||
const struct ril_cell_info_lte *l2 = &c2->info.lte;
|
||||
|
||||
GASSERT(c1->type == RIL_CELL_INFO_TYPE_LTE);
|
||||
if (l1->ci != l2->ci) {
|
||||
return l1->ci - l2->ci;
|
||||
} else if (l1->pci != l2->pci) {
|
||||
return l1->pci - l2->pci;
|
||||
} else {
|
||||
return l1->tac - l2->tac;
|
||||
}
|
||||
}
|
||||
} else if (c1) {
|
||||
return 1;
|
||||
} else if (c2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
g_slice_free(struct sailfish_cell, cell);
|
||||
}
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
static void ril_cell_free1(gpointer cell)
|
||||
{
|
||||
return ril_cell_compare_location(v1, v2);
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
@@ -126,80 +89,101 @@ static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
|
||||
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||
{
|
||||
if (!ril_cell_info_list_identical(self->cells, l)) {
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
self->cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals[
|
||||
SIGNAL_CELLS_CHANGED], 0);
|
||||
if (!ril_cell_info_list_identical(self->info.cells, l)) {
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
self->info.cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals
|
||||
[SIGNAL_CELLS_CHANGED], 0);
|
||||
} else {
|
||||
g_slist_free_full(l, g_free);
|
||||
g_slist_free_full(l, ril_cell_free1);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = INT_MAX;
|
||||
gsm->bsic = INT_MAX;
|
||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||
gsm->timingAdvance = INT_MAX;
|
||||
/* RIL_CellIdentityGsm */
|
||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->lac) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->cid) &&
|
||||
(version < 12 || /* RIL_CellIdentityGsm_v12 part */
|
||||
(grilio_parser_get_int32(rilp, &gsm->arfcn) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bsic))) &&
|
||||
/* RIL_GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate)) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,"
|
||||
"strength=%d,err=%d", registered, gsm->mcc, gsm->mnc,
|
||||
gsm->lac, gsm->cid, gsm->signalStrength,
|
||||
gsm->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_GSM;
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
|
||||
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
|
||||
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,arfcn=%d,"
|
||||
"bsic=%d,strength=%d,err=%d,t=%d", registered,
|
||||
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
|
||||
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
|
||||
gsm->timingAdvance);
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = INT_MAX;
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->cid) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->psc) &&
|
||||
(version < 12 || /* RIL_CellIdentityWcdma_v12 part */
|
||||
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
|
||||
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
|
||||
"strength=%d,err=%d", registered, wcdma->mcc,
|
||||
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
|
||||
wcdma->signalStrength, wcdma->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_WCDMA;
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_lte *lte = &cell->info.lte;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = INT_MAX;
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
grilio_parser_get_int32(rilp, <e->pci) &&
|
||||
grilio_parser_get_int32(rilp, <e->tac) &&
|
||||
(version < 12 || /* RIL_CellIdentityLte_v12 part */
|
||||
grilio_parser_get_int32(rilp, <e->earfcn)) &&
|
||||
grilio_parser_get_int32(rilp, <e->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrp) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrq) &&
|
||||
@@ -207,40 +191,44 @@ static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=0x%x,rssnr=0x%x,cqi=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
cell->type = RIL_CELL_INFO_TYPE_LTE;
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
struct ril_cell **cell_ptr)
|
||||
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
|
||||
struct sailfish_cell **cell_ptr)
|
||||
{
|
||||
int type, reg;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &type) &&
|
||||
grilio_parser_get_int32(rilp, ®) &&
|
||||
/* Skip timestamp */
|
||||
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||
int skip = 0;
|
||||
struct ril_cell *cell = NULL;
|
||||
struct sailfish_cell *cell = NULL;
|
||||
|
||||
/* Normalize the boolean value */
|
||||
reg = (reg != FALSE);
|
||||
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, reg);
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, reg);
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, reg);
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
skip = 10;
|
||||
@@ -255,20 +243,20 @@ static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
|
||||
if (cell) {
|
||||
*cell_ptr = cell;
|
||||
return type;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||
*cell_ptr = NULL;
|
||||
return type;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*cell_ptr = NULL;
|
||||
return RIL_CELL_INFO_TYPE_NONE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
|
||||
{
|
||||
GSList *l = NULL;
|
||||
GRilIoParser rilp;
|
||||
@@ -276,17 +264,18 @@ static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct ril_cell *c;
|
||||
struct sailfish_cell *c;
|
||||
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, &c); i++) {
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
|
||||
if (c) {
|
||||
l = g_slist_insert_sorted(l, c,
|
||||
ril_cell_compare_func);
|
||||
sailfish_cell_compare_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -296,40 +285,39 @@ static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
|
||||
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->set_rate_id);
|
||||
priv->set_rate_id = 0;
|
||||
GASSERT(self->set_rate_id);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = grilio_channel_send_request_full(priv->io, req,
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_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);
|
||||
@@ -337,14 +325,13 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id, FALSE);
|
||||
priv->set_rate_id = grilio_channel_send_request_full(priv->io, req,
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_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);
|
||||
@@ -352,29 +339,22 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
|
||||
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
ril_cell_info_set_rate(self,
|
||||
(priv->mce->display_state == RIL_MCE_DISPLAY_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
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(struct ril_mce *mce, void *arg)
|
||||
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
|
||||
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
@@ -392,126 +372,153 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
const gboolean sim_card_was_ready = priv->sim_card_ready;
|
||||
|
||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (priv->sim_card_ready != sim_card_was_ready) {
|
||||
ril_cell_info_refresh(self);
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||
ril_cell_info_refresh(self);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
|
||||
ril_cell_info_cb_t cb, void *arg)
|
||||
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
|
||||
gulong id)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
if (G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_mce *mce,
|
||||
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)
|
||||
{
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
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
|
||||
};
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->mce = ril_mce_ref(mce);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
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, "");
|
||||
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
priv->display_state_event_id =
|
||||
ril_mce_add_display_state_changed_handler(mce,
|
||||
self->display_state_event_id =
|
||||
mce_display_add_state_changed_handler(display,
|
||||
ril_cell_info_display_state_cb, self);
|
||||
priv->radio_state_event_id =
|
||||
self->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(radio,
|
||||
ril_cell_info_radio_state_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
self->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_CELL_INFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_unref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_CELL_INFO(self));
|
||||
}
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
ril_cell_info_refresh(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_CELL_INFO_TYPE,
|
||||
struct ril_cell_info_priv);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, &priv->event_id, 1);
|
||||
if (priv->query_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = 0;
|
||||
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
|
||||
if (self->query_id) {
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = 0;
|
||||
}
|
||||
if (priv->set_rate_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
|
||||
if (self->set_rate_id) {
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id,
|
||||
FALSE);
|
||||
priv->set_rate_id = 0;
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
if (priv->display_state_event_id) {
|
||||
ril_mce_remove_handler(priv->mce, priv->display_state_event_id);
|
||||
priv->display_state_event_id = 0;
|
||||
}
|
||||
ril_radio_remove_handlers(priv->radio, &priv->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(priv->sim_card,
|
||||
&priv->sim_status_event_id, 1);
|
||||
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);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
ril_mce_unref(priv->mce);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
g_free(self->log_prefix);
|
||||
grilio_channel_unref(self->io);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -521,7 +528,6 @@ static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_cell_info_priv));
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-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
|
||||
@@ -17,40 +17,12 @@
|
||||
#define RIL_CELL_INFO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include <mce_display.h>
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
struct ril_cell {
|
||||
enum ril_cell_info_type type;
|
||||
gboolean registered;
|
||||
union {
|
||||
struct ril_cell_info_gsm gsm;
|
||||
struct ril_cell_info_wcdma wcdma;
|
||||
struct ril_cell_info_lte lte;
|
||||
} info;
|
||||
};
|
||||
|
||||
struct ril_cell_info_priv;
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct ril_cell_info_priv *priv;
|
||||
GSList *cells;
|
||||
};
|
||||
|
||||
typedef void (*ril_cell_info_cb_t)(struct ril_cell_info *info, void *arg);
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2);
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2);
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_mce *mce,
|
||||
struct 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);
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *info);
|
||||
void ril_cell_info_unref(struct ril_cell_info *info);
|
||||
struct ril_cell *ril_cell_find_cell(struct ril_cell_info *info,
|
||||
const struct ril_cell *cell);
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *info,
|
||||
ril_cell_info_cb_t cb, void *arg);
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *info, gulong id);
|
||||
|
||||
#endif /* RIL_CELL_INFO_H */
|
||||
|
||||
|
||||
@@ -1,586 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
struct ril_cell_entry {
|
||||
guint cell_id;
|
||||
char *path;
|
||||
struct ril_cell cell;
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus {
|
||||
struct ril_modem *md;
|
||||
struct ril_cell_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
};
|
||||
|
||||
#define RIL_CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
|
||||
#define RIL_CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define RIL_CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
#define RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
|
||||
#define RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define RIL_CELL_DBUS_REMOVED_SIGNAL "Removed"
|
||||
|
||||
struct ril_cell_property {
|
||||
const char *name;
|
||||
glong off;
|
||||
int flag;
|
||||
};
|
||||
|
||||
#define RIL_CELL_GSM_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_gsm,name), value }
|
||||
#define RIL_CELL_WCDMA_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_wcdma,name), value }
|
||||
#define RIL_CELL_LTE_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_lte,name), value }
|
||||
|
||||
static const struct ril_cell_property ril_cell_gsm_properties [] = {
|
||||
RIL_CELL_GSM_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_GSM_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_GSM_PROPERTY(0x04,lac),
|
||||
RIL_CELL_GSM_PROPERTY(0x08,cid),
|
||||
RIL_CELL_GSM_PROPERTY(0x10,signalStrength),
|
||||
RIL_CELL_GSM_PROPERTY(0x20,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_wcdma_properties [] = {
|
||||
RIL_CELL_WCDMA_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x04,lac),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x08,cid),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x10,psc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x20,signalStrength),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x40,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_lte_properties [] = {
|
||||
RIL_CELL_LTE_PROPERTY(0x001,mcc),
|
||||
RIL_CELL_LTE_PROPERTY(0x002,mnc),
|
||||
RIL_CELL_LTE_PROPERTY(0x004,ci),
|
||||
RIL_CELL_LTE_PROPERTY(0x008,pci),
|
||||
RIL_CELL_LTE_PROPERTY(0x010,tac),
|
||||
RIL_CELL_LTE_PROPERTY(0x020,signalStrength),
|
||||
RIL_CELL_LTE_PROPERTY(0x040,rsrp),
|
||||
RIL_CELL_LTE_PROPERTY(0x080,rsrq),
|
||||
RIL_CELL_LTE_PROPERTY(0x100,rssnr),
|
||||
RIL_CELL_LTE_PROPERTY(0x200,cqi),
|
||||
RIL_CELL_LTE_PROPERTY(0x400,timingAdvance)
|
||||
};
|
||||
|
||||
#define RIL_CELL_PROPERTY_REGISTERED 0x1000
|
||||
|
||||
typedef void (*ril_cell_info_dbus_append_fn)(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry);
|
||||
|
||||
static const char *ril_cell_info_dbus_cell_type_str(enum ril_cell_info_type t)
|
||||
{
|
||||
switch (t) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
return "gsm";
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
return "cdma";
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
return "lte";
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
return "wcdma";
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
return "tdscdma";
|
||||
case RIL_CELL_INFO_TYPE_NONE:
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ril_cell_property *ril_cell_info_dbus_cell_properties(
|
||||
enum ril_cell_info_type type, int *count)
|
||||
{
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
*count = G_N_ELEMENTS(ril_cell_gsm_properties);
|
||||
return ril_cell_gsm_properties;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
*count = G_N_ELEMENTS(ril_cell_wcdma_properties);
|
||||
return ril_cell_wcdma_properties;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
*count = G_N_ELEMENTS(ril_cell_lte_properties);
|
||||
return ril_cell_lte_properties;
|
||||
default:
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static void ril_cell_info_destroy_entry(struct ril_cell_entry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
g_free(entry->path);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_reply(DBusMessage *msg,
|
||||
const struct ril_cell_entry *entry,
|
||||
ril_cell_info_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
append(&it, entry);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_version(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_int32_t version = RIL_CELL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
const char *type = ril_cell_info_dbus_cell_type_str(entry->cell.type);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
int i, n;
|
||||
DBusMessageIter dict;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
||||
for (i = 0; i < n; i++) {
|
||||
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
|
||||
if (value != INT_MAX) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_close_container(it, &dict);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_all(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
ril_cell_info_dbus_append_version(it, entry);
|
||||
ril_cell_info_dbus_append_type(it, entry);
|
||||
ril_cell_info_dbus_append_registered(it, entry);
|
||||
ril_cell_info_dbus_append_properties(it, entry);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_type(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_type);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_registered(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_registered);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_properties(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_properties);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_cell_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll", NULL,
|
||||
GDBUS_ARGS({ "version", "i" },
|
||||
{ "type", "s" },
|
||||
{ "registered", "b" },
|
||||
{ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
|
||||
GDBUS_ARGS({ "version", "i" }),
|
||||
ril_cell_info_dbus_cell_get_version) },
|
||||
{ GDBUS_METHOD("GetType", NULL,
|
||||
GDBUS_ARGS({ "type", "s" }),
|
||||
ril_cell_info_dbus_cell_get_type) },
|
||||
{ GDBUS_METHOD("GetRegistered", NULL,
|
||||
GDBUS_ARGS({ "registered", "b" }),
|
||||
ril_cell_info_dbus_cell_get_registered) },
|
||||
{ GDBUS_METHOD("GetProperties", NULL,
|
||||
GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_properties) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_cell_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "registered", "b" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_id(
|
||||
struct ril_cell_info_dbus *dbus, guint id)
|
||||
{
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (entry->cell_id == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint ril_cell_info_dbus_next_cell_id(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
while (ril_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
|
||||
dbus->next_cell_id++;
|
||||
}
|
||||
return dbus->next_cell_id++;
|
||||
}
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_cell(
|
||||
struct ril_cell_info_dbus *dbus, const struct ril_cell *cell)
|
||||
{
|
||||
if (cell) {
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!ril_cell_compare_location(&entry->cell, cell)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_emit_path_list(struct ril_cell_info_dbus *dbus,
|
||||
const char *name, GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static int ril_cell_info_dbus_compare(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
{
|
||||
if (c1->type == c2->type) {
|
||||
int i, n, mask = 0;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(c1->type, &n);
|
||||
|
||||
if (c1->registered != c2->registered) {
|
||||
mask |= RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const glong offset = prop[i].off;
|
||||
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
|
||||
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
|
||||
if (v1 != v2) {
|
||||
mask |= prop[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_property_changed(struct ril_cell_info_dbus *dbus,
|
||||
const struct ril_cell_entry *entry, int mask)
|
||||
{
|
||||
int i, n;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & RIL_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
mask &= ~RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, RIL_CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_update_entries(struct ril_cell_info_dbus *dbus,
|
||||
gboolean emit_signals)
|
||||
{
|
||||
GSList *l;
|
||||
GPtrArray* added = NULL;
|
||||
GPtrArray* removed = NULL;
|
||||
|
||||
/* Remove non-existent cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
|
||||
ril_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
if (emit_signals) {
|
||||
if (!removed) {
|
||||
removed =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_free);
|
||||
}
|
||||
/* Steal the path */
|
||||
g_ptr_array_add(removed, entry->path);
|
||||
entry->path = NULL;
|
||||
}
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
|
||||
/* Add new cells */
|
||||
for (l = dbus->info->cells; l; l = l->next) {
|
||||
const struct ril_cell *cell = l->data;
|
||||
struct ril_cell_entry *entry =
|
||||
ril_cell_info_dbus_find_cell(dbus, cell);
|
||||
|
||||
if (entry) {
|
||||
if (emit_signals) {
|
||||
int diff = ril_cell_info_dbus_compare(cell,
|
||||
&entry->cell);
|
||||
entry->cell = *cell;
|
||||
ril_cell_info_dbus_property_changed(dbus,
|
||||
entry, diff);
|
||||
} else {
|
||||
entry->cell = *cell;
|
||||
}
|
||||
} else {
|
||||
entry = g_new0(struct ril_cell_entry, 1);
|
||||
entry->cell = *cell;
|
||||
entry->cell_id = ril_cell_info_dbus_next_cell_id(dbus);
|
||||
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
|
||||
entry->cell_id);
|
||||
dbus->entries = g_slist_append(dbus->entries, entry);
|
||||
DBG("%s added", entry->path);
|
||||
g_dbus_register_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
ril_cell_info_dbus_cell_methods,
|
||||
ril_cell_info_dbus_cell_signals, NULL,
|
||||
entry, NULL);
|
||||
if (emit_signals) {
|
||||
if (!added) {
|
||||
added = g_ptr_array_new();
|
||||
}
|
||||
g_ptr_array_add(added, entry->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
|
||||
g_ptr_array_free(removed, TRUE);
|
||||
}
|
||||
|
||||
if (added) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
|
||||
g_ptr_array_free(added, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_cells_changed_cb(struct ril_cell_info *info,
|
||||
void *arg)
|
||||
{
|
||||
DBG("");
|
||||
ril_cell_info_dbus_update_entries((struct ril_cell_info_dbus *)arg,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct ril_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
ril_cell_info_dbus_get_cells) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = g_new0(struct ril_cell_info_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->md = md;
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->info = ril_cell_info_ref(info);
|
||||
dbus->handler_id = ril_cell_info_add_cells_changed_handler(info,
|
||||
ril_cell_info_dbus_cells_changed_cb, dbus);
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, ril_cell_info_dbus_methods,
|
||||
ril_cell_info_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ril_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_cell_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
/* Unregister cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
l = l->next;
|
||||
}
|
||||
g_slist_free(dbus->entries);
|
||||
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
ril_cell_info_remove_handler(dbus->info, dbus->handler_id);
|
||||
ril_cell_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,10 +14,15 @@
|
||||
*/
|
||||
|
||||
#include "ril_config.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
{
|
||||
char *val = g_key_file_get_string(file, group, key, NULL);
|
||||
|
||||
@@ -29,6 +34,31 @@ char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
return val;
|
||||
}
|
||||
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
const char *key, char delimiter)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
|
||||
if (str) {
|
||||
char **strv, **p;
|
||||
char delimiter_str[2];
|
||||
|
||||
delimiter_str[0] = delimiter;
|
||||
delimiter_str[1] = 0;
|
||||
strv = g_strsplit(str, delimiter_str, -1);
|
||||
|
||||
/* Strip whitespaces */
|
||||
for (p = strv; *p; p++) {
|
||||
*p = g_strstrip(*p);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
return strv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *out_value)
|
||||
{
|
||||
@@ -106,6 +136,93 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
g_strstrip(str);
|
||||
if (strcasecmp(str, name)) {
|
||||
va_list args;
|
||||
va_start(args, value);
|
||||
while ((name = va_arg(args, char*)) != NULL) {
|
||||
value = va_arg(args, int);
|
||||
if (!strcasecmp(str, name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
ofono_error("Invalid %s config value (%s)", key, str);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
|
||||
if (name) {
|
||||
if (result) {
|
||||
*result = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key)
|
||||
{
|
||||
char *value = ril_config_get_string(file, group, key);
|
||||
|
||||
if (value) {
|
||||
char **values = g_strsplit(value, ",", -1);
|
||||
char **ptr = values;
|
||||
GUtilIntArray *array = gutil_int_array_new();
|
||||
|
||||
while (*ptr) {
|
||||
int val;
|
||||
|
||||
if (ril_parse_int(*ptr++, 0, &val)) {
|
||||
gutil_int_array_append(array, val);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
g_strfreev(values);
|
||||
return gutil_int_array_free_to_ints(array);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
{
|
||||
if (ints) {
|
||||
guint i, n;
|
||||
const int *data = gutil_ints_get_data(ints, &n);
|
||||
GString *buf = g_string_new(NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
if (buf->len > 0) {
|
||||
g_string_append_c(buf, separator);
|
||||
}
|
||||
g_string_append_printf(buf, "%d", data[i]);
|
||||
}
|
||||
return g_string_free(buf, FALSE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -22,13 +22,22 @@
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
const char *key, char delimiter);
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *value);
|
||||
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||
const char *key, gboolean *value);
|
||||
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags);
|
||||
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...);
|
||||
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 */
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* RIL constants adopted from AOSP's header:
|
||||
*
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2016 Jolla Ltd.
|
||||
* Copyright (C) 2013-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,37 +19,70 @@
|
||||
#ifndef __RIL_CONSTANTS_H
|
||||
#define __RIL_CONSTANTS_H 1
|
||||
|
||||
#define RIL_MAX_UUID_LENGTH 64
|
||||
|
||||
/* Error Codes */
|
||||
#define RIL_E_SUCCESS 0
|
||||
#define RIL_E_RADIO_NOT_AVAILABLE 1
|
||||
#define RIL_E_GENERIC_FAILURE 2
|
||||
#define RIL_E_PASSWORD_INCORRECT 3
|
||||
#define RIL_E_SIM_PIN2 4
|
||||
#define RIL_E_SIM_PUK2 5
|
||||
#define RIL_E_REQUEST_NOT_SUPPORTED 6
|
||||
#define RIL_E_CANCELLED 7
|
||||
#define RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL 8
|
||||
#define RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW 9
|
||||
#define RIL_E_SMS_SEND_FAIL_RETRY 10
|
||||
#define RIL_E_SIM_ABSENT 11
|
||||
#define RIL_E_SUBSCRIPTION_NOT_AVAILABLE 12
|
||||
#define RIL_E_MODE_NOT_SUPPORTED 13
|
||||
#define RIL_E_FDN_CHECK_FAILURE 14
|
||||
#define RIL_E_ILLEGAL_SIM_OR_ME 15
|
||||
#define RIL_E_UNUSED 16
|
||||
#define RIL_E_DIAL_MODIFIED_TO_USSD 17
|
||||
#define RIL_E_DIAL_MODIFIED_TO_SS 18
|
||||
#define RIL_E_DIAL_MODIFIED_TO_DIAL 19
|
||||
#define RIL_E_USSD_MODIFIED_TO_DIAL 20
|
||||
#define RIL_E_USSD_MODIFIED_TO_SS 21
|
||||
#define RIL_E_USSD_MODIFIED_TO_USSD 22
|
||||
#define RIL_E_SS_MODIFIED_TO_DIAL 23
|
||||
#define RIL_E_SS_MODIFIED_TO_USSD 24
|
||||
#define RIL_E_SS_MODIFIED_TO_SS 25
|
||||
#define RIL_E_SUBSCRIPTION_NOT_SUPPORTED 26
|
||||
#define RIL_E_MISSING_RESOURCE 27
|
||||
#define RIL_E_NO_SUCH_ELEMENT 28
|
||||
#define RIL_E_INVALID_PARAMETER 29
|
||||
enum ril_status {
|
||||
RIL_E_SUCCESS = 0,
|
||||
RIL_E_RADIO_NOT_AVAILABLE = 1,
|
||||
RIL_E_GENERIC_FAILURE = 2,
|
||||
RIL_E_PASSWORD_INCORRECT = 3,
|
||||
RIL_E_SIM_PIN2 = 4,
|
||||
RIL_E_SIM_PUK2 = 5,
|
||||
RIL_E_REQUEST_NOT_SUPPORTED = 6,
|
||||
RIL_E_CANCELLED = 7,
|
||||
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
|
||||
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
|
||||
RIL_E_SMS_SEND_FAIL_RETRY = 10,
|
||||
RIL_E_SIM_ABSENT = 11,
|
||||
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
|
||||
RIL_E_MODE_NOT_SUPPORTED = 13,
|
||||
RIL_E_FDN_CHECK_FAILURE = 14,
|
||||
RIL_E_ILLEGAL_SIM_OR_ME = 15,
|
||||
RIL_E_MISSING_RESOURCE = 16,
|
||||
RIL_E_NO_SUCH_ELEMENT = 17,
|
||||
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
|
||||
RIL_E_DIAL_MODIFIED_TO_SS = 19,
|
||||
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
|
||||
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
|
||||
RIL_E_USSD_MODIFIED_TO_SS = 22,
|
||||
RIL_E_USSD_MODIFIED_TO_USSD = 23,
|
||||
RIL_E_SS_MODIFIED_TO_DIAL = 24,
|
||||
RIL_E_SS_MODIFIED_TO_USSD = 25,
|
||||
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
|
||||
RIL_E_SS_MODIFIED_TO_SS = 27,
|
||||
RIL_E_LCE_NOT_SUPPORTED = 36,
|
||||
RIL_E_NO_MEMORY = 37,
|
||||
RIL_E_INTERNAL_ERR = 38,
|
||||
RIL_E_SYSTEM_ERR = 39,
|
||||
RIL_E_MODEM_ERR = 40,
|
||||
RIL_E_INVALID_STATE = 41,
|
||||
RIL_E_NO_RESOURCES = 42,
|
||||
RIL_E_SIM_ERR = 43,
|
||||
RIL_E_INVALID_ARGUMENTS = 44,
|
||||
RIL_E_INVALID_SIM_STATE = 45,
|
||||
RIL_E_INVALID_MODEM_STATE = 46,
|
||||
RIL_E_INVALID_CALL_ID = 47,
|
||||
RIL_E_NO_SMS_TO_ACK = 48,
|
||||
RIL_E_NETWORK_ERR = 49,
|
||||
RIL_E_REQUEST_RATE_LIMITED = 50,
|
||||
RIL_E_SIM_BUSY = 51,
|
||||
RIL_E_SIM_FULL = 52,
|
||||
RIL_E_NETWORK_REJECT = 53,
|
||||
RIL_E_OPERATION_NOT_ALLOWED = 54,
|
||||
RIL_E_EMPTY_RECORD = 55,
|
||||
RIL_E_INVALID_SMS_FORMAT = 56,
|
||||
RIL_E_ENCODING_ERR = 57,
|
||||
RIL_E_INVALID_SMSC_ADDRESS = 58,
|
||||
RIL_E_NO_SUCH_ENTRY = 59,
|
||||
RIL_E_NETWORK_NOT_READY = 60,
|
||||
RIL_E_NOT_PROVISIONED = 61,
|
||||
RIL_E_NO_SUBSCRIPTION = 62,
|
||||
RIL_E_NO_NETWORK_FOUND = 63,
|
||||
RIL_E_DEVICE_IN_USE = 64,
|
||||
RIL_E_ABORTED = 65,
|
||||
RIL_E_INVALID_RESPONSE = 66
|
||||
};
|
||||
|
||||
/* call states */
|
||||
enum ril_call_state {
|
||||
@@ -114,49 +146,125 @@ enum ril_radio_tech {
|
||||
RADIO_TECH_HSPAP = 15,
|
||||
RADIO_TECH_GSM = 16,
|
||||
RADIO_TECH_TD_SCDMA = 17,
|
||||
RADIO_TECH_IWLAN = 18
|
||||
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 */
|
||||
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
|
||||
#define CALL_FAIL_NORMAL 16
|
||||
#define CALL_FAIL_BUSY 17
|
||||
#define CALL_FAIL_CONGESTION 34
|
||||
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
|
||||
#define CALL_FAIL_CALL_BARRED 240
|
||||
#define CALL_FAIL_FDN_BLOCKED 241
|
||||
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
|
||||
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
|
||||
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
|
||||
#define CALL_FAIL_CDMA_DROP 1001
|
||||
#define CALL_FAIL_CDMA_INTERCEPT 1002
|
||||
#define CALL_FAIL_CDMA_REORDER 1003
|
||||
#define CALL_FAIL_CDMA_SO_REJECT 1004
|
||||
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
|
||||
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
|
||||
#define CALL_FAIL_CDMA_PREEMPTED 1007
|
||||
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
|
||||
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
|
||||
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
|
||||
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. */
|
||||
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
|
||||
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
|
||||
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
|
||||
#define CALL_FAIL_NO_USER_RESPONDING 18
|
||||
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
|
||||
#define CALL_FAIL_CALL_REJECTED 21
|
||||
#define CALL_FAIL_NUMBER_CHANGED 22
|
||||
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
|
||||
#define CALL_FAIL_PRE_EMPTION 25
|
||||
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
|
||||
#define CALL_FAIL_INCOMPLETE_NUMBER 28
|
||||
#define CALL_FAIL_FACILITY_REJECTED 29
|
||||
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
|
||||
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
|
||||
CALL_FAIL_PRE_EMPTION = 25
|
||||
};
|
||||
|
||||
enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_NONE = 0,
|
||||
@@ -287,40 +395,7 @@ enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
struct ril_cell_info_gsm {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct ril_cell_info_wcdma {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
|
||||
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct ril_cell_info_lte {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int ci; /* Cell Identity */
|
||||
int pci; /* Physical cell id (0..503) */
|
||||
int tac; /* Tracking area code */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
|
||||
int rsrp; /* Reference Signal Receive Power TS 36.133 */
|
||||
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
|
||||
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
|
||||
int cqi; /* Channel Quality Indicator TS 36.101 */
|
||||
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
|
||||
};
|
||||
|
||||
/* RIL Request Messages */
|
||||
/* RIL Request Messages, ofono -> rild */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK 3
|
||||
@@ -455,7 +530,7 @@ struct ril_cell_info_lte {
|
||||
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
|
||||
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
|
||||
|
||||
/* RIL Unsolicited Messages */
|
||||
/* RIL Unsolicited Messages, rild -> ofono */
|
||||
#define RIL_UNSOL_RESPONSE_BASE 1000
|
||||
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
|
||||
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
|
||||
@@ -503,6 +578,9 @@ struct ril_cell_info_lte {
|
||||
#define RIL_UNSOL_ON_SS 1043
|
||||
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
|
||||
|
||||
/* A special request, ofono -> rild */
|
||||
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -27,15 +27,14 @@
|
||||
#include <grilio_parser.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#define SETUP_DATA_CALL_PARAMS 7
|
||||
#define DATA_PROFILE_DEFAULT_STR "0"
|
||||
#define DEACTIVATE_DATA_CALL_PARAMS 2
|
||||
|
||||
#define PROTO_IP_STR "IP"
|
||||
#define PROTO_IPV6_STR "IPV6"
|
||||
#define PROTO_IPV4V6_STR "IPV4V6"
|
||||
|
||||
enum ril_data_priv_flags {
|
||||
RIL_DATA_FLAG_NONE = 0x00,
|
||||
RIL_DATA_FLAG_ALLOWED = 0x01,
|
||||
RIL_DATA_FLAG_MAX_SPEED = 0x02,
|
||||
RIL_DATA_FLAG_ON = 0x04
|
||||
@@ -95,11 +94,13 @@ struct ril_data_priv {
|
||||
struct ril_network *network;
|
||||
struct ril_data_manager *dm;
|
||||
enum ril_data_priv_flags flags;
|
||||
struct ril_vendor_hook *vendor_hook;
|
||||
|
||||
struct ril_data_request *req_queue;
|
||||
struct ril_data_request *pending_req;
|
||||
|
||||
enum ril_data_allow_data_opt allow_data;
|
||||
struct ril_data_options options;
|
||||
guint slot;
|
||||
char *log_prefix;
|
||||
guint query_id;
|
||||
gulong io_event_id;
|
||||
@@ -159,7 +160,8 @@ struct ril_data_request_setup {
|
||||
char *password;
|
||||
enum ofono_gprs_proto proto;
|
||||
enum ofono_gprs_auth_method auth_method;
|
||||
int retry_count;
|
||||
guint retry_count;
|
||||
guint retry_delay_id;
|
||||
};
|
||||
|
||||
struct ril_data_request_deact {
|
||||
@@ -167,12 +169,11 @@ struct ril_data_request_deact {
|
||||
int cid;
|
||||
};
|
||||
|
||||
struct ril_data_request_2g {
|
||||
struct ril_data_request_allow_data {
|
||||
struct ril_data_request req;
|
||||
gulong handler_id;
|
||||
gboolean allow;
|
||||
};
|
||||
|
||||
static gboolean ril_data_manager_handover(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
|
||||
|
||||
@@ -182,6 +183,26 @@ static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
|
||||
g_signal_emit(self, ril_data_signals[id], 0);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* RIL requests
|
||||
*==========================================================================*/
|
||||
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow)
|
||||
{
|
||||
return grilio_request_array_int32_new(1, allow);
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, 2 /* Parameter count */);
|
||||
grilio_request_append_format(req, "%d", cid);
|
||||
grilio_request_append_format(req, "%d",
|
||||
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
|
||||
return req;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ril_data_call
|
||||
*==========================================================================*/
|
||||
@@ -272,7 +293,8 @@ static int ril_data_protocol_to_ofono(gchar *str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp)
|
||||
static struct ril_data_call *ril_data_call_parse(int version,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
int prot;
|
||||
char *prot_str;
|
||||
@@ -280,6 +302,7 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
|
||||
guint32 active = RIL_DATA_CALL_INACTIVE;
|
||||
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
|
||||
|
||||
/* RIL_Data_Call_Response_v6 (see ril.h) */
|
||||
grilio_parser_get_uint32(rilp, &status);
|
||||
grilio_parser_get_int32(rilp, &call->retry_time);
|
||||
grilio_parser_get_int32(rilp, &call->cid);
|
||||
@@ -299,9 +322,12 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
|
||||
call->status = status;
|
||||
call->active = active;
|
||||
|
||||
/* RIL_Data_Call_Response_v9 */
|
||||
if (version >= 9) {
|
||||
/* PCSCF */
|
||||
grilio_parser_skip_string(rilp);
|
||||
|
||||
/* RIL_Data_Call_Response_v11 */
|
||||
if (version >= 11) {
|
||||
/* MTU */
|
||||
grilio_parser_get_int32(rilp, &call->mtu);
|
||||
@@ -312,7 +338,8 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
|
||||
return call;
|
||||
}
|
||||
|
||||
struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
|
||||
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
|
||||
guint len, enum ril_data_call_format format)
|
||||
{
|
||||
unsigned int version, n, i;
|
||||
GRilIoParser rilp;
|
||||
@@ -323,8 +350,13 @@ struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
|
||||
struct ril_data_call_list *list =
|
||||
g_new0(struct ril_data_call_list, 1);
|
||||
|
||||
DBG("version=%u,num=%u", version, n);
|
||||
list->version = version;
|
||||
if (format == RIL_DATA_CALL_FORMAT_AUTO || format == version) {
|
||||
DBG("version=%u,num=%u", version, n);
|
||||
list->version = version;
|
||||
} else {
|
||||
DBG("version=%u(%d),num=%u", version, format, n);
|
||||
list->version = format;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
|
||||
struct ril_data_call *call =
|
||||
@@ -494,7 +526,8 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
|
||||
priv->query_id = 0;
|
||||
}
|
||||
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format));
|
||||
}
|
||||
|
||||
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
@@ -503,10 +536,18 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
|
||||
struct ril_data *self = RIL_DATA(user_data);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* Only RIL_E_SUCCESS and RIL_E_RADIO_NOT_AVAILABLE are expected here,
|
||||
* all other errors are filtered out by ril_voicecall_clcc_retry()
|
||||
*/
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
|
||||
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format));
|
||||
} else {
|
||||
/* RADIO_NOT_AVAILABLE == no calls */
|
||||
ril_data_set_calls(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,11 +622,11 @@ static gboolean ril_data_request_do_cancel(struct ril_data_request *req)
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
|
||||
DBG_(req->data, "canceling %s request %p", req->name, req);
|
||||
if (req->cancel) {
|
||||
req->cancel(req);
|
||||
}
|
||||
if (priv->pending_req == req) {
|
||||
/* Request has been submitted already */
|
||||
if (req->cancel) {
|
||||
req->cancel(req);
|
||||
}
|
||||
priv->pending_req = NULL;
|
||||
} else if (priv->req_queue == req) {
|
||||
/* It's the first one in the queue */
|
||||
@@ -668,15 +709,33 @@ static void ril_data_request_queue(struct ril_data_request *req)
|
||||
|
||||
static void ril_data_call_setup_cancel(struct ril_data_request *req)
|
||||
{
|
||||
if (req->pending_id) {
|
||||
grilio_queue_cancel_request(req->data->priv->q,
|
||||
req->pending_id, FALSE);
|
||||
req->pending_id = 0;
|
||||
if (req->cb.setup) {
|
||||
req->cb.setup(req->data, GRILIO_STATUS_CANCELLED,
|
||||
NULL, req->arg);
|
||||
}
|
||||
struct ril_data_request_setup *setup =
|
||||
G_CAST(req, struct ril_data_request_setup, req);
|
||||
|
||||
ril_data_request_cancel_io(req);
|
||||
if (setup->retry_delay_id) {
|
||||
g_source_remove(setup->retry_delay_id);
|
||||
setup->retry_delay_id = 0;
|
||||
}
|
||||
if (req->cb.setup) {
|
||||
ril_data_call_setup_cb_t cb = req->cb.setup;
|
||||
req->cb.setup = NULL;
|
||||
cb(req->data, GRILIO_STATUS_CANCELLED, NULL, req->arg);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_data_call_setup_retry(void *user_data)
|
||||
{
|
||||
struct ril_data_request_setup *setup = user_data;
|
||||
struct ril_data_request *req = &setup->req;
|
||||
|
||||
GASSERT(setup->retry_delay_id);
|
||||
setup->retry_delay_id = 0;
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
req->data->priv->options.data_call_retry_limit);
|
||||
req->submit(req);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
@@ -685,11 +744,13 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
struct ril_data_request_setup *setup = user_data;
|
||||
struct ril_data_request *req = &setup->req;
|
||||
struct ril_data *self = req->data;
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_data_call_list *list = NULL;
|
||||
struct ril_data_call *call = NULL;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
list = ril_data_call_list_parse(data, len);
|
||||
list = ril_data_call_list_parse(data, len,
|
||||
priv->options.data_call_format);
|
||||
}
|
||||
|
||||
if (list) {
|
||||
@@ -702,15 +763,25 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
|
||||
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
|
||||
!setup->retry_count) {
|
||||
setup->retry_count < priv->options.data_call_retry_limit) {
|
||||
/*
|
||||
* Retry silently according to comment in ril.h
|
||||
* (no more than once though)
|
||||
* According to the comment from ril.h we should silently
|
||||
* retry. First time we retry immediately and if that doedsn't
|
||||
* work, then after certain delay.
|
||||
*/
|
||||
DBG("retrying silently");
|
||||
setup->retry_count++;
|
||||
req->pending_id = 0;
|
||||
req->submit(req);
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
priv->options.data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
guint ms = priv->options.data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
}
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
@@ -742,8 +813,8 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
G_CAST(req, struct ril_data_request_setup, req);
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
const char *proto_str = ril_data_ofono_protocol_to_ril(setup->proto);
|
||||
GRilIoRequest* ioreq;
|
||||
int tech, auth;
|
||||
GRilIoRequest *ioreq;
|
||||
int tech, auth = RIL_AUTH_NONE;
|
||||
|
||||
GASSERT(proto_str);
|
||||
|
||||
@@ -766,21 +837,29 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
tech = RADIO_TECH_HSPA;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
|
||||
* android/internal/telephony/dataconnection/DataConnection.java,
|
||||
* onConnect(), and use authentication or not depending on whether
|
||||
* the user field is empty or not.
|
||||
*/
|
||||
auth = (setup->username && setup->username[0]) ?
|
||||
RIL_AUTH_BOTH : RIL_AUTH_NONE;
|
||||
if (setup->username && setup->username[0]) {
|
||||
switch (setup->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
auth = RIL_AUTH_BOTH;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
auth = RIL_AUTH_NONE;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = RIL_AUTH_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = RIL_AUTH_PAP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: add comments about tethering, other non-public
|
||||
* profiles...
|
||||
*/
|
||||
ioreq = grilio_request_new();
|
||||
grilio_request_append_int32(ioreq, SETUP_DATA_CALL_PARAMS);
|
||||
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
|
||||
grilio_request_append_format(ioreq, "%d", tech);
|
||||
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
|
||||
grilio_request_append_utf8(ioreq, setup->apn);
|
||||
@@ -839,14 +918,11 @@ static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
|
||||
|
||||
static void ril_data_call_deact_cancel(struct ril_data_request *req)
|
||||
{
|
||||
if (req->pending_id) {
|
||||
grilio_queue_cancel_request(req->data->priv->q,
|
||||
req->pending_id, FALSE);
|
||||
req->pending_id = 0;
|
||||
if (req->cb.setup) {
|
||||
req->cb.deact(req->data, GRILIO_STATUS_CANCELLED,
|
||||
req->arg);
|
||||
}
|
||||
ril_data_request_cancel_io(req);
|
||||
if (req->cb.deact) {
|
||||
ril_data_call_deactivate_cb_t cb = req->cb.deact;
|
||||
req->cb.deact = NULL;
|
||||
cb(req->data, GRILIO_STATUS_CANCELLED, req->arg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,6 +958,10 @@ static void ril_data_call_deact_cb(GRilIoChannel *io, int ril_status,
|
||||
ril_data_call_free(call);
|
||||
ril_data_signal_emit(data, SIGNAL_CALLS_CHANGED);
|
||||
}
|
||||
} else {
|
||||
/* Something seems to be slightly broken, request the
|
||||
* current state */
|
||||
ril_data_poll_call_state(data);
|
||||
}
|
||||
|
||||
if (req->cb.deact) {
|
||||
@@ -896,12 +976,8 @@ static gboolean ril_data_call_deact_submit(struct ril_data_request *req)
|
||||
struct ril_data_request_deact *deact =
|
||||
G_CAST(req, struct ril_data_request_deact, req);
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
GRilIoRequest* ioreq = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(ioreq, DEACTIVATE_DATA_CALL_PARAMS);
|
||||
grilio_request_append_format(ioreq, "%d", deact->cid);
|
||||
grilio_request_append_format(ioreq, "%d",
|
||||
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
|
||||
GRilIoRequest *ioreq =
|
||||
ril_request_deactivate_data_call_new(deact->cid);
|
||||
|
||||
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
||||
RIL_REQUEST_DEACTIVATE_DATA_CALL,
|
||||
@@ -933,15 +1009,6 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
|
||||
* ril_data_allow_request
|
||||
*==========================================================================*/
|
||||
|
||||
static GRilIoRequest *ril_data_allow_req(gboolean allow)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, allow != FALSE);
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *req_data, guint len, void *user_data)
|
||||
{
|
||||
@@ -951,13 +1018,22 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
ril_data_request_completed(req);
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS &&
|
||||
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
|
||||
GASSERT(!ril_data_allowed(data));
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
GASSERT(ril_data_allowed(data));
|
||||
DBG_(data, "data on");
|
||||
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
const gboolean was_allowed = ril_data_allowed(data);
|
||||
struct ril_data_request_allow_data *ad =
|
||||
G_CAST(req, struct ril_data_request_allow_data, req);
|
||||
|
||||
if (ad->allow) {
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
DBG_(data, "data on");
|
||||
} else {
|
||||
priv->flags &= ~RIL_DATA_FLAG_ON;
|
||||
DBG_(data, "data off");
|
||||
}
|
||||
|
||||
if (ril_data_allowed(data) != was_allowed) {
|
||||
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
ril_data_request_finish(req);
|
||||
@@ -965,25 +1041,32 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
static gboolean ril_data_allow_submit(struct ril_data_request *req)
|
||||
{
|
||||
GRilIoRequest *ioreq = ril_data_allow_req(TRUE);
|
||||
struct ril_data_request_allow_data *ad =
|
||||
G_CAST(req, struct ril_data_request_allow_data, req);
|
||||
GRilIoRequest *ioreq = ril_request_allow_data_new(ad->allow);
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
|
||||
grilio_request_set_retry(ioreq, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_blocking(ioreq, TRUE);
|
||||
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
||||
RIL_REQUEST_ALLOW_DATA, ril_data_allow_cb, NULL, req);
|
||||
grilio_request_unref(ioreq);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct ril_data_request *ril_data_allow_new(struct ril_data *data)
|
||||
static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
|
||||
gboolean allow)
|
||||
{
|
||||
struct ril_data_request *req = g_new0(struct ril_data_request, 1);
|
||||
struct ril_data_request_allow_data *ad =
|
||||
g_new0(struct ril_data_request_allow_data, 1);
|
||||
struct ril_data_request *req = &ad->req;
|
||||
|
||||
req->name = "ALLOW_DATA";
|
||||
req->data = data;
|
||||
req->submit = ril_data_allow_submit;
|
||||
req->cancel = ril_data_request_cancel_io;
|
||||
req->flags = DATA_REQUEST_FLAG_CANCEL_WHEN_DISALLOWED;
|
||||
ad->allow = allow;
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -1018,35 +1101,47 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
|
||||
ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
|
||||
}
|
||||
|
||||
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ril_data *d1 = a;
|
||||
const struct ril_data *d2 = b;
|
||||
const struct ril_data_priv *p1 = d1->priv;
|
||||
const struct ril_data_priv *p2 = d2->priv;
|
||||
|
||||
return p1->slot < p2->slot ? (-1) : p1->slot > p2->slot ? 1 : 0;
|
||||
}
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, enum ril_data_allow_data_opt opt)
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
GASSERT(dm);
|
||||
if (G_LIKELY(dm)) {
|
||||
struct ril_data *self = g_object_new(RIL_DATA_TYPE, NULL);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_sim_settings *settings = network->settings;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
switch (opt) {
|
||||
case RIL_ALLOW_DATA_ON:
|
||||
case RIL_ALLOW_DATA_OFF:
|
||||
priv->allow_data = opt;
|
||||
priv->options = *options;
|
||||
switch (priv->options.allow_data) {
|
||||
case RIL_ALLOW_DATA_ENABLED:
|
||||
case RIL_ALLOW_DATA_DISABLED:
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* When RIL_REQUEST_ALLOW_DATA first appeared in ril.h
|
||||
* RIL_VERSION was 10
|
||||
*/
|
||||
priv->allow_data = (io->ril_version > 10) ?
|
||||
RIL_ALLOW_DATA_ON : RIL_ALLOW_DATA_OFF;
|
||||
priv->options.allow_data = (io->ril_version > 10) ?
|
||||
RIL_ALLOW_DATA_ENABLED :
|
||||
RIL_ALLOW_DATA_DISABLED;
|
||||
break;
|
||||
}
|
||||
|
||||
priv->log_prefix = (name && name[0]) ?
|
||||
g_strconcat(name, " ", NULL) : g_strdup("");
|
||||
|
||||
priv->slot = config->slot;
|
||||
priv->q = grilio_queue_new(io);
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->dm = ril_data_manager_ref(dm);
|
||||
@@ -1064,19 +1159,50 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
ril_data_settings_changed, self);
|
||||
|
||||
/* Request the current state */
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->query_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_DATA_CALL_LIST,
|
||||
ril_data_query_data_calls_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
ril_data_poll_call_state(self);
|
||||
|
||||
dm->data_list = g_slist_append(dm->data_list, self);
|
||||
/* Order data contexts according to slot numbers */
|
||||
dm->data_list = g_slist_insert_sorted(dm->data_list, self,
|
||||
ril_data_compare_cb);
|
||||
ril_data_manager_check_network_mode(dm);
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_data_poll_call_state_retry(GRilIoRequest* req,
|
||||
int ril_status, const void* resp_data, guint resp_len, void* user_data)
|
||||
{
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_data_poll_call_state(struct ril_data *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (!priv->query_id) {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_retry_func(req,
|
||||
ril_data_poll_call_state_retry);
|
||||
priv->query_id =
|
||||
grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_DATA_CALL_LIST,
|
||||
ril_data_query_data_calls_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_data *ril_data_ref(struct ril_data *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
@@ -1123,8 +1249,7 @@ static void ril_data_power_update(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (priv->pending_req || priv->req_queue ||
|
||||
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
|
||||
if (priv->pending_req || priv->req_queue) {
|
||||
ril_radio_power_on(priv->radio, self);
|
||||
} else {
|
||||
ril_radio_power_off(priv->radio, self);
|
||||
@@ -1154,10 +1279,11 @@ static void ril_data_cancel_requests(struct ril_data *self,
|
||||
static void ril_data_disallow(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
const gboolean was_allowed = ril_data_allowed(self);
|
||||
|
||||
DBG_(self, "disallowed");
|
||||
GASSERT(priv->flags & RIL_DATA_FLAG_ALLOWED);
|
||||
priv->flags &= ~(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
|
||||
priv->flags &= ~RIL_DATA_FLAG_ALLOWED;
|
||||
|
||||
/*
|
||||
* Cancel all requests that can be canceled.
|
||||
@@ -1170,7 +1296,20 @@ static void ril_data_disallow(struct ril_data *self)
|
||||
* requests are already pending? That's quite unlikely though)
|
||||
*/
|
||||
ril_data_deactivate_all(self);
|
||||
ril_data_power_update(self);
|
||||
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
/* Tell rild that the data is now disabled */
|
||||
ril_data_request_queue(ril_data_allow_new(self, FALSE));
|
||||
} else {
|
||||
priv->flags &= ~RIL_DATA_FLAG_ON;
|
||||
GASSERT(!ril_data_allowed(self));
|
||||
DBG_(self, "data off");
|
||||
ril_data_power_update(self);
|
||||
}
|
||||
|
||||
if (ril_data_allowed(self) != was_allowed) {
|
||||
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
|
||||
@@ -1187,12 +1326,7 @@ static void ril_data_disallow_cb(gpointer data_ptr, gpointer allowed)
|
||||
struct ril_data *data = data_ptr;
|
||||
|
||||
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
const gboolean was_allowed = ril_data_allowed(data);
|
||||
ril_data_disallow(data);
|
||||
if (was_allowed) {
|
||||
ril_data_signal_emit(data,
|
||||
SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1246,13 +1380,7 @@ void ril_data_allow(struct ril_data *self, enum ril_data_role role)
|
||||
}
|
||||
} else {
|
||||
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
gboolean was_allowed = ril_data_allowed(self);
|
||||
|
||||
ril_data_disallow(self);
|
||||
if (was_allowed) {
|
||||
ril_data_signal_emit(self,
|
||||
SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
ril_data_manager_check_data(dm);
|
||||
}
|
||||
}
|
||||
@@ -1374,6 +1502,16 @@ void ril_data_manager_unref(struct ril_data_manager *self)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
|
||||
{
|
||||
/*
|
||||
* The 3G/LTE handover thing only makes sense if we are managing
|
||||
* more than one SIM slot. Otherwise leave things where they are.
|
||||
*/
|
||||
return (self->data_list && self->data_list->next &&
|
||||
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
|
||||
}
|
||||
|
||||
static gboolean ril_data_manager_requests_pending(struct ril_data_manager *self)
|
||||
{
|
||||
GSList *l;
|
||||
@@ -1393,53 +1531,54 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
GSList *l;
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
gboolean need_fast_access = FALSE;
|
||||
struct ril_network *lte_network = NULL;
|
||||
int non_gsm_count = 0;
|
||||
|
||||
/*
|
||||
* Count number of SIMs for which GSM is selected
|
||||
* Count number of SIMs for which non-GSM mode is selected
|
||||
*/
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_data_priv *priv = data->priv;
|
||||
struct ril_sim_settings *sim = priv->network->settings;
|
||||
struct ril_network *network = priv->network;
|
||||
struct ril_sim_settings *sim = network->settings;
|
||||
|
||||
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM &&
|
||||
sim->imsi) {
|
||||
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) {
|
||||
non_gsm_count++;
|
||||
if (priv->flags & RIL_DATA_FLAG_MAX_SPEED) {
|
||||
need_fast_access = TRUE;
|
||||
if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) &&
|
||||
!lte_network) {
|
||||
lte_network = network;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the SIM selected for internet access has non-GSM mode
|
||||
* enabled and non-GSM mode is enabled for more than one SIM,
|
||||
* then we need to limit other SIMs to GSM. Otherwise, turn
|
||||
* all limits off.
|
||||
* If there's no SIM selected for internet access
|
||||
* then choose the first slot for LTE.
|
||||
*/
|
||||
if (need_fast_access && non_gsm_count > 1) {
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_data_priv *priv = data->priv;
|
||||
|
||||
ril_network_set_max_pref_mode(priv->network,
|
||||
(priv->flags & RIL_DATA_FLAG_MAX_SPEED) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
return;
|
||||
if (!lte_network) {
|
||||
struct ril_data *data = self->data_list->data;
|
||||
lte_network = data->priv->network;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise there's no reason to limit anything */
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
ril_network_set_max_pref_mode(data->priv->network,
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_network *network = data->priv->network;
|
||||
|
||||
ril_network_set_max_pref_mode(network,
|
||||
(network == lte_network) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Otherwise there's no reason to limit anything */
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
ril_network_set_max_pref_mode(data->priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1457,16 +1596,6 @@ static struct ril_data *ril_data_manager_allowed(struct ril_data_manager *self)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
|
||||
{
|
||||
/*
|
||||
* The 3G/LTE handover thing only makes sense if we are managing
|
||||
* more than one SIM slot. Otherwise leave things where they are.
|
||||
*/
|
||||
return (self->data_list && self->data_list->next &&
|
||||
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
|
||||
}
|
||||
|
||||
static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
struct ril_data *data)
|
||||
{
|
||||
@@ -1480,9 +1609,8 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
|
||||
}
|
||||
|
||||
|
||||
if (priv->allow_data == RIL_ALLOW_DATA_ON) {
|
||||
ril_data_request_queue(ril_data_allow_new(data));
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
ril_data_request_queue(ril_data_allow_new(data, TRUE));
|
||||
} else {
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
GASSERT(ril_data_allowed(data));
|
||||
@@ -1505,6 +1633,16 @@ static void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
}
|
||||
}
|
||||
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *self)
|
||||
{
|
||||
if (self) {
|
||||
struct ril_data *data = ril_data_manager_allowed(self);
|
||||
if (data) {
|
||||
ril_data_request_queue(ril_data_allow_new(data, TRUE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -56,8 +56,22 @@ enum ril_data_manager_flags {
|
||||
|
||||
enum ril_data_allow_data_opt {
|
||||
RIL_ALLOW_DATA_AUTO,
|
||||
RIL_ALLOW_DATA_ON,
|
||||
RIL_ALLOW_DATA_OFF
|
||||
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 {
|
||||
@@ -70,6 +84,7 @@ 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,
|
||||
@@ -79,11 +94,13 @@ 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, enum ril_data_allow_data_opt opt);
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config);
|
||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||
void ril_data_unref(struct ril_data *data);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
void ril_data_poll_call_state(struct ril_data *data);
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
@@ -107,6 +124,10 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
int cid);
|
||||
|
||||
/* Constructors of various kinds of RIL requests */
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||
|
||||
#endif /* RIL_DATA_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,16 +17,24 @@
|
||||
#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;
|
||||
guint register_id;
|
||||
guint imei_id;
|
||||
GUtilIdleQueue *iq;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
};
|
||||
|
||||
@@ -36,6 +44,7 @@ struct ril_devinfo_cbd {
|
||||
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(
|
||||
@@ -62,7 +71,7 @@ static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
|
||||
cb(ril_error_failure(&error), "", data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
|
||||
static void ril_devinfo_query_revision_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
@@ -73,7 +82,7 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
res = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", res);
|
||||
DBG_(cbd->di, "%s", res);
|
||||
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
|
||||
g_free(res);
|
||||
} else {
|
||||
@@ -86,23 +95,46 @@ static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG("");
|
||||
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
|
||||
ril_devinfo_query_cb, ril_devinfo_cbd_free,
|
||||
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 gboolean ril_devinfo_query_serial_cb(void *user_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;
|
||||
|
||||
GASSERT(di->imei_id);
|
||||
di->imei_id = 0;
|
||||
|
||||
DBG_(di, "%s", di->imei);
|
||||
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -111,29 +143,28 @@ static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
GASSERT(!di->imei_id);
|
||||
if (di->imei_id) {
|
||||
g_source_remove(di->imei_id);
|
||||
di->imei_id = 0;
|
||||
}
|
||||
|
||||
DBG("%s", di->imei);
|
||||
di->imei_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_devinfo_query_serial_cb,
|
||||
ril_devinfo_cbd_new(di, cb, data),
|
||||
ril_devinfo_cbd_free);
|
||||
DBG_(di, "");
|
||||
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
|
||||
ril_devinfo_query_serial_cb, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_devinfo_register(gpointer user_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->register_id = 0;
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_register(di->info);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
@@ -142,13 +173,18 @@ static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
|
||||
|
||||
DBG("%s %s %p", ril_modem_get_path(modem), modem->imei, di);
|
||||
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->register_id = g_idle_add(ril_devinfo_register, di);
|
||||
di->iq = gutil_idle_queue_new();
|
||||
gutil_idle_queue_add(di->iq, ril_devinfo_register, di);
|
||||
ofono_devinfo_set_data(info, di);
|
||||
return 0;
|
||||
}
|
||||
@@ -157,19 +193,14 @@ static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG("%p", di);
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_set_data(info, NULL);
|
||||
|
||||
if (di->register_id > 0) {
|
||||
g_source_remove(di->register_id);
|
||||
}
|
||||
|
||||
if (di->imei_id > 0) {
|
||||
g_source_remove(di->imei_id);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -178,10 +209,11 @@ const struct ofono_devinfo_driver ril_devinfo_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_devinfo_probe,
|
||||
.remove = ril_devinfo_remove,
|
||||
.query_manufacturer = ril_devinfo_query_unsupported,
|
||||
/* 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_serial = ril_devinfo_query_serial,
|
||||
.query_svn = ril_devinfo_query_svn
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,14 +17,15 @@
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_mtu.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))
|
||||
|
||||
@@ -42,8 +43,8 @@ struct ril_gprs_context {
|
||||
struct ril_network *network;
|
||||
struct ril_data *data;
|
||||
guint active_ctx_cid;
|
||||
gulong calls_changed_event_id;
|
||||
struct ril_mtu_watch *mtu_watch;
|
||||
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;
|
||||
@@ -55,53 +56,32 @@ static inline struct ril_gprs_context *ril_gprs_context_get_data(
|
||||
return ofono_gprs_context_get_data(gprs);
|
||||
}
|
||||
|
||||
static char *ril_gprs_context_netmask(const char *address)
|
||||
static char *ril_gprs_context_netmask(const char *bits)
|
||||
{
|
||||
if (address) {
|
||||
const char *suffix = strchr(address, '/');
|
||||
if (suffix) {
|
||||
int nbits = atoi(suffix + 1);
|
||||
if (nbits > 0 && nbits < 33) {
|
||||
const char* str;
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||
((1 << nbits)-1) << (32-nbits));
|
||||
str = inet_ntoa(in);
|
||||
if (str) {
|
||||
return g_strdup(str);
|
||||
}
|
||||
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 g_strdup("255.255.255.0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_ipv4(struct ofono_gprs_context *gc,
|
||||
char * const *ip_addr)
|
||||
static int ril_gprs_context_address_family(const char *addr)
|
||||
{
|
||||
const guint n = gutil_strv_length(ip_addr);
|
||||
|
||||
if (n > 0) {
|
||||
ofono_gprs_context_set_ipv4_address(gc, ip_addr[0], TRUE);
|
||||
if (n > 1) {
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, ip_addr[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_ipv6(struct ofono_gprs_context *gc,
|
||||
char * const *ipv6_addr)
|
||||
{
|
||||
const guint n = gutil_strv_length(ipv6_addr);
|
||||
|
||||
if (n > 0) {
|
||||
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr[0]);
|
||||
if (n > 1) {
|
||||
const int p = atoi(ipv6_addr[1]);
|
||||
if (p > 0 && p <= 128) {
|
||||
ofono_gprs_context_set_ipv6_prefix_length(gc, p);
|
||||
}
|
||||
}
|
||||
if (strchr(addr, ':')) {
|
||||
return AF_INET6;
|
||||
} else if (strchr(addr, '.')) {
|
||||
return AF_INET;
|
||||
} else {
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,12 +91,12 @@ static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = NULL;
|
||||
}
|
||||
if (gcd->calls_changed_event_id) {
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
|
||||
gcd->calls_changed_event_id = 0;
|
||||
if (gcd->calls_changed_id) {
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id = 0;
|
||||
}
|
||||
if (gcd->mtu_watch) {
|
||||
ril_mtu_watch_free(gcd->mtu_watch);
|
||||
mtu_watch_free(gcd->mtu_watch);
|
||||
gcd->mtu_watch = NULL;
|
||||
}
|
||||
}
|
||||
@@ -128,9 +108,9 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = ril_data_call_dup(call);
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = ril_mtu_watch_new(MAX_MTU);
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||
}
|
||||
ril_mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
} else {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
}
|
||||
@@ -174,97 +154,161 @@ static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_split_ip_by_protocol(char **ip_array,
|
||||
char ***split_ip_addr,
|
||||
char ***split_ipv6_addr)
|
||||
static void ril_gprs_context_set_address(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const int n = gutil_strv_length(ip_array);
|
||||
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;
|
||||
|
||||
*split_ipv6_addr = *split_ip_addr = NULL;
|
||||
for (i = 0; i < n && (!*split_ipv6_addr || !*split_ip_addr); i++) {
|
||||
const char *addr = ip_array[i];
|
||||
switch (ril_address_family(addr)) {
|
||||
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 (!*split_ip_addr) {
|
||||
char *mask = ril_gprs_context_netmask(addr);
|
||||
*split_ip_addr = g_strsplit(addr, "/", 2);
|
||||
if (gutil_strv_length(*split_ip_addr) == 2) {
|
||||
g_free((*split_ip_addr)[1]);
|
||||
(*split_ip_addr)[1] = mask;
|
||||
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 {
|
||||
/* This is rather unlikely to happen */
|
||||
*split_ip_addr =
|
||||
gutil_strv_add(*split_ip_addr,
|
||||
mask);
|
||||
g_free(mask);
|
||||
ip_addr = addr;
|
||||
}
|
||||
if (!ip_mask) {
|
||||
ip_mask = g_strdup("255.255.255.0");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!*split_ipv6_addr) {
|
||||
*split_ipv6_addr = g_strsplit(addr, "/", 2);
|
||||
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_split_gw_by_protocol(char **gw_array, char **ip_gw,
|
||||
char **ipv6_gw)
|
||||
static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const int n = gutil_strv_length(gw_array);
|
||||
const char *ip_gw = NULL;
|
||||
const char *ipv6_gw = NULL;
|
||||
char * const *list = call->gateways;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
*ip_gw = *ipv6_gw = NULL;
|
||||
for (i = 0; i < n && (!*ipv6_gw || !*ip_gw); i++) {
|
||||
const char *gw_addr = gw_array[i];
|
||||
switch (ril_address_family(gw_addr)) {
|
||||
/* 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 = g_strdup(gw_addr);
|
||||
if (!ip_gw) ip_gw = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!*ipv6_gw) *ipv6_gw = g_strdup(gw_addr);
|
||||
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_split_dns_by_protocol(char **dns_array, char ***dns_addr,
|
||||
char ***dns_ipv6_addr)
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const int n = gutil_strv_length(dns_array);
|
||||
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;
|
||||
|
||||
*dns_ipv6_addr = *dns_addr = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *addr = dns_array[i];
|
||||
switch (ril_address_family(addr)) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
*dns_addr = gutil_strv_add(*dns_addr, addr);
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
*dns_ipv6_addr = gutil_strv_add(*dns_ipv6_addr, addr);
|
||||
*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 */
|
||||
static gboolean ril_gprs_context_data_call_equal(
|
||||
#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 TRUE;
|
||||
return 0;
|
||||
} else if (c1 && c2) {
|
||||
return c1->cid == c2->cid &&
|
||||
c1->active == c2->active && c1->prot == c2->prot &&
|
||||
!g_strcmp0(c1->ifname, c2->ifname) &&
|
||||
gutil_strv_equal(c1->dnses, c2->dnses) &&
|
||||
gutil_strv_equal(c1->gateways, c2->gateways) &&
|
||||
gutil_strv_equal(c1->addresses, c2->addresses);
|
||||
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 FALSE;
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,30 +325,25 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
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) {
|
||||
/* Check if the call has been disconnected */
|
||||
if (call->active == RIL_DATA_CALL_INACTIVE) {
|
||||
ofono_error("Clearing active context");
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
call = NULL;
|
||||
|
||||
if (call && call->active != RIL_DATA_CALL_INACTIVE) {
|
||||
/* Compare it against the last known state */
|
||||
} else if (ril_gprs_context_data_call_equal(call, prev_call)) {
|
||||
DBG("call %u didn't change", call->cid);
|
||||
call = NULL;
|
||||
|
||||
} else {
|
||||
DBG("call %u changed", call->cid);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -319,102 +358,27 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
ofono_info("data call status: %d", call->status);
|
||||
}
|
||||
|
||||
if (call->active == RIL_DATA_CALL_ACTIVE) {
|
||||
gboolean signal = FALSE;
|
||||
|
||||
if (call->ifname && g_strcmp0(call->ifname, prev_call->ifname)) {
|
||||
DBG("interface changed");
|
||||
signal = TRUE;
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(call->addresses, prev_call->addresses)) {
|
||||
char **split_ip_addr = NULL;
|
||||
char **split_ipv6_addr = NULL;
|
||||
|
||||
DBG("address changed");
|
||||
signal = TRUE;
|
||||
|
||||
/* Pick 1 address of each protocol */
|
||||
ril_gprs_split_ip_by_protocol(call->addresses,
|
||||
&split_ip_addr, &split_ipv6_addr);
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
|
||||
split_ipv6_addr) {
|
||||
ril_gprs_context_set_ipv6(gc, split_ipv6_addr);
|
||||
}
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IP) &&
|
||||
split_ip_addr) {
|
||||
ril_gprs_context_set_ipv4(gc, split_ip_addr);
|
||||
}
|
||||
|
||||
g_strfreev(split_ip_addr);
|
||||
g_strfreev(split_ipv6_addr);
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(call->gateways, prev_call->gateways)){
|
||||
char *ip_gw = NULL;
|
||||
char *ipv6_gw = NULL;
|
||||
|
||||
DBG("gateway changed");
|
||||
signal = TRUE;
|
||||
|
||||
/* Pick 1 gw for each protocol*/
|
||||
ril_gprs_split_gw_by_protocol(call->gateways,
|
||||
&ip_gw, &ipv6_gw);
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
|
||||
ipv6_gw) {
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IP) &&
|
||||
ip_gw) {
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
}
|
||||
|
||||
g_free(ip_gw);
|
||||
g_free(ipv6_gw);
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(call->dnses, prev_call->dnses)){
|
||||
char **dns_ip = NULL;
|
||||
char **dns_ipv6 = NULL;
|
||||
|
||||
DBG("name server(s) changed");
|
||||
signal = TRUE;
|
||||
|
||||
/* split based on protocol*/
|
||||
ril_gprs_split_dns_by_protocol(call->dnses,
|
||||
&dns_ip, &dns_ipv6);
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
|
||||
dns_ipv6) {
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc,
|
||||
(const char **) dns_ipv6);
|
||||
}
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IP) && dns_ip) {
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc,
|
||||
(const char**)dns_ip);
|
||||
}
|
||||
|
||||
g_strfreev(dns_ip);
|
||||
g_strfreev(dns_ipv6);
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
}
|
||||
if (change & DATA_CALL_IFNAME_CHANGED) {
|
||||
DBG("interface changed");
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_ADDRESS_CHANGED) {
|
||||
DBG("address changed");
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_GATEWAY_CHANGED) {
|
||||
DBG("gateway changed");
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_DNS_CHANGED) {
|
||||
DBG("name server(s) changed");
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
|
||||
@@ -425,12 +389,6 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
struct ofono_error error;
|
||||
char **split_ip_addr = NULL;
|
||||
char **split_ipv6_addr = NULL;
|
||||
char* ip_gw = NULL;
|
||||
char* ipv6_gw = NULL;
|
||||
char** dns_addr = NULL;
|
||||
char** dns_ipv6_addr = NULL;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer cb_data;
|
||||
|
||||
@@ -438,80 +396,40 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("GPRS context: Reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (call->status != PDP_FAIL_NONE) {
|
||||
} 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;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Must have interface */
|
||||
if (!call->ifname) {
|
||||
} else if (!call->ifname) {
|
||||
/* Must have interface */
|
||||
ofono_error("GPRS context: No interface");
|
||||
goto done;
|
||||
} 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);
|
||||
}
|
||||
|
||||
ofono_info("setting up data call");
|
||||
|
||||
/* Check the ip address */
|
||||
ril_gprs_split_ip_by_protocol(call->addresses, &split_ip_addr,
|
||||
&split_ipv6_addr);
|
||||
if (!split_ip_addr && !split_ipv6_addr) {
|
||||
ofono_error("GPRS context: No IP address");
|
||||
goto done;
|
||||
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
}
|
||||
|
||||
ril_error_init_ok(&error);
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
|
||||
GASSERT(!gcd->calls_changed_event_id);
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
|
||||
gcd->calls_changed_event_id =
|
||||
ril_data_add_calls_changed_handler(gcd->data,
|
||||
ril_gprs_context_call_list_changed, gcd);
|
||||
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
ril_gprs_split_gw_by_protocol(call->gateways, &ip_gw, &ipv6_gw);
|
||||
ril_gprs_split_dns_by_protocol(call->dnses, &dns_addr, &dns_ipv6_addr);
|
||||
|
||||
if (split_ipv6_addr &&
|
||||
(call->prot == OFONO_GPRS_PROTO_IPV6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV4V6)) {
|
||||
ril_gprs_context_set_ipv6(gc, split_ipv6_addr);
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc,
|
||||
(const char **) dns_ipv6_addr);
|
||||
}
|
||||
|
||||
if (split_ip_addr &&
|
||||
(call->prot == OFONO_GPRS_PROTO_IP ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV4V6)) {
|
||||
ril_gprs_context_set_ipv4(gc, split_ip_addr);
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc,
|
||||
(const char **) dns_addr);
|
||||
}
|
||||
|
||||
done:
|
||||
g_strfreev(split_ip_addr);
|
||||
g_strfreev(split_ipv6_addr);
|
||||
g_strfreev(dns_addr);
|
||||
g_strfreev(dns_ipv6_addr);
|
||||
g_free(ip_gw);
|
||||
g_free(ipv6_gw);
|
||||
|
||||
cb = gcd->activate.cb;
|
||||
cb_data = gcd->activate.data;
|
||||
GASSERT(gcd->activate.req);
|
||||
memset(&gcd->activate, 0, sizeof(gcd->activate));
|
||||
|
||||
if (cb) {
|
||||
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
}
|
||||
cb(&error, cb_data);
|
||||
}
|
||||
}
|
||||
@@ -527,18 +445,18 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
/* 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) &&
|
||||
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 %d (roaming)",
|
||||
ofono_info("Can't activate context %u (roaming)",
|
||||
ctx->cid);
|
||||
cb(ril_error_failure(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Activating context: %d", ctx->cid);
|
||||
ofono_info("Activating context: %u", ctx->cid);
|
||||
GASSERT(!gcd->activate.req);
|
||||
GASSERT(ctx->cid != CTX_ID_NONE);
|
||||
|
||||
@@ -592,7 +510,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivate primary");
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
gcd->deactivate.cb = cb;
|
||||
@@ -609,7 +527,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int id)
|
||||
{
|
||||
DBG("%d", id);
|
||||
DBG("%u", id);
|
||||
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -654,11 +572,11 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
|
||||
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);
|
||||
ril_mtu_watch_free(gcd->mtu_watch);
|
||||
mtu_watch_free(gcd->mtu_watch);
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_mce.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
/* <mce/dbus-names.h> */
|
||||
#define MCE_SERVICE "com.nokia.mce"
|
||||
#define MCE_SIGNAL_IF "com.nokia.mce.signal"
|
||||
#define MCE_REQUEST_IF "com.nokia.mce.request"
|
||||
#define MCE_REQUEST_PATH "/com/nokia/mce/request"
|
||||
#define MCE_DISPLAY_STATUS_GET "get_display_status"
|
||||
#define MCE_DISPLAY_SIG "display_status_ind"
|
||||
#define MCE_DISPLAY_DIM_STRING "dimmed"
|
||||
#define MCE_DISPLAY_ON_STRING "on"
|
||||
#define MCE_DISPLAY_OFF_STRING "off"
|
||||
|
||||
typedef GObjectClass RilMceClass;
|
||||
typedef struct ril_mce RilMce;
|
||||
|
||||
struct ril_mce_priv {
|
||||
GRilIoChannel *io;
|
||||
DBusConnection *conn;
|
||||
DBusPendingCall *req;
|
||||
guint daemon_watch;
|
||||
guint signal_watch;
|
||||
};
|
||||
|
||||
enum ril_mce_signal {
|
||||
SIGNAL_DISPLAY_STATE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_DISPLAY_STATE_CHANGED_NAME "ril-mce-display-state-changed"
|
||||
|
||||
static guint ril_mce_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilMce, ril_mce, G_TYPE_OBJECT)
|
||||
#define RIL_MCE_TYPE (ril_mce_get_type())
|
||||
#define RIL_MCE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_MCE_TYPE,RilMce))
|
||||
|
||||
static const char *ril_mce_display_state_string(enum ril_mce_display_state ds)
|
||||
{
|
||||
switch (ds) {
|
||||
case RIL_MCE_DISPLAY_OFF:
|
||||
return MCE_DISPLAY_OFF_STRING;
|
||||
case RIL_MCE_DISPLAY_DIM:
|
||||
return MCE_DISPLAY_DIM_STRING;
|
||||
case RIL_MCE_DISPLAY_ON:
|
||||
return MCE_DISPLAY_ON_STRING;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static enum ril_mce_display_state ril_mce_parse_display_state(DBusMessage *msg)
|
||||
{
|
||||
DBusMessageIter it;
|
||||
|
||||
if (dbus_message_iter_init(msg, &it) &&
|
||||
dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_STRING) {
|
||||
const char *value = NULL;
|
||||
|
||||
dbus_message_iter_get_basic(&it, &value);
|
||||
if (!g_strcmp0(value, MCE_DISPLAY_OFF_STRING)) {
|
||||
return RIL_MCE_DISPLAY_OFF;
|
||||
} else if (!g_strcmp0(value, MCE_DISPLAY_DIM_STRING)) {
|
||||
return RIL_MCE_DISPLAY_DIM;
|
||||
} else {
|
||||
GASSERT(!g_strcmp0(value, MCE_DISPLAY_ON_STRING));
|
||||
}
|
||||
}
|
||||
|
||||
return RIL_MCE_DISPLAY_ON;
|
||||
}
|
||||
|
||||
static void ril_mce_update_display_state(struct ril_mce *self,
|
||||
enum ril_mce_display_state state)
|
||||
{
|
||||
if (self->display_state != state) {
|
||||
self->display_state = state;
|
||||
g_signal_emit(self, ril_mce_signals[
|
||||
SIGNAL_DISPLAY_STATE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_mce_display_changed(DBusConnection *conn,
|
||||
DBusMessage *msg, void *user_data)
|
||||
{
|
||||
enum ril_mce_display_state state = ril_mce_parse_display_state(msg);
|
||||
|
||||
DBG("%s", ril_mce_display_state_string(state));
|
||||
ril_mce_update_display_state(RIL_MCE(user_data), state);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ril_mce_display_status_reply(DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
struct ril_mce *self = RIL_MCE(user_data);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
enum ril_mce_display_state state = ril_mce_parse_display_state(reply);
|
||||
|
||||
GASSERT(priv->req);
|
||||
dbus_message_unref(reply);
|
||||
dbus_pending_call_unref(priv->req);
|
||||
priv->req = NULL;
|
||||
|
||||
DBG("%s", ril_mce_display_state_string(state));
|
||||
ril_mce_update_display_state(self, state);
|
||||
}
|
||||
|
||||
static void ril_mce_connect(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
struct ril_mce *self = RIL_MCE(user_data);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
DBG("");
|
||||
if (!priv->req) {
|
||||
DBusMessage *msg = dbus_message_new_method_call(MCE_SERVICE,
|
||||
MCE_REQUEST_PATH, MCE_REQUEST_IF,
|
||||
MCE_DISPLAY_STATUS_GET);
|
||||
if (g_dbus_send_message_with_reply(conn, msg, &priv->req, -1)) {
|
||||
dbus_pending_call_set_notify(priv->req,
|
||||
ril_mce_display_status_reply,
|
||||
self, NULL);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
}
|
||||
if (!priv->signal_watch) {
|
||||
priv->signal_watch = g_dbus_add_signal_watch(conn,
|
||||
MCE_SERVICE, NULL, MCE_SIGNAL_IF, MCE_DISPLAY_SIG,
|
||||
ril_mce_display_changed, self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mce_disconnect(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
struct ril_mce *self = user_data;
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
DBG("");
|
||||
if (priv->signal_watch) {
|
||||
g_dbus_remove_watch(conn, priv->signal_watch);
|
||||
priv->signal_watch = 0;
|
||||
}
|
||||
if (priv->req) {
|
||||
dbus_pending_call_cancel(priv->req);
|
||||
dbus_pending_call_unref(priv->req);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_mce *ril_mce_new()
|
||||
{
|
||||
struct ril_mce *self = g_object_new(RIL_MCE_TYPE, NULL);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
DBG("");
|
||||
priv->daemon_watch = g_dbus_add_service_watch(priv->conn, MCE_SERVICE,
|
||||
ril_mce_connect, ril_mce_disconnect, self, NULL);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_mce *ril_mce_ref(struct ril_mce *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_MCE(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_mce_unref(struct ril_mce *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_MCE(self));
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_mce_add_display_state_changed_handler(struct ril_mce *self,
|
||||
ril_mce_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_DISPLAY_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_mce_remove_handler(struct ril_mce *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mce_init(struct ril_mce *self)
|
||||
{
|
||||
struct ril_mce_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_MCE_TYPE, struct ril_mce_priv);
|
||||
|
||||
priv->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
self->priv = priv;
|
||||
}
|
||||
|
||||
static void ril_mce_dispose(GObject *object)
|
||||
{
|
||||
struct ril_mce *self = RIL_MCE(object);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
if (priv->signal_watch) {
|
||||
g_dbus_remove_watch(priv->conn, priv->signal_watch);
|
||||
priv->signal_watch = 0;
|
||||
}
|
||||
if (priv->daemon_watch) {
|
||||
g_dbus_remove_watch(priv->conn, priv->daemon_watch);
|
||||
priv->daemon_watch = 0;
|
||||
}
|
||||
if (priv->req) {
|
||||
dbus_pending_call_cancel(priv->req);
|
||||
dbus_pending_call_unref(priv->req);
|
||||
}
|
||||
G_OBJECT_CLASS(ril_mce_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_mce_finalize(GObject *object)
|
||||
{
|
||||
struct ril_mce *self = RIL_MCE(object);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
dbus_connection_unref(priv->conn);
|
||||
G_OBJECT_CLASS(ril_mce_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_mce_class_init(RilMceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_mce_dispose;
|
||||
object_class->finalize = ril_mce_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_mce_priv));
|
||||
ril_mce_signals[SIGNAL_DISPLAY_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_DISPLAY_STATE_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_MCE_H
|
||||
#define RIL_MCE_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
enum ril_mce_display_state {
|
||||
RIL_MCE_DISPLAY_OFF,
|
||||
RIL_MCE_DISPLAY_DIM,
|
||||
RIL_MCE_DISPLAY_ON
|
||||
};
|
||||
|
||||
struct ril_mce_priv;
|
||||
struct ril_mce {
|
||||
GObject object;
|
||||
struct ril_mce_priv *priv;
|
||||
enum ril_mce_display_state display_state;
|
||||
};
|
||||
|
||||
struct ril_mce *ril_mce_new(void);
|
||||
struct ril_mce *ril_mce_ref(struct ril_mce *mce);
|
||||
void ril_mce_unref(struct ril_mce *mce);
|
||||
|
||||
typedef void (*ril_mce_cb_t)(struct ril_mce *mce, void *arg);
|
||||
gulong ril_mce_add_display_state_changed_handler(struct ril_mce *mce,
|
||||
ril_mce_cb_t cb, void *arg);
|
||||
void ril_mce_remove_handler(struct ril_mce *mce, gulong id);
|
||||
|
||||
#endif /* RIL_MCE_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,12 +18,15 @@
|
||||
#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 */
|
||||
|
||||
@@ -49,29 +52,26 @@ struct ril_modem_online_request {
|
||||
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
struct sailfish_watch *watch;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_radio_settings *radio_settings;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gboolean pre_sim_done;
|
||||
gboolean allow_data;
|
||||
gulong imsi_event_id;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
gulong radio_state_event_id;
|
||||
|
||||
ril_modem_cb_t removed_cb;
|
||||
void *removed_cb_data;
|
||||
|
||||
ril_modem_online_cb_t online_cb;
|
||||
void *online_cb_data;
|
||||
|
||||
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);
|
||||
@@ -79,11 +79,6 @@ static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||
return md;
|
||||
}
|
||||
|
||||
static struct ril_modem_data *ril_modem_data_from_modem(struct ril_modem *m)
|
||||
{
|
||||
return m ? G_CAST(m, struct ril_modem_data, modem) : NULL;
|
||||
}
|
||||
|
||||
static void *ril_modem_get_atom_data(struct ril_modem *modem,
|
||||
enum ofono_atom_type type)
|
||||
{
|
||||
@@ -114,6 +109,12 @@ 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) {
|
||||
@@ -121,24 +122,6 @@ void ril_modem_delete(struct ril_modem *md)
|
||||
}
|
||||
}
|
||||
|
||||
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
|
||||
|
||||
md->removed_cb = cb;
|
||||
md->removed_cb_data = data;
|
||||
}
|
||||
|
||||
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
|
||||
|
||||
md->online_cb = cb;
|
||||
md->online_cb_data = data;
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
@@ -222,17 +205,23 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
if (md->modem.radio->state == RADIO_STATE_ON) {
|
||||
if (!md->radio_settings) {
|
||||
DBG("Initializing radio settings interface");
|
||||
md->radio_settings =
|
||||
ofono_radio_settings_create(md->modem.ofono, 0,
|
||||
RILMODEM_DRIVER, 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");
|
||||
}
|
||||
} else if (md->radio_settings) {
|
||||
DBG("Removing radio settings interface");
|
||||
ofono_radio_settings_remove(md->radio_settings);
|
||||
md->radio_settings = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,16 +234,24 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
ril_modem_update_radio_settings(md);
|
||||
}
|
||||
|
||||
static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->pre_sim_done = TRUE;
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ril_modem_update_radio_settings(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,
|
||||
@@ -288,6 +285,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||
}
|
||||
|
||||
@@ -300,26 +298,25 @@ static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
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");
|
||||
|
||||
if (md->online_cb) {
|
||||
md->online_cb(&md->modem, online, md->online_cb_data);
|
||||
}
|
||||
|
||||
ril_radio_set_online(radio, online);
|
||||
if (online) {
|
||||
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_online;
|
||||
} else {
|
||||
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_power_off(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_offline;
|
||||
}
|
||||
|
||||
@@ -368,20 +365,15 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
if (md->removed_cb) {
|
||||
ril_modem_cb_t cb = md->removed_cb;
|
||||
void *data = md->removed_cb_data;
|
||||
|
||||
md->removed_cb = NULL;
|
||||
md->removed_cb_data = NULL;
|
||||
cb(modem, data);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -397,23 +389,28 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
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 struct ril_slot_info *slot, struct ril_radio *radio,
|
||||
struct ril_network *network, struct ril_sim_card *card,
|
||||
struct ril_data *data, struct ril_sim_settings *settings)
|
||||
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(slot->path + 1,
|
||||
struct ofono_modem *ofono = ofono_modem_create(path + 1,
|
||||
RILMODEM_DRIVER);
|
||||
if (ofono) {
|
||||
int err;
|
||||
@@ -424,23 +421,32 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
* ril_plugin.c must wait until IMEI becomes known before
|
||||
* creating the modem
|
||||
*/
|
||||
GASSERT(slot->imei);
|
||||
GASSERT(imei);
|
||||
|
||||
/* Copy config */
|
||||
modem->config = *slot->config;
|
||||
modem->imei = md->imei = g_strdup(slot->imei);
|
||||
modem->log_prefix = log_prefix;
|
||||
modem->ecclist_file =
|
||||
md->ecclist_file = g_strdup(slot->ecclist_file);
|
||||
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);
|
||||
@@ -456,6 +462,17 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
ofono_modem_set_powered(modem->ofono, FALSE);
|
||||
ofono_modem_set_powered(modem->ofono, TRUE);
|
||||
md->power_state = POWERED_ON;
|
||||
|
||||
/*
|
||||
* With some RIL implementations, querying available
|
||||
* band modes causes some magic Android properties to
|
||||
* appear. Otherwise this request is pretty harmless
|
||||
* and useless.
|
||||
*/
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
} else {
|
||||
ofono_error("Error %d registering %s",
|
||||
|
||||
203
ofono/drivers/ril/ril_netmon.c
Normal file
203
ofono/drivers/ril/ril_netmon.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
struct ril_netmon {
|
||||
struct ofono_netmon *netmon;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
guint register_id;
|
||||
};
|
||||
|
||||
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
||||
{
|
||||
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
{
|
||||
s_mcc[0] = 0;
|
||||
s_mnc[0] = 0;
|
||||
|
||||
if (mcc >= 0 && mcc <= 999) {
|
||||
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
|
||||
if (mnc >= 0 && mnc <= 999) {
|
||||
const unsigned int mnclen = mnclength(mcc, mnc);
|
||||
const char *format[] = { "%d", "%02d", "%03d" };
|
||||
const char *fmt = (mnclen > 0 &&
|
||||
mnclen <= G_N_ELEMENTS(format)) ?
|
||||
format[mnclen - 1] : format[0];
|
||||
snprintf(s_mnc, OFONO_MAX_MNC_LENGTH + 1, fmt, mnc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_gsm *gsm)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, gsm->mcc, gsm->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_GSM,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_LAC, gsm->lac,
|
||||
OFONO_NETMON_INFO_CI, gsm->cid,
|
||||
OFONO_NETMON_INFO_RSSI, gsm->signalStrength,
|
||||
OFONO_NETMON_INFO_BER, gsm->bitErrorRate,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_wcdma *wcdma)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, wcdma->mcc, wcdma->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_UMTS,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_LAC, wcdma->lac,
|
||||
OFONO_NETMON_INFO_CI, wcdma->cid,
|
||||
OFONO_NETMON_INFO_PSC, wcdma->psc,
|
||||
OFONO_NETMON_INFO_RSSI, wcdma->signalStrength,
|
||||
OFONO_NETMON_INFO_BER, wcdma->bitErrorRate,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||
const struct sailfish_cell_info_lte *lte)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
|
||||
ril_netmon_format_mccmnc(mcc, mnc, lte->mcc, lte->mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_LTE,
|
||||
OFONO_NETMON_INFO_MCC, mcc,
|
||||
OFONO_NETMON_INFO_MNC, mnc,
|
||||
OFONO_NETMON_INFO_CI, lte->ci,
|
||||
OFONO_NETMON_INFO_RSSI, lte->signalStrength,
|
||||
OFONO_NETMON_INFO_TIMING_ADVANCE, lte->timingAdvance,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
}
|
||||
|
||||
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||
struct ofono_error error;
|
||||
GSList *l;
|
||||
|
||||
for (l = nm->cell_info->cells; l; l = l->next) {
|
||||
const struct sailfish_cell *cell = l->data;
|
||||
|
||||
if (cell->registered) {
|
||||
switch (cell->type) {
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
ril_netmon_notify_gsm(netmon,
|
||||
&cell->info.gsm);
|
||||
break;
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
ril_netmon_notify_wcdma(netmon,
|
||||
&cell->info.wcdma);
|
||||
break;
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
ril_netmon_notify_lte(netmon,
|
||||
&cell->info.lte);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
static gboolean ril_netmon_register(gpointer user_data)
|
||||
{
|
||||
struct ril_netmon *nm = user_data;
|
||||
|
||||
GASSERT(nm->register_id);
|
||||
nm->register_id = 0;
|
||||
ofono_netmon_register(nm->netmon);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
int ret;
|
||||
|
||||
if (modem->cell_info) {
|
||||
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
|
||||
|
||||
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
|
||||
nm->netmon = netmon;
|
||||
|
||||
ofono_netmon_set_data(netmon, nm);
|
||||
nm->register_id = g_idle_add(ril_netmon_register, nm);
|
||||
ret = 0;
|
||||
} else {
|
||||
DBG("%s no", modem->log_prefix ? modem->log_prefix : "");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
DBG("%s %d", modem->log_prefix ? modem->log_prefix : "", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ril_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
|
||||
if (nm->register_id > 0) {
|
||||
g_source_remove(nm->register_id);
|
||||
}
|
||||
|
||||
sailfish_cell_info_unref(nm->cell_info);
|
||||
g_slice_free(struct ril_netmon, nm);
|
||||
}
|
||||
|
||||
const struct ofono_netmon_driver ril_netmon_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_netmon_probe,
|
||||
.remove = ril_netmon_remove,
|
||||
.request_update = ril_netmon_request_update,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -499,7 +499,7 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
DBG("%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -47,12 +47,17 @@ enum ril_network_radio_event {
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_unsol_event {
|
||||
UNSOL_EVENT_NETWORK_STATE,
|
||||
UNSOL_EVENT_RADIO_CAPABILITY,
|
||||
UNSOL_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
enum ofono_radio_access_mode max_pref_mode;
|
||||
int rat;
|
||||
char *log_prefix;
|
||||
guint operator_poll_id;
|
||||
@@ -61,11 +66,12 @@ struct ril_network_priv {
|
||||
guint timer[TIMER_COUNT];
|
||||
gulong query_rat_id;
|
||||
gulong set_rat_id;
|
||||
gulong ril_event_id;
|
||||
gulong unsol_event_id[UNSOL_EVENT_COUNT];
|
||||
gulong settings_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
};
|
||||
|
||||
enum ril_network_signal {
|
||||
@@ -73,13 +79,15 @@ enum ril_network_signal {
|
||||
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_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 };
|
||||
|
||||
@@ -196,12 +204,18 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
* supply some reasonable default. We don't need more than 2
|
||||
* simultaneous data calls anyway.
|
||||
*/
|
||||
if (nparams <= 5) {
|
||||
if (reg->max_calls < 1) {
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
|
||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
||||
if (!ril_parse_int(slac, 16, ®->lac)) {
|
||||
reg->lac = -1;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(sci, 16, ®->ci)) {
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
||||
@@ -420,13 +434,16 @@ static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (self->settings->enable_4g) {
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
return PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
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;
|
||||
}
|
||||
@@ -436,9 +453,30 @@ 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;
|
||||
const enum ofono_radio_access_mode pref_mode = priv->max_pref_mode ?
|
||||
MIN(settings->pref_mode, priv->max_pref_mode) :
|
||||
settings->pref_mode;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@@ -465,7 +503,7 @@ static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
* and SIM card state change callbacks will schedule a new check
|
||||
* when it's appropriate.
|
||||
*/
|
||||
if (priv->rat != rat) {
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
@@ -506,6 +544,9 @@ static void ril_network_set_pref_mode(struct ril_network *self, int rat)
|
||||
ril_network_set_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* Don't do it too often */
|
||||
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
@@ -533,8 +574,7 @@ static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (priv->rat != rat) {
|
||||
/* Something isn't right, we need to fix it */
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
@@ -555,6 +595,31 @@ static int ril_network_parse_pref_resp(const void *data, guint len)
|
||||
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)
|
||||
{
|
||||
@@ -598,17 +663,25 @@ void ril_network_set_max_pref_mode(struct ril_network *self,
|
||||
enum ofono_radio_access_mode max_mode,
|
||||
gboolean force_check)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
if (priv->max_pref_mode != max_mode || 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));
|
||||
priv->max_pref_mode = max_mode;
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
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)
|
||||
{
|
||||
@@ -637,6 +710,13 @@ gulong ril_network_add_pref_mode_changed_handler(struct ril_network *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)) {
|
||||
@@ -649,7 +729,7 @@ void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
|
||||
gutil_disconnect_handlers(self, ids, n);
|
||||
}
|
||||
|
||||
static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
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);
|
||||
@@ -659,10 +739,23 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
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(RIL_NETWORK(data));
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,8 +811,9 @@ static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card,
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings)
|
||||
{
|
||||
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
@@ -733,9 +827,14 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->ril_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_voice_state_changed_cb,
|
||||
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);
|
||||
@@ -753,6 +852,9 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
* 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);
|
||||
}
|
||||
@@ -788,57 +890,45 @@ static void ril_network_init(struct ril_network *self)
|
||||
priv->rat = -1;
|
||||
}
|
||||
|
||||
static void ril_network_dispose(GObject *object)
|
||||
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;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, &priv->ril_event_id, 1);
|
||||
ril_radio_remove_handlers(priv->radio, priv->radio_event_id,
|
||||
G_N_ELEMENTS(priv->radio_event_id));
|
||||
ril_sim_settings_remove_handlers(self->settings,
|
||||
&priv->settings_event_id, 1);
|
||||
ril_sim_card_remove_handlers(priv->sim_card,
|
||||
&priv->sim_status_event_id, 1);
|
||||
DBG_(self, "");
|
||||
|
||||
for (tid=0; tid<TIMER_COUNT; tid++) {
|
||||
ril_network_stop_timer(self, tid);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
priv->set_rat_id = 0;
|
||||
priv->query_rat_id = 0;
|
||||
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
|
||||
G_N_ELEMENTS(priv->unsol_event_id));
|
||||
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_network_finalize(GObject *object)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_handler(priv->sim_card,
|
||||
priv->sim_status_event_id);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
ril_sim_settings_remove_handler(self->settings,
|
||||
priv->settings_event_id);
|
||||
ril_sim_settings_unref(self->settings);
|
||||
g_free(priv->log_prefix);
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_network_class_init(RilNetworkClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_network_dispose;
|
||||
object_class->finalize = ril_network_finalize;
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
@@ -38,14 +36,16 @@ struct ril_network {
|
||||
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(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card,
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings);
|
||||
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
@@ -53,6 +53,7 @@ void ril_network_unref(struct ril_network *net);
|
||||
void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||
enum ofono_radio_access_mode max_pref_mode,
|
||||
gboolean force_check);
|
||||
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||
@@ -61,6 +62,8 @@ 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);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -24,7 +24,6 @@
|
||||
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
|
||||
|
||||
struct ril_oem_raw {
|
||||
struct ril_modem *modem;
|
||||
GRilIoQueue *q;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
@@ -118,7 +117,6 @@ struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
oem->modem = 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));
|
||||
@@ -144,8 +142,6 @@ void ril_oem_raw_free(struct ril_oem_raw *oem)
|
||||
DBG("%s", oem->path);
|
||||
g_dbus_unregister_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
ofono_modem_remove_interface(oem->modem->ofono,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
dbus_connection_unref(oem->conn);
|
||||
|
||||
grilio_queue_cancel_all(oem->q, TRUE);
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* Copyright (C) ST-Ericsson SA 2010.
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013 Jolla Ltd
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2016 Jolla Ltd
|
||||
* Contact: Jussi Kangas <jussi.kangas@tieto.com>
|
||||
* Copyright (C) 2014 Canonical Ltd
|
||||
*
|
||||
@@ -17,11 +17,6 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
@@ -31,24 +26,6 @@
|
||||
#include "simutil.h"
|
||||
#include "util.h"
|
||||
|
||||
struct cb_data {
|
||||
void *cb;
|
||||
void *data;
|
||||
void *user;
|
||||
};
|
||||
|
||||
static inline struct cb_data *cb_data_new(void *cb, void *data, void *user)
|
||||
{
|
||||
struct cb_data *ret;
|
||||
|
||||
ret = g_new0(struct cb_data, 1);
|
||||
ret->cb = cb;
|
||||
ret->data = data;
|
||||
ret->user = user;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CALLBACK_WITH_FAILURE(cb, args...) \
|
||||
do { \
|
||||
struct ofono_error cb_e; \
|
||||
@@ -155,6 +132,8 @@ struct pb_data {
|
||||
const unsigned char *df_path;
|
||||
guint register_id;
|
||||
size_t df_size;
|
||||
ofono_phonebook_cb_t cb;
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static void read_info_cb(int ok, unsigned char file_status,
|
||||
@@ -588,6 +567,20 @@ static void decode_read_response(const struct record_to_read *rec_data,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean free_entry(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
struct phonebook_entry *entry = value;
|
||||
|
||||
g_free(entry->name);
|
||||
g_free(entry->number);
|
||||
g_free(entry->email);
|
||||
g_free(entry->anr);
|
||||
g_free(entry->sne);
|
||||
g_free(entry);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean export_entry(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
struct ofono_phonebook *pb = data;
|
||||
@@ -602,29 +595,18 @@ static gboolean export_entry(gpointer key, gpointer value, gpointer data)
|
||||
entry->email,
|
||||
NULL, NULL);
|
||||
|
||||
g_free(entry->name);
|
||||
g_free(entry->number);
|
||||
g_free(entry->email);
|
||||
g_free(entry->anr);
|
||||
g_free(entry->sne);
|
||||
g_free(entry);
|
||||
|
||||
return FALSE;
|
||||
return free_entry(key, value, NULL);
|
||||
}
|
||||
|
||||
static void export_and_return(gboolean ok, struct cb_data *cbd)
|
||||
static void free_pb_refs(struct pb_data *pbd, GTraverseFunc entry_func,
|
||||
struct ofono_phonebook *pb)
|
||||
{
|
||||
struct ofono_phonebook *pb = cbd->user;
|
||||
ofono_phonebook_cb_t cb = cbd->cb;
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
GSList *l;
|
||||
|
||||
DBG("phonebook fully read");
|
||||
|
||||
for (l = pbd->pb_refs; l != NULL; l = l->next) {
|
||||
struct pb_ref_rec *ref = l->data;
|
||||
|
||||
g_tree_foreach(ref->phonebook, export_entry, pb);
|
||||
g_tree_foreach(ref->phonebook, entry_func, pb);
|
||||
g_tree_destroy(ref->phonebook);
|
||||
g_slist_free_full(ref->pending_records, g_free);
|
||||
g_slist_free_full(ref->pb_files, g_free);
|
||||
@@ -632,28 +614,38 @@ static void export_and_return(gboolean ok, struct cb_data *cbd)
|
||||
|
||||
g_slist_free_full(pbd->pb_refs, g_free);
|
||||
pbd->pb_refs = NULL;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
static void export_and_return(struct ofono_phonebook *pb, gboolean ok)
|
||||
{
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
|
||||
g_free(cbd);
|
||||
DBG("phonebook fully read");
|
||||
free_pb_refs(pbd, export_entry, pb);
|
||||
|
||||
if (pbd->cb) {
|
||||
if (ok) {
|
||||
CALLBACK_WITH_SUCCESS(pbd->cb, pbd->cb_data);
|
||||
} else {
|
||||
CALLBACK_WITH_FAILURE(pbd->cb, pbd->cb_data);
|
||||
}
|
||||
pbd->cb = NULL;
|
||||
pbd->cb_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_record_cb(int ok, int total_length, int record,
|
||||
const unsigned char *data,
|
||||
int record_length, void *userdata)
|
||||
{
|
||||
struct cb_data *cbd = userdata;
|
||||
struct ofono_phonebook *pb = cbd->user;
|
||||
struct ofono_phonebook *pb = userdata;
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
struct pb_ref_rec *ref = pbd->pb_ref_next->data;
|
||||
struct record_to_read *rec;
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("%s: error %d", __func__, ok);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -679,13 +671,13 @@ static void read_record_cb(int ok, int total_length, int record,
|
||||
rec->record,
|
||||
rec->record_length,
|
||||
pbd->df_path, pbd->df_size,
|
||||
read_record_cb, cbd);
|
||||
read_record_cb, pb);
|
||||
} else {
|
||||
/* Read files from next EF_PBR record, if any */
|
||||
|
||||
pbd->pb_ref_next = pbd->pb_ref_next->next;
|
||||
if (pbd->pb_ref_next == NULL) {
|
||||
export_and_return(TRUE, cbd);
|
||||
export_and_return(pb, TRUE);
|
||||
} else {
|
||||
struct pb_ref_rec *ref;
|
||||
|
||||
@@ -694,7 +686,7 @@ static void read_record_cb(int ok, int total_length, int record,
|
||||
ref = pbd->pb_ref_next->data;
|
||||
|
||||
if (!ref->pb_files) {
|
||||
export_and_return(TRUE, cbd);
|
||||
export_and_return(pb, TRUE);
|
||||
} else {
|
||||
struct pb_file_info *file_info;
|
||||
|
||||
@@ -705,7 +697,7 @@ static void read_record_cb(int ok, int total_length, int record,
|
||||
file_info->file_id,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pbd->df_path, pbd->df_size,
|
||||
read_info_cb, cbd);
|
||||
read_info_cb, pb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -715,15 +707,14 @@ static void pb_adn_cb(int ok, int total_length, int record,
|
||||
const unsigned char *data,
|
||||
int record_length, void *userdata)
|
||||
{
|
||||
struct cb_data *cbd = userdata;
|
||||
struct ofono_phonebook *pb = cbd->user;
|
||||
struct ofono_phonebook *pb = userdata;
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
struct pb_ref_rec *ref = pbd->pb_ref_next->data;
|
||||
GSList *l;
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("%s: error %d", __func__, ok);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -769,9 +760,9 @@ static void pb_adn_cb(int ok, int total_length, int record,
|
||||
rec->record,
|
||||
rec->record_length,
|
||||
pbd->df_path, pbd->df_size,
|
||||
read_record_cb, cbd);
|
||||
read_record_cb, pb);
|
||||
} else {
|
||||
export_and_return(TRUE, cbd);
|
||||
export_and_return(pb, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -780,8 +771,7 @@ static void read_info_cb(int ok, unsigned char file_status,
|
||||
int total_length, int record_length,
|
||||
void *userdata)
|
||||
{
|
||||
struct cb_data *cbd = userdata;
|
||||
struct ofono_phonebook *pb = cbd->user;
|
||||
struct ofono_phonebook *pb = userdata;
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
struct pb_file_info *file_info;
|
||||
struct pb_ref_rec *ref = pbd->pb_ref_next->data;
|
||||
@@ -804,7 +794,7 @@ static void read_info_cb(int ok, unsigned char file_status,
|
||||
if (ref->pb_next == NULL) {
|
||||
if (ref->pb_files == NULL) {
|
||||
ofono_warn("%s: no phonebook on SIM", __func__);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -814,20 +804,19 @@ static void read_info_cb(int ok, unsigned char file_status,
|
||||
ofono_sim_read_path(pbd->sim_context, file_info->file_id,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pbd->df_path, pbd->df_size,
|
||||
pb_adn_cb, cbd);
|
||||
pb_adn_cb, pb);
|
||||
} else {
|
||||
file_info = ref->pb_next->data;
|
||||
|
||||
ofono_sim_read_info(pbd->sim_context, file_info->file_id,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pbd->df_path, pbd->df_size,
|
||||
read_info_cb, cbd);
|
||||
read_info_cb, pb);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_sim_app_read(struct cb_data *cbd)
|
||||
static void start_sim_app_read(struct ofono_phonebook *pb)
|
||||
{
|
||||
struct ofono_phonebook *pb = cbd->user;
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
struct pb_ref_rec *ref_rec;
|
||||
struct pb_file_info *f_info;
|
||||
@@ -839,7 +828,7 @@ static void start_sim_app_read(struct cb_data *cbd)
|
||||
ref_rec = g_try_malloc0(sizeof(*ref_rec));
|
||||
if (ref_rec == NULL) {
|
||||
ofono_error("%s: OOM", __func__);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -850,7 +839,7 @@ static void start_sim_app_read(struct cb_data *cbd)
|
||||
f_info = g_try_malloc0(sizeof(*f_info));
|
||||
if (f_info == NULL) {
|
||||
ofono_error("%s: OOM", __func__);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -862,7 +851,7 @@ static void start_sim_app_read(struct cb_data *cbd)
|
||||
f_ext1 = g_try_malloc0(sizeof(*f_ext1));
|
||||
if (f_ext1 == NULL) {
|
||||
ofono_error("%s: OOM", __func__);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -880,15 +869,14 @@ static void start_sim_app_read(struct cb_data *cbd)
|
||||
ofono_sim_read_info(pbd->sim_context, f_info->file_id,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pbd->df_path, pbd->df_size,
|
||||
read_info_cb, cbd);
|
||||
read_info_cb, pb);
|
||||
}
|
||||
|
||||
static void pb_reference_data_cb(int ok, int total_length, int record,
|
||||
const unsigned char *sdata,
|
||||
int record_length, void *userdata)
|
||||
{
|
||||
struct cb_data *cbd = userdata;
|
||||
struct ofono_phonebook *pb = cbd->user;
|
||||
struct ofono_phonebook *pb = userdata;
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
const unsigned char *ptr = sdata;
|
||||
gboolean finished = FALSE;
|
||||
@@ -900,14 +888,14 @@ static void pb_reference_data_cb(int ok, int total_length, int record,
|
||||
if (!ok) {
|
||||
/* We migh have a SIM instead of USIM application: try that */
|
||||
DBG("%s: error %d, trying SIM files", __func__, ok);
|
||||
start_sim_app_read(cbd);
|
||||
start_sim_app_read(pb);
|
||||
return;
|
||||
}
|
||||
|
||||
ref_rec = g_try_malloc0(sizeof(*ref_rec));
|
||||
if (ref_rec == NULL) {
|
||||
ofono_error("%s: OOM", __func__);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -931,7 +919,7 @@ static void pb_reference_data_cb(int ok, int total_length, int record,
|
||||
g_try_new0(struct pb_file_info, 1);
|
||||
if (!file_info) {
|
||||
ofono_error("%s: OOM", __func__);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -973,7 +961,7 @@ static void pb_reference_data_cb(int ok, int total_length, int record,
|
||||
|
||||
if (ref->pb_files == NULL) {
|
||||
ofono_error("%s: no files to read", __func__);
|
||||
export_and_return(FALSE, cbd);
|
||||
export_and_return(pb, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -985,7 +973,7 @@ static void pb_reference_data_cb(int ok, int total_length, int record,
|
||||
ofono_sim_read_info(pbd->sim_context, file_info->file_id,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pbd->df_path, pbd->df_size,
|
||||
read_info_cb, cbd);
|
||||
read_info_cb, pb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,7 +982,6 @@ static void ril_export_entries(struct ofono_phonebook *pb,
|
||||
ofono_phonebook_cb_t cb, void *data)
|
||||
{
|
||||
struct pb_data *pbd = ofono_phonebook_get_data(pb);
|
||||
struct cb_data *cbd;
|
||||
|
||||
DBG("Storage %s", storage);
|
||||
|
||||
@@ -1004,7 +991,8 @@ static void ril_export_entries(struct ofono_phonebook *pb,
|
||||
return;
|
||||
}
|
||||
|
||||
cbd = cb_data_new(cb, data, pb);
|
||||
pbd->cb = cb;
|
||||
pbd->cb_data = data;
|
||||
|
||||
/* Assume USIM, change in case EF_PBR is not present */
|
||||
pbd->df_path = usim_path;
|
||||
@@ -1012,7 +1000,7 @@ static void ril_export_entries(struct ofono_phonebook *pb,
|
||||
|
||||
ofono_sim_read(pbd->sim_context, SIM_EFPBR_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pb_reference_data_cb, cbd);
|
||||
pb_reference_data_cb, pb);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
@@ -1059,6 +1047,7 @@ static void ril_phonebook_remove(struct ofono_phonebook *pb)
|
||||
ofono_phonebook_set_data(pb, NULL);
|
||||
ofono_sim_context_free(pbd->sim_context);
|
||||
|
||||
free_pb_refs(pbd, free_entry, NULL);
|
||||
g_free(pbd);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,6 +17,7 @@
|
||||
#define RIL_PLUGIN_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include "sailfish_manager.h"
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-barring.h>
|
||||
@@ -35,6 +36,7 @@
|
||||
#include <ofono/stk.h>
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/voicecall.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
@@ -42,34 +44,14 @@
|
||||
|
||||
#define RILMODEM_DRIVER "ril"
|
||||
|
||||
typedef struct ril_slot_info const *ril_slot_info_ptr;
|
||||
|
||||
struct ril_slot_info {
|
||||
const char *path;
|
||||
const char *imei;
|
||||
const char *ecclist_file;
|
||||
gboolean enabled;
|
||||
gboolean sim_present;
|
||||
const struct ril_slot_config *config;
|
||||
};
|
||||
|
||||
struct ril_plugin {
|
||||
const char *mms_imsi;
|
||||
const char *mms_path;
|
||||
const char *default_voice_imsi;
|
||||
const char *default_data_imsi;
|
||||
const char *default_voice_path;
|
||||
const char *default_data_path;
|
||||
const ril_slot_info_ptr *slots;
|
||||
gboolean ready;
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -78,62 +60,22 @@ struct ril_modem {
|
||||
struct ril_slot_config config;
|
||||
};
|
||||
|
||||
#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
|
||||
#define RIL_PLUGIN_SIGNAL_DATA_IMSI (0x02)
|
||||
#define RIL_PLUGIN_SIGNAL_VOICE_PATH (0x04)
|
||||
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x08)
|
||||
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x10)
|
||||
#define RIL_PLUGIN_SIGNAL_MMS_IMSI (0x20)
|
||||
#define RIL_PLUGIN_SIGNAL_MMS_PATH (0x40)
|
||||
#define RIL_PLUGIN_SIGNAL_READY (0x80)
|
||||
|
||||
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
|
||||
typedef void (*ril_modem_online_cb_t)(struct ril_modem *modem, gboolean online,
|
||||
void *data);
|
||||
|
||||
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
|
||||
gboolean ril_plugin_set_mms_imsi(struct ril_plugin *plugin, const char *imsi);
|
||||
void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
|
||||
const char *imsi);
|
||||
void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
|
||||
const char *imsi);
|
||||
|
||||
struct ril_oem_raw;
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *md,
|
||||
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_sim_info_dbus;
|
||||
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_sim_info *info);
|
||||
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
|
||||
|
||||
struct ril_cell_info_dbus;
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info);
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
|
||||
|
||||
struct ril_plugin_dbus;
|
||||
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
|
||||
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
|
||||
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
|
||||
gboolean clock);
|
||||
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
|
||||
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
|
||||
gboolean present);
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const struct ril_slot_info *slot, struct ril_radio *radio,
|
||||
struct ril_network *network, struct ril_sim_card *card,
|
||||
struct ril_data *data, struct ril_sim_settings *settings);
|
||||
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);
|
||||
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
|
||||
void *data);
|
||||
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
void *data);
|
||||
|
||||
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
|
||||
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
|
||||
@@ -141,7 +83,7 @@ void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
#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 *netreg, gint status);
|
||||
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;
|
||||
@@ -160,6 +102,7 @@ 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 */
|
||||
|
||||
|
||||
@@ -1,851 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_log.h>
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
typedef void (*ril_plugin_dbus_append_fn)(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus);
|
||||
typedef gboolean (*ril_plugin_dbus_slot_select_fn)
|
||||
(const struct ril_slot_info *slot);
|
||||
typedef const char *(*ril_plugin_dbus_slot_string_fn)
|
||||
(const struct ril_slot_info *slot);
|
||||
|
||||
struct ril_plugin_dbus_request {
|
||||
DBusMessage *msg;
|
||||
ril_plugin_dbus_append_fn fn;
|
||||
};
|
||||
|
||||
struct ril_plugin_dbus {
|
||||
struct ril_plugin *plugin;
|
||||
DBusConnection *conn;
|
||||
gboolean block_imei_req;
|
||||
GSList *blocked_imei_req;
|
||||
guint mms_watch;
|
||||
};
|
||||
|
||||
#define RIL_DBUS_PATH "/"
|
||||
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
|
||||
#define RIL_DBUS_INTERFACE_VERSION (5)
|
||||
|
||||
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
|
||||
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED "DefaultVoiceSimChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED "DefaultDataSimChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED "DefaultVoiceModemChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED "DefaultDataModemChanged"
|
||||
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
|
||||
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
|
||||
#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
|
||||
#define RIL_DBUS_IMSI_AUTO "auto"
|
||||
|
||||
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
|
||||
{
|
||||
return slot->enabled;
|
||||
}
|
||||
|
||||
static gboolean ril_plugin_dbus_present(const struct ril_slot_info *slot)
|
||||
{
|
||||
return slot->sim_present;
|
||||
}
|
||||
|
||||
static const char *ril_plugin_dbus_imei(const struct ril_slot_info *slot)
|
||||
{
|
||||
return slot->imei;
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_path_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn selector)
|
||||
{
|
||||
DBusMessageIter array;
|
||||
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
|
||||
|
||||
while (*ptr) {
|
||||
const struct ril_slot_info *slot = *ptr++;
|
||||
if (!selector || selector(slot)) {
|
||||
const char *path = slot->path;
|
||||
dbus_message_iter_append_basic(&array,
|
||||
DBUS_TYPE_OBJECT_PATH, &path);
|
||||
}
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(it, &array);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_string_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_string_fn fn)
|
||||
{
|
||||
DBusMessageIter array;
|
||||
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_STRING_AS_STRING, &array);
|
||||
|
||||
while (*ptr) {
|
||||
const struct ril_slot_info *slot = *ptr++;
|
||||
const char *str = fn(slot);
|
||||
|
||||
if (!str) str = "";
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(it, &array);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_boolean_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn value)
|
||||
{
|
||||
DBusMessageIter array;
|
||||
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_BOOLEAN_AS_STRING, &array);
|
||||
|
||||
while (*ptr) {
|
||||
const struct ril_slot_info *slot = *ptr++;
|
||||
dbus_bool_t b = value(slot);
|
||||
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_BOOLEAN, &b);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(it, &array);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_boolean(DBusMessageIter *it, dbus_bool_t b)
|
||||
{
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &b);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_string(DBusMessageIter *it, const char *str)
|
||||
{
|
||||
if (!str) str = "";
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_imsi(DBusMessageIter *it, const char *imsi)
|
||||
{
|
||||
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &imsi);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_path(DBusMessageIter *it, const char *path)
|
||||
{
|
||||
if (!path) path = "";
|
||||
/* It's DBUS_TYPE_STRING because DBUS_TYPE_OBJECT_PATH can't be empty */
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &path);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_message_append_path_array(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(msg, &iter);
|
||||
ril_plugin_dbus_append_path_array(&iter, dbus, fn);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
|
||||
const char *name, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
DBusMessage *signal = dbus_message_new_signal(RIL_DBUS_PATH,
|
||||
RIL_DBUS_INTERFACE, name);
|
||||
|
||||
ril_plugin_dbus_message_append_path_array(signal, dbus, fn);
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static inline void ril_plugin_dbus_signal_imsi(struct ril_plugin_dbus *dbus,
|
||||
const char *name, const char *imsi)
|
||||
{
|
||||
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
name, DBUS_TYPE_STRING, &imsi, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static inline void ril_plugin_dbus_signal_string(struct ril_plugin_dbus *dbus,
|
||||
const char *name, const char *str)
|
||||
{
|
||||
if (!str) str = "";
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
name, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static inline void ril_plugin_dbus_signal_boolean(struct ril_plugin_dbus *dbus,
|
||||
const char *name, dbus_bool_t value)
|
||||
{
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
name, DBUS_TYPE_BOOLEAN, &value, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
|
||||
{
|
||||
if (dbus) {
|
||||
if (mask & RIL_PLUGIN_SIGNAL_VOICE_IMSI) {
|
||||
ril_plugin_dbus_signal_imsi(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
|
||||
dbus->plugin->default_voice_imsi);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_DATA_IMSI) {
|
||||
ril_plugin_dbus_signal_imsi(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
|
||||
dbus->plugin->default_data_imsi);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_MMS_IMSI) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
|
||||
dbus->plugin->mms_imsi);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_ENABLED_SLOTS) {
|
||||
ril_plugin_dbus_signal_path_array(dbus,
|
||||
RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
|
||||
ril_plugin_dbus_enabled);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_VOICE_PATH) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
|
||||
dbus->plugin->default_voice_path);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_DATA_PATH) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
|
||||
dbus->plugin->default_data_path);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_MMS_PATH) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
|
||||
dbus->plugin->mms_path);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_READY) {
|
||||
ril_plugin_dbus_signal_boolean(dbus,
|
||||
RIL_DBUS_SIGNAL_READY_CHANGED,
|
||||
dbus->plugin->ready);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
|
||||
gboolean present)
|
||||
{
|
||||
dbus_bool_t value = present;
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
|
||||
DBUS_TYPE_INT32, &index,
|
||||
DBUS_TYPE_BOOLEAN, &value,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
|
||||
ril_plugin_dbus_message_append_path_array(reply, dbus, fn);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
append(&iter, dbus);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_unblock_request(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct ril_plugin_dbus_request *req = data;
|
||||
|
||||
DBG("unblocking IMEI request %p", req);
|
||||
__ofono_dbus_pending_reply(&req->msg, ril_plugin_dbus_reply(req->msg,
|
||||
(struct ril_plugin_dbus *)user_data, req->fn));
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_cancel_request(gpointer data)
|
||||
{
|
||||
struct ril_plugin_dbus_request *req = data;
|
||||
|
||||
DBG("canceling IMEI request %p", req);
|
||||
__ofono_dbus_pending_reply(&req->msg, __ofono_error_canceled(req->msg));
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
|
||||
gboolean block)
|
||||
{
|
||||
dbus->block_imei_req = block;
|
||||
if (!block && dbus->blocked_imei_req) {
|
||||
g_slist_foreach(dbus->blocked_imei_req,
|
||||
ril_plugin_dbus_unblock_request, dbus);
|
||||
g_slist_free(dbus->blocked_imei_req);
|
||||
dbus->blocked_imei_req = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_imei_reply(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn fn)
|
||||
{
|
||||
if (dbus->block_imei_req) {
|
||||
struct ril_plugin_dbus_request *req =
|
||||
g_new(struct ril_plugin_dbus_request, 1);
|
||||
|
||||
req->msg = dbus_message_ref(msg);
|
||||
req->fn = fn;
|
||||
dbus->blocked_imei_req = g_slist_append(dbus->blocked_imei_req,
|
||||
req);
|
||||
DBG("blocking IMEI request %p", req);
|
||||
return NULL;
|
||||
} else {
|
||||
return ril_plugin_dbus_reply(msg, dbus, fn);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_version(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
dbus_int32_t version = RIL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_version(it, dbus);
|
||||
ril_plugin_dbus_append_path_array(it, dbus, NULL);
|
||||
ril_plugin_dbus_append_path_array(it, dbus, ril_plugin_dbus_enabled);
|
||||
ril_plugin_dbus_append_imsi(it, dbus->plugin->default_data_imsi);
|
||||
ril_plugin_dbus_append_imsi(it, dbus->plugin->default_voice_imsi);
|
||||
ril_plugin_dbus_append_path(it, dbus->plugin->default_data_path);
|
||||
ril_plugin_dbus_append_path(it, dbus->plugin->default_voice_path);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all2(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all(it, dbus);
|
||||
ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all3(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all2(it, dbus);
|
||||
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all4(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all3(it, dbus);
|
||||
ril_plugin_dbus_append_string(it, dbus->plugin->mms_imsi);
|
||||
ril_plugin_dbus_append_path(it, dbus->plugin->mms_path);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all4(it, dbus);
|
||||
ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all2(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all2);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all3(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all3);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all4(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all4);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all5);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_available_modems(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply_with_path_array(msg,
|
||||
(struct ril_plugin_dbus *)data, NULL);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_enabled_modems(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply_with_path_array(msg,
|
||||
(struct ril_plugin_dbus *)data, ril_plugin_dbus_enabled);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_present_sims(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_present_sims(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_present_sims);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_imei_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_imei(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_imei_array);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_string(DBusMessage *msg,
|
||||
const char *str)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_plugin_dbus_append_string(&iter, str);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_imsi(DBusMessage *msg,
|
||||
const char *imsi)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_plugin_dbus_append_imsi(&iter, imsi);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_data_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_imsi(msg,
|
||||
dbus->plugin->default_data_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_voice_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_imsi(msg,
|
||||
dbus->plugin->default_voice_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_mms_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_string(msg, dbus->plugin->mms_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_path(DBusMessage *msg,
|
||||
const char *path)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_plugin_dbus_append_path(&iter, path);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_data_modem(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_path(msg,
|
||||
dbus->plugin->default_data_path);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_voice_modem(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_path(msg,
|
||||
dbus->plugin->default_voice_path);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_mms_modem(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_path(msg, dbus->plugin->mms_path);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
ril_plugin_dbus_append_boolean(&it, dbus->plugin->ready);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
|
||||
char **paths = NULL;
|
||||
DBusMessageIter array;
|
||||
|
||||
dbus_message_iter_recurse(&iter, &array);
|
||||
while (dbus_message_iter_get_arg_type(&array) ==
|
||||
DBUS_TYPE_OBJECT_PATH) {
|
||||
DBusBasicValue value;
|
||||
|
||||
dbus_message_iter_get_basic(&array, &value);
|
||||
paths = gutil_strv_add(paths, value.str);
|
||||
dbus_message_iter_next(&array);
|
||||
}
|
||||
|
||||
ril_plugin_set_enabled_slots(dbus->plugin, paths);
|
||||
g_strfreev(paths);
|
||||
return dbus_message_new_method_return(msg);
|
||||
} else {
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_imsi(struct ril_plugin_dbus *dbus,
|
||||
DBusMessage *msg, void (*apply)(struct ril_plugin *plugin,
|
||||
const char *imsi))
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
|
||||
DBusBasicValue value;
|
||||
const char *imsi;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &value);
|
||||
imsi = value.str;
|
||||
if (!g_strcmp0(imsi, RIL_DBUS_IMSI_AUTO)) imsi = NULL;
|
||||
apply(dbus->plugin, imsi);
|
||||
return dbus_message_new_method_return(msg);
|
||||
} else {
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_default_voice_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
GASSERT(conn == dbus->conn);
|
||||
return ril_plugin_dbus_set_imsi(dbus, msg,
|
||||
ril_plugin_set_default_voice_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_default_data_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
GASSERT(conn == dbus->conn);
|
||||
return ril_plugin_dbus_set_imsi(dbus, msg,
|
||||
ril_plugin_set_default_data_imsi);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_mms_disconnect(DBusConnection *conn, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
dbus->mms_watch = 0;
|
||||
if (dbus->plugin->mms_imsi) {
|
||||
DBG("MMS client is gone");
|
||||
ril_plugin_set_mms_imsi(dbus->plugin, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
GASSERT(conn == dbus->conn);
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
|
||||
DBusBasicValue value;
|
||||
const char *imsi;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &value);
|
||||
imsi = value.str;
|
||||
|
||||
/*
|
||||
* MMS IMSI is not persistent and has to be eventually
|
||||
* reset by the client or cleaned up if the client
|
||||
* unexpectedly disappears.
|
||||
*/
|
||||
if (ril_plugin_set_mms_imsi(dbus->plugin, imsi)) {
|
||||
|
||||
/*
|
||||
* Clear the previous MMS owner
|
||||
*/
|
||||
if (dbus->mms_watch) {
|
||||
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
|
||||
dbus->mms_watch = 0;
|
||||
}
|
||||
|
||||
if (dbus->plugin->mms_imsi &&
|
||||
dbus->plugin->mms_imsi[0]) {
|
||||
/*
|
||||
* This client becomes the owner
|
||||
*/
|
||||
DBG("Owner: %s", dbus_message_get_sender(msg));
|
||||
dbus->mms_watch =
|
||||
g_dbus_add_disconnect_watch(dbus->conn,
|
||||
dbus_message_get_sender(msg),
|
||||
ril_plugin_dbus_mms_disconnect,
|
||||
dbus, NULL);
|
||||
}
|
||||
|
||||
return ril_plugin_dbus_reply_with_string(msg,
|
||||
dbus->plugin->mms_path);
|
||||
} else {
|
||||
return __ofono_error_not_available(msg);
|
||||
}
|
||||
} else {
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The client can call GetInterfaceVersion followed by the appropriate
|
||||
* GetAllx call to get all settings in two steps. Alternatively, it can
|
||||
* call GetAll followed by GetAllx based on the interface version returned
|
||||
* by GetAll. In either case, two D-Bus calls are required, unless the
|
||||
* client is willing to make the assumption about the ofono version it's
|
||||
* talking to.
|
||||
*/
|
||||
|
||||
#define RIL_DBUS_GET_ALL_ARGS \
|
||||
{"version", "i" }, \
|
||||
{"availableModems", "ao" }, \
|
||||
{"enabledModems", "ao" }, \
|
||||
{"defaultDataSim", "s" }, \
|
||||
{"defaultVoiceSim", "s" }, \
|
||||
{"defaultDataModem", "s" }, \
|
||||
{"defaultVoiceModem" , "s"}
|
||||
#define RIL_DBUS_GET_ALL2_ARGS \
|
||||
RIL_DBUS_GET_ALL_ARGS, \
|
||||
{"presentSims" , "ab"}
|
||||
#define RIL_DBUS_GET_ALL3_ARGS \
|
||||
RIL_DBUS_GET_ALL2_ARGS, \
|
||||
{"imei" , "as"}
|
||||
#define RIL_DBUS_GET_ALL4_ARGS \
|
||||
RIL_DBUS_GET_ALL3_ARGS, \
|
||||
{"mmsSim", "s" }, \
|
||||
{"mmsModem" , "s"}
|
||||
#define RIL_DBUS_GET_ALL5_ARGS \
|
||||
RIL_DBUS_GET_ALL4_ARGS, \
|
||||
{"ready" , "b"}
|
||||
|
||||
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
|
||||
ril_plugin_dbus_get_all) },
|
||||
{ GDBUS_METHOD("GetAll2",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL2_ARGS),
|
||||
ril_plugin_dbus_get_all2) },
|
||||
{ GDBUS_ASYNC_METHOD("GetAll3",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL3_ARGS),
|
||||
ril_plugin_dbus_get_all3) },
|
||||
{ GDBUS_ASYNC_METHOD("GetAll4",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL4_ARGS),
|
||||
ril_plugin_dbus_get_all4) },
|
||||
{ GDBUS_ASYNC_METHOD("GetAll5",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
|
||||
ril_plugin_dbus_get_all5) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion",
|
||||
NULL, GDBUS_ARGS({ "version", "i" }),
|
||||
ril_plugin_dbus_get_interface_version) },
|
||||
{ GDBUS_METHOD("GetAvailableModems",
|
||||
NULL, GDBUS_ARGS({ "modems", "ao" }),
|
||||
ril_plugin_dbus_get_available_modems) },
|
||||
{ GDBUS_METHOD("GetEnabledModems",
|
||||
NULL, GDBUS_ARGS({ "modems", "ao" }),
|
||||
ril_plugin_dbus_get_enabled_modems) },
|
||||
{ GDBUS_METHOD("GetPresentSims",
|
||||
NULL, GDBUS_ARGS({ "presentSims", "ab" }),
|
||||
ril_plugin_dbus_get_present_sims) },
|
||||
{ GDBUS_ASYNC_METHOD("GetIMEI",
|
||||
NULL, GDBUS_ARGS({ "imei", "as" }),
|
||||
ril_plugin_dbus_get_imei) },
|
||||
{ GDBUS_METHOD("GetDefaultDataSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_plugin_dbus_get_default_data_sim) },
|
||||
{ GDBUS_METHOD("GetDefaultVoiceSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_plugin_dbus_get_default_voice_sim) },
|
||||
{ GDBUS_METHOD("GetMmsSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_plugin_dbus_get_mms_sim) },
|
||||
{ GDBUS_METHOD("GetDefaultDataModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
ril_plugin_dbus_get_default_data_modem) },
|
||||
{ GDBUS_METHOD("GetDefaultVoiceModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
ril_plugin_dbus_get_default_voice_modem) },
|
||||
{ GDBUS_METHOD("GetMmsModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
ril_plugin_dbus_get_mms_modem) },
|
||||
{ GDBUS_METHOD("GetReady",
|
||||
NULL, GDBUS_ARGS({ "ready", "b" }),
|
||||
ril_plugin_dbus_get_ready) },
|
||||
{ GDBUS_METHOD("SetEnabledModems",
|
||||
GDBUS_ARGS({ "modems", "ao" }), NULL,
|
||||
ril_plugin_dbus_set_enabled_modems) },
|
||||
{ GDBUS_METHOD("SetDefaultDataSim",
|
||||
GDBUS_ARGS({ "imsi", "s" }), NULL,
|
||||
ril_plugin_dbus_set_default_data_sim) },
|
||||
{ GDBUS_METHOD("SetDefaultVoiceSim",
|
||||
GDBUS_ARGS({ "imsi", "s" }), NULL,
|
||||
ril_plugin_dbus_set_default_voice_sim) },
|
||||
{ GDBUS_METHOD("SetMmsSim",
|
||||
GDBUS_ARGS({ "imsi", "s" }), NULL,
|
||||
ril_plugin_dbus_set_mms_sim) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
|
||||
GDBUS_ARGS({ "modems", "ao" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
|
||||
GDBUS_ARGS({"index", "i" },
|
||||
{"present" , "b"})) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
|
||||
GDBUS_ARGS({ "ready", "b" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = g_new0(struct ril_plugin_dbus, 1);
|
||||
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->plugin = plugin;
|
||||
if (g_dbus_register_interface(dbus->conn, RIL_DBUS_PATH,
|
||||
RIL_DBUS_INTERFACE, ril_plugin_dbus_methods,
|
||||
ril_plugin_dbus_signals, NULL, dbus, NULL)) {
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_plugin_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
if (dbus->mms_watch) {
|
||||
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
|
||||
}
|
||||
|
||||
g_slist_free_full(dbus->blocked_imei_req,
|
||||
ril_plugin_dbus_cancel_request);
|
||||
g_dbus_unregister_interface(dbus->conn, RIL_DBUS_PATH,
|
||||
RIL_DBUS_INTERFACE);
|
||||
dbus_connection_unref(dbus->conn);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -99,13 +99,14 @@ static inline void ril_radio_emit_signal(struct ril_radio *self,
|
||||
|
||||
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
|
||||
ril_radio_submit_power_request(self,
|
||||
ril_radio_power_should_be_on(self));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
@@ -126,7 +127,7 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (!priv->pending_id) {
|
||||
const gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
if (ril_radio_state_on(self->priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
@@ -157,7 +158,7 @@ static void ril_radio_check_state(struct ril_radio *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 = user_data;
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
@@ -177,11 +178,17 @@ static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
|
||||
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;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
|
||||
|
||||
priv->next_state_valid = FALSE;
|
||||
priv->next_state = on;
|
||||
@@ -189,8 +196,10 @@ static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
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);
|
||||
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -330,7 +339,7 @@ enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
|
||||
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = 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);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -44,6 +44,9 @@ 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 */
|
||||
|
||||
/*
|
||||
|
||||
1416
ofono/drivers/ril/ril_radio_caps.c
Normal file
1416
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:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ril_radio_settings {
|
||||
struct ofono_radio_settings *rs;
|
||||
@@ -113,15 +112,11 @@ 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;
|
||||
guint rats = OFONO_RADIO_ACCESS_MODE_GSM | OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
|
||||
if (cbd->rsd->settings->enable_4g) {
|
||||
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
}
|
||||
|
||||
GASSERT(cbd->rsd->source_id);
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rsd->settings->techs,
|
||||
cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
@@ -132,8 +127,8 @@ static void ril_radio_settings_query_available_rats(
|
||||
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);
|
||||
ril_radio_settings_later(rsd,
|
||||
ril_radio_settings_query_available_rats_cb, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -24,6 +24,15 @@
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
|
||||
|
||||
/* SIM I/O idle timeout is measured in the number of idle loops.
|
||||
* When active SIM I/O is going on, the idle loop count very rarely
|
||||
* exceeds 1 between the requests, so 10 is more than enough. Idle
|
||||
* loop is actually more accurate criteria than a timeout because
|
||||
* it doesn't depend that much on the system load. */
|
||||
#define SIM_IO_IDLE_LOOPS (10)
|
||||
|
||||
typedef GObjectClass RilSimCardClass;
|
||||
typedef struct ril_sim_card RilSimCard;
|
||||
|
||||
@@ -38,7 +47,11 @@ struct ril_sim_card_priv {
|
||||
GRilIoQueue *q;
|
||||
int flags;
|
||||
guint status_req_id;
|
||||
guint sub_req_id;
|
||||
gulong event_id[EVENT_COUNT];
|
||||
guint sim_io_idle_id;
|
||||
guint sim_io_idle_count;
|
||||
GHashTable* sim_io_pending;
|
||||
};
|
||||
|
||||
enum ril_sim_card_signal {
|
||||
@@ -46,13 +59,15 @@ enum ril_sim_card_signal {
|
||||
SIGNAL_STATUS_CHANGED,
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_APP_CHANGED,
|
||||
SIGNAL_SIM_IO_ACTIVE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
|
||||
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
|
||||
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
|
||||
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
|
||||
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
|
||||
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
|
||||
#define SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME "ril-simcard-sim-io-active-changed"
|
||||
|
||||
static guint ril_sim_card_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
@@ -61,11 +76,16 @@ G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
|
||||
#define RIL_SIMCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_SIMCARD_TYPE, RilSimCard))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) NEW_SIGNAL_(klass,name##_CHANGED)
|
||||
#define NEW_SIGNAL_(klass,name) \
|
||||
ril_sim_card_signals[SIGNAL_##name] = \
|
||||
g_signal_new(SIGNAL_##name##_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define RIL_SIMCARD_STATE_CHANGED (0x01)
|
||||
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self);
|
||||
|
||||
static gboolean ril_sim_card_app_equal(const struct ril_sim_card_app *a1,
|
||||
const struct ril_sim_card_app *a2)
|
||||
{
|
||||
@@ -137,29 +157,71 @@ static void ril_sim_card_status_free(struct ril_sim_card_status *status)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self,
|
||||
int app_index, int sub_status)
|
||||
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
* removed from the list of pending requests) */
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
}
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||
const void* data, guint len, void* user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
GASSERT(status == GRILIO_STATUS_OK);
|
||||
GASSERT(priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
DBG("UICC subscription OK for slot %u", self->slot);
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
||||
enum ril_uicc_subscription_action sub_action)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||
const guint sub_id = self->slot;
|
||||
guint code;
|
||||
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_status);
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
|
||||
grilio_request_append_int32(req, self->slot);
|
||||
grilio_request_append_int32(req, app_index);
|
||||
grilio_request_append_int32(req, sub_id);
|
||||
grilio_request_append_int32(req, sub_status);
|
||||
grilio_queue_send_request(priv->q, req, (priv->io->ril_version <= 9 &&
|
||||
grilio_request_append_int32(req, sub_action);
|
||||
|
||||
grilio_request_set_retry(req, 0, -1);
|
||||
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
|
||||
code = (priv->io->ril_version <= 9 &&
|
||||
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
|
||||
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
|
||||
RIL_REQUEST_SET_UICC_SUBSCRIPTION);
|
||||
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
|
||||
RIL_REQUEST_SET_UICC_SUBSCRIPTION;
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
* removed from the list of pending requests) */
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
}
|
||||
|
||||
/* Don't allow any requests other that GET_SIM_STATUS until
|
||||
* we are done with the subscription */
|
||||
grilio_queue_transaction_start(priv->q);
|
||||
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
|
||||
req, code, ril_sim_card_subscribe_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
|
||||
{
|
||||
int selected_app = -1;
|
||||
guint i;
|
||||
int i, selected_app = -1;
|
||||
|
||||
for (i = 0; i < status->num_apps; i++) {
|
||||
const int type = status->apps[i].app_type;
|
||||
@@ -185,14 +247,17 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
if (status->gsm_umts_index >= 0 &&
|
||||
status->gsm_umts_index < status->num_apps) {
|
||||
app_index = status->gsm_umts_index;
|
||||
ril_sim_card_subscription_done(self);
|
||||
} else {
|
||||
app_index = ril_sim_card_select_app(status);
|
||||
if (app_index >= 0) {
|
||||
ril_sim_card_subscribe(self, app_index, 1);
|
||||
ril_sim_card_subscribe(self, app_index,
|
||||
RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app_index = -1;
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
if (app_index >= 0 &&
|
||||
@@ -203,8 +268,8 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
}
|
||||
|
||||
if (!ril_sim_card_app_equal(old_app, self->app)) {
|
||||
g_signal_emit(self,
|
||||
ril_sim_card_signals[SIGNAL_APP_CHANGED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_APP_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,23 +283,23 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
|
||||
self->status = status;
|
||||
ril_sim_card_update_app(self);
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_RECEIVED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
if (diff & RIL_SIMCARD_STATUS_CHANGED) {
|
||||
DBG("status changed");
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_CHANGED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_CHANGED], 0);
|
||||
}
|
||||
if (diff & RIL_SIMCARD_STATE_CHANGED) {
|
||||
DBG("state changed");
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATE_CHANGED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATE_CHANGED], 0);
|
||||
}
|
||||
ril_sim_card_status_free(old_status);
|
||||
} else {
|
||||
ril_sim_card_status_free(status);
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_RECEIVED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +382,8 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
status->num_apps = num_apps;
|
||||
|
||||
if (num_apps > 0) {
|
||||
status->apps = g_new0(struct ril_sim_card_app, num_apps);
|
||||
status->apps =
|
||||
g_new0(struct ril_sim_card_app, num_apps);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_apps; i++) {
|
||||
@@ -338,6 +404,7 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
}
|
||||
|
||||
if (i == num_apps) {
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
return status;
|
||||
} else {
|
||||
ril_sim_card_status_free(status);
|
||||
@@ -349,7 +416,7 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_card *self = user_data;
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->status_req_id);
|
||||
@@ -365,28 +432,105 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->status_req_id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, priv->status_req_id);
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
if (priv->status_req_id) {
|
||||
/* Retry right away, don't wait for retry
|
||||
* timeout to expire */
|
||||
grilio_channel_retry_request(priv->io,
|
||||
priv->status_req_id);
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->status_req_id = grilio_queue_send_request_full(priv->q,
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->status_req_id =
|
||||
grilio_queue_send_request_full(priv->q,
|
||||
req, RIL_REQUEST_GET_SIM_STATUS,
|
||||
ril_sim_card_status_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_sim_io_active(struct ril_sim_card *self)
|
||||
{
|
||||
/* SIM I/O is considered active for certain period of time after
|
||||
* the last request has completed. That's because SIM_IO requests
|
||||
* are usually submitted in large quantities and quick succession.
|
||||
* Some RILs don't like being bothered while they are doing SIM I/O
|
||||
* and some time after that too. That sucks but what else can we
|
||||
* do about it? */
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
const gboolean active = priv->sim_io_idle_id ||
|
||||
g_hash_table_size(priv->sim_io_pending);
|
||||
|
||||
if (self->sim_io_active != active) {
|
||||
self->sim_io_active = active;
|
||||
DBG("SIM I/O for slot %u is %sactive", self->slot,
|
||||
active ? "" : "in");
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_SIM_IO_ACTIVE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *self, guint id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(id);
|
||||
|
||||
g_hash_table_insert(priv->sim_io_pending, key, key);
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
priv->sim_io_idle_id = 0;
|
||||
priv->sim_io_idle_count = 0;
|
||||
}
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_card_sim_io_idle_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (++(priv->sim_io_idle_count) >= SIM_IO_IDLE_LOOPS) {
|
||||
priv->sim_io_idle_id = 0;
|
||||
priv->sim_io_idle_count = 0;
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
return G_SOURCE_REMOVE;
|
||||
} else {
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *self, guint id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(id);
|
||||
|
||||
if (g_hash_table_remove(priv->sim_io_pending, key) &&
|
||||
!g_hash_table_size(priv->sim_io_pending)) {
|
||||
/* Reset the idle loop count */
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
priv->sim_io_idle_count = 0;
|
||||
}
|
||||
priv->sim_io_idle_id =
|
||||
g_idle_add(ril_sim_card_sim_io_idle_cb, self);
|
||||
}
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_card *self = user_data;
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
@@ -474,6 +618,13 @@ gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *self,
|
||||
SIGNAL_APP_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
@@ -488,8 +639,11 @@ void ril_sim_card_remove_handlers(struct ril_sim_card *self, gulong *ids, int n)
|
||||
|
||||
static void ril_sim_card_init(struct ril_sim_card *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIMCARD_TYPE,
|
||||
struct ril_sim_card_priv);
|
||||
struct ril_sim_card_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_SIMCARD_TYPE, struct ril_sim_card_priv);
|
||||
|
||||
self->priv = priv;
|
||||
priv->sim_io_pending = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void ril_sim_card_dispose(GObject *object)
|
||||
@@ -507,6 +661,10 @@ static void ril_sim_card_finalize(GObject *object)
|
||||
struct ril_sim_card *self = RIL_SIMCARD(object);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
}
|
||||
g_hash_table_destroy(priv->sim_io_pending);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_sim_card_status_free(self->status);
|
||||
@@ -520,22 +678,11 @@ static void ril_sim_card_class_init(RilSimCardClass *klass)
|
||||
object_class->dispose = ril_sim_card_dispose;
|
||||
object_class->finalize = ril_sim_card_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_card_priv));
|
||||
ril_sim_card_signals[SIGNAL_STATUS_RECEIVED] =
|
||||
g_signal_new(SIGNAL_STATUS_RECEIVED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_STATUS_CHANGED] =
|
||||
g_signal_new(SIGNAL_STATUS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_STATE_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_APP_CHANGED] =
|
||||
g_signal_new(SIGNAL_APP_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
NEW_SIGNAL_(klass,STATUS_RECEIVED);
|
||||
NEW_SIGNAL(klass,STATUS);
|
||||
NEW_SIGNAL(klass,STATE);
|
||||
NEW_SIGNAL(klass,APP);
|
||||
NEW_SIGNAL(klass,SIM_IO_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -44,6 +44,7 @@ struct ril_sim_card {
|
||||
struct ril_sim_card_priv *priv;
|
||||
struct ril_sim_card_status *status;
|
||||
const struct ril_sim_card_app *app;
|
||||
gboolean sim_io_active;
|
||||
guint slot;
|
||||
};
|
||||
|
||||
@@ -55,6 +56,9 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_unref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_request_status(struct ril_sim_card *sc);
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
|
||||
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
|
||||
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
@@ -64,6 +68,8 @@ gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
|
||||
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
|
||||
|
||||
|
||||
@@ -1,653 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_sim_info.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define RIL_SIM_INFO_STORE "cache"
|
||||
#define RIL_SIM_INFO_STORE_GROUP "sim"
|
||||
#define RIL_SIM_INFO_STORE_SPN "spn"
|
||||
|
||||
/* ICCID -> IMSI map */
|
||||
#define RIL_SIM_ICCID_MAP "iccidmap"
|
||||
#define RIL_SIM_ICCID_MAP_IMSI "imsi"
|
||||
|
||||
#define RIL_SIM_DEFAULT_SPN_BUFSIZE 8
|
||||
G_STATIC_ASSERT(RIL_SIM_DEFAULT_SPN_BUFSIZE >= \
|
||||
OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
|
||||
|
||||
typedef GObjectClass RilSimInfoClass;
|
||||
typedef struct ril_sim_info RilSimInfo;
|
||||
|
||||
typedef void (*ril_sim_info_remove_cb_t)(struct ofono_sim *sim,
|
||||
unsigned int id);
|
||||
typedef void (*ril_sim_info_set_value_cb_t)(struct ril_sim_info *info,
|
||||
const char *value);
|
||||
|
||||
struct ril_sim_info_watch {
|
||||
ril_sim_info_set_value_cb_t set_value;
|
||||
ril_sim_info_remove_cb_t remove;
|
||||
struct ril_sim_info *info;
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
struct ril_sim_info_priv {
|
||||
char *log_prefix;
|
||||
char *iccid;
|
||||
char *imsi;
|
||||
char *cached_spn;
|
||||
char *sim_spn;
|
||||
char *public_spn;
|
||||
char default_spn[RIL_SIM_DEFAULT_SPN_BUFSIZE];
|
||||
struct ofono_sim *sim;
|
||||
struct ril_sim_info_watch state_watch;
|
||||
struct ril_sim_info_watch iccid_watch;
|
||||
struct ril_sim_info_watch imsi_watch;
|
||||
struct ril_sim_info_watch spn_watch;
|
||||
struct ril_network *network;
|
||||
gulong network_operator_changed_id;
|
||||
gboolean update_imsi_cache;
|
||||
gboolean update_iccid_map;
|
||||
};
|
||||
|
||||
enum ril_sim_info_signal {
|
||||
SIGNAL_ICCID_CHANGED,
|
||||
SIGNAL_IMSI_CHANGED,
|
||||
SIGNAL_SPN_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_ICCID_CHANGED_NAME "ril-sim-info-iccid-changed"
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-info-imsi-changed"
|
||||
#define SIGNAL_SPN_CHANGED_NAME "ril-sim-info-spn-changed"
|
||||
|
||||
static guint ril_sim_info_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilSimInfo, ril_sim_info, G_TYPE_OBJECT)
|
||||
#define RIL_SIMINFO_TYPE (ril_sim_info_get_type())
|
||||
#define RIL_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_SIMINFO_TYPE, RilSimInfo))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_sim_info_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_(info,fmt,args...) DBG("%s" fmt, (info)->priv->log_prefix, ##args)
|
||||
|
||||
static void ril_sim_info_signal_emit(struct ril_sim_info *self,
|
||||
enum ril_sim_info_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_sim_info_signals[id], 0);
|
||||
}
|
||||
|
||||
static void ril_sim_info_watch_remove(struct ril_sim_info_watch *watch)
|
||||
{
|
||||
if (watch->id) {
|
||||
struct ril_sim_info_priv *priv = watch->info->priv;
|
||||
|
||||
GASSERT(priv->sim);
|
||||
if (priv->sim) {
|
||||
watch->remove(priv->sim, watch->id);
|
||||
GASSERT(!watch->id);
|
||||
}
|
||||
|
||||
watch->id = 0;
|
||||
}
|
||||
|
||||
if (watch->set_value) {
|
||||
watch->set_value(watch->info, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim,
|
||||
unsigned int id)
|
||||
{
|
||||
ofono_sim_remove_spn_watch(sim, &id);
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_imsi_cache(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
|
||||
priv->cached_spn && priv->cached_spn[0]) {
|
||||
gboolean save = FALSE;
|
||||
const char *store = RIL_SIM_INFO_STORE;
|
||||
GKeyFile *cache = storage_open(priv->imsi, store);
|
||||
char *spn = g_key_file_get_string(cache,
|
||||
RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, NULL);
|
||||
|
||||
if (g_strcmp0(priv->cached_spn, spn)) {
|
||||
save = TRUE;
|
||||
g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, priv->cached_spn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (save) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s/%s",
|
||||
priv->imsi, store);
|
||||
storage_close(priv->imsi, store, cache, TRUE);
|
||||
} else {
|
||||
g_key_file_free(cache);
|
||||
}
|
||||
|
||||
g_free(spn);
|
||||
priv->update_imsi_cache = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_iccid_map(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
|
||||
priv->imsi && priv->imsi[0]) {
|
||||
const char *store = RIL_SIM_ICCID_MAP;
|
||||
GKeyFile *map = storage_open(NULL, store);
|
||||
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, NULL);
|
||||
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (g_strcmp0(imsi, priv->imsi)) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s", store);
|
||||
g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, priv->imsi);
|
||||
storage_close(NULL, store, map, TRUE);
|
||||
} else {
|
||||
g_key_file_free(map);
|
||||
}
|
||||
|
||||
g_free(imsi);
|
||||
priv->update_iccid_map = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_imsi(struct ril_sim_info *self, const char *imsi)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->imsi, imsi)) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(imsi);
|
||||
priv->update_iccid_map = TRUE;
|
||||
ril_sim_info_update_iccid_map(self);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_public_spn(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
const char *spn = priv->sim_spn ? priv->sim_spn :
|
||||
priv->cached_spn ? priv->cached_spn :
|
||||
priv->default_spn;
|
||||
|
||||
if (g_strcmp0(priv->public_spn, spn)) {
|
||||
g_free(priv->public_spn);
|
||||
self->spn = priv->public_spn = g_strdup(spn);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_cached_spn(struct ril_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->cached_spn, spn)) {
|
||||
DBG_(self, "cached spn \"%s\"", spn);
|
||||
g_free(priv->cached_spn);
|
||||
priv->cached_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_sim_spn(struct ril_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->sim_spn, spn)) {
|
||||
g_free(priv->sim_spn);
|
||||
priv->sim_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
ril_sim_info_set_cached_spn(self, spn);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_default_spn(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
char buf[RIL_SIM_DEFAULT_SPN_BUFSIZE];
|
||||
const char *mcc = NULL;
|
||||
const char *mnc = NULL;
|
||||
|
||||
if (priv->sim &&
|
||||
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
|
||||
mcc = ofono_sim_get_mcc(priv->sim);
|
||||
mnc = ofono_sim_get_mnc(priv->sim);
|
||||
}
|
||||
|
||||
if (mcc && mnc) {
|
||||
snprintf(buf, RIL_SIM_DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
|
||||
buf[RIL_SIM_DEFAULT_SPN_BUFSIZE - 1] = 0;
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
if (strcmp(buf, priv->default_spn)) {
|
||||
strncpy(priv->default_spn, buf, RIL_SIM_DEFAULT_SPN_BUFSIZE);
|
||||
DBG_(self, "default spn \"%s\"", priv->default_spn);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_network_check(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->network && priv->network->operator && priv->sim &&
|
||||
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
|
||||
const char *mcc = ofono_sim_get_mcc(priv->sim);
|
||||
const char *mnc = ofono_sim_get_mnc(priv->sim);
|
||||
const struct ofono_network_operator *op =
|
||||
priv->network->operator;
|
||||
|
||||
if (mcc && mcc[0] && !strcmp(mcc, op->mcc) &&
|
||||
mnc && mnc[0] && !strcmp(mnc, op->mnc)) {
|
||||
|
||||
/*
|
||||
* If EFspn is present then sim_spn should be set
|
||||
* before we get registered with the network.
|
||||
*/
|
||||
DBG_(self, "home network \"%s\"", op->name);
|
||||
if (!priv->sim_spn) {
|
||||
ril_sim_info_set_cached_spn(self, op->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_network_operator_changed(struct ril_network *network,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_info_load_cache(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->iccid && priv->iccid[0]) {
|
||||
GKeyFile *map = storage_open(NULL, RIL_SIM_ICCID_MAP);
|
||||
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, NULL);
|
||||
g_key_file_free(map);
|
||||
|
||||
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
/* Need to update ICCID -> IMSI map */
|
||||
DBG_(self, "IMSI changed %s -> %s",
|
||||
priv->imsi, imsi);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = imsi;
|
||||
DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
|
||||
ril_sim_info_update_iccid_map(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
} else if (imsi) {
|
||||
g_free(imsi);
|
||||
} else {
|
||||
DBG_(self, "no imsi for iccid %s", priv->iccid);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
GKeyFile *cache = storage_open(priv->imsi, RIL_SIM_INFO_STORE);
|
||||
char *spn = g_key_file_get_string(cache,
|
||||
RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, NULL);
|
||||
g_key_file_free(cache);
|
||||
|
||||
if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
|
||||
if (priv->cached_spn && priv->cached_spn[0]) {
|
||||
/* Need to update the cache file */
|
||||
DBG_(self, "spn changing %s -> %s",
|
||||
priv->cached_spn, spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->cached_spn);
|
||||
priv->cached_spn = spn;
|
||||
DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
} else if (spn) {
|
||||
g_free(spn);
|
||||
} else {
|
||||
DBG_(self, "no spn for imsi %s", priv->imsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_iccid(struct ril_sim_info *self, const char *iccid)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->iccid, iccid)) {
|
||||
g_free(priv->iccid);
|
||||
self->iccid = priv->iccid = g_strdup(iccid);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
|
||||
if (iccid) {
|
||||
ril_sim_info_load_cache(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_imsi_watch_cb(const char *imsi, void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
DBG_(watch->info, "%s", imsi);
|
||||
ril_sim_info_set_imsi(watch->info, imsi);
|
||||
}
|
||||
|
||||
static void ril_sim_info_spn_watch_cb(const char *spn, const char *dc,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
DBG_(watch->info, "%s", spn);
|
||||
ril_sim_info_set_sim_spn(watch->info, spn);
|
||||
}
|
||||
|
||||
static void ril_sim_info_iccid_watch_cb(const char *iccid, void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
DBG_(watch->info, "%s", iccid);
|
||||
ril_sim_info_set_iccid(watch->info, iccid);
|
||||
}
|
||||
|
||||
static void ril_sim_info_watch_done(void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
GASSERT(watch->id);
|
||||
watch->id = 0;
|
||||
}
|
||||
|
||||
static void ril_sim_info_handle_sim_state(struct ril_sim_info *self,
|
||||
enum ofono_sim_state state)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
struct ril_sim_info_watch *watch;
|
||||
|
||||
DBG_(self, "%d", state);
|
||||
|
||||
switch (state) {
|
||||
case OFONO_SIM_STATE_READY:
|
||||
/* SPN */
|
||||
watch = &priv->spn_watch;
|
||||
if (!watch->id) {
|
||||
ofono_sim_add_spn_watch(priv->sim, &watch->id,
|
||||
ril_sim_info_spn_watch_cb, watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(priv->spn_watch.id);
|
||||
}
|
||||
/* IMSI */
|
||||
watch = &priv->imsi_watch;
|
||||
if (!watch->id) {
|
||||
watch->id = ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_info_imsi_watch_cb, watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(watch->id);
|
||||
}
|
||||
/* no break */
|
||||
case OFONO_SIM_STATE_INSERTED:
|
||||
case OFONO_SIM_STATE_LOCKED_OUT:
|
||||
/* ICCID */
|
||||
watch = &priv->iccid_watch;
|
||||
if (!watch->id) {
|
||||
watch->id = ofono_sim_add_iccid_watch(priv->sim,
|
||||
ril_sim_info_iccid_watch_cb, watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(watch->id);
|
||||
}
|
||||
break;
|
||||
case OFONO_SIM_STATE_NOT_PRESENT:
|
||||
case OFONO_SIM_STATE_RESETTING:
|
||||
ril_sim_info_watch_remove(&priv->spn_watch);
|
||||
ril_sim_info_watch_remove(&priv->imsi_watch);
|
||||
ril_sim_info_watch_remove(&priv->iccid_watch);
|
||||
break;
|
||||
}
|
||||
|
||||
ril_sim_info_update_default_spn(self);
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
ril_sim_info_handle_sim_state(watch->info, new_state);
|
||||
}
|
||||
|
||||
struct ril_sim_info *ril_sim_info_new(const char *log_prefix)
|
||||
{
|
||||
struct ril_sim_info *self = g_object_new(RIL_SIMINFO_TYPE, NULL);
|
||||
|
||||
self->priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIMINFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_unref(struct ril_sim_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIMINFO(self));
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim != sim) {
|
||||
ril_sim_info_watch_remove(&priv->state_watch);
|
||||
ril_sim_info_watch_remove(&priv->iccid_watch);
|
||||
ril_sim_info_watch_remove(&priv->imsi_watch);
|
||||
ril_sim_info_watch_remove(&priv->spn_watch);
|
||||
|
||||
priv->update_imsi_cache = FALSE;
|
||||
priv->update_iccid_map = FALSE;
|
||||
priv->sim = sim;
|
||||
|
||||
if (sim) {
|
||||
priv->state_watch.id =
|
||||
ofono_sim_add_state_watch(sim,
|
||||
ril_sim_info_state_watch_cb,
|
||||
&priv->state_watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(priv->state_watch.id);
|
||||
DBG_(self, "attached to sim");
|
||||
ril_sim_info_handle_sim_state(self,
|
||||
ofono_sim_get_state(sim));
|
||||
}
|
||||
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_set_network(struct ril_sim_info *self,
|
||||
struct ril_network *network)
|
||||
{
|
||||
if (G_LIKELY(self) && self->priv->network != network) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->network) {
|
||||
ril_network_remove_handlers(priv->network,
|
||||
&priv->network_operator_changed_id, 1);
|
||||
ril_network_unref(priv->network);
|
||||
}
|
||||
if (network) {
|
||||
priv->network_operator_changed_id =
|
||||
ril_network_add_operator_changed_handler(network,
|
||||
ril_sim_info_network_operator_changed,
|
||||
self);
|
||||
priv->network = ril_network_ref(network);
|
||||
ril_sim_info_network_check(self);
|
||||
} else {
|
||||
priv->network = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *self,
|
||||
ril_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *self,
|
||||
ril_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *self,
|
||||
ril_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_info_remove_handler(struct ril_sim_info *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_watch_init(struct ril_sim_info *self,
|
||||
struct ril_sim_info_watch *watch,
|
||||
ril_sim_info_set_value_cb_t set_value,
|
||||
ril_sim_info_remove_cb_t remove)
|
||||
{
|
||||
watch->info = self;
|
||||
watch->set_value = set_value;
|
||||
watch->remove = remove;
|
||||
}
|
||||
|
||||
static void ril_sim_info_init(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_SIMINFO_TYPE, struct ril_sim_info_priv);
|
||||
|
||||
self->priv = priv;
|
||||
ril_sim_info_watch_init(self, &priv->state_watch,
|
||||
NULL, ofono_sim_remove_state_watch);
|
||||
ril_sim_info_watch_init(self, &priv->iccid_watch,
|
||||
ril_sim_info_set_iccid, ofono_sim_remove_iccid_watch);
|
||||
ril_sim_info_watch_init(self, &priv->imsi_watch,
|
||||
ril_sim_info_set_imsi, ofono_sim_remove_imsi_watch);
|
||||
ril_sim_info_watch_init(self, &priv->spn_watch,
|
||||
ril_sim_info_set_sim_spn, ril_sim_info_remove_spn_watch);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(object);
|
||||
|
||||
ril_sim_info_set_ofono_sim(self, NULL);
|
||||
ril_sim_info_set_network(self, NULL);
|
||||
G_OBJECT_CLASS(ril_sim_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_sim_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(object);
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
g_free(priv->log_prefix);
|
||||
g_free(priv->cached_spn);
|
||||
g_free(priv->public_spn);
|
||||
GASSERT(!priv->iccid);
|
||||
GASSERT(!priv->imsi);
|
||||
GASSERT(!priv->sim_spn);
|
||||
G_OBJECT_CLASS(ril_sim_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_info_class_init(RilSimInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_sim_info_dispose;
|
||||
object_class->finalize = ril_sim_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_info_priv));
|
||||
NEW_SIGNAL(klass, ICCID);
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, SPN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_SIM_INFO_H
|
||||
#define RIL_SIM_INFO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_sim_info {
|
||||
GObject object;
|
||||
struct ril_sim_info_priv *priv;
|
||||
const char *iccid;
|
||||
const char *imsi;
|
||||
const char *spn;
|
||||
};
|
||||
|
||||
struct ofono_sim;
|
||||
typedef void (*ril_sim_info_cb_t)(struct ril_sim_info *info, void *arg);
|
||||
|
||||
struct ril_sim_info *ril_sim_info_new(const char *log_prefix);
|
||||
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *info);
|
||||
void ril_sim_info_unref(struct ril_sim_info *si);
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *si, struct ofono_sim *sim);
|
||||
void ril_sim_info_set_network(struct ril_sim_info *si, struct ril_network *net);
|
||||
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *si,
|
||||
ril_sim_info_cb_t cb, void *arg);
|
||||
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *si,
|
||||
ril_sim_info_cb_t cb, void *arg);
|
||||
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *si,
|
||||
ril_sim_info_cb_t cb, void *arg);
|
||||
void ril_sim_info_remove_handler(struct ril_sim_info *si, gulong id);
|
||||
|
||||
#endif /* RIL_SIM_INFO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_info.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
|
||||
enum sim_info_event_id {
|
||||
SIM_INFO_EVENT_ICCID,
|
||||
SIM_INFO_EVENT_IMSI,
|
||||
SIM_INFO_EVENT_SPN,
|
||||
SIM_INFO_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_info_dbus {
|
||||
struct ril_modem *md;
|
||||
struct ril_sim_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id[SIM_INFO_EVENT_COUNT];
|
||||
};
|
||||
|
||||
#define RIL_SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
|
||||
#define RIL_SIM_INFO_DBUS_INTERFACE_VERSION (1)
|
||||
|
||||
#define RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
|
||||
#define RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
|
||||
#define RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
|
||||
|
||||
static void ril_sim_info_dbus_append_string(DBusMessageIter *it, const char *s)
|
||||
{
|
||||
if (!s) s = "";
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &s);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_reply_with_string(DBusMessage *msg,
|
||||
const char *str)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_sim_info_dbus_append_string(&iter, str);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
struct ril_sim_info *info = dbus->info;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
const dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
|
||||
ril_sim_info_dbus_append_string(&iter, info->iccid);
|
||||
ril_sim_info_dbus_append_string(&iter, info->imsi);
|
||||
ril_sim_info_dbus_append_string(&iter, info->spn);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_version(DBusConnection *dc,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_iccid(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_imsi(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_spn(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_sim_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll",
|
||||
NULL, GDBUS_ARGS({"version", "i" },
|
||||
{"iccid", "s" },
|
||||
{"imsi", "s" },
|
||||
{"spn" , "s"}),
|
||||
ril_sim_info_dbus_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion",
|
||||
NULL, GDBUS_ARGS({ "version", "i" }),
|
||||
ril_sim_info_dbus_get_version) },
|
||||
{ GDBUS_METHOD("GetCardIdentifier",
|
||||
NULL, GDBUS_ARGS({ "iccid", "s" }),
|
||||
ril_sim_info_dbus_get_iccid) },
|
||||
{ GDBUS_METHOD("GetSubscriberIdentity",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_sim_info_dbus_get_imsi) },
|
||||
{ GDBUS_METHOD("GetServiceProviderName",
|
||||
NULL, GDBUS_ARGS({ "spn", "s" }),
|
||||
ril_sim_info_dbus_get_spn) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_sim_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "iccid", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "spn", "s" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void ril_sim_info_dbus_emit(struct ril_sim_info_dbus *dbus,
|
||||
const char *signal, const char *value)
|
||||
{
|
||||
const char *arg = value;
|
||||
if (!arg) arg = "";
|
||||
g_dbus_emit_signal(dbus->conn, dbus->path, RIL_SIM_INFO_DBUS_INTERFACE,
|
||||
signal, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dbus_iccid_cb(struct ril_sim_info *info, void *arg)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = arg;
|
||||
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
|
||||
info->iccid);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dbus_imsi_cb(struct ril_sim_info *info, void *arg)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = arg;
|
||||
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
|
||||
info->imsi);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dbus_spn_cb(struct ril_sim_info *info, void *arg)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = arg;
|
||||
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
|
||||
info->spn);
|
||||
}
|
||||
|
||||
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_sim_info *info)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = g_new0(struct ril_sim_info_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->md = md;
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->info = ril_sim_info_ref(info);
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE, ril_sim_info_dbus_methods,
|
||||
ril_sim_info_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE);
|
||||
|
||||
dbus->handler_id[SIM_INFO_EVENT_ICCID] =
|
||||
ril_sim_info_add_iccid_changed_handler(info,
|
||||
ril_sim_info_dbus_iccid_cb, dbus);
|
||||
dbus->handler_id[SIM_INFO_EVENT_IMSI] =
|
||||
ril_sim_info_add_imsi_changed_handler(info,
|
||||
ril_sim_info_dbus_imsi_cb, dbus);
|
||||
dbus->handler_id[SIM_INFO_EVENT_SPN] =
|
||||
ril_sim_info_add_spn_changed_handler(info,
|
||||
ril_sim_info_dbus_spn_cb, dbus);
|
||||
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
ril_sim_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
unsigned int i;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE);
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(dbus->handler_id); i++) {
|
||||
ril_sim_info_remove_handler(dbus->info,
|
||||
dbus->handler_id[i]);
|
||||
}
|
||||
ril_sim_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -16,27 +16,28 @@
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "storage.h"
|
||||
|
||||
#define RIL_SIM_STORE "ril"
|
||||
#define RIL_SIM_STORE_GROUP "Settings"
|
||||
#define RIL_SIM_STORE_PREF_MODE "TechnologyPreference"
|
||||
|
||||
#define RIL_SIM_STORE_PREF_MODE_DEFAULT(self) ((self)->enable_4g ? \
|
||||
OFONO_RADIO_ACCESS_MODE_LTE : OFONO_RADIO_ACCESS_MODE_UMTS)
|
||||
#define RIL_PREF_MODE_DEFAULT(self) (\
|
||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
|
||||
OFONO_RADIO_ACCESS_MODE_LTE : \
|
||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_UMTS) ? \
|
||||
OFONO_RADIO_ACCESS_MODE_UMTS : \
|
||||
OFONO_RADIO_ACCESS_MODE_GSM)
|
||||
|
||||
typedef GObjectClass RilSimSettingsClass;
|
||||
typedef struct ril_sim_settings RilSimSettings;
|
||||
|
||||
enum sailfish_watch_events {
|
||||
WATCH_EVENT_IMSI,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_settings_priv {
|
||||
struct ofono_sim *sim;
|
||||
guint imsi_watch_id;
|
||||
guint state_watch_id;
|
||||
GKeyFile *storage;
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
struct sailfish_watch *watch;
|
||||
char *imsi;
|
||||
};
|
||||
|
||||
@@ -62,162 +63,77 @@ G_DEFINE_TYPE(RilSimSettings, ril_sim_settings, G_TYPE_OBJECT)
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
/* Skip the leading slash from the modem path: */
|
||||
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
|
||||
|
||||
static void ril_sim_settings_signal_emit(struct ril_sim_settings *self,
|
||||
enum ril_sim_settings_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_sim_settings_signals[id], 0);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_reload(struct ril_sim_settings *self)
|
||||
{
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
if (priv->storage) {
|
||||
g_key_file_free(priv->storage);
|
||||
priv->storage = NULL;
|
||||
}
|
||||
|
||||
if (priv->imsi) {
|
||||
char *mode_str;
|
||||
enum ofono_radio_access_mode mode;
|
||||
priv->storage = storage_open(priv->imsi, RIL_SIM_STORE);
|
||||
mode_str = g_key_file_get_string(priv->storage,
|
||||
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_PREF_MODE, NULL);
|
||||
if (ofono_radio_access_mode_from_string(mode_str, &mode)) {
|
||||
if (!self->enable_4g &&
|
||||
mode == OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
} else {
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
if (mode == OFONO_RADIO_ACCESS_MODE_ANY) {
|
||||
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
|
||||
} else {
|
||||
self->pref_mode = mode;
|
||||
}
|
||||
g_free(mode_str);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
if (G_LIKELY(self) && self->pref_mode != mode) {
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
const char *mode_str = ofono_radio_access_mode_to_string(mode);
|
||||
|
||||
GASSERT(priv->storage);
|
||||
if (mode_str) {
|
||||
if (priv->storage) {
|
||||
g_key_file_set_string(priv->storage,
|
||||
RIL_SIM_STORE_GROUP,
|
||||
RIL_SIM_STORE_PREF_MODE, mode_str);
|
||||
storage_sync(self->imsi, RIL_SIM_STORE,
|
||||
priv->storage);
|
||||
}
|
||||
self->pref_mode = mode;
|
||||
ril_sim_settings_signal_emit(self,
|
||||
SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
self->pref_mode = mode;
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_set_imsi(struct ril_sim_settings *self,
|
||||
const char *imsi)
|
||||
{
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
if (g_strcmp0(priv->imsi, imsi)) {
|
||||
enum ofono_radio_access_mode prev_mode = self->pref_mode;
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(imsi);
|
||||
ril_sim_settings_reload(self);
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
if (prev_mode != self->pref_mode) {
|
||||
ril_sim_settings_signal_emit(self,
|
||||
SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_imsi_watch_cb(const char *imsi, void *user_data)
|
||||
{
|
||||
ril_sim_settings_set_imsi(RIL_SIM_SETTINGS(user_data), imsi);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_imsi_watch_done(void *user_data)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->imsi_watch_id);
|
||||
priv->imsi_watch_id = 0;
|
||||
}
|
||||
|
||||
static void ril_sim_settings_ready(struct ril_sim_settings *self)
|
||||
{
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
GASSERT(!priv->imsi_watch_id);
|
||||
priv->imsi_watch_id = ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_settings_imsi_watch_cb, self,
|
||||
ril_sim_settings_imsi_watch_done);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
|
||||
static void ril_sim_settings_imsi_changed(struct sailfish_watch *watch,
|
||||
void *user_data)
|
||||
{
|
||||
if (new_state == OFONO_SIM_STATE_READY) {
|
||||
ril_sim_settings_ready(RIL_SIM_SETTINGS(user_data));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_watch_done(void *user_data)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->state_watch_id);
|
||||
priv->state_watch_id = 0;
|
||||
}
|
||||
|
||||
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
if (priv->sim != sim) {
|
||||
GASSERT(priv->sim || !priv->imsi_watch_id);
|
||||
if (priv->imsi_watch_id) {
|
||||
ofono_sim_remove_imsi_watch(priv->sim,
|
||||
priv->imsi_watch_id);
|
||||
/* ril_sim_settings_imsi_watch_done clears it */
|
||||
GASSERT(!priv->imsi_watch_id);
|
||||
}
|
||||
if (priv->state_watch_id) {
|
||||
ofono_sim_remove_state_watch(priv->sim,
|
||||
priv->state_watch_id);
|
||||
/* ril_sim_settings_state_watch_done clears it */
|
||||
GASSERT(!priv->state_watch_id);
|
||||
}
|
||||
priv->sim = sim;
|
||||
if (sim) {
|
||||
priv->state_watch_id =
|
||||
ofono_sim_add_state_watch(sim,
|
||||
ril_sim_settings_state_watch, self,
|
||||
ril_sim_settings_state_watch_done);
|
||||
GASSERT(priv->state_watch_id);
|
||||
if (ofono_sim_get_state(sim) ==
|
||||
OFONO_SIM_STATE_READY) {
|
||||
ril_sim_settings_ready(self);
|
||||
}
|
||||
} else {
|
||||
ril_sim_settings_set_imsi(self, NULL);
|
||||
}
|
||||
}
|
||||
if (g_strcmp0(priv->imsi, watch->imsi)) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(watch->imsi);
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
enum ofono_radio_access_mode techs)
|
||||
{
|
||||
struct ril_sim_settings *self = NULL;
|
||||
|
||||
if (G_LIKELY(path)) {
|
||||
struct ril_sim_settings_priv *priv;
|
||||
|
||||
self = g_object_new(RIL_SIM_SETTINGS_TYPE, NULL);
|
||||
priv = self->priv;
|
||||
self->techs = techs;
|
||||
self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
|
||||
priv->watch = sailfish_watch_new(path);
|
||||
priv->watch_event_id[WATCH_EVENT_IMSI] =
|
||||
sailfish_watch_add_imsi_changed_handler(priv->watch,
|
||||
ril_sim_settings_imsi_changed, self);
|
||||
self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIM_SETTINGS(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIM_SETTINGS(self));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
|
||||
ril_sim_settings_cb_t cb, void *arg)
|
||||
{
|
||||
@@ -246,51 +162,26 @@ void ril_sim_settings_remove_handlers(struct ril_sim_settings *self,
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc)
|
||||
{
|
||||
struct ril_sim_settings *self = g_object_new(RIL_SIM_SETTINGS_TYPE, 0);
|
||||
self->enable_4g = sc->enable_4g;
|
||||
self->slot = sc->slot;
|
||||
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIM_SETTINGS(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIM_SETTINGS(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_init(struct ril_sim_settings *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIM_SETTINGS_TYPE,
|
||||
struct ril_sim_settings_priv);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_dispose(GObject *object)
|
||||
static void ril_sim_settings_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
ril_sim_settings_set_ofono_sim(self, NULL);
|
||||
G_OBJECT_CLASS(ril_sim_settings_parent_class)->dispose(object);
|
||||
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
|
||||
sailfish_watch_unref(priv->watch);
|
||||
g_free(priv->imsi);
|
||||
G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_class_init(RilSimSettingsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_sim_settings_dispose;
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_sim_settings_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, PREF_MODE);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -18,26 +18,22 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
struct ril_sim_settings_priv;
|
||||
|
||||
struct ril_sim_settings {
|
||||
GObject object;
|
||||
struct ril_sim_settings_priv *priv;
|
||||
gboolean enable_4g;
|
||||
guint slot;
|
||||
const char *imsi;
|
||||
enum ofono_radio_access_mode techs;
|
||||
enum ofono_radio_access_mode pref_mode;
|
||||
};
|
||||
|
||||
typedef void (*ril_sim_settings_cb_t)(struct ril_sim_settings *s, void *arg);
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc);
|
||||
struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
enum ofono_radio_access_mode techs);
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *s,
|
||||
struct ofono_sim *sim);
|
||||
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *s,
|
||||
enum ofono_radio_access_mode mode);
|
||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *s,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -255,8 +254,9 @@ static void ril_sms_submit(struct ofono_sms *sms, const unsigned char *pdu,
|
||||
|
||||
DBG("%s", tpdu);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SEND_SMS, ril_sms_submit_cb,
|
||||
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
|
||||
mms ? RIL_REQUEST_SEND_SMS_EXPECT_MORE : RIL_REQUEST_SEND_SMS,
|
||||
ril_sms_submit_cb, ril_sms_cbd_free,
|
||||
ril_sms_cbd_new(sd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
g_free(tpdu);
|
||||
}
|
||||
@@ -471,7 +471,7 @@ static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
|
||||
|
||||
static void ril_sms_remove(struct ofono_sms *sms)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
|
||||
DBG("");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
@@ -269,7 +268,7 @@ static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
|
||||
static void ril_stk_remove(struct ofono_stk *stk)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
DBG("");
|
||||
ofono_stk_set_data(stk, NULL);
|
||||
|
||||
@@ -13,6 +13,21 @@
|
||||
|
||||
[Settings]
|
||||
|
||||
# This option stops RIL plugin from creating any RIL modems.
|
||||
# If it's set to true, all [ril_x] sections are ignored even
|
||||
# if they are present, and no default configurtation is created.
|
||||
#
|
||||
# Default is false
|
||||
#
|
||||
#EmptyConfig=false
|
||||
|
||||
# User and group for the ofono process. RIL clients are typically
|
||||
# expected to run under radio:radio.
|
||||
#
|
||||
# Default is radio:radio
|
||||
#
|
||||
#Identity=radio:radio
|
||||
|
||||
# If the phone has more than one SIM slot, the 3G/LTE module may be
|
||||
# shared by all modems, meaning that only one of the slots can use
|
||||
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
|
||||
@@ -27,6 +42,17 @@
|
||||
#
|
||||
#3GLTEHandover=true
|
||||
|
||||
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# It's involved in 3G/LTE handover between the modems, meaning that it only
|
||||
# makes sense if you have more than one slot.
|
||||
#
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default is auto (enable for RIL version >= 11)
|
||||
#
|
||||
#SetRadioCapability=auto
|
||||
|
||||
[ril_0]
|
||||
|
||||
# Required entry, defines the RIL socket path
|
||||
@@ -59,9 +85,15 @@ socket=/dev/socket/rild
|
||||
#
|
||||
#timeout=0
|
||||
|
||||
# Setting this one to false would disable 4G technology selection.
|
||||
# Comma-separated list of radio technologies supported by the modem.
|
||||
# Valid technologies are "gsm", "umts" and "lte". The special value
|
||||
# "all" means that all technologies are supported.
|
||||
#
|
||||
# By default 4G is enabled
|
||||
# The default is all
|
||||
#
|
||||
#technologies=all
|
||||
|
||||
# This one is deprecated, use the technologies entry instead (above).
|
||||
#
|
||||
#enable4G=true
|
||||
|
||||
@@ -92,6 +124,81 @@ socket=/dev/socket/rild
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default is auto (usage based on the RIL version)
|
||||
# Default is auto (enable for RIL version >= 11)
|
||||
#
|
||||
#allowDataReq=auto
|
||||
|
||||
# Since RIL interface doesn't provide the standard way of querying the
|
||||
# number of pin retries left, some RIL implementation (namely Qualcomm)
|
||||
# allow to query the retry count by sending the empty pin. If your RIL
|
||||
# actually does check the empty pin (and decrements the retry count)
|
||||
# then you should turn this feature off.
|
||||
#
|
||||
# Default is true
|
||||
#
|
||||
#emptyPinQuery=true
|
||||
|
||||
# Different RILs use different data call structures which don't necessarily
|
||||
# match the format specified in the data list header. The header may have
|
||||
# version 9 but the list may contain RIL_Data_Call_Response_v6 structures,
|
||||
# list version 10 may contain RIL_Data_Call_Response_v11 and so on. By default
|
||||
# ofono assumes that the version from the list header matches the contents
|
||||
# but sometimes you have to explicitly tell ofono which one to use.
|
||||
# Possible values are 6, 9, 11 and auto.
|
||||
#
|
||||
# Default is auto
|
||||
#
|
||||
#dataCallFormat=auto
|
||||
|
||||
# Data call may fail with status 65535 which according to ril.h means that
|
||||
# we need to retry silently. The maximum number of retries is limited by
|
||||
# this parameter. Usually, one retry is enough. The first retry occurs
|
||||
# immediately, the subsequent ones after dataCallRetryDelay (see below)
|
||||
#
|
||||
# Default is 4
|
||||
#
|
||||
#dataCallRetryLimit=4
|
||||
|
||||
# Delay between data call retries, in milliseconds. Note that the first
|
||||
# retry occurs immediately after the first failure, the delays are only
|
||||
# applied if the first retry fails too.
|
||||
#
|
||||
# Default is 200 ms
|
||||
#
|
||||
#dataCallRetryDelay=200
|
||||
|
||||
# Additional local and remote hangup reasons. Remote reasons are checked
|
||||
# first. Normally, RIL plugin figures it out automatically. You would only
|
||||
# need to define these if your RIL does something unusual.
|
||||
#
|
||||
# No default
|
||||
#
|
||||
#remoteHangupReasons=20
|
||||
#localHangupReasons=23
|
||||
|
||||
# Voice call support. Some devices like USB modems and tablets don't support
|
||||
# voice calls. By default, voice calls are enabled and this option allows you
|
||||
# to disable voice call handling.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableVoicecall=true
|
||||
|
||||
# Timeout for the modem to show up, in milliseconds. Those that don't
|
||||
# show up before this timeout expires, will be dropped (ignored).
|
||||
#
|
||||
# In some fairly rare cases it makes sense to shorten this timeout for
|
||||
# optional modems (which may or may not be available), to speed up the
|
||||
# boot up process.
|
||||
#
|
||||
# The default is 20000 (20 seconds)
|
||||
#
|
||||
#startTimeout=20000
|
||||
|
||||
# This allows to use deprecated RIL_REQUEST_GET_IMEI instead of
|
||||
# RIL_REQUEST_DEVICE_IDENTITY to query IMEI from the modem. Some
|
||||
# RILs (e.g. MTK) still don't understand RIL_REQUEST_DEVICE_IDENTITY.
|
||||
#
|
||||
# Default is false (use RIL_REQUEST_DEVICE_IDENTITY)
|
||||
#
|
||||
#legacyImeiQuery=false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -23,11 +23,12 @@
|
||||
#include <grilio_types.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
@@ -39,19 +40,19 @@ struct ofono_sim;
|
||||
#define RIL_RETRY_SECS (2)
|
||||
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
|
||||
|
||||
struct ril_mce;
|
||||
struct ril_data;
|
||||
struct ril_modem;
|
||||
struct ril_radio;
|
||||
struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_sim_info;
|
||||
struct ril_sim_settings;
|
||||
struct ril_cell_info;
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
gboolean enable_4g;
|
||||
enum ofono_radio_access_mode techs;
|
||||
gboolean empty_pin_query;
|
||||
gboolean enable_voicecall;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
};
|
||||
|
||||
#endif /* RIL_TYPES_H */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
@@ -50,17 +49,15 @@ static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data)
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_ussd_cb(GRilIoChannel *io, int status,
|
||||
static void ril_ussd_cancel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
/* Always report sucessful completion, otherwise ofono may get
|
||||
* stuck in the USSD_STATE_ACTIVE state */
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
@@ -120,7 +117,8 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
|
||||
ril_ussd_cb, ril_ussd_cbd_free, ril_ussd_cbd_new(cb, data));
|
||||
ril_ussd_cancel_cb, ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(cb, data));
|
||||
}
|
||||
|
||||
static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
@@ -128,32 +126,32 @@ static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
{
|
||||
struct ril_ussd *ud = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *ussd_from_network = NULL;
|
||||
char *type = NULL;
|
||||
int ussdtype = 0;
|
||||
char *type;
|
||||
guint32 n = 0;
|
||||
|
||||
ofono_info("ussd_received");
|
||||
ofono_info("ussd received");
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_uint32(&rilp, NULL);
|
||||
grilio_parser_get_uint32(&rilp, &n);
|
||||
type = grilio_parser_get_utf8(&rilp);
|
||||
ussd_from_network = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
ussdtype = g_ascii_xdigit_value(*type);
|
||||
if (type) {
|
||||
int ussdtype = g_ascii_xdigit_value(*type);
|
||||
char *msg = (n > 1) ? grilio_parser_get_utf8(&rilp) : NULL;
|
||||
|
||||
if (ussd_from_network) {
|
||||
const int data_len = strlen(ussd_from_network);
|
||||
DBG("ussd_received, length %d", data_len);
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0xFF,
|
||||
(const unsigned char *) ussd_from_network, data_len);
|
||||
} else {
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0, NULL, 0);
|
||||
if (msg) {
|
||||
const int msglen = strlen(msg);
|
||||
DBG("ussd length %d", msglen);
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0xFF,
|
||||
(const unsigned char *)msg, msglen);
|
||||
/* msg is freed by core if dcs is 0xFF */
|
||||
} else {
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0, NULL, 0);
|
||||
}
|
||||
|
||||
g_free(type);
|
||||
}
|
||||
|
||||
/* ussd_from_network not freed because core does that if dcs is 0xFF */
|
||||
g_free(type);
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean ril_ussd_register(gpointer user_data)
|
||||
@@ -170,7 +168,7 @@ static gboolean ril_ussd_register(gpointer user_data)
|
||||
ril_ussd_notify, RIL_UNSOL_ON_USSD, ud);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "netreg.h"
|
||||
@@ -48,7 +50,8 @@ const char *ril_error_to_string(int error)
|
||||
RIL_E_(MODE_NOT_SUPPORTED);
|
||||
RIL_E_(FDN_CHECK_FAILURE);
|
||||
RIL_E_(ILLEGAL_SIM_OR_ME);
|
||||
RIL_E_(UNUSED);
|
||||
RIL_E_(MISSING_RESOURCE);
|
||||
RIL_E_(NO_SUCH_ELEMENT);
|
||||
RIL_E_(DIAL_MODIFIED_TO_USSD);
|
||||
RIL_E_(DIAL_MODIFIED_TO_SS);
|
||||
RIL_E_(DIAL_MODIFIED_TO_DIAL);
|
||||
@@ -57,11 +60,39 @@ const char *ril_error_to_string(int error)
|
||||
RIL_E_(USSD_MODIFIED_TO_USSD);
|
||||
RIL_E_(SS_MODIFIED_TO_DIAL);
|
||||
RIL_E_(SS_MODIFIED_TO_USSD);
|
||||
RIL_E_(SS_MODIFIED_TO_SS);
|
||||
RIL_E_(SUBSCRIPTION_NOT_SUPPORTED);
|
||||
RIL_E_(MISSING_RESOURCE);
|
||||
RIL_E_(NO_SUCH_ELEMENT);
|
||||
RIL_E_(INVALID_PARAMETER);
|
||||
RIL_E_(SS_MODIFIED_TO_SS);
|
||||
RIL_E_(LCE_NOT_SUPPORTED);
|
||||
RIL_E_(NO_MEMORY);
|
||||
RIL_E_(INTERNAL_ERR);
|
||||
RIL_E_(SYSTEM_ERR);
|
||||
RIL_E_(MODEM_ERR);
|
||||
RIL_E_(INVALID_STATE);
|
||||
RIL_E_(NO_RESOURCES);
|
||||
RIL_E_(SIM_ERR);
|
||||
RIL_E_(INVALID_ARGUMENTS);
|
||||
RIL_E_(INVALID_SIM_STATE);
|
||||
RIL_E_(INVALID_MODEM_STATE);
|
||||
RIL_E_(INVALID_CALL_ID);
|
||||
RIL_E_(NO_SMS_TO_ACK);
|
||||
RIL_E_(NETWORK_ERR);
|
||||
RIL_E_(REQUEST_RATE_LIMITED);
|
||||
RIL_E_(SIM_BUSY);
|
||||
RIL_E_(SIM_FULL);
|
||||
RIL_E_(NETWORK_REJECT);
|
||||
RIL_E_(OPERATION_NOT_ALLOWED);
|
||||
RIL_E_(EMPTY_RECORD);
|
||||
RIL_E_(INVALID_SMS_FORMAT);
|
||||
RIL_E_(ENCODING_ERR);
|
||||
RIL_E_(INVALID_SMSC_ADDRESS);
|
||||
RIL_E_(NO_SUCH_ENTRY);
|
||||
RIL_E_(NETWORK_NOT_READY);
|
||||
RIL_E_(NOT_PROVISIONED);
|
||||
RIL_E_(NO_SUBSCRIPTION);
|
||||
RIL_E_(NO_NETWORK_FOUND);
|
||||
RIL_E_(DEVICE_IN_USE);
|
||||
RIL_E_(ABORTED);
|
||||
RIL_E_(INVALID_RESPONSE);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "%d", error);
|
||||
return unknown;
|
||||
@@ -204,6 +235,8 @@ const char *ril_request_to_string(guint request)
|
||||
RIL_REQUEST_(SHUTDOWN);
|
||||
RIL_REQUEST_(GET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(SET_RADIO_CAPABILITY);
|
||||
case RIL_RESPONSE_ACKNOWLEDGEMENT:
|
||||
return "RESPONSE_ACK";
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "RIL_REQUEST_%d", request);
|
||||
return unknown;
|
||||
@@ -288,24 +321,12 @@ const char *ril_radio_state_to_string(int radio_state)
|
||||
}
|
||||
}
|
||||
|
||||
int ril_address_family(const char *addr)
|
||||
{
|
||||
if (strchr(addr, ':')) {
|
||||
return AF_INET6;
|
||||
} else if (strchr(addr, '.')) {
|
||||
return AF_INET;
|
||||
} else {
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns enum access_technology or -1 on failure. */
|
||||
int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
int access_tech = -1;
|
||||
int tech = -1;
|
||||
if (stech && stech[0]) {
|
||||
tech = atoi(stech);
|
||||
if (ril_parse_int(stech, 0, &tech)) {
|
||||
switch (tech) {
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
@@ -362,8 +383,8 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
|
||||
if (i == OFONO_MAX_MCC_LENGTH) {
|
||||
/* Usually 2 but sometimes 3 digit network code */
|
||||
for (i=0;
|
||||
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mnc[i] = *ptr++;
|
||||
}
|
||||
@@ -390,6 +411,26 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_parse_int(const char *str, int base, int *value)
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (str && str[0]) {
|
||||
char *str2 = g_strstrip(g_strdup(str));
|
||||
char *end = str2;
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(str2, &end, base);
|
||||
ok = !*end && errno != ERANGE && l >= INT_MIN && l <= INT_MAX;
|
||||
if (ok && value) {
|
||||
*value = (int)l;
|
||||
}
|
||||
g_free(str2);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -25,16 +25,19 @@ const char *ril_request_to_string(guint request);
|
||||
const char *ril_unsol_event_to_string(guint event);
|
||||
const char *ril_radio_state_to_string(int radio_state);
|
||||
int ril_parse_tech(const char *stech, int *ril_tech);
|
||||
int ril_address_family(const char *addr);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
gboolean ril_parse_int(const char *str, int base, int *value);
|
||||
|
||||
#define ril_error_init_ok(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
||||
#define ril_error_init_failure(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_FAILURE)
|
||||
#define ril_error_init_sim_error(err,sw1,sw2) \
|
||||
((err)->error = ((sw1) << 8)|(sw2), (err)->type = OFONO_ERROR_TYPE_SIM)
|
||||
|
||||
#define ril_error_ok(err) (ril_error_init_ok(err), err)
|
||||
#define ril_error_failure(err) (ril_error_init_failure(err), err)
|
||||
#define ril_error_sim(err,sw1,sw2) (ril_error_init_sim_error(err,sw1,sw2), err)
|
||||
|
||||
#endif /* RIL_UTIL_H */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,17 +14,21 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_ring.h>
|
||||
#include <gutil_idlequeue.h>
|
||||
#include <gutil_intarray.h>
|
||||
|
||||
#define FLAG_NEED_CLIP 1
|
||||
|
||||
#define VOICECALL_BLOCK_TIMEOUT_MS (5*1000)
|
||||
|
||||
enum ril_voicecall_events {
|
||||
VOICECALL_EVENT_CALL_STATE_CHANGED,
|
||||
VOICECALL_EVENT_SUPP_SVC_NOTIFICATION,
|
||||
@@ -38,12 +42,14 @@ struct ril_voicecall {
|
||||
GRilIoQueue *q;
|
||||
struct ofono_voicecall *vc;
|
||||
struct ril_ecclist *ecclist;
|
||||
unsigned int local_release;
|
||||
unsigned char flags;
|
||||
ofono_voicecall_cb_t cb;
|
||||
void *data;
|
||||
guint timer_id;
|
||||
GUtilRing* dtmf_queue;
|
||||
GUtilIntArray *local_release_ids;
|
||||
GUtilIdleQueue *idleq;
|
||||
GUtilRing *dtmf_queue;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
guint send_dtmf_id;
|
||||
guint clcc_poll_id;
|
||||
gulong event_id[VOICECALL_EVENT_COUNT];
|
||||
@@ -52,35 +58,48 @@ struct ril_voicecall {
|
||||
gulong ecclist_change_id;
|
||||
};
|
||||
|
||||
struct ril_voicecall_change_state_req {
|
||||
struct ril_voicecall_request_data {
|
||||
int ref_count;
|
||||
int pending_call_count;
|
||||
int success;
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
gpointer data;
|
||||
int affected_types;
|
||||
};
|
||||
|
||||
struct lastcause_req {
|
||||
struct ofono_voicecall *vc;
|
||||
struct ril_voicecall *vd;
|
||||
int id;
|
||||
};
|
||||
|
||||
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
|
||||
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
|
||||
|
||||
/*
|
||||
* structs ofono_voicecall and voicecall are fully defined
|
||||
* in src/voicecall.c; we need (read) access to the
|
||||
* call objects, so partially redefine them here.
|
||||
*/
|
||||
struct ofono_voicecall {
|
||||
GSList *call_list;
|
||||
/* ... */
|
||||
};
|
||||
struct ril_voicecall_request_data *ril_voicecall_request_data_new
|
||||
(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall_request_data *req =
|
||||
g_slice_new0(struct ril_voicecall_request_data);
|
||||
|
||||
struct voicecall {
|
||||
struct ofono_call *call;
|
||||
/* ... */
|
||||
};
|
||||
req->ref_count = 1;
|
||||
req->vc = vc;
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_voicecall_request_data_unref
|
||||
(struct ril_voicecall_request_data *req)
|
||||
{
|
||||
if (!--req->ref_count) {
|
||||
g_slice_free(struct ril_voicecall_request_data, req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_request_data_free(gpointer data)
|
||||
{
|
||||
ril_voicecall_request_data_unref(data);
|
||||
}
|
||||
|
||||
static inline struct ril_voicecall *ril_voicecall_get_data(
|
||||
struct ofono_voicecall *vc)
|
||||
@@ -166,38 +185,76 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
|
||||
}
|
||||
|
||||
/* Valid call statuses have value >= 0 */
|
||||
static int call_status_with_id(struct ofono_voicecall *vc, int id)
|
||||
static int ril_voicecall_status_with_id(struct ofono_voicecall *vc,
|
||||
unsigned int id)
|
||||
{
|
||||
GSList *l;
|
||||
struct voicecall *v;
|
||||
struct ofono_call *call = ofono_voicecall_find_call(vc, id);
|
||||
|
||||
GASSERT(vc);
|
||||
return call ? call->status : -1;
|
||||
}
|
||||
|
||||
for (l = vc->call_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
if (v->call->id == id) {
|
||||
return v->call->status;
|
||||
/* Tries to parse the payload as a uint followed by a string */
|
||||
static int ril_voicecall_parse_lastcause_1(const void *data, guint len)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (len > 8) {
|
||||
int code;
|
||||
char *msg = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &code) && code >= 0 &&
|
||||
(msg = grilio_parser_get_utf8(&rilp)) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
DBG("%d \"%s\"", code, msg);
|
||||
result = code;
|
||||
}
|
||||
g_free(msg);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct lastcause_req *reqdata = user_data;
|
||||
struct ofono_voicecall *vc = reqdata->vc;
|
||||
int tmp;
|
||||
struct ril_voicecall *vd = reqdata->vd;
|
||||
struct ofono_voicecall *vc = vd->vc;
|
||||
int id = reqdata->id;
|
||||
int call_status;
|
||||
|
||||
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
|
||||
grilio_parser_get_int32(&rilp, &last_cause);
|
||||
int last_cause;
|
||||
|
||||
/*
|
||||
* According to ril.h:
|
||||
*
|
||||
* "response" is a "int *"
|
||||
* ((int *)response)[0] is RIL_LastCallFailCause. GSM failure
|
||||
* reasons are mapped to cause codes defined in TS 24.008 Annex H
|
||||
* where possible.
|
||||
*
|
||||
* However some RILs feel free to invent their own formats,
|
||||
* try those first.
|
||||
*/
|
||||
|
||||
last_cause = ril_voicecall_parse_lastcause_1(data, len);
|
||||
if (last_cause < 0) {
|
||||
GRilIoParser rilp;
|
||||
int num, code;
|
||||
|
||||
/* Default format described in ril.h */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &num) && num == 1 &&
|
||||
grilio_parser_get_int32(&rilp, &code) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
last_cause = code;
|
||||
} else {
|
||||
ofono_warn("Unable to parse last call fail cause");
|
||||
last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -208,7 +265,14 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
|
||||
* from a network failure.
|
||||
*/
|
||||
switch (last_cause) {
|
||||
if (gutil_ints_contains(vd->remote_hangup_reasons, last_cause)) {
|
||||
DBG("hangup cause %d => remote hangup", last_cause);
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
} else if (gutil_ints_contains(vd->local_hangup_reasons, last_cause)) {
|
||||
DBG("hangup cause %d => local hangup", last_cause);
|
||||
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
|
||||
} else {
|
||||
switch (last_cause) {
|
||||
case CALL_FAIL_UNOBTAINABLE_NUMBER:
|
||||
case CALL_FAIL_NORMAL:
|
||||
case CALL_FAIL_BUSY:
|
||||
@@ -216,19 +280,19 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
|
||||
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
|
||||
case CALL_FAIL_NO_USER_RESPONDING:
|
||||
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
|
||||
case CALL_FAIL_NO_ANSWER_FROM_USER:
|
||||
case CALL_FAIL_CALL_REJECTED:
|
||||
case CALL_FAIL_NUMBER_CHANGED:
|
||||
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
|
||||
case CALL_FAIL_PRE_EMPTION:
|
||||
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
|
||||
case CALL_FAIL_INCOMPLETE_NUMBER:
|
||||
case CALL_FAIL_INVALID_NUMBER_FORMAT:
|
||||
case CALL_FAIL_FACILITY_REJECTED:
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
break;
|
||||
|
||||
case CALL_FAIL_NORMAL_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
call_status = ril_voicecall_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_ACTIVE ||
|
||||
call_status == CALL_STATUS_HELD ||
|
||||
call_status == CALL_STATUS_DIALING ||
|
||||
@@ -240,9 +304,10 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
break;
|
||||
|
||||
case CALL_FAIL_ERROR_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
call_status = ril_voicecall_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
call_status == CALL_STATUS_ALERTING ||
|
||||
call_status == CALL_STATUS_INCOMING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
}
|
||||
break;
|
||||
@@ -250,6 +315,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
default:
|
||||
reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
|
||||
@@ -269,14 +335,18 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
GASSERT(vd->clcc_poll_id);
|
||||
vd->clcc_poll_id = 0;
|
||||
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("We are polling CLCC and received an error");
|
||||
ofono_error("All bets are off for call management");
|
||||
return;
|
||||
/*
|
||||
* Only RIL_E_SUCCESS and RIL_E_RADIO_NOT_AVAILABLE are expected here,
|
||||
* all other errors are filtered out by ril_voicecall_clcc_retry()
|
||||
*/
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
calls = ril_voicecall_parse_clcc(data, len);
|
||||
} else {
|
||||
/* RADIO_NOT_AVAILABLE == no calls */
|
||||
GASSERT(status == RIL_E_RADIO_NOT_AVAILABLE);
|
||||
calls = NULL;
|
||||
}
|
||||
|
||||
calls = ril_voicecall_parse_clcc(data, len);
|
||||
|
||||
n = calls;
|
||||
o = vd->calls;
|
||||
|
||||
@@ -285,7 +355,9 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_call *oc = o ? o->data : NULL;
|
||||
|
||||
if (oc && (nc == NULL || (nc->id > oc->id))) {
|
||||
if (vd->local_release & (1 << oc->id)) {
|
||||
/* old call is gone */
|
||||
if (gutil_int_array_remove_all_fast(
|
||||
vd->local_release_ids, oc->id)) {
|
||||
ofono_voicecall_disconnected(vd->vc, oc->id,
|
||||
OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
|
||||
NULL);
|
||||
@@ -295,7 +367,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
struct lastcause_req *reqdata =
|
||||
g_new0(struct lastcause_req, 1);
|
||||
|
||||
reqdata->vc = vd->vc;
|
||||
reqdata->vd = vd;
|
||||
reqdata->id = oc->id;
|
||||
grilio_queue_send_request_full(vd->q, NULL,
|
||||
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
|
||||
@@ -365,9 +437,19 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
vd->local_release = 0;
|
||||
}
|
||||
|
||||
static gboolean ril_voicecall_clcc_retry(GRilIoRequest* req, int ril_status,
|
||||
const void* response_data, guint response_len, void* user_data)
|
||||
{
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
@@ -376,6 +458,7 @@ static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
if (!vd->clcc_poll_id) {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_request_set_retry_func(req, ril_voicecall_clcc_retry);
|
||||
vd->clcc_poll_id = grilio_queue_send_request_full(vd->q,
|
||||
req, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||
ril_voicecall_clcc_poll_cb, NULL, vd);
|
||||
@@ -386,52 +469,47 @@ static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
static void ril_voicecall_request_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall_change_state_req *req = user_data;
|
||||
struct ril_voicecall_request_data *req = user_data;
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(req->vc);
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GSList *l;
|
||||
|
||||
if (req->affected_types) {
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
|
||||
if (req->affected_types & (1 << call->status)) {
|
||||
vd->local_release |= (1 << call->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ofono_error("generic fail");
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
ril_voicecall_clcc_poll(vd);
|
||||
|
||||
/* We have to callback after we schedule a poll if required */
|
||||
if (req->cb) {
|
||||
/*
|
||||
* The ofono API call is considered successful if at least one
|
||||
* associated RIL request succeeds.
|
||||
*/
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
req->success++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only invoke the callback if this is the last request associated
|
||||
* with this ofono api call (pending call count becomes zero).
|
||||
*/
|
||||
GASSERT(req->pending_call_count > 0);
|
||||
if (!--req->pending_call_count && req->cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (req->success) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
req->cb(&error, req->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
|
||||
unsigned int affected_types, GRilIoRequest *ioreq,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
static void ril_voicecall_request(const guint code, struct ofono_voicecall *vc,
|
||||
GRilIoRequest *req, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall_change_state_req *req;
|
||||
struct ril_voicecall_request_data *req_data =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
|
||||
req = g_new0(struct ril_voicecall_change_state_req, 1);
|
||||
req->vc = vc;
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
req->affected_types = affected_types;
|
||||
|
||||
grilio_queue_send_request_full(vd->q, ioreq, rreq,
|
||||
ril_voicecall_request_cb, g_free, req);
|
||||
req_data->pending_call_count++;
|
||||
grilio_queue_send_request_full(ril_voicecall_get_data(vc)->q, req,
|
||||
code, ril_voicecall_request_cb,
|
||||
ril_voicecall_request_data_free, req_data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
|
||||
@@ -489,47 +567,68 @@ static void ril_voicecall_dial(struct ofono_voicecall *vc,
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
|
||||
int id, struct ril_voicecall_request_data *req)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
GRilIoRequest *ioreq = grilio_request_array_int32_new(1, id);
|
||||
|
||||
/* Append the call id to the list of calls being released locally */
|
||||
GASSERT(!gutil_int_array_contains(vd->local_release_ids, id));
|
||||
gutil_int_array_append(vd->local_release_ids, id);
|
||||
|
||||
/* Send request to RIL. ril_voicecall_request_data_free will unref
|
||||
* the request data */
|
||||
req->ref_count++;
|
||||
req->pending_call_count++;
|
||||
grilio_queue_send_request_full(vd->q, ioreq, RIL_REQUEST_HANGUP,
|
||||
ril_voicecall_request_cb,
|
||||
ril_voicecall_request_data_free, req);
|
||||
grilio_request_unref(ioreq);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ofono_error error;
|
||||
GSList *l;
|
||||
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
if (vd->calls) {
|
||||
GSList *l;
|
||||
struct ril_voicecall_request_data *req =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
|
||||
/* TODO: Hangup just the active ones once we have call
|
||||
* state tracking (otherwise it can't handle ringing) */
|
||||
DBG("Hanging up call with id %d", call->id);
|
||||
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
|
||||
grilio_request_append_int32(req, call->id);
|
||||
/*
|
||||
* Here the idea is that we submit (potentially) multiple
|
||||
* hangup requests to RIL and invoke the callback after
|
||||
* the last request has completed (pending call count
|
||||
* becomes zero).
|
||||
*/
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
|
||||
/* Send request to RIL */
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req,
|
||||
NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
/* Send request to RIL */
|
||||
DBG("Hanging up call with id %d", call->id);
|
||||
ril_voicecall_submit_hangup_req(vc, call->id, req);
|
||||
}
|
||||
|
||||
/* Release our reference */
|
||||
ril_voicecall_request_data_unref(req);
|
||||
} else {
|
||||
/* No calls */
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
/* TODO: Deal in case of an error at hungup */
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_specific(struct ofono_voicecall *vc,
|
||||
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
|
||||
int id, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
struct ofono_error error;
|
||||
struct ril_voicecall_request_data *req =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
|
||||
DBG("Hanging up call with id %d", id);
|
||||
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
|
||||
grilio_request_append_int32(req, id);
|
||||
|
||||
/* Send request to RIL */
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
ril_voicecall_submit_hangup_req(vc, id, req);
|
||||
ril_voicecall_request_data_unref(req);
|
||||
}
|
||||
|
||||
static void ril_voicecall_call_state_changed_event(GRilIoChannel *io,
|
||||
@@ -584,7 +683,7 @@ static void ril_voicecall_answer(struct ofono_voicecall *vc,
|
||||
{
|
||||
/* Send request to RIL */
|
||||
DBG("Answering current call");
|
||||
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, 0, NULL, cb, data);
|
||||
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
|
||||
@@ -650,90 +749,81 @@ static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_clcc_poll_on_success(GRilIoChannel *io,
|
||||
int status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ril_voicecall_clcc_poll((struct ril_voicecall *)user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
grilio_queue_send_request_full(vd->q, NULL, RIL_REQUEST_CONFERENCE,
|
||||
ril_voicecall_clcc_poll_on_success, NULL, vd);
|
||||
ril_voicecall_request(RIL_REQUEST_CONFERENCE, vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_transfer(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_EXPLICIT_CALL_TRANSFER,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, id);
|
||||
grilio_queue_send_request_full(vd->q, req,
|
||||
RIL_REQUEST_SEPARATE_CONNECTION,
|
||||
ril_voicecall_clcc_poll_on_success, NULL, vd);
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, id);
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("Private chat with id %d", id);
|
||||
ril_voicecall_request(RIL_REQUEST_SEPARATE_CONNECTION,
|
||||
vc, req, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_swap_without_accept(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hold_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_all_held(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
|
||||
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* size of array */
|
||||
grilio_request_append_int32(req, 1); /* notifications enabled */
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, 1);
|
||||
|
||||
grilio_request_set_timeout(req, VOICECALL_BLOCK_TIMEOUT_MS);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_queue_send_request(vd->q, req,
|
||||
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Makes this a single shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
|
||||
@@ -761,12 +851,10 @@ static void ril_voicecall_ecclist_changed(struct ril_ecclist *list, void *data)
|
||||
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
static void ril_voicecall_register(gpointer user_data)
|
||||
{
|
||||
struct ril_voicecall *vd = user_data;
|
||||
|
||||
GASSERT(vd->timer_id);
|
||||
vd->timer_id = 0;
|
||||
ofono_voicecall_register(vd->vc);
|
||||
|
||||
/* Emergency Call Codes */
|
||||
@@ -800,15 +888,13 @@ static gboolean ril_delayed_register(gpointer user_data)
|
||||
grilio_channel_add_unsol_event_handler(vd->io,
|
||||
ril_voicecall_ringback_tone_event,
|
||||
RIL_UNSOL_RINGBACK_TONE, vd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
const struct ril_slot_config *cfg = &modem->config;
|
||||
struct ril_voicecall *vd;
|
||||
|
||||
DBG("");
|
||||
@@ -816,13 +902,17 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
vd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
vd->q = grilio_queue_new(vd->io);
|
||||
vd->dtmf_queue = gutil_ring_new();
|
||||
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
|
||||
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
|
||||
vd->local_release_ids = gutil_int_array_new();
|
||||
vd->idleq = gutil_idle_queue_new();
|
||||
vd->vc = vc;
|
||||
vd->timer_id = g_idle_add(ril_delayed_register, vd);
|
||||
if (modem->ecclist_file) {
|
||||
vd->ecclist = ril_ecclist_new(modem->ecclist_file);
|
||||
}
|
||||
ril_voicecall_clear_dtmf_queue(vd);
|
||||
ofono_voicecall_set_data(vc, vd);
|
||||
gutil_idle_queue_add(vd->idleq, ril_voicecall_register, vd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -834,10 +924,6 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
if (vd->timer_id > 0) {
|
||||
g_source_remove(vd->timer_id);
|
||||
}
|
||||
|
||||
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
|
||||
ril_ecclist_unref(vd->ecclist);
|
||||
|
||||
@@ -847,6 +933,10 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
gutil_ring_unref(vd->dtmf_queue);
|
||||
gutil_ints_unref(vd->local_hangup_reasons);
|
||||
gutil_ints_unref(vd->remote_hangup_reasons);
|
||||
gutil_int_array_free(vd->local_release_ids, TRUE);
|
||||
gutil_idle_queue_free(vd->idleq);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
@@ -857,7 +947,7 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
|
||||
.dial = ril_voicecall_dial,
|
||||
.answer = ril_voicecall_answer,
|
||||
.hangup_all = ril_voicecall_hangup_all,
|
||||
.release_specific = ril_voicecall_hangup_specific,
|
||||
.release_specific = ril_voicecall_release_specific,
|
||||
.send_tones = ril_voicecall_send_dtmf,
|
||||
.create_multiparty = ril_voicecall_create_multiparty,
|
||||
.transfer = ril_voicecall_transfer,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2014 Jolla Ltd
|
||||
* Contact: Miia Leinonen
|
||||
* 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
|
||||
@@ -20,65 +21,63 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
|
||||
#include <ofono/call-barring.h>
|
||||
#include "common.h"
|
||||
|
||||
#include "gril.h"
|
||||
#include "call-barring.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
/* See 3GPP 27.007 7.4 for possible values */
|
||||
#define RIL_MAX_SERVICE_LENGTH 3
|
||||
|
||||
/*
|
||||
* ril.h does not state that string count must be given, but that is
|
||||
* still expected by the modem
|
||||
*/
|
||||
#define RIL_QUERY_STRING_COUNT 4
|
||||
#define RIL_SET_STRING_COUNT 5
|
||||
#define RIL_SET_PW_STRING_COUNT 3
|
||||
|
||||
#define RIL_LENGTH_ZERO 0
|
||||
|
||||
struct barring_data {
|
||||
GRil *ril;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* RIL modems do not support 7 as default bearer class. According to TS 22.030
|
||||
* Annex C: When service code is not given it corresponds to "All tele and
|
||||
* bearer services"
|
||||
*/
|
||||
#define FIXUP_CLS() \
|
||||
if (cls == BEARER_CLASS_DEFAULT) \
|
||||
cls = SERVICE_CLASS_NONE \
|
||||
|
||||
static void ril_call_barring_query_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct parcel rilp;
|
||||
struct ofono_error error;
|
||||
ofono_call_barring_query_cb_t cb = cbd->cb;
|
||||
int bearer_class = 0;
|
||||
struct barring_data *bd = cbd->user;
|
||||
struct parcel rilp;
|
||||
int bearer_class;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("Call Barring query failed, err: %i",
|
||||
message->error);
|
||||
decode_ril_error(&error, "FAIL");
|
||||
goto out;
|
||||
}
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
/* TODO: infineon returns two integers, use a quirk here */
|
||||
if (parcel_r_int32(&rilp) < 1)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Services for which the specified barring facility is active.
|
||||
* "0" means "disabled for all, -1 if unknown"
|
||||
*/
|
||||
parcel_r_int32(&rilp); /* count - we know there is only 1 */
|
||||
bearer_class = parcel_r_int32(&rilp);
|
||||
DBG("Active services: %i", bearer_class);
|
||||
|
||||
decode_ril_error(&error, "OK");
|
||||
if (bearer_class < 0 || rilp.malformed)
|
||||
goto error;
|
||||
|
||||
out:
|
||||
cb(&error, bearer_class, cbd->data);
|
||||
g_ril_append_print_buf(bd->ril, "{%d}", bearer_class);
|
||||
g_ril_print_response(bd->ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, bearer_class, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_call_barring_query(struct ofono_call_barring *cb,
|
||||
@@ -87,65 +86,67 @@ static void ril_call_barring_query(struct ofono_call_barring *cb,
|
||||
void *data)
|
||||
{
|
||||
struct barring_data *bd = ofono_call_barring_get_data(cb);
|
||||
struct cb_data *cbd = cb_data_new(callback, data);
|
||||
struct cb_data *cbd = cb_data_new(callback, data, bd);
|
||||
struct parcel rilp;
|
||||
int ret = 0;
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
char svcs_str[4];
|
||||
|
||||
DBG("lock: %s, services to query: %i", lock, cls);
|
||||
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;
|
||||
FIXUP_CLS();
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/*
|
||||
* See 3GPP 27.007 7.4 for parameter descriptions.
|
||||
* According to ril.h password should be empty string "" when not
|
||||
* needed, but in reality we only need to give string length as 0
|
||||
*/
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, RIL_QUERY_STRING_COUNT); /* Nbr of strings */
|
||||
parcel_w_string(&rilp, (char *) lock); /* Facility code */
|
||||
parcel_w_int32(&rilp, RIL_LENGTH_ZERO); /* Password length */
|
||||
parcel_w_string(&rilp, (char *) cls_textual);
|
||||
parcel_w_string(&rilp, NULL); /* AID (for FDN, not yet supported) */
|
||||
parcel_w_int32(&rilp, 4); /* # of strings */
|
||||
parcel_w_string(&rilp, lock);
|
||||
parcel_w_string(&rilp, ""); /* Password is empty when not needed */
|
||||
snprintf(svcs_str, sizeof(svcs_str), "%d", cls);
|
||||
parcel_w_string(&rilp, svcs_str);
|
||||
parcel_w_string(&rilp, NULL); /* AID (for FDN, not yet supported) */
|
||||
|
||||
ret = g_ril_send(bd->ril, RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
rilp.data, rilp.size, ril_call_barring_query_cb,
|
||||
cbd, g_free);
|
||||
g_ril_append_print_buf(bd->ril, "(%s,\"\",%s,(null))",
|
||||
lock, svcs_str);
|
||||
|
||||
parcel_free(&rilp);
|
||||
if (g_ril_send(bd->ril, RIL_REQUEST_QUERY_FACILITY_LOCK, &rilp,
|
||||
ril_call_barring_query_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("Sending Call Barring query failed, err: %i", ret);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(callback, -1, data);
|
||||
}
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(callback, -1, data);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_error error;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb;
|
||||
struct barring_data *bd = cbd->user;
|
||||
struct parcel rilp;
|
||||
int retries = -1;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("Call Barring Set request failed, err: %i",
|
||||
message->error);
|
||||
decode_ril_error(&error, "FAIL");
|
||||
goto out;
|
||||
}
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
decode_ril_error(&error, "OK");
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
out:
|
||||
cb(&error, cbd->data);
|
||||
/* mako reply has no payload for call barring */
|
||||
if (parcel_data_avail(&rilp) == 0)
|
||||
goto done;
|
||||
|
||||
if (parcel_r_int32(&rilp) != 1)
|
||||
goto error;
|
||||
|
||||
retries = parcel_r_int32(&rilp);
|
||||
|
||||
if (rilp.malformed)
|
||||
goto error;
|
||||
|
||||
done:
|
||||
g_ril_append_print_buf(bd->ril, "{%d}", retries);
|
||||
g_ril_print_response(bd->ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set(struct ofono_call_barring *cb,
|
||||
@@ -155,69 +156,54 @@ static void ril_call_barring_set(struct ofono_call_barring *cb,
|
||||
void *data)
|
||||
{
|
||||
struct barring_data *bd = ofono_call_barring_get_data(cb);
|
||||
struct cb_data *cbd = cb_data_new(callback, data);
|
||||
struct cb_data *cbd = cb_data_new(callback, data, bd);
|
||||
struct parcel rilp;
|
||||
int ret = 0;
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
char svcs_str[4];
|
||||
|
||||
DBG("lock: %s, enable: %i, bearer class: %i", lock, enable, cls);
|
||||
DBG("lock: %s, enable: %d, bearer class: %d", 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;
|
||||
FIXUP_CLS();
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/* See 3GPP 27.007 7.4 for parameter descriptions */
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, RIL_SET_STRING_COUNT); /* Nbr of strings */
|
||||
parcel_w_string(&rilp, (char *) lock); /* Facility code */
|
||||
|
||||
if (enable)
|
||||
parcel_w_string(&rilp, RIL_FACILITY_LOCK);
|
||||
else
|
||||
parcel_w_string(&rilp, RIL_FACILITY_UNLOCK);
|
||||
|
||||
parcel_w_string(&rilp, (char *) passwd);
|
||||
parcel_w_string(&rilp, (char *) cls_textual);
|
||||
parcel_w_int32(&rilp, 5); /* # of strings */
|
||||
parcel_w_string(&rilp, lock);
|
||||
parcel_w_string(&rilp, enable ? "1" : "0");
|
||||
parcel_w_string(&rilp, passwd);
|
||||
snprintf(svcs_str, sizeof(svcs_str), "%d", cls);
|
||||
parcel_w_string(&rilp, svcs_str);
|
||||
parcel_w_string(&rilp, NULL); /* AID (for FDN, not yet supported) */
|
||||
|
||||
ret = g_ril_send(bd->ril, RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
rilp.data, rilp.size, ril_call_barring_set_cb,
|
||||
cbd, g_free);
|
||||
g_ril_append_print_buf(bd->ril, "(%s,%s,%s,%s,(null))",
|
||||
lock, enable ? "1" : "0", passwd, svcs_str);
|
||||
|
||||
parcel_free(&rilp);
|
||||
if (g_ril_send(bd->ril, RIL_REQUEST_SET_FACILITY_LOCK, &rilp,
|
||||
ril_call_barring_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("Sending Call Barring Set request failed, err: %i",
|
||||
ret);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(callback, data);
|
||||
}
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(callback, data);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_error error;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb;
|
||||
struct barring_data *bd = cbd->user;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("Call Barring Set PW req failed, err: %i",
|
||||
message->error);
|
||||
decode_ril_error(&error, "FAIL");
|
||||
goto out;
|
||||
ofono_error("%s: set password failed, err: %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
decode_ril_error(&error, "OK");
|
||||
g_ril_print_response_no_args(bd->ril, message);
|
||||
|
||||
out:
|
||||
cb(&error, cbd->data);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd(struct ofono_call_barring *barr,
|
||||
@@ -228,38 +214,32 @@ static void ril_call_barring_set_passwd(struct ofono_call_barring *barr,
|
||||
void *data)
|
||||
{
|
||||
struct barring_data *bd = ofono_call_barring_get_data(barr);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, bd);
|
||||
struct parcel rilp;
|
||||
int ret = 0;
|
||||
|
||||
DBG("");
|
||||
DBG("lock %s old %s new %s", lock, old_passwd, new_passwd);
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, RIL_SET_PW_STRING_COUNT); /* Nbr of strings */
|
||||
parcel_w_string(&rilp, (char *) lock); /* Facility code */
|
||||
parcel_w_string(&rilp, (char *) old_passwd);
|
||||
parcel_w_string(&rilp, (char *) new_passwd);
|
||||
|
||||
ret = g_ril_send(bd->ril, RIL_REQUEST_CHANGE_BARRING_PASSWORD,
|
||||
rilp.data, rilp.size, ril_call_barring_set_passwd_cb,
|
||||
cbd, g_free);
|
||||
parcel_w_int32(&rilp, 3); /* # of strings */
|
||||
parcel_w_string(&rilp, lock);
|
||||
parcel_w_string(&rilp, old_passwd);
|
||||
parcel_w_string(&rilp, new_passwd);
|
||||
|
||||
parcel_free(&rilp);
|
||||
g_ril_append_print_buf(bd->ril, "(%s,%s,%s)",
|
||||
lock, old_passwd, new_passwd);
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("Sending Call Barring Set PW req failed, err: %i",
|
||||
ret);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
if (g_ril_send(bd->ril, RIL_REQUEST_CHANGE_BARRING_PASSWORD, &rilp,
|
||||
ril_call_barring_set_passwd_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_barring *cb = user_data;
|
||||
struct barring_data *bd = ofono_call_barring_get_data(cb);
|
||||
|
||||
bd->timer_id = 0;
|
||||
|
||||
ofono_call_barring_register(cb);
|
||||
return FALSE;
|
||||
@@ -270,10 +250,13 @@ static int ril_call_barring_probe(struct ofono_call_barring *cb,
|
||||
{
|
||||
GRil *ril = user;
|
||||
struct barring_data *bd = g_try_new0(struct barring_data, 1);
|
||||
if (bd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
bd->ril = g_ril_clone(ril);
|
||||
ofono_call_barring_set_data(cb, bd);
|
||||
bd->timer_id = g_timeout_add_seconds(2, ril_delayed_register, cb);
|
||||
|
||||
g_idle_add(ril_delayed_register, cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -283,9 +266,6 @@ static void ril_call_barring_remove(struct ofono_call_barring *cb)
|
||||
struct barring_data *data = ofono_call_barring_get_data(cb);
|
||||
ofono_call_barring_set_data(cb, NULL);
|
||||
|
||||
if (data->timer_id > 0)
|
||||
g_source_remove(data->timer_id);
|
||||
|
||||
g_ril_unref(data->ril);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2014 Jolla Ltd
|
||||
* Copyright (C) 2013 Jolla Ltd
|
||||
* Contact: Jussi Kangas <jussi.kangas@tieto.com>
|
||||
* 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
|
||||
@@ -35,39 +36,235 @@
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-forwarding.h>
|
||||
#include "common.h"
|
||||
|
||||
#include "gril.h"
|
||||
#include "grilutil.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
|
||||
#include "ril_constants.h"
|
||||
#include "common.h"
|
||||
|
||||
struct forw_data {
|
||||
GRil *ril;
|
||||
guint timer_id;
|
||||
int last_cls;
|
||||
};
|
||||
|
||||
enum call_forward_cmd {
|
||||
CF_ACTION_DISABLE,
|
||||
CF_ACTION_ENABLE,
|
||||
CF_ACTION_UNUSED,
|
||||
CF_ACTION_REGISTRATION,
|
||||
CF_ACTION_ERASURE,
|
||||
};
|
||||
static void ril_query_call_fwd_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cbd->user);
|
||||
ofono_call_forwarding_query_cb_t cb = cbd->cb;
|
||||
struct ofono_call_forwarding_condition *list;
|
||||
struct parcel rilp;
|
||||
unsigned int list_size;
|
||||
unsigned int i;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: rild error: %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
if (rilp.size < sizeof(int32_t))
|
||||
goto error;
|
||||
|
||||
list_size = parcel_r_int32(&rilp);
|
||||
if (list_size == 0) {
|
||||
list = g_new0(struct ofono_call_forwarding_condition, 1);
|
||||
list_size = 1;
|
||||
|
||||
list->status = 0;
|
||||
list->cls = fd->last_cls;
|
||||
goto done;
|
||||
}
|
||||
|
||||
list = g_new0(struct ofono_call_forwarding_condition, list_size);
|
||||
|
||||
g_ril_append_print_buf(fd->ril, "{");
|
||||
|
||||
for (i = 0; i < list_size; i++) {
|
||||
char *str;
|
||||
|
||||
list[i].status = parcel_r_int32(&rilp);
|
||||
|
||||
parcel_r_int32(&rilp); /* skip reason */
|
||||
|
||||
list[i].cls = parcel_r_int32(&rilp);
|
||||
list[i].phone_number.type = parcel_r_int32(&rilp);
|
||||
|
||||
str = parcel_r_string(&rilp);
|
||||
|
||||
if (str != NULL) {
|
||||
strncpy(list[i].phone_number.number, str,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
g_free(str);
|
||||
|
||||
list[i].phone_number.number[
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
}
|
||||
|
||||
list[i].time = parcel_r_int32(&rilp);
|
||||
|
||||
if (rilp.malformed) {
|
||||
ofono_error("%s: malformed parcel", __func__);
|
||||
g_free(list);
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_ril_append_print_buf(fd->ril, "%s [%d,%d,%d,%s,%d]",
|
||||
print_buf,
|
||||
list[i].status,
|
||||
list[i].cls,
|
||||
list[i].phone_number.type,
|
||||
list[i].phone_number.number,
|
||||
list[i].time);
|
||||
|
||||
}
|
||||
|
||||
g_ril_append_print_buf(fd->ril, "%s}", print_buf);
|
||||
g_ril_print_response(fd->ril, message);
|
||||
|
||||
done:
|
||||
CALLBACK_WITH_SUCCESS(cb, (int) list_size, list, cbd->data);
|
||||
g_free(list);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_set_forward_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_call_forwarding_set_cb_t cb = cbd->cb;
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cbd->user);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else {
|
||||
ofono_error("CF setting failed");
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: failed; rild error: %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
g_ril_print_response_no_args(fd->ril, message);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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_NONE as with it e.g.
|
||||
* ./send-ussd '*21*<phone_number>#' returns cls:53 i.e. 1+4+16+32 as
|
||||
* service class.
|
||||
*/
|
||||
#define FIXUP_CLS() \
|
||||
if (cls == BEARER_CLASS_DEFAULT) \
|
||||
cls = SERVICE_CLASS_NONE \
|
||||
|
||||
/*
|
||||
* Activation/deactivation/erasure actions, have no number associated with them,
|
||||
* but apparently rild expects a number anyway. So fields need to be filled.
|
||||
* Otherwise there is no response.
|
||||
*/
|
||||
#define APPEND_DUMMY_NUMBER() \
|
||||
parcel_w_int32(&rilp, 0x81); \
|
||||
parcel_w_string(&rilp, "1234567890") \
|
||||
|
||||
/*
|
||||
* Time has no real meaing for action commands other then registration, so
|
||||
* if not needed, set arbitrary 60s time so rild doesn't return an error.
|
||||
*/
|
||||
#define APPEND_DUMMY_TIME() \
|
||||
parcel_w_int32(&rilp, 60);
|
||||
|
||||
static void ril_activate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cf);
|
||||
struct parcel rilp;
|
||||
|
||||
FIXUP_CLS();
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1); /* Activation: 1 */
|
||||
parcel_w_int32(&rilp, type);
|
||||
parcel_w_int32(&rilp, cls);
|
||||
APPEND_DUMMY_NUMBER();
|
||||
APPEND_DUMMY_TIME();
|
||||
|
||||
g_ril_append_print_buf(fd->ril, "(action: 1, type: %d cls: %d "
|
||||
"number type: %d number: %s time: %d)",
|
||||
type, cls, 0x81, "1234567890", 60);
|
||||
|
||||
if (g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
&rilp, ril_set_forward_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_erasure(struct ofono_call_forwarding *cf,
|
||||
int type, int cls,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cf);
|
||||
struct parcel rilp;
|
||||
|
||||
FIXUP_CLS();
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 4); /* Erasure: 4 */
|
||||
parcel_w_int32(&rilp, type);
|
||||
parcel_w_int32(&rilp, cls);
|
||||
APPEND_DUMMY_NUMBER();
|
||||
APPEND_DUMMY_TIME();
|
||||
|
||||
g_ril_append_print_buf(fd->ril, "(action: 4, type: %d cls: %d "
|
||||
"number type: %d number: %s time: %d)",
|
||||
type, cls, 0x81, "1234567890", 60);
|
||||
|
||||
if (g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
&rilp, ril_set_forward_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_deactivate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cf);
|
||||
struct parcel rilp;
|
||||
|
||||
FIXUP_CLS();
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 0); /* Deactivation: 0 */
|
||||
parcel_w_int32(&rilp, type);
|
||||
parcel_w_int32(&rilp, cls);
|
||||
APPEND_DUMMY_NUMBER();
|
||||
APPEND_DUMMY_TIME();
|
||||
|
||||
g_ril_append_print_buf(fd->ril, "(action: 0, type: %d cls: %d "
|
||||
"number type: %d number: %s time: %d)",
|
||||
type, cls, 0x81, "1234567890", 60);
|
||||
|
||||
if (g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
&rilp, ril_set_forward_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_registration(struct ofono_call_forwarding *cf, int type,
|
||||
@@ -77,173 +274,31 @@ static void ril_registration(struct ofono_call_forwarding *cf, int type,
|
||||
void *data)
|
||||
{
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cf);
|
||||
struct parcel rilp;
|
||||
int ret = 0;
|
||||
|
||||
ofono_info("cf registration");
|
||||
FIXUP_CLS();
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, CF_ACTION_REGISTRATION);
|
||||
|
||||
parcel_w_int32(&rilp, 3); /* Registration: 3 */
|
||||
parcel_w_int32(&rilp, type);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* BEARER_CLASS_VOICE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT)
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
|
||||
parcel_w_int32(&rilp, cls);
|
||||
|
||||
parcel_w_int32(&rilp, number->type);
|
||||
|
||||
parcel_w_string(&rilp, (char *) number->number);
|
||||
|
||||
parcel_w_string(&rilp, number->number);
|
||||
parcel_w_int32(&rilp, time);
|
||||
|
||||
ret = g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
rilp.data, rilp.size, ril_set_forward_cb, cbd, g_free);
|
||||
g_ril_append_print_buf(fd->ril, "(action: 3, type: %d cls: %d "
|
||||
"number type: %d number: %s time: %d)",
|
||||
type, cls, number->type, number->number,
|
||||
time);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
ofono_error("CF registration failed");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
}
|
||||
if (g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
&rilp, ril_set_forward_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
static void ril_send_forward_cmd(struct ofono_call_forwarding *cf,
|
||||
int type, int cls,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data,
|
||||
int action)
|
||||
{
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct parcel rilp;
|
||||
int ret = 0;
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, action);
|
||||
|
||||
parcel_w_int32(&rilp, type);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* BEARER_CLASS_VOICE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT)
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
|
||||
parcel_w_int32(&rilp, cls); /* Service class */
|
||||
|
||||
/* Following 3 values have no real meaning in erasure
|
||||
* but apparently RIL expects them so fields need to
|
||||
* be filled. Otherwise there is no response
|
||||
* */
|
||||
|
||||
parcel_w_int32(&rilp, 0x81); /* TOA unknown */
|
||||
|
||||
parcel_w_string(&rilp, "1234567890");
|
||||
|
||||
parcel_w_int32(&rilp, 60);
|
||||
|
||||
ret = g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
rilp.data, rilp.size, ril_set_forward_cb, cbd, g_free);
|
||||
|
||||
parcel_free(&rilp);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
ofono_error("CF action failed");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_erasure(struct ofono_call_forwarding *cf,
|
||||
int type, int cls,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("CF_ACTION_ERASURE");
|
||||
ril_send_forward_cmd(cf, type, cls, cb, data, CF_ACTION_ERASURE);
|
||||
}
|
||||
|
||||
static void ril_deactivate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("CF_ACTION_DISABLE");
|
||||
ril_send_forward_cmd(cf, type, cls, cb, data, CF_ACTION_DISABLE);
|
||||
}
|
||||
|
||||
static void ril_activate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("CF_ACTION_ENABLE");
|
||||
ril_send_forward_cmd(cf, type, cls, cb, data, CF_ACTION_ENABLE);
|
||||
}
|
||||
|
||||
static void ril_query_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_call_forwarding_query_cb_t cb = cbd->cb;
|
||||
struct ofono_call_forwarding_condition *list = NULL;
|
||||
struct parcel rilp;
|
||||
int nmbr_of_resps = 0;
|
||||
int i;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
nmbr_of_resps = parcel_r_int32(&rilp);
|
||||
|
||||
list = g_new0(
|
||||
struct ofono_call_forwarding_condition,
|
||||
nmbr_of_resps);
|
||||
|
||||
for (i = 0; i < nmbr_of_resps; i++) {
|
||||
char *str = NULL;
|
||||
|
||||
list[i].status = parcel_r_int32(&rilp);
|
||||
|
||||
parcel_r_int32(&rilp);
|
||||
|
||||
list[i].cls = parcel_r_int32(&rilp);
|
||||
|
||||
list[i].phone_number.type = parcel_r_int32(&rilp);
|
||||
|
||||
str = parcel_r_string(&rilp);
|
||||
if (str) {
|
||||
strncpy(list[i].phone_number.number,
|
||||
str,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
|
||||
list[i].phone_number.number[
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
g_free(str);
|
||||
}
|
||||
list[i].time = parcel_r_int32(&rilp);
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, nmbr_of_resps, list, cbd->data);
|
||||
|
||||
g_free(list);
|
||||
} else {
|
||||
ofono_error("CF query failed");
|
||||
CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
|
||||
}
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_query(struct ofono_call_forwarding *cf, int type, int cls,
|
||||
@@ -251,60 +306,36 @@ static void ril_query(struct ofono_call_forwarding *cf, int type, int cls,
|
||||
void *data)
|
||||
{
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cf);
|
||||
struct parcel rilp;
|
||||
int ret = 0;
|
||||
|
||||
ofono_info("cf query");
|
||||
FIXUP_CLS();
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 2);
|
||||
|
||||
parcel_w_int32(&rilp, 2); /* Interrogation: 2 */
|
||||
parcel_w_int32(&rilp, type);
|
||||
|
||||
/*
|
||||
* 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_NONE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT)
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
|
||||
parcel_w_int32(&rilp, cls);
|
||||
APPEND_DUMMY_NUMBER();
|
||||
APPEND_DUMMY_TIME();
|
||||
|
||||
/* Following 3 values have no real meaning in query
|
||||
* but apparently RIL expects them so fields need to
|
||||
* be filled. Otherwise there is no response
|
||||
*/
|
||||
g_ril_append_print_buf(fd->ril, "(action: 2, type: %d cls: %d "
|
||||
"number type: %d number: %s time: %d)",
|
||||
type, cls, 0x81, "1234567890", 60);
|
||||
|
||||
parcel_w_int32(&rilp, 0x81); /* TOA unknown */
|
||||
fd->last_cls = cls;
|
||||
|
||||
parcel_w_string(&rilp, "1234567890");
|
||||
if (g_ril_send(fd->ril, RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
&rilp, ril_query_call_fwd_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
parcel_w_int32(&rilp, 60);
|
||||
|
||||
ret = g_ril_send(fd->ril, RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
rilp.data, rilp.size, ril_query_cb, cbd, g_free);
|
||||
|
||||
parcel_free(&rilp);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
ofono_error("unable to send CF query");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
|
||||
}
|
||||
CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_forwarding *cf = user_data;
|
||||
struct forw_data *fd = ofono_call_forwarding_get_data(cf);
|
||||
|
||||
fd->timer_id = 0;
|
||||
|
||||
ofono_call_forwarding_register(cf);
|
||||
return FALSE;
|
||||
@@ -314,10 +345,23 @@ static int ril_call_forwarding_probe(struct ofono_call_forwarding *cf,
|
||||
unsigned int vendor, void *user)
|
||||
{
|
||||
GRil *ril = user;
|
||||
struct forw_data *fd = g_try_new0(struct forw_data, 1);
|
||||
struct forw_data *fd;
|
||||
|
||||
fd = g_try_new0(struct forw_data, 1);
|
||||
if (fd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
fd->ril = g_ril_clone(ril);
|
||||
ofono_call_forwarding_set_data(cf, fd);
|
||||
fd->timer_id = g_timeout_add_seconds(2, ril_delayed_register, cf);
|
||||
|
||||
/*
|
||||
* ofono_call_forwarding_register() needs to be called after
|
||||
* the driver has been set in ofono_call_forwarding_create(),
|
||||
* which calls this function. Most other drivers make
|
||||
* some kind of capabilities query to the modem, and then
|
||||
* call register in the callback; we use an idle event instead.
|
||||
*/
|
||||
g_idle_add(ril_delayed_register, cf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -327,15 +371,12 @@ static void ril_call_forwarding_remove(struct ofono_call_forwarding *cf)
|
||||
struct forw_data *data = ofono_call_forwarding_get_data(cf);
|
||||
ofono_call_forwarding_set_data(cf, NULL);
|
||||
|
||||
if (data->timer_id > 0)
|
||||
g_source_remove(data->timer_id);
|
||||
|
||||
g_ril_unref(data->ril);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static struct ofono_call_forwarding_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.name = RILMODEM,
|
||||
.probe = ril_call_forwarding_probe,
|
||||
.remove = ril_call_forwarding_remove,
|
||||
.erasure = ril_erasure,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013 Jolla Ltd
|
||||
* Copyright (C) 2013 Canonical Ltd
|
||||
* Contact: Jussi Kangas <jussi.kangas@tieto.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -36,81 +37,59 @@
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-settings.h>
|
||||
#include "common.h"
|
||||
|
||||
#include "gril.h"
|
||||
#include "grilutil.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
#include "ril_constants.h"
|
||||
#include "common.h"
|
||||
|
||||
struct settings_data {
|
||||
GRil *ril;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
static void ril_clip_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb;
|
||||
struct parcel rilp;
|
||||
int res = 0;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
/* data length of the response */
|
||||
res = parcel_r_int32(&rilp);
|
||||
|
||||
if (res > 0)
|
||||
res = parcel_r_int32(&rilp);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, res, cbd->data);
|
||||
} else
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_set_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_call_settings *cs = cbd->user;
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
ofono_call_settings_set_cb_t cb = cbd->cb;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
g_ril_print_response_no_args(sd->ril, message);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else
|
||||
} else {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cw_set(struct ofono_call_settings *cs, int mode, int cls,
|
||||
ofono_call_settings_set_cb_t cb, void *data){
|
||||
ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int ret = 0;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cs);
|
||||
int ret;
|
||||
struct parcel rilp;
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 2); /* Number of params */
|
||||
|
||||
parcel_w_int32(&rilp, mode); /* on/off */
|
||||
|
||||
/* Modem seems to respond with error to all queries
|
||||
/*
|
||||
* 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.
|
||||
* default bearer.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT)
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
|
||||
parcel_w_int32(&rilp, cls); /* Service class */
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 2); /* Number of params */
|
||||
parcel_w_int32(&rilp, mode); /* on/off */
|
||||
parcel_w_int32(&rilp, cls); /* Service class */
|
||||
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_SET_CALL_WAITING,
|
||||
rilp.data, rilp.size, ril_set_cb, cbd, g_free);
|
||||
g_ril_append_print_buf(sd->ril, "(%d, 0x%x)", mode, cls);
|
||||
|
||||
parcel_free(&rilp);
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_SET_CALL_WAITING, &rilp,
|
||||
ril_set_cb, cbd, g_free);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
@@ -122,55 +101,63 @@ static void ril_cw_set(struct ofono_call_settings *cs, int mode, int cls,
|
||||
static void ril_cw_query_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_call_settings *cs = cbd->user;
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb;
|
||||
struct parcel rilp;
|
||||
int res = 0;
|
||||
int sv = 0;
|
||||
int numparams;
|
||||
int enabled;
|
||||
int cls;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
/* first value in int[] is len so let's skip that */
|
||||
parcel_r_int32(&rilp);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
numparams = parcel_r_int32(&rilp);
|
||||
if (numparams < 1)
|
||||
goto error;
|
||||
|
||||
/* status of call waiting service, disabled is returned only if
|
||||
* service is not active for any service class */
|
||||
res = parcel_r_int32(&rilp);
|
||||
DBG("CW enabled/disabled: %d", res);
|
||||
enabled = parcel_r_int32(&rilp);
|
||||
if (enabled && numparams < 2)
|
||||
goto error;
|
||||
|
||||
if (res > 0) {
|
||||
/* services for which call waiting is enabled, 27.007 7.12 */
|
||||
sv = parcel_r_int32(&rilp);
|
||||
DBG("CW enabled for: %d", sv);
|
||||
}
|
||||
if (enabled > 0)
|
||||
cls = parcel_r_int32(&rilp);
|
||||
else
|
||||
cls = 0;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, sv, cbd->data);
|
||||
} else
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
g_ril_append_print_buf(sd->ril, "{%d,0x%x}", enabled, cls);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cls, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_cw_query(struct ofono_call_settings *cs, int cls,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int ret = 0;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cs);
|
||||
int ret;
|
||||
struct parcel rilp;
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1); /* Number of params */
|
||||
|
||||
/*
|
||||
* RILD expects service class to be 0 as certain carriers can reject the
|
||||
* query with specific service class
|
||||
*/
|
||||
parcel_w_int32(&rilp, 0);
|
||||
cls = 0;
|
||||
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_QUERY_CALL_WAITING,
|
||||
rilp.data, rilp.size, ril_cw_query_cb, cbd, g_free);
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1); /* Number of params */
|
||||
parcel_w_int32(&rilp, cls); /* Service Class */
|
||||
|
||||
parcel_free(&rilp);
|
||||
g_ril_append_print_buf(sd->ril, "(0)");
|
||||
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_QUERY_CALL_WAITING, &rilp,
|
||||
ril_cw_query_cb, cbd, g_free);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
@@ -179,16 +166,44 @@ static void ril_cw_query(struct ofono_call_settings *cs, int cls,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_clip_query_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_call_settings *cs = cbd->user;
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb;
|
||||
struct parcel rilp;
|
||||
int clip_status;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
if (parcel_r_int32(&rilp) != 1)
|
||||
goto error;
|
||||
|
||||
clip_status = parcel_r_int32(&rilp);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%d}", clip_status);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, clip_status, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_clip_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int ret = 0;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cs);
|
||||
int ret;
|
||||
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_QUERY_CLIP,
|
||||
NULL, 0, ril_clip_cb, cbd, g_free);
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_QUERY_CLIP, NULL,
|
||||
ril_clip_query_cb, cbd, g_free);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
@@ -197,38 +212,49 @@ static void ril_clip_query(struct ofono_call_settings *cs,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_clir_cb(struct ril_msg *message, gpointer user_data)
|
||||
static void ril_clir_query_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_call_settings *cs = cbd->user;
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
ofono_call_settings_clir_cb_t cb = cbd->cb;
|
||||
struct parcel rilp;
|
||||
int override, network;
|
||||
int override;
|
||||
int network;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: Reply failure: %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
/*first value in int[] is len so let's skip that*/
|
||||
parcel_r_int32(&rilp);
|
||||
/* Set HideCallerId property from network */
|
||||
override = parcel_r_int32(&rilp);
|
||||
/* CallingLineRestriction indicates the state of
|
||||
the CLIR supplementary service in the network */
|
||||
network = parcel_r_int32(&rilp);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, override, network, cbd->data);
|
||||
} else
|
||||
CALLBACK_WITH_FAILURE(cb, -1, -1, cbd->data);
|
||||
if (parcel_r_int32(&rilp) != 2)
|
||||
goto error;
|
||||
|
||||
override = parcel_r_int32(&rilp);
|
||||
network = parcel_r_int32(&rilp);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%d,%d}", override, network);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, override, network, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_clir_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_clir_cb_t cb, void *data)
|
||||
{
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int ret = 0;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cs);
|
||||
int ret;
|
||||
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_GET_CLIR,
|
||||
NULL, 0, ril_clir_cb, cbd, g_free);
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_GET_CLIR, NULL,
|
||||
ril_clir_query_cb, cbd, g_free);
|
||||
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
@@ -241,20 +267,19 @@ static void ril_clir_set(struct ofono_call_settings *cs, int mode,
|
||||
ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int ret = 0;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cs);
|
||||
struct parcel rilp;
|
||||
int ret;
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1); /* Number of params */
|
||||
parcel_w_int32(&rilp, 1); /* Number of params */
|
||||
parcel_w_int32(&rilp, mode);
|
||||
|
||||
parcel_w_int32(&rilp, mode); /* for outgoing calls */
|
||||
g_ril_append_print_buf(sd->ril, "(%d)", mode);
|
||||
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_SET_CLIR,
|
||||
rilp.data, rilp.size, ril_set_cb, cbd, g_free);
|
||||
|
||||
parcel_free(&rilp);
|
||||
ret = g_ril_send(sd->ril, RIL_REQUEST_SET_CLIR, &rilp,
|
||||
ril_set_cb, cbd, g_free);
|
||||
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
@@ -265,9 +290,6 @@ static void ril_clir_set(struct ofono_call_settings *cs, int mode,
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_settings *cs = user_data;
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
|
||||
sd->timer_id = 0;
|
||||
|
||||
ofono_call_settings_register(cs);
|
||||
|
||||
@@ -278,14 +300,13 @@ static int ril_call_settings_probe(struct ofono_call_settings *cs,
|
||||
unsigned int vendor, void *user)
|
||||
{
|
||||
GRil *ril = user;
|
||||
|
||||
struct settings_data *sd = g_try_new0(struct settings_data, 1);
|
||||
struct settings_data *sd = g_new0(struct settings_data, 1);
|
||||
|
||||
sd->ril = g_ril_clone(ril);
|
||||
|
||||
ofono_call_settings_set_data(cs, sd);
|
||||
|
||||
sd->timer_id = g_timeout_add_seconds(2, ril_delayed_register, cs);
|
||||
g_idle_add(ril_delayed_register, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -295,15 +316,12 @@ static void ril_call_settings_remove(struct ofono_call_settings *cs)
|
||||
struct settings_data *sd = ofono_call_settings_get_data(cs);
|
||||
ofono_call_settings_set_data(cs, NULL);
|
||||
|
||||
if (sd->timer_id > 0)
|
||||
g_source_remove(sd->timer_id);
|
||||
|
||||
g_ril_unref(sd->ril);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
static struct ofono_call_settings_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.name = RILMODEM,
|
||||
.probe = ril_call_settings_probe,
|
||||
.remove = ril_call_settings_remove,
|
||||
.clip_query = ril_clip_query,
|
||||
@@ -316,7 +334,7 @@ static struct ofono_call_settings_driver driver = {
|
||||
* Not supported in RIL API
|
||||
* .colp_query = ril_colp_query,
|
||||
* .colr_query = ril_colr_query
|
||||
*/
|
||||
*/
|
||||
};
|
||||
|
||||
void ril_call_settings_init(void)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012 Canonical Ltd.
|
||||
* Copyright (C) 2012-2013 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
|
||||
@@ -34,19 +34,15 @@
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-volume.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "grilutil.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "gril.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
#include "parcel.h"
|
||||
|
||||
struct cv_data {
|
||||
GRil *ril;
|
||||
unsigned int vendor;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
static void volume_mute_cb(struct ril_msg *message, gpointer user_data)
|
||||
@@ -70,33 +66,27 @@ static void volume_mute_cb(struct ril_msg *message, gpointer user_data)
|
||||
}
|
||||
|
||||
static void ril_call_volume_mute(struct ofono_call_volume *cv, int muted,
|
||||
ofono_call_volume_cb_t cb, void *data)
|
||||
ofono_call_volume_cb_t cb, void *data)
|
||||
{
|
||||
struct cv_data *cvd = ofono_call_volume_get_data(cv);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, cvd);
|
||||
struct parcel rilp;
|
||||
int request = RIL_REQUEST_SET_MUTE;
|
||||
int ret;
|
||||
cbd->user = cvd;
|
||||
|
||||
DBG("");
|
||||
DBG("muted: %d", muted);
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1);
|
||||
parcel_w_int32(&rilp, muted);
|
||||
DBG("Initial ril muted state: %d", muted);
|
||||
ret = g_ril_send(cvd->ril, request, rilp.data,
|
||||
rilp.size, volume_mute_cb, cbd, g_free);
|
||||
parcel_free(&rilp);
|
||||
|
||||
g_ril_append_print_buf(cvd->ril, "(%d)", muted);
|
||||
g_ril_print_request(cvd->ril, ret, request);
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("Send RIL_REQUEST_SET_MUTE failed.");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
if (g_ril_send(cvd->ril, RIL_REQUEST_SET_MUTE, &rilp,
|
||||
volume_mute_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void probe_mute_cb(struct ril_msg *message, gpointer user_data)
|
||||
@@ -106,13 +96,12 @@ static void probe_mute_cb(struct ril_msg *message, gpointer user_data)
|
||||
struct parcel rilp;
|
||||
int muted;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("Could not retrive the ril mute state");
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
return;
|
||||
}
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
/*first item in int[] is len so let's skip that*/
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
/* skip length of int[] */
|
||||
parcel_r_int32(&rilp);
|
||||
muted = parcel_r_int32(&rilp);
|
||||
|
||||
@@ -126,24 +115,15 @@ static void call_probe_mute(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_volume *cv = user_data;
|
||||
struct cv_data *cvd = ofono_call_volume_get_data(cv);
|
||||
int request = RIL_REQUEST_GET_MUTE;
|
||||
int ret;
|
||||
|
||||
ret = g_ril_send(cvd->ril, request, NULL, 0,
|
||||
probe_mute_cb, cv, NULL);
|
||||
|
||||
g_ril_print_request_no_args(cvd->ril, ret, request);
|
||||
g_ril_send(cvd->ril, RIL_REQUEST_GET_MUTE, NULL,
|
||||
probe_mute_cb, cv, NULL);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_volume *cv = user_data;
|
||||
struct cv_data *cvd = ofono_call_volume_get_data(cv);
|
||||
|
||||
DBG("");
|
||||
|
||||
cvd->timer_id = 0;
|
||||
|
||||
ofono_call_volume_register(cv);
|
||||
|
||||
/* Probe the mute state */
|
||||
@@ -154,7 +134,7 @@ static gboolean ril_delayed_register(gpointer user_data)
|
||||
}
|
||||
|
||||
static int ril_call_volume_probe(struct ofono_call_volume *cv,
|
||||
unsigned int vendor, void *data)
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
GRil *ril = data;
|
||||
struct cv_data *cvd;
|
||||
@@ -169,16 +149,13 @@ static int ril_call_volume_probe(struct ofono_call_volume *cv,
|
||||
ofono_call_volume_set_data(cv, cvd);
|
||||
|
||||
/*
|
||||
* TODO: analyze if capability check is needed
|
||||
* and/or timer should be adjusted.
|
||||
*
|
||||
* ofono_call_volume_register() needs to be called after
|
||||
* the driver has been set in ofono_call_volume_create(),
|
||||
* which calls this function. Most other drivers make
|
||||
* some kind of capabilities query to the modem, and then
|
||||
* call register in the callback; we use a timer instead.
|
||||
* some kind of capabilities query to the modem, and then
|
||||
* call register in the callback; we use an idle event instead.
|
||||
*/
|
||||
cvd->timer_id = g_timeout_add_seconds(2, ril_delayed_register, cv);
|
||||
g_idle_add(ril_delayed_register, cv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -189,9 +166,6 @@ static void ril_call_volume_remove(struct ofono_call_volume *cv)
|
||||
|
||||
ofono_call_volume_set_data(cv, NULL);
|
||||
|
||||
if (cvd->timer_id > 0)
|
||||
g_source_remove(cvd->timer_id);
|
||||
|
||||
g_ril_unref(cvd->ril);
|
||||
g_free(cvd);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013 Jolla Ltd
|
||||
* Copyright (C) 2008-2016 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
|
||||
@@ -27,124 +26,180 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/cbs.h>
|
||||
#include "util.h"
|
||||
|
||||
#include "gril.h"
|
||||
#include "grilutil.h"
|
||||
#include <gril.h>
|
||||
#include <parcel.h>
|
||||
|
||||
#include "rilmodem.h"
|
||||
#include "ril_constants.h"
|
||||
#include "vendor.h"
|
||||
|
||||
struct cbs_data {
|
||||
GRil *ril;
|
||||
guint timer_id;
|
||||
unsigned int vendor;
|
||||
};
|
||||
|
||||
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *user_data)
|
||||
static void ril_cbs_set_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
/*
|
||||
* Although this does not do anything real
|
||||
* towards network or modem, it is needed
|
||||
* because without it ofono core does not
|
||||
* change powered flag and it would reject
|
||||
* incoming cb messages.
|
||||
*/
|
||||
CALLBACK_WITH_SUCCESS(cb, user_data);
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_cbs_set_cb_t cb = cbd->cb;
|
||||
struct cbs_data *cd = cbd->user;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
} else {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(cd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *user_data)
|
||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *user_data)
|
||||
{
|
||||
/*
|
||||
* Although this does not do anything real
|
||||
* towards network or modem, it is needed
|
||||
* because without it ofono core does not
|
||||
* change powered flag and it would allow
|
||||
* incoming cb messages.
|
||||
*/
|
||||
CALLBACK_WITH_SUCCESS(cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_cbs_notify(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_cbs *cbs = user_data;
|
||||
|
||||
/*
|
||||
* Ofono does not support UMTS CB - see
|
||||
* src/smsutil.c method cbs_decode.
|
||||
* But let's let the core to make
|
||||
* the rejection reserve memory here
|
||||
* for maximum UMTS CB length
|
||||
*/
|
||||
|
||||
unsigned char pdu[1252];
|
||||
char *resp;
|
||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, cd);
|
||||
int i = 0, from, to;
|
||||
const char *p, *pto;
|
||||
char **segments;
|
||||
struct parcel rilp;
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
segments = g_strsplit(topics, ",", 0);
|
||||
|
||||
resp = parcel_r_string(&rilp);
|
||||
while (segments[i])
|
||||
i++;
|
||||
|
||||
memcpy(resp, pdu, strlen((char *)resp));
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, i);
|
||||
|
||||
ofono_cbs_notify(cbs, pdu, strlen((char *)resp));
|
||||
i = 0;
|
||||
while (segments[i]) {
|
||||
p = segments[i++];
|
||||
from = atoi(p);
|
||||
to = from;
|
||||
|
||||
pto = strchr(p, '-');
|
||||
if (pto)
|
||||
to = atoi(pto + 1);
|
||||
|
||||
parcel_w_int32(&rilp, from);
|
||||
parcel_w_int32(&rilp, to);
|
||||
|
||||
parcel_w_int32(&rilp, 0);
|
||||
parcel_w_int32(&rilp, 0xFF);
|
||||
|
||||
parcel_w_int32(&rilp, 1);
|
||||
}
|
||||
|
||||
g_strfreev(segments);
|
||||
|
||||
if (g_ril_send(cd->ril, RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, &rilp,
|
||||
ril_cbs_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *user_data)
|
||||
{
|
||||
ril_cbs_set_topics(cbs, "", cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_cbs_received(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_cbs *cbs = user_data;
|
||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||
struct parcel rilp;
|
||||
int pdulen;
|
||||
unsigned char *pdu;
|
||||
|
||||
cd->timer_id = 0;
|
||||
g_ril_print_unsol_no_args(cd->ril, message);
|
||||
|
||||
ofono_cbs_register(cbs);
|
||||
DBG("req: %d; data_len: %d", message->req, (int) message->buf_len);
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
pdu = parcel_r_raw(&rilp, &pdulen);
|
||||
|
||||
if (!pdu || pdulen != 88) {
|
||||
ofono_error("%s: it isn't a gsm cell broadcast msg", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_cbs_notify(cbs, pdu, pdulen);
|
||||
g_free(pdu);
|
||||
}
|
||||
|
||||
static void ril_cbs_register(const struct ofono_error *error, void *data)
|
||||
{
|
||||
struct ofono_cbs *cbs = data;
|
||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
g_ril_register(cd->ril, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||
ril_cbs_notify, cbs);
|
||||
ril_cbs_received, cbs);
|
||||
|
||||
return FALSE;
|
||||
ofono_cbs_register(cbs);
|
||||
}
|
||||
|
||||
static void get_cbs_config_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_cbs *cbs = user_data;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: RIL error %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
ofono_cbs_remove(cbs);
|
||||
return;
|
||||
}
|
||||
|
||||
ril_cbs_clear_topics(cbs, ril_cbs_register, cbs);
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
void *user)
|
||||
{
|
||||
GRil *ril = user;
|
||||
struct cbs_data *data;
|
||||
|
||||
struct cbs_data *cd = g_try_new0(struct cbs_data, 1);
|
||||
data = g_new0(struct cbs_data, 1);
|
||||
data->ril = g_ril_clone(ril);
|
||||
data->vendor = vendor;
|
||||
|
||||
cd->ril = g_ril_clone(ril);
|
||||
ofono_cbs_set_data(cbs, data);
|
||||
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
|
||||
cd->timer_id = g_timeout_add_seconds(2, ril_delayed_register, cbs);
|
||||
if (g_ril_send(ril, RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, NULL,
|
||||
get_cbs_config_cb, cbs, NULL) == 0)
|
||||
ofono_error("%s: send failed", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct cbs_data *cd = ofono_cbs_get_data(cbs);
|
||||
struct cbs_data *data = ofono_cbs_get_data(cbs);
|
||||
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
|
||||
if (cd->timer_id > 0)
|
||||
g_source_remove(cd->timer_id);
|
||||
|
||||
g_ril_unref(cd->ril);
|
||||
g_free(cd);
|
||||
g_ril_unref(data->ril);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static struct ofono_cbs_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_set_topics,
|
||||
.clear_topics = ril_clear_topics
|
||||
.name = RILMODEM,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics,
|
||||
};
|
||||
|
||||
void ril_cbs_init(void)
|
||||
@@ -156,4 +211,3 @@ void ril_cbs_exit(void)
|
||||
{
|
||||
ofono_cbs_driver_unregister(&driver);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
* oFono - Open Source Telephony - RIL Modem Support
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012 Canonical Ltd.
|
||||
* Copyright (C) 2013 Jolla Ltd.
|
||||
* Copyright (C) 2012-2013 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
|
||||
@@ -41,150 +40,165 @@
|
||||
|
||||
#include "rilmodem.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?
|
||||
*/
|
||||
guint timer_id;
|
||||
|
||||
static void ril_query_manufacturer(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
CALLBACK_WITH_FAILURE(cb, "", data);
|
||||
/* TODO: Implement properly */
|
||||
CALLBACK_WITH_SUCCESS(cb, "Fake Modem Manufacturer", data);
|
||||
}
|
||||
|
||||
static void ril_query_model(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
CALLBACK_WITH_FAILURE(cb, "", data);
|
||||
/* TODO: Implement properly */
|
||||
CALLBACK_WITH_SUCCESS(cb, "Fake Modem Model", data);
|
||||
}
|
||||
|
||||
static void query_revision_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_devinfo_query_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
GRil *ril = cbd->user;
|
||||
struct parcel rilp;
|
||||
gchar *revision;
|
||||
char *revision;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
decode_ril_error(&error, "OK");
|
||||
} else {
|
||||
decode_ril_error(&error, "FAIL");
|
||||
cb(&error, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
revision = parcel_r_string(&rilp);
|
||||
|
||||
cb(&error, revision, cbd->data);
|
||||
g_ril_append_print_buf(ril, "{%s}", revision);
|
||||
g_ril_print_response(ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, revision, cbd->data);
|
||||
g_free(revision);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_query_revision(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
GRil *ril = ofono_devinfo_get_data(info);
|
||||
int request = RIL_REQUEST_BASEBAND_VERSION;
|
||||
int ret;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, ril);
|
||||
|
||||
ret = g_ril_send(ril, request, NULL, 0,
|
||||
query_revision_cb, cbd, g_free);
|
||||
if (g_ril_send(ril, RIL_REQUEST_BASEBAND_VERSION, NULL,
|
||||
query_revision_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_ril_print_request_no_args(ril, ret, request);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
static void query_svn_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_devinfo_query_cb_t cb = cbd->cb;
|
||||
GRil *ril = cbd->user;
|
||||
struct parcel rilp;
|
||||
char *imeisv;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
imeisv = parcel_r_string(&rilp);
|
||||
|
||||
g_ril_append_print_buf(ril, "{%s}", imeisv);
|
||||
g_ril_print_response(ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, imeisv, cbd->data);
|
||||
g_free(imeisv);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_query_svn(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
GRil *ril = ofono_devinfo_get_data(info);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, ril);
|
||||
|
||||
if (g_ril_send(ril, RIL_REQUEST_GET_IMEISV, NULL,
|
||||
query_svn_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
|
||||
static void query_serial_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_devinfo_query_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
GRil *ril = cbd->user;
|
||||
struct parcel rilp;
|
||||
gchar *imei;
|
||||
char *imei;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
decode_ril_error(&error, "OK");
|
||||
} else {
|
||||
decode_ril_error(&error, "FAIL");
|
||||
cb(&error, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
imei = parcel_r_string(&rilp);
|
||||
|
||||
cb(&error, imei, cbd->data);
|
||||
g_ril_append_print_buf(ril, "{%s}", imei);
|
||||
g_ril_print_response(ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, imei, cbd->data);
|
||||
g_free(imei);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_query_serial(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
GRil *ril = ofono_devinfo_get_data(info);
|
||||
/* TODO: make it support both RIL_REQUEST_GET_IMEI (deprecated) and
|
||||
* RIL_REQUEST_DEVICE_IDENTITY depending on the rild version used */
|
||||
int request = RIL_REQUEST_GET_IMEI;
|
||||
int ret;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, ril);
|
||||
|
||||
ret = g_ril_send(ril, request, NULL, 0,
|
||||
query_serial_cb, cbd, g_free);
|
||||
/*
|
||||
* TODO: make it support both RIL_REQUEST_GET_IMEI (deprecated) and
|
||||
* RIL_REQUEST_DEVICE_IDENTITY depending on the rild version used
|
||||
*/
|
||||
if (g_ril_send(ril, RIL_REQUEST_GET_IMEI, NULL,
|
||||
query_serial_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_ril_print_request_no_args(ril, ret, request);
|
||||
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_devinfo *info = user_data;
|
||||
DBG("");
|
||||
|
||||
timer_id = 0;
|
||||
DBG("");
|
||||
|
||||
ofono_devinfo_register(info);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
GRil *ril = NULL;
|
||||
|
||||
if (data != NULL)
|
||||
ril = g_ril_clone(data);
|
||||
GRil *ril = g_ril_clone(data);
|
||||
|
||||
ofono_devinfo_set_data(info, ril);
|
||||
|
||||
DBG("");
|
||||
|
||||
/*
|
||||
* TODO: analyze if capability check is needed
|
||||
* and/or timer should be adjusted.
|
||||
*
|
||||
* ofono_devinfo_register() needs to be called after
|
||||
* the driver has been set in ofono_devinfo_create(),
|
||||
* which calls this function. Most other drivers make
|
||||
* some kind of capabilities query to the modem, and then
|
||||
* call register in the callback; we use a timer instead.
|
||||
*/
|
||||
timer_id = g_timeout_add_seconds(1, ril_delayed_register, info);
|
||||
g_idle_add(ril_delayed_register, info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -195,20 +209,18 @@ static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||
|
||||
ofono_devinfo_set_data(info, NULL);
|
||||
|
||||
if (timer_id > 0)
|
||||
g_source_remove(timer_id);
|
||||
|
||||
g_ril_unref(ril);
|
||||
}
|
||||
|
||||
static struct ofono_devinfo_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.name = RILMODEM,
|
||||
.probe = ril_devinfo_probe,
|
||||
.remove = ril_devinfo_remove,
|
||||
.query_manufacturer = ril_query_manufacturer,
|
||||
.query_model = ril_query_model,
|
||||
.query_revision = ril_query_revision,
|
||||
.query_serial = ril_query_serial
|
||||
.query_serial = ril_query_serial,
|
||||
.query_svn = ril_query_svn
|
||||
};
|
||||
|
||||
void ril_devinfo_init(void)
|
||||
|
||||
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