forked from sailfishos/ofono
Compare commits
960 Commits
mer/1.14+g
...
mer/1.19+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cea5b9f96 | ||
|
|
5fb35d5fb4 | ||
|
|
e8d57bb928 | ||
|
|
2bfde2418e | ||
|
|
c710ce76c1 | ||
|
|
78acd90464 | ||
|
|
e51b3ca0c8 | ||
|
|
b3c8813bd4 | ||
|
|
e2a3acd9d0 | ||
|
|
2054ca9570 | ||
|
|
48dbb7912a | ||
|
|
d7e7ad671d | ||
|
|
5b5a86dc80 | ||
|
|
c232524e99 | ||
|
|
bfd09a5c14 | ||
|
|
f8adcd2550 | ||
|
|
2a97567147 | ||
|
|
04d84b615e | ||
|
|
6e34792323 | ||
|
|
d6a59f5dc4 | ||
|
|
23e299055f | ||
|
|
a56ef3ba0f | ||
|
|
7294433906 | ||
|
|
d7263cd344 | ||
|
|
2f3b469fbb | ||
|
|
4187e7ee8f | ||
|
|
4d3f89bae0 | ||
|
|
cbd1c5d524 | ||
|
|
7976e44746 | ||
|
|
3d6e220686 | ||
|
|
919526d392 | ||
|
|
b7082146e8 | ||
|
|
094a296a14 | ||
|
|
5c259e751b | ||
|
|
69e5d5b356 | ||
|
|
56e7d0e8ea | ||
|
|
bb2ae6d1a1 | ||
|
|
cf7692db49 | ||
|
|
63f3311cd6 | ||
|
|
c5aae77d41 | ||
|
|
f8e21c8ad4 | ||
|
|
8e6dfe433b | ||
|
|
ae23bb552b | ||
|
|
2becd051d4 | ||
|
|
8cfb1d5ca3 | ||
|
|
50f35458f6 | ||
|
|
51843accf7 | ||
|
|
fb856dc7d6 | ||
|
|
1482748183 | ||
|
|
869ffda61e | ||
|
|
f875cbfda2 | ||
|
|
2a60eaa6e3 | ||
|
|
29b6c41d48 | ||
|
|
2f6491d005 | ||
|
|
1a25047e9d | ||
|
|
899e14bf17 | ||
|
|
2520664c63 | ||
|
|
445bbbd66f | ||
|
|
08fc4b0d03 | ||
|
|
c82e94ffb4 | ||
|
|
fd3712940b | ||
|
|
8410c985c9 | ||
|
|
0878decdc0 | ||
|
|
cb69984722 | ||
|
|
1fe8701f1a | ||
|
|
c5286fee70 | ||
|
|
3c5f6f84e1 | ||
|
|
8b87b55e8d | ||
|
|
bce34cbff3 | ||
|
|
f8351cacf1 | ||
|
|
6b9b8583dc | ||
|
|
1df56480ba | ||
|
|
adc8fce399 | ||
|
|
d24ce4d9de | ||
|
|
f726af3309 | ||
|
|
0ba1fd641b | ||
|
|
41c0b0a2e6 | ||
|
|
322282258a | ||
|
|
f6a7c39bba | ||
|
|
3d3f68c798 | ||
|
|
e8d057c39e | ||
|
|
357e5b69ca | ||
|
|
e77efed603 | ||
|
|
fa252b8d4a | ||
|
|
321c092d6b | ||
|
|
ee912bafe3 | ||
|
|
35eb528a70 | ||
|
|
22a6c4438b | ||
|
|
652bdc15ad | ||
|
|
a71e277850 | ||
|
|
fbee06e8be | ||
|
|
26029566e2 | ||
|
|
0074ff2660 | ||
|
|
82fa5e977a | ||
|
|
823f13a1fa | ||
|
|
7b34498b1e | ||
|
|
37d4e1983b | ||
|
|
e6f26f3bcf | ||
|
|
23e1d2c516 | ||
|
|
1f246cc28c | ||
|
|
ec20f44124 | ||
|
|
8b6139aea8 | ||
|
|
b79c3c3a95 | ||
|
|
c885744273 | ||
|
|
cdd0e4eaff | ||
|
|
402783f877 | ||
|
|
4755990237 | ||
|
|
7a91b4e069 | ||
|
|
35d4ca1e53 | ||
|
|
ea334e9daa | ||
|
|
16964bb8f2 | ||
|
|
0b93ab2d76 | ||
|
|
0bed313ecb | ||
|
|
cfd1d2c30a | ||
|
|
cb7c408beb | ||
|
|
202d8cf162 | ||
|
|
a15a558af6 | ||
|
|
fd8429465f | ||
|
|
8db1008790 | ||
|
|
3e3b4971da | ||
|
|
7c8245e432 | ||
|
|
5a06b04e05 | ||
|
|
1c12df9e99 | ||
|
|
fa3d80cd39 | ||
|
|
18507364ea | ||
|
|
c409ec2940 | ||
|
|
bba910a1d6 | ||
|
|
a7867d24e9 | ||
|
|
8909d4928b | ||
|
|
d9e39a69a5 | ||
|
|
0477eeb75f | ||
|
|
2ff3613e9b | ||
|
|
e5d040f7f9 | ||
|
|
604a3dd22e | ||
|
|
5eb923ad28 | ||
|
|
94fa037b93 | ||
|
|
41135af282 | ||
|
|
47359a3083 | ||
|
|
9c6c354d5a | ||
|
|
8ca5fc24ed | ||
|
|
aecb63423f | ||
|
|
f72f84ec0f | ||
|
|
e593476d81 | ||
|
|
1a4f1b0f9f | ||
|
|
14904ddaeb | ||
|
|
5fc9827e5d | ||
|
|
3539b5c9f9 | ||
|
|
916c1ac904 | ||
|
|
9f659d47b0 | ||
|
|
7d3ec8e9dc | ||
|
|
d5977f9014 | ||
|
|
513b922814 | ||
|
|
7f0cc63b3d | ||
|
|
9fb47a6382 | ||
|
|
ae35e7bff3 | ||
|
|
c7dc8cf262 | ||
|
|
213df4e7c4 | ||
|
|
e78daccea9 | ||
|
|
4f10d24638 | ||
|
|
cfa7ec6dd5 | ||
|
|
d18ba4e9a4 | ||
|
|
8846c58b53 | ||
|
|
4f088c85c7 | ||
|
|
6587a2456a | ||
|
|
edab9dbf2b | ||
|
|
b6cc94bf84 | ||
|
|
4039bed591 | ||
|
|
1f56e8350b | ||
|
|
34b0d68cdd | ||
|
|
ec60fa4eac | ||
|
|
a066917c4d | ||
|
|
da23ddbc15 | ||
|
|
207f67ab62 | ||
|
|
3e3720f416 | ||
|
|
985dbf9795 | ||
|
|
8b56a11936 | ||
|
|
40aa517183 | ||
|
|
6fdf38b74b | ||
|
|
8dc0b46bb3 | ||
|
|
b772df434b | ||
|
|
3726a1a48a | ||
|
|
5e309e5d45 | ||
|
|
ea65572935 | ||
|
|
83f8e1cbe6 | ||
|
|
c97d28cd23 | ||
|
|
9279a008ed | ||
|
|
e9c1603c8b | ||
|
|
5a8eb818ee | ||
|
|
7ab6bffd07 | ||
|
|
86f8a5c1f6 | ||
|
|
f1a87e5f6c | ||
|
|
4dbdf95b12 | ||
|
|
dab3e86325 | ||
|
|
b62f6c1041 | ||
|
|
f41a998695 | ||
|
|
42fa3983ef | ||
|
|
f8a47ae530 | ||
|
|
cf202b1568 | ||
|
|
14ebdfe7b9 | ||
|
|
8732a885a3 | ||
|
|
3f5fa672a5 | ||
|
|
e358485f37 | ||
|
|
e964307ced | ||
|
|
d1d69cf667 | ||
|
|
bf6210bdbb | ||
|
|
bcdd5a95c1 | ||
|
|
fcea7919f9 | ||
|
|
6fd1c1ef33 | ||
|
|
4d960d898d | ||
|
|
a9f47b77ce | ||
|
|
fb81c3571b | ||
|
|
7809498588 | ||
|
|
4d05522b2a | ||
|
|
b6b0306b39 | ||
|
|
5c938a5b64 | ||
|
|
b04d30ff3e | ||
|
|
4bdc8ac62c | ||
|
|
fa20be318d | ||
|
|
3598f4edab | ||
|
|
0524862743 | ||
|
|
d2cfc16201 | ||
|
|
fd874f3a4c | ||
|
|
0a039db7da | ||
|
|
0e6ce9a38e | ||
|
|
3cad68861c | ||
|
|
70d9366499 | ||
|
|
6c17d2b79c | ||
|
|
811b478903 | ||
|
|
6fcc2a1f68 | ||
|
|
792c4674c2 | ||
|
|
e9df792102 | ||
|
|
eb92f42c7d | ||
|
|
bcafdc8d70 | ||
|
|
5aa8f72aaa | ||
|
|
704a3ae354 | ||
|
|
a4f91f2d80 | ||
|
|
e655837ccb | ||
|
|
800ad72129 | ||
|
|
e6cae75c40 | ||
|
|
d655aec432 | ||
|
|
cd2d6a28aa | ||
|
|
8507197fa6 | ||
|
|
ee6b3385db | ||
|
|
24b6aeab5c | ||
|
|
5436c2beea | ||
|
|
87d947fe48 | ||
|
|
af45298bc7 | ||
|
|
cdb32c9139 | ||
|
|
85a9daa5f4 | ||
|
|
17a4fd7b78 | ||
|
|
d42b983dee | ||
|
|
33b14a3326 | ||
|
|
09ac10c3ac | ||
|
|
f47fe40799 | ||
|
|
ef0532222f | ||
|
|
edf7608da8 | ||
|
|
1bd019aec7 | ||
|
|
57ea46e0d7 | ||
|
|
90c4dfe1e5 | ||
|
|
4112433e86 | ||
|
|
97830c757f | ||
|
|
2dcfd64ff4 | ||
|
|
cba91bff8b | ||
|
|
7bf1f707ff | ||
|
|
aa6eed4eeb | ||
|
|
18e6d86edd | ||
|
|
e40d9e80c7 | ||
|
|
4176a82a0b | ||
|
|
447d0af56c | ||
|
|
284c7dfc48 | ||
|
|
a1a6ff7976 | ||
|
|
e2e4b7c868 | ||
|
|
5103af4321 | ||
|
|
b3a10881e7 | ||
|
|
cbc9ce47e0 | ||
|
|
cf059171d7 | ||
|
|
ddabae7a54 | ||
|
|
aabfd23aed | ||
|
|
f7a1089bd6 | ||
|
|
1ba9668f55 | ||
|
|
f6adb2a47e | ||
|
|
1254716006 | ||
|
|
1da578f9af | ||
|
|
863b91f79e | ||
|
|
5c4cd29fc2 | ||
|
|
78ea7d9946 | ||
|
|
e684560e16 | ||
|
|
0af7fd0c2c | ||
|
|
9b20f4c904 | ||
|
|
1c217547fd | ||
|
|
1939a251a0 | ||
|
|
deaee2b27d | ||
|
|
28d59901c2 | ||
|
|
d6ffc2dae7 | ||
|
|
59d80cdaa2 | ||
|
|
e680c7a3dc | ||
|
|
8fb813ab94 | ||
|
|
ca507cbfaf | ||
|
|
d40079d0b5 | ||
|
|
9579ce72a0 | ||
|
|
59880f886c | ||
|
|
3cb3b96104 | ||
|
|
4a384a95a0 | ||
|
|
c69b01677f | ||
|
|
fd358758ce | ||
|
|
b2d55c3bc4 | ||
|
|
d0c9970d15 | ||
|
|
daccbdbeaf | ||
|
|
71c032167d | ||
|
|
82ed6eeba5 | ||
|
|
51cb5c773a | ||
|
|
da3fd754a7 | ||
|
|
7b70463912 | ||
|
|
3107fa0ce4 | ||
|
|
ade915136b | ||
|
|
4ad21b004a | ||
|
|
9ef2e5353c | ||
|
|
1ca3716e8f | ||
|
|
3df6a64280 | ||
|
|
476af72e35 | ||
|
|
b8c7bcc996 | ||
|
|
0418a7db78 | ||
|
|
1ab5d2e278 | ||
|
|
4155f4ad82 | ||
|
|
4b5ebcbefd | ||
|
|
1298be1adb | ||
|
|
52a4e9b5e6 | ||
|
|
23373e6ce7 | ||
|
|
ed23172c8b | ||
|
|
1c3fc7dedc | ||
|
|
8f4101d57e | ||
|
|
2cda8bc793 | ||
|
|
51d004c32c | ||
|
|
74e7e2444f | ||
|
|
5e6a565274 | ||
|
|
f2c7812932 | ||
|
|
8ce00e707b | ||
|
|
6aaae6bc6a | ||
|
|
d34c5fd54d | ||
|
|
8ed185e32d | ||
|
|
d789992c87 | ||
|
|
d3f266372b | ||
|
|
8e036c29fc | ||
|
|
8950228a9f | ||
|
|
54cfafa20d | ||
|
|
17fdc3f451 | ||
|
|
8fe0b753e8 | ||
|
|
06e61e1d8b | ||
|
|
4cbc64e4e9 | ||
|
|
7d90b6e86c | ||
|
|
01fcc3df4b | ||
|
|
52a0680c31 | ||
|
|
809cd31f3f | ||
|
|
c05b8864b0 | ||
|
|
f12701af82 | ||
|
|
f6f27acb04 | ||
|
|
5f45c9487b | ||
|
|
fc286131db | ||
|
|
e037227dc1 | ||
|
|
7cd35aaac3 | ||
|
|
0c52074896 | ||
|
|
c351edd7a5 | ||
|
|
80ead5dedb | ||
|
|
0684eeffc0 | ||
|
|
918706835b | ||
|
|
67b37c9cd5 | ||
|
|
9bcb302884 | ||
|
|
80f7393415 | ||
|
|
58759583fa | ||
|
|
63b3dc2be9 | ||
|
|
57a242851a | ||
|
|
b5f01aa8d2 | ||
|
|
19563292d9 | ||
|
|
6780b25091 | ||
|
|
7c9242398e | ||
|
|
e244554917 | ||
|
|
60782673dc | ||
|
|
8442cc21cd | ||
|
|
1d6082005e | ||
|
|
2a45912752 | ||
|
|
bef4e531b7 | ||
|
|
cc2781ee50 | ||
|
|
340b66025b | ||
|
|
9879fd990c | ||
|
|
74db6eb392 | ||
|
|
771d338001 | ||
|
|
6808dd688e | ||
|
|
2d46bbac4d | ||
|
|
442b427a19 | ||
|
|
bebe9d8d8a | ||
|
|
1b21edb1f5 | ||
|
|
52ee74f0af | ||
|
|
296dd76ff7 | ||
|
|
0e68c13837 | ||
|
|
d332624f5c | ||
|
|
fbee20e850 | ||
|
|
eb52bc247a | ||
|
|
0741acca48 | ||
|
|
70d2d70623 | ||
|
|
baca4c0371 | ||
|
|
aa5e04cbca | ||
|
|
f1cc9990b3 | ||
|
|
6bd0264a22 | ||
|
|
19166a33ef | ||
|
|
eb6128ccb6 | ||
|
|
46e5909e17 | ||
|
|
b5652aaf09 | ||
|
|
aa4b7c2a89 | ||
|
|
1b274a6470 | ||
|
|
cc6a53b191 | ||
|
|
1b5b1b545b | ||
|
|
4389fffb72 | ||
|
|
95ca9ae64d | ||
|
|
71aded607f | ||
|
|
d209f372d4 | ||
|
|
aa16342fc1 | ||
|
|
2a7a6f7f0c | ||
|
|
08a320ad90 | ||
|
|
ff1dffebe4 | ||
|
|
fac809eac9 | ||
|
|
6420640395 | ||
|
|
400cfed044 | ||
|
|
eef25504f9 | ||
|
|
4db63e87f7 | ||
|
|
440da3c009 | ||
|
|
d3e2ce9c9b | ||
|
|
93cd410a7b | ||
|
|
e0fbec976b | ||
|
|
f34d2f9dcf | ||
|
|
361c552898 | ||
|
|
d675c3362f | ||
|
|
9c014fba03 | ||
|
|
89a76af30f | ||
|
|
120f200ba1 | ||
|
|
f2a8ccf079 | ||
|
|
dec2dcd735 | ||
|
|
29a1f8d9ed | ||
|
|
3b7ef48976 | ||
|
|
b9ea2e0924 | ||
|
|
0845da6a2e | ||
|
|
300a11c2e3 | ||
|
|
c5cc1ff7c8 | ||
|
|
cdaa2fedab | ||
|
|
2684fbf24d | ||
|
|
93300ee95e | ||
|
|
8c175ab282 | ||
|
|
24b9943dc1 | ||
|
|
3e711843cb | ||
|
|
ead815513d | ||
|
|
dd78ee5fcb | ||
|
|
e61bfe0f38 | ||
|
|
f22a531051 | ||
|
|
c2a1c60b92 | ||
|
|
82bf1057bb | ||
|
|
1a25661400 | ||
|
|
466a65f2da | ||
|
|
a672583053 | ||
|
|
f47e720628 | ||
|
|
c0433efc12 | ||
|
|
5fc98f5b59 | ||
|
|
e7d60078db | ||
|
|
b6abbc0ece | ||
|
|
a7eb318f01 | ||
|
|
1674126665 | ||
|
|
b1bb48e59f | ||
|
|
abfebddbb9 | ||
|
|
5fb4a13562 | ||
|
|
4ff1488b2e | ||
|
|
2b4db9a52b | ||
|
|
05ca5c155b | ||
|
|
c55ac50f4c | ||
|
|
aa32435945 | ||
|
|
e940b97389 | ||
|
|
24ba9a3cf7 | ||
|
|
f7b8c07a3b | ||
|
|
159083d9c3 | ||
|
|
37d7bc057c | ||
|
|
6d1521313f | ||
|
|
1d926b9415 | ||
|
|
f665278df3 | ||
|
|
0bd5130e02 | ||
|
|
af2c27ea0f | ||
|
|
3370c09c89 | ||
|
|
cd23203094 | ||
|
|
64fcdddaac | ||
|
|
2039b1bd09 | ||
|
|
a52666dc20 | ||
|
|
3b4ce1f47b | ||
|
|
d8aefd40c4 | ||
|
|
e79055354c | ||
|
|
5e75f650c3 | ||
|
|
ae782ca6f2 | ||
|
|
b929a8e8c8 | ||
|
|
530c3bc812 | ||
|
|
0e1a58781f | ||
|
|
77a26177e5 | ||
|
|
f6ea7e4c36 | ||
|
|
babea14604 | ||
|
|
e13ae6d5b3 | ||
|
|
40ce8f7185 | ||
|
|
f68585a784 | ||
|
|
16105b8ace | ||
|
|
91245de799 | ||
|
|
c52471132a | ||
|
|
a8e7b86733 | ||
|
|
8829682fad | ||
|
|
246e30d1a5 | ||
|
|
83267e1fa5 | ||
|
|
e1ab11ad25 | ||
|
|
a9193282d5 | ||
|
|
f80bb5c5bb | ||
|
|
66eb87777f | ||
|
|
e5291006fd | ||
|
|
c609d7cc07 | ||
|
|
0de562b019 | ||
|
|
60b11f712c | ||
|
|
80d347b964 | ||
|
|
97abd10984 | ||
|
|
5201fc0183 | ||
|
|
14e4ef8e07 | ||
|
|
22bc6d526e | ||
|
|
baa4fe30e5 | ||
|
|
d0d0793ccb | ||
|
|
55dd461ce7 | ||
|
|
4da1a30290 | ||
|
|
303f527d79 | ||
|
|
27e8621c0b | ||
|
|
200237372a | ||
|
|
9cae262c80 | ||
|
|
5e23459b67 | ||
|
|
a88d7af6c8 | ||
|
|
290c3d2388 | ||
|
|
ee880398ad | ||
|
|
d65bbc3236 | ||
|
|
655544be45 | ||
|
|
50a544a191 | ||
|
|
9e7a4a4d72 | ||
|
|
c5b5e3109d | ||
|
|
deb106343a | ||
|
|
771e8becf2 | ||
|
|
a0b69f974a | ||
|
|
b3a4aaea95 | ||
|
|
137e504e10 | ||
|
|
2de3e445f0 | ||
|
|
1cd0d60768 | ||
|
|
d1f1f16355 | ||
|
|
4df72c9376 | ||
|
|
a35ca2bbd9 | ||
|
|
8376174c76 | ||
|
|
b6f5befcac | ||
|
|
403f29320c | ||
|
|
54209b39bd | ||
|
|
3ca442ad15 | ||
|
|
3a579dd7be | ||
|
|
a7266fc9c8 | ||
|
|
04dbd344b3 | ||
|
|
296534c2a8 | ||
|
|
6114482e2a | ||
|
|
8281885ba5 | ||
|
|
9cd3b84421 | ||
|
|
8d65aaefed | ||
|
|
ce15cfe48d | ||
|
|
3a1e37b498 | ||
|
|
ecef97dd83 | ||
|
|
a68f1e9c4d | ||
|
|
42808ed0f7 | ||
|
|
d896ebcb37 | ||
|
|
93c57284bd | ||
|
|
91436f9643 | ||
|
|
d0d2587b2a | ||
|
|
3e10878348 | ||
|
|
6de8c4aa85 | ||
|
|
a9da50f890 | ||
|
|
3ca5161a78 | ||
|
|
03b3ca7776 | ||
|
|
6e5316aba9 | ||
|
|
49b752f0ad | ||
|
|
268684eebf | ||
|
|
24db1db2b1 | ||
|
|
55977c1dac | ||
|
|
1025a6c6ed | ||
|
|
98a143233d | ||
|
|
88013ff63e | ||
|
|
efbe8b12c9 | ||
|
|
ba9cc0eb4a | ||
|
|
46b5f22464 | ||
|
|
a31332ebae | ||
|
|
b30141c3d3 | ||
|
|
e8ae8bba1c | ||
|
|
3ea25fb81f | ||
|
|
197df7141d | ||
|
|
eef6993391 | ||
|
|
f1a5941b35 | ||
|
|
5f6a258d0a | ||
|
|
9fa18f967b | ||
|
|
4d17a2e3b9 | ||
|
|
c34b3c39b2 | ||
|
|
df1824b2e2 | ||
|
|
b3a18326e1 | ||
|
|
93e564d5e5 | ||
|
|
42847e03b5 | ||
|
|
f0d6b69972 | ||
|
|
2100a8d975 | ||
|
|
c393e63e4e | ||
|
|
b24bc9761b | ||
|
|
06daa7cf21 | ||
|
|
49215d60b2 | ||
|
|
f3f3b73d6f | ||
|
|
113d9424b5 | ||
|
|
2a8489c4d9 | ||
|
|
c4f968b87a | ||
|
|
537c7ae8b4 | ||
|
|
b320fc7f59 | ||
|
|
edf49e6e99 | ||
|
|
b7985a1d67 | ||
|
|
bbb2c68a72 | ||
|
|
bd3f7f35eb | ||
|
|
65bf1a24fa | ||
|
|
0c37015145 | ||
|
|
a8551cdce7 | ||
|
|
5bd2b96240 | ||
|
|
3bf309b887 | ||
|
|
c14b9bbf93 | ||
|
|
568bd615cd | ||
|
|
4d55f94015 | ||
|
|
95d06963cd | ||
|
|
479458138a | ||
|
|
c221d677d1 | ||
|
|
a32da19192 | ||
|
|
a20da10621 | ||
|
|
64c754c3b9 | ||
|
|
d64fd7dca7 | ||
|
|
f608c0821a | ||
|
|
7d29ef130a | ||
|
|
141eadee1d | ||
|
|
e84602d79c | ||
|
|
b63b6355d5 | ||
|
|
f7f007a122 | ||
|
|
5769656848 | ||
|
|
bbc276b4c7 | ||
|
|
4b79de53fe | ||
|
|
12ffd8acf9 | ||
|
|
df9b35b440 | ||
|
|
76e991d3da | ||
|
|
90803904be | ||
|
|
84e547c2ed | ||
|
|
652798d592 | ||
|
|
979a3bcef3 | ||
|
|
69178c8ecb | ||
|
|
1ac1c9268d | ||
|
|
5483a8ecc0 | ||
|
|
95dacebb0c | ||
|
|
b92b1ce13f | ||
|
|
70ab2175a0 | ||
|
|
9810a258a1 | ||
|
|
760c17052f | ||
|
|
e77b62a91e | ||
|
|
7103c81a77 | ||
|
|
2bc610353d | ||
|
|
dd04ac248d | ||
|
|
c5b3357000 | ||
|
|
ddbdf9f649 | ||
|
|
7b5be51527 | ||
|
|
5aef6a8356 | ||
|
|
b99cd4f8ca | ||
|
|
47ee85e955 | ||
|
|
b500f4fa65 | ||
|
|
c2c048dc05 | ||
|
|
df923b481f | ||
|
|
ed0c1f94f6 | ||
|
|
6d2852cdaf | ||
|
|
72a1ecf5d0 | ||
|
|
2fa10fb265 | ||
|
|
f907c3a85d | ||
|
|
4a7b325191 | ||
|
|
a8103a39fa | ||
|
|
4076502017 | ||
|
|
7ed41beadd | ||
|
|
e45389cf84 | ||
|
|
4bae61c83e | ||
|
|
11d6e76f0a | ||
|
|
4cfa5cdf36 | ||
|
|
135923532c | ||
|
|
d112c042e3 | ||
|
|
b9407ff65f | ||
|
|
5a92625c9f | ||
|
|
c684033671 | ||
|
|
59cb9c39b9 | ||
|
|
0831fd803a | ||
|
|
1b6c20759c | ||
|
|
3681eb63b1 | ||
|
|
5303f766a9 | ||
|
|
2f68eeea6c | ||
|
|
7a7744781a | ||
|
|
fc1491c634 | ||
|
|
c631a48c41 | ||
|
|
21e90e5abd | ||
|
|
bfcf8b726b | ||
|
|
3b69c9843b | ||
|
|
f24252e2c6 | ||
|
|
4be4cb4f57 | ||
|
|
9d4f682b14 | ||
|
|
bd736f7aa6 | ||
|
|
ff328c2a73 | ||
|
|
10e908fa96 | ||
|
|
4aa59c7274 | ||
|
|
d61be44bb4 | ||
|
|
0ed1ef1e4c | ||
|
|
2fa193ad5b | ||
|
|
e686240eeb | ||
|
|
18bc7a3ad8 | ||
|
|
6624066917 | ||
|
|
6015490d41 | ||
|
|
a135d0ea52 | ||
|
|
f86159c180 | ||
|
|
de2b622f3b | ||
|
|
077f3f2e1e | ||
|
|
acbd40f9ad | ||
|
|
26398c769f | ||
|
|
60c53428f0 | ||
|
|
90824a8906 | ||
|
|
b85b8f0019 | ||
|
|
29069fd152 | ||
|
|
8e4e88e4fc | ||
|
|
40f148c134 | ||
|
|
730d5ff9b5 | ||
|
|
c6000fd909 | ||
|
|
f2edab4ed8 | ||
|
|
9915ccb3ba | ||
|
|
b5be8420ab | ||
|
|
5498e22839 | ||
|
|
802d351ab0 | ||
|
|
3d62d57d20 | ||
|
|
3b1b272967 | ||
|
|
5e2a7afabd | ||
|
|
f7fa1c81f3 | ||
|
|
62a0b3518b | ||
|
|
d7cbedc0e9 | ||
|
|
1e75448127 | ||
|
|
7ab4da0c91 | ||
|
|
f13991d04e | ||
|
|
c451110c39 | ||
|
|
cb9183f3ff | ||
|
|
c1a9d7a578 | ||
|
|
9aee7ccadd | ||
|
|
0777b2853a | ||
|
|
b7bd9ca425 | ||
|
|
8929d131a3 | ||
|
|
97e34cc851 | ||
|
|
e558d48b6f | ||
|
|
51fc828c5e | ||
|
|
ac14de37ca | ||
|
|
665c053803 | ||
|
|
aca873a5c4 | ||
|
|
a12e10e36f | ||
|
|
7cd3fb74d4 | ||
|
|
84289d83fd | ||
|
|
f826abdbc7 | ||
|
|
4e9cbcdb89 | ||
|
|
f6ac328110 | ||
|
|
8d46ababee | ||
|
|
9ec8d03c7c | ||
|
|
3e6bbc676f | ||
|
|
8be0245664 | ||
|
|
ca105f7040 | ||
|
|
dbb3ec13e5 | ||
|
|
1b3302322a | ||
|
|
cd76f913f0 | ||
|
|
8dc220bc11 | ||
|
|
b04fabcda3 | ||
|
|
71df8bb15e | ||
|
|
35ebbf4c97 | ||
|
|
a2acb227fd | ||
|
|
def77f7653 | ||
|
|
c3af639874 | ||
|
|
b2b67fa74e | ||
|
|
96754c0dfc | ||
|
|
f2c474c55a | ||
|
|
07144c2dd5 | ||
|
|
58076d9a00 | ||
|
|
4a937b96aa | ||
|
|
fceb5a41c2 | ||
|
|
0073dc7bfc | ||
|
|
297bdaba0f | ||
|
|
f14db3b2a6 | ||
|
|
4a0182616d | ||
|
|
bbdfc8f46d | ||
|
|
fbd59a8dc9 | ||
|
|
48da783732 | ||
|
|
eebe2f3ac2 | ||
|
|
7eb6d5559a | ||
|
|
9a47510eb5 | ||
|
|
8fc7ae836f | ||
|
|
4677729502 | ||
|
|
8c0f4f27eb | ||
|
|
b932bed519 | ||
|
|
db83ac369b | ||
|
|
e26df8a645 | ||
|
|
5144f3fa14 | ||
|
|
0d6459b9b0 | ||
|
|
10328e626d | ||
|
|
5b407d654a | ||
|
|
d88af05dc3 | ||
|
|
99cae6876f | ||
|
|
89e6593f9c | ||
|
|
93ccb84761 | ||
|
|
e70afdd9dc | ||
|
|
1edb6eec9b | ||
|
|
946b568f43 | ||
|
|
f3f3dabfac | ||
|
|
4c0f783f5c | ||
|
|
444611c086 | ||
|
|
8e9085f5ab | ||
|
|
c33a48ea0c | ||
|
|
f8d9485dc2 | ||
|
|
23c45abd57 | ||
|
|
a371f46735 | ||
|
|
ce0529fcf6 | ||
|
|
fc3f937a67 | ||
|
|
7d4a19b114 | ||
|
|
4242f6ee72 | ||
|
|
b31a3c2390 | ||
|
|
8d47f97106 | ||
|
|
fdba39b8ed | ||
|
|
288364295c | ||
|
|
bce5d9579c | ||
|
|
1c2987670d | ||
|
|
44585697c3 | ||
|
|
3860230644 | ||
|
|
07da2f3fa7 | ||
|
|
7d0d72a4a9 | ||
|
|
f9ee2ae9b8 | ||
|
|
063234a433 | ||
|
|
c006d822f1 | ||
|
|
a5b040b781 | ||
|
|
97abe1751d | ||
|
|
2f75b13ecd | ||
|
|
73e517bcca | ||
|
|
dae225a0d6 | ||
|
|
97ac3f7c76 | ||
|
|
26a00f2f31 | ||
|
|
cede3700f7 | ||
|
|
318d313fc9 | ||
|
|
8e6ebab83b | ||
|
|
7331c88b41 | ||
|
|
063eefbac1 | ||
|
|
12b510b4e7 | ||
|
|
c04f5df8ec | ||
|
|
011bc0741a | ||
|
|
773834c5a3 | ||
|
|
d8edd49535 | ||
|
|
8660527b11 | ||
|
|
d6bc91ebfc | ||
|
|
3d592d7d46 | ||
|
|
e2398b4dfa | ||
|
|
42deee76a1 | ||
|
|
2af3c733b7 | ||
|
|
604fa223f4 | ||
|
|
04218d3a86 | ||
|
|
41fadd3787 | ||
|
|
d539ed19f3 | ||
|
|
25f926c733 | ||
|
|
151b837428 | ||
|
|
c9e426ecd7 | ||
|
|
10f173981c | ||
|
|
bb71141d79 | ||
|
|
4e466f6fec | ||
|
|
a89f8cd56d | ||
|
|
95482cb84a | ||
|
|
fce95b767a | ||
|
|
44049f064a | ||
|
|
b899f4aca2 | ||
|
|
e1cbc5c5ea | ||
|
|
5210b85c22 | ||
|
|
e6048f1dc1 | ||
|
|
6bdc109ec0 | ||
|
|
7dca0a7315 | ||
|
|
19519b2132 | ||
|
|
42ebb69384 | ||
|
|
45478b17cf | ||
|
|
88f46a9b01 | ||
|
|
2abcb85809 | ||
|
|
331700a697 | ||
|
|
a753d6c012 | ||
|
|
d39007c948 | ||
|
|
6c4ac05fbc | ||
|
|
934ea9a9fe | ||
|
|
cf90f1505d | ||
|
|
f9d5ee5fa9 | ||
|
|
e2785b1865 | ||
|
|
fb1b213e22 | ||
|
|
d3560b3784 | ||
|
|
017c1161d4 | ||
|
|
de02f68a2e | ||
|
|
0f28d9206d | ||
|
|
eef67018b6 | ||
|
|
299ffc9620 | ||
|
|
39f08a5e1c | ||
|
|
6c0f90fc1b | ||
|
|
33537adb9f | ||
|
|
e176a9019f | ||
|
|
7166aebd51 | ||
|
|
debb0d2d3e | ||
|
|
ab5b6d1217 | ||
|
|
7e3a6628fa | ||
|
|
fa105c4ba6 | ||
|
|
99c03292ad | ||
|
|
66cf2a30fa | ||
|
|
a4fa356b16 | ||
|
|
43e83852dc | ||
|
|
36a21da227 | ||
|
|
bef4d610a3 | ||
|
|
2d158167c2 | ||
|
|
02c5b73f6e | ||
|
|
0727da1d5b | ||
|
|
d292e0e0ed | ||
|
|
881207ce18 | ||
|
|
0f0733c348 | ||
|
|
8ebb17977b | ||
|
|
7fb4899970 | ||
|
|
1e0c41889f | ||
|
|
08e673050a | ||
|
|
1b1b1861ab | ||
|
|
8a4c29ca74 | ||
|
|
9aeea028ed | ||
|
|
22e892a22e | ||
|
|
361eed7b9a | ||
|
|
864efe1add | ||
|
|
0d8a06af30 | ||
|
|
293c701e25 | ||
|
|
cca3e085b3 | ||
|
|
7f29608feb | ||
|
|
1f3e30f1ba | ||
|
|
7ab4034bf4 | ||
|
|
bb1984cabb | ||
|
|
6df64cd1a9 | ||
|
|
4a0831bc80 | ||
|
|
b2bfdd69d2 | ||
|
|
1588e7c082 | ||
|
|
5cffd8af95 | ||
|
|
d2f6ffc18d | ||
|
|
6369cc902c | ||
|
|
d05b718cc0 | ||
|
|
c144fadca6 | ||
|
|
532e8020e5 | ||
|
|
310915429b | ||
|
|
9285ec0d89 | ||
|
|
8cbe061c3b | ||
|
|
3e13676766 | ||
|
|
73831c3d76 | ||
|
|
7011dcdf2f | ||
|
|
f6341502c8 | ||
|
|
8edaaaf210 | ||
|
|
a88662d23c | ||
|
|
1dd8580930 | ||
|
|
65be2b344c | ||
|
|
62c34467a2 | ||
|
|
d9f252fb61 | ||
|
|
815d62888f | ||
|
|
35feae07e5 |
6
ofono/.gitignore
vendored
6
ofono/.gitignore
vendored
@@ -42,6 +42,12 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
unit/test-rilmodem-sms
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
|
||||
tools/huawei-audio
|
||||
tools/auto-enable
|
||||
|
||||
@@ -96,3 +96,23 @@ Tony Espy <espy@canonical.com>
|
||||
Martin Pitt <martin.pitt@ubuntu.com>
|
||||
Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
|
||||
Jussi Pakkanen <jussi.pakkanen@canonical.com>
|
||||
Sergio Checa Blanco <sergio.checa@bmw-carit.de>
|
||||
Philip Paeps <philip@paeps.cx>
|
||||
Kuba Pawlak <kubax.t.pawlak@intel.com>
|
||||
Tommi Kenakkala <tommi.kenakkala@tieto.com>
|
||||
Alex J Lennon <ajlennon@dynamicdevices.co.uk>
|
||||
Sergey Alirzaev <zl29ah@gmail.com>
|
||||
Marko Sulejic <marko.sulejic@hale.at>
|
||||
Johannes 'josch' Schauer <josch@mister-muffin.de>
|
||||
Simon Fels <simon.fels@canonical.com>
|
||||
John Ernberg <john.ernberg@actia.se>
|
||||
Dongsu Park <dongsu@endocode.com>
|
||||
Dragos Tatulea <dragos@endocode.com>
|
||||
Samrat Guha Niyogi <samrat.guha.niyogi@intel.com>
|
||||
Anirudh Gargi <anirudh.gargi@intel.com>
|
||||
Nishanth V <nishanth.v@intel.com>
|
||||
Antara Borwankar <antara.borwankar@gmail.com>
|
||||
Martin Chaplet <m.chaplet@kerlink.fr>
|
||||
Suman Mallela <suman.m@intel.com>
|
||||
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
|
||||
Antoine Aubert <a.aubert@overkiz.com>
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
ver 1.19:
|
||||
Fix issue with DHCP parsing and Huawei modems.
|
||||
Fix issue with detecting Huawei E3372 modem.
|
||||
Fix issue with handling serving cell info.
|
||||
Fix issue with handling SIM SC facility lock.
|
||||
Fix issue with Android RIL PIN retry logic.
|
||||
Fix issue with Android RIL and RAT handling.
|
||||
Add support for Android RIL cell broadcast.
|
||||
Add support for SoFIA 3GR thermal management.
|
||||
|
||||
ver 1.18:
|
||||
Fix issue with cell broadcast and use-after-fee.
|
||||
Fix issue with repeated held call indicator.
|
||||
Fix issue with +CCWA and connection setup.
|
||||
Fix issue with empty operator scan results.
|
||||
Fix issue with persistent RAT mode handling.
|
||||
Fix issue with multiparty call introspection.
|
||||
Fix issue with GRPS context introspection.
|
||||
Fix issue with stale context deactivation.
|
||||
Add support for automatic context activation.
|
||||
Add support for SIM service provider names.
|
||||
Add support for handling allowed APN lists.
|
||||
Add support for network monitoring interface.
|
||||
Add support for U-Blox TOBY-L2 modem series.
|
||||
Add support for Sierra MC73xx QMI modems.
|
||||
Add support for SoFIA 3GR modem series.
|
||||
Add support for upower battery monitoring.
|
||||
Add support for gateway audio card types.
|
||||
Add support for Handsfree audio driver.
|
||||
Add support for Android RIL integration.
|
||||
|
||||
ver 1.17:
|
||||
Fix issue with alphanumeric TP-OA handling.
|
||||
Fix issue with push notification origin port.
|
||||
Fix issue with reading of EF_MWIS records.
|
||||
Fix issue with handling AT+CPINR results.
|
||||
Fix issue with SIM state polling for Sierra modems.
|
||||
Fix issue with HFP handling and AT command prefixes.
|
||||
Fix issue with HFP and extra CCWA event handling.
|
||||
Fix issue with HFP call state and +CHUP errors.
|
||||
|
||||
ver 1.16:
|
||||
Fix issue with PIN retry handling.
|
||||
Fix issue with HFP and multiple calls.
|
||||
Add support for Distracted Driving Reduction.
|
||||
Add support for available technologies property.
|
||||
Add support for Telit location reporting driver.
|
||||
Add support for u-blox SARA-U270 modems.
|
||||
Add support for Quectel UC15 modems.
|
||||
|
||||
ver 1.15:
|
||||
Fix issue with EF_PNN access affecting PLMN display.
|
||||
Fix issue with SIM detection and Telit HE910 modems.
|
||||
Fix issue with Mobile Provider Database provisioning.
|
||||
Fix issue with bit-shifting and ID mapping allocations.
|
||||
Fix issue with Handsfree and unsolicited notifications.
|
||||
Fix issue with Handsfree and three way calling feature.
|
||||
Add support for Handsfree subscriber number feature.
|
||||
Add support for Handsfree multiple DTMF characters.
|
||||
Add support for PAP authentication.
|
||||
|
||||
ver 1.14:
|
||||
Add support for Apple Siri specific Handsfree commands.
|
||||
Add support for provisioning of MMSC and Message Proxy.
|
||||
|
||||
@@ -113,3 +113,5 @@ doc/coding-style.txt.
|
||||
a feature that touches files under 'include/', 'src/' and 'drivers/'
|
||||
directories, split in three separated patches, taking care not to
|
||||
break compilation.
|
||||
|
||||
4) Submit patches using git send-email to ofono@ofono.org
|
||||
|
||||
@@ -21,8 +21,9 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/cdma-connman.h include/gnss.h \
|
||||
include/private-network.h include/cdma-netreg.h \
|
||||
include/cdma-provision.h include/handsfree.h \
|
||||
include/handsfree-audio.h include/sim-mnclength.h \
|
||||
include/oemraw.h include/siri.h
|
||||
include/sim-mnclength.h \
|
||||
include/handsfree-audio.h include/siri.h \
|
||||
include/netmon.h
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
@@ -96,14 +97,12 @@ 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
|
||||
|
||||
@@ -118,20 +117,72 @@ builtin_sources += plugins/udevng.c
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if JOLLA_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 \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_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_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_info.c \
|
||||
drivers/ril/ril_sim_info_dbus.c \
|
||||
drivers/ril/ril_sim_settings.c \
|
||||
drivers/ril/ril_sms.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
drivers/ril/ril_ussd.c \
|
||||
drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
builtin_modules += rildev
|
||||
builtin_sources += plugins/rildev.c
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += plugins/ril.c
|
||||
builtin_sources += plugins/ril.c plugins/ril.h
|
||||
|
||||
builtin_modules += infineon
|
||||
builtin_sources += plugins/infineon.c
|
||||
|
||||
builtin_modules += ril_sofia3gr
|
||||
builtin_sources += plugins/ril_sofia3gr.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 \
|
||||
@@ -139,16 +190,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
|
||||
|
||||
drivers/rilmodem/netmon.c \
|
||||
drivers/rilmodem/stk.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/infineonmodem/infineon_constants.h
|
||||
endif
|
||||
endif
|
||||
|
||||
if ISIMODEM
|
||||
@@ -235,8 +286,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 \
|
||||
@@ -312,6 +362,12 @@ builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/mbmmodem/stk.c \
|
||||
drivers/mbmmodem/location-reporting.c
|
||||
|
||||
builtin_modules += telitmodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/telitmodem/telitmodem.h \
|
||||
drivers/telitmodem/telitmodem.c \
|
||||
drivers/telitmodem/location-reporting.c
|
||||
|
||||
builtin_modules += hsomodem
|
||||
builtin_sources += drivers/atmodem/atutil.h \
|
||||
drivers/hsomodem/hsomodem.h \
|
||||
@@ -368,15 +424,19 @@ 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
|
||||
|
||||
|
||||
if PHONESIM
|
||||
builtin_modules += phonesim
|
||||
builtin_sources += plugins/phonesim.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += plugins/phonesim.conf
|
||||
if RILMODEM
|
||||
dist_conf_DATA += gril/ril_subscription.conf
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -432,8 +492,8 @@ builtin_sources += plugins/stemgr.c
|
||||
builtin_modules += caif
|
||||
builtin_sources += plugins/caif.c
|
||||
|
||||
builtin_modules += tc65
|
||||
builtin_sources += plugins/tc65.c
|
||||
builtin_modules += cinterion
|
||||
builtin_sources += plugins/cinterion.c
|
||||
|
||||
builtin_modules += nokia
|
||||
builtin_sources += plugins/nokia.c
|
||||
@@ -461,19 +521,22 @@ builtin_sources += plugins/samsung.c
|
||||
|
||||
builtin_modules += sim900
|
||||
builtin_sources += plugins/sim900.c
|
||||
|
||||
builtin_modules += quectel
|
||||
builtin_sources += plugins/quectel.c
|
||||
|
||||
builtin_modules += ublox
|
||||
builtin_sources += plugins/ublox.c
|
||||
|
||||
builtin_modules += he910
|
||||
builtin_sources += plugins/he910.c
|
||||
endif
|
||||
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += he910
|
||||
builtin_sources += plugins/he910.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
|
||||
|
||||
@@ -483,11 +546,25 @@ 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@
|
||||
@@ -496,15 +573,13 @@ 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
|
||||
endif
|
||||
|
||||
if UPOWER
|
||||
builtin_modules += upower
|
||||
builtin_sources += plugins/upower.c
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -544,6 +619,9 @@ builtin_sources += examples/private-network.c
|
||||
|
||||
builtin_modules += stktest
|
||||
builtin_sources += plugins/stktest.c
|
||||
|
||||
builtin_modules += emulator_fuzz
|
||||
builtin_sources += plugins/emulator_fuzz.c
|
||||
endif
|
||||
|
||||
builtin_modules += smart_messaging
|
||||
@@ -559,12 +637,20 @@ builtin_cflags += @WSPCODEC_CFLAGS@
|
||||
builtin_libadd += @WSPCODEC_LIBS@
|
||||
endif
|
||||
|
||||
if DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/debuglog.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/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 \
|
||||
@@ -589,8 +675,9 @@ src_ofonod_SOURCES = $(builtin_sources) src/ofono.ver \
|
||||
src/cdma-sms.c src/private-network.c src/cdma-netreg.c \
|
||||
src/cdma-provision.c src/handsfree.c \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/hfp.h src/sim-mnclength.c src/oemraw.c \
|
||||
src/siri.c src/voicecallagent.c
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/hfp.h src/siri.c \
|
||||
src/netmon.c
|
||||
|
||||
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
|
||||
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
|
||||
@@ -633,9 +720,12 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/sim-api.txt doc/stk-api.txt \
|
||||
doc/audio-settings-api.txt doc/text-telephony-api.txt \
|
||||
doc/calypso-modem.txt doc/message-api.txt \
|
||||
doc/location-reporting-api.txt doc/smshistory-api.txt \
|
||||
doc/oemraw-api.txt \
|
||||
doc/certification.txt doc/siri-api.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/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -669,6 +759,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 \
|
||||
@@ -732,7 +823,16 @@ test_scripts = test/backtrace \
|
||||
test/display-icon \
|
||||
test/set-msisdn \
|
||||
test/test-voicecallagent \
|
||||
test/get-network-time
|
||||
test/get-network-time \
|
||||
test/set-ddr \
|
||||
test/register-auto \
|
||||
test/register-operator \
|
||||
test/set-sms-smsc \
|
||||
test/set-sms-bearer \
|
||||
test/get-serving-cell-info \
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -750,12 +850,20 @@ 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
|
||||
|
||||
if RILMODEM
|
||||
if JOLLA_RILMODEM
|
||||
|
||||
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
|
||||
|
||||
@@ -806,21 +914,6 @@ unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
|
||||
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 \
|
||||
@@ -828,6 +921,43 @@ unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_provision_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
|
||||
|
||||
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
|
||||
===========
|
||||
|
||||
@@ -12,7 +12,7 @@ AC_DEFUN([AC_PROG_CC_PIE], [
|
||||
|
||||
AC_DEFUN([COMPILER_FLAGS], [
|
||||
if (test "${CFLAGS}" = ""); then
|
||||
CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2"
|
||||
CFLAGS="-Wall -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2"
|
||||
fi
|
||||
if (test "$USE_MAINTAINER_MODE" = "yes"); then
|
||||
CFLAGS="$CFLAGS -Werror -Wextra"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.14)
|
||||
AC_INIT(ofono, 1.19)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -42,6 +42,7 @@ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
|
||||
if (test "${enableval}" = "yes" &&
|
||||
test "${ac_cv_prog_cc_g}" = "yes"); then
|
||||
CFLAGS="$CFLAGS -g"
|
||||
CPPFLAGS="$CPPFLAGS -DDEBUG"
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -63,8 +64,8 @@ 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)
|
||||
|
||||
@@ -166,6 +167,22 @@ 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")
|
||||
|
||||
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))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
|
||||
[disable Qualcomm QMI modem support]),
|
||||
[enable_qmimodem=${enableval}])
|
||||
@@ -201,7 +218,7 @@ AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE],
|
||||
[location of provision database]), [path_provisiondb=${withval}])
|
||||
|
||||
AC_ARG_ENABLE(provision, AC_HELP_STRING([--disable-provision],
|
||||
[disable provisioning suport]),
|
||||
[disable provisioning support]),
|
||||
[enable_provision=${enableval}])
|
||||
if (test "${enable_provision}" != "no"); then
|
||||
if (test -n "${path_provisiondb}"); then
|
||||
@@ -221,6 +238,11 @@ 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}])
|
||||
@@ -237,6 +259,17 @@ if (test "${enable_pushforwarder}" != "no"); then
|
||||
AC_SUBST(WSPCODEC_LIBS)
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(debuglog,
|
||||
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
|
||||
[enable_debuglog=${enableval}], [enable_debuglog="no"])
|
||||
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
|
||||
if (test "${enable_debuglog}" = "yes"); then
|
||||
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 "${prefix}" = "NONE"); then
|
||||
dnl no prefix and no localstatedir, so default to /var
|
||||
if (test "$localstatedir" = '${prefix}/var'); 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.
|
||||
@@ -306,6 +306,13 @@ Example:
|
||||
2)
|
||||
0x1 << y // Wrong
|
||||
|
||||
M17: Avoid forward-declaration of static functions
|
||||
==================================================
|
||||
|
||||
Functions that are static should not be forward-declared. The only exception
|
||||
to this rule is if a circular dependency condition exists, and the forward
|
||||
declaration cannot be avoided.
|
||||
|
||||
O1: Shorten the name
|
||||
====================
|
||||
Better to use abbreviation, rather than full name, to name a variable,
|
||||
|
||||
@@ -60,6 +60,16 @@ Methods dict GetProperties()
|
||||
[service].Error.NotFound
|
||||
[service].Error.Failed
|
||||
|
||||
void ResetContexts()
|
||||
|
||||
Removes all contexts and re-provisions from the APN
|
||||
database. Contexts must all be deactivated for this
|
||||
method to work, and the atom must not be powered.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.NotAllowed
|
||||
|
||||
Signals PropertyChanged(string property, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
@@ -96,7 +106,7 @@ Properties boolean Attached [readonly]
|
||||
GPRS service registration (if known).
|
||||
|
||||
Possible values are:
|
||||
"none", "gsm", "edge", "umts", "hsdpa", "hsupa",
|
||||
"none", "gprs", "edge", "umts", "hsdpa", "hsupa",
|
||||
"hspa" (HSDPA and HSUPA at the same time) and
|
||||
"lte"
|
||||
|
||||
@@ -189,6 +199,10 @@ Properties boolean Active [readwrite]
|
||||
"wap" - Used by WAP related services
|
||||
"ims" - Used by IMS related services
|
||||
|
||||
string AuthenticationMethod [readwrite]
|
||||
Holds the PPP authentication method to use. Valid
|
||||
values are "pap" and "chap". Defaults to "chap".
|
||||
|
||||
string Username [readwrite]
|
||||
|
||||
Holds the username to be used for authentication
|
||||
|
||||
@@ -19,6 +19,8 @@ Methods dict GetProperties()
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.NotSupported
|
||||
|
||||
string RequestPhoneNumber()
|
||||
|
||||
@@ -51,6 +53,7 @@ Properties array{string} Features [readonly]
|
||||
"private-chat"
|
||||
"create-multiparty"
|
||||
"transfer"
|
||||
"hf-indicators"
|
||||
|
||||
boolean InbandRinging [readonly]
|
||||
|
||||
@@ -63,7 +66,7 @@ Properties array{string} Features [readonly]
|
||||
to activate or deactivate the function from the HF, or
|
||||
the AG could autonomously initiate it.
|
||||
|
||||
boolean EchoCancelingNoiseReduction [readwrite]
|
||||
boolean EchoCancelingNoiseReduction [readwrite, optional]
|
||||
|
||||
Non-persistent Boolean property representing whether
|
||||
echo canceling and noise reduction is enabled in the
|
||||
@@ -80,3 +83,10 @@ Properties array{string} Features [readonly]
|
||||
array{string} SubscriberNumbers [readonly]
|
||||
|
||||
List of subscriber numbers provided by the AG.
|
||||
|
||||
boolean DistractedDrivingReduction [readwrite, optional]
|
||||
|
||||
Non-persistent property representing whether
|
||||
distracted driving reduction mode should be enabled in
|
||||
the AG. Support for this feature is optional on the
|
||||
AG.
|
||||
|
||||
@@ -89,6 +89,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]
|
||||
===============================
|
||||
|
||||
@@ -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
|
||||
|
||||
83
ofono/doc/networkmonitor-api.txt
Normal file
83
ofono/doc/networkmonitor-api.txt
Normal file
@@ -0,0 +1,83 @@
|
||||
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.
|
||||
@@ -45,6 +45,11 @@ Properties string TechnologyPreference [readwrite]
|
||||
"umts" Only UMTS used for radio access.
|
||||
"lte" Only LTE used for radio access.
|
||||
|
||||
array{string} AvailableTechnologies [readonly, optional]
|
||||
|
||||
List of values for TechnologyPreference property
|
||||
supported by the modem.
|
||||
|
||||
string GsmBand [readwrite, optional]
|
||||
|
||||
Frequency band in which the modem is allowed to
|
||||
|
||||
@@ -93,6 +93,11 @@ Properties boolean Present [readonly]
|
||||
|
||||
Contains the IMSI of the SIM, if available.
|
||||
|
||||
string ServiceProviderName [readonly, optional]
|
||||
|
||||
Contains the service provider name fetched from the
|
||||
SIM card, if available.
|
||||
|
||||
string MobileCountryCode [readonly, optional]
|
||||
|
||||
Contains the Mobile Country Code (MCC) of the home
|
||||
|
||||
19
ofono/doc/telit-modem.txt
Normal file
19
ofono/doc/telit-modem.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
oFono - Open Source Telephony
|
||||
*****************************
|
||||
|
||||
Purpose
|
||||
=======
|
||||
The purpose of this document is to identify issues and configuration
|
||||
requirements with Telit's modems.
|
||||
|
||||
HE910
|
||||
=====
|
||||
|
||||
GPS:
|
||||
To enable location reporting on the Telit HE910 the modem needs to be
|
||||
switched to Port Configuration #8. Please refer to Telit's
|
||||
'HE910 UE910 Family Ports Arrangements' section 4.1.3 for rationale and
|
||||
'AT Commands Reference Guide' section 3.5.7.1.96 for specific AT command.
|
||||
After setting the configuration, a power cycle is required.
|
||||
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
|
||||
can be checked using 'AT+CGMR'.
|
||||
@@ -59,6 +59,7 @@ enum state {
|
||||
struct gprs_context_data {
|
||||
GAtChat *chat;
|
||||
unsigned int active_context;
|
||||
GAtPPPAuthMethod auth_method;
|
||||
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
|
||||
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
|
||||
GAtPPP *ppp;
|
||||
@@ -154,6 +155,7 @@ static gboolean setup_ppp(struct ofono_gprs_context *gc)
|
||||
if (getenv("OFONO_PPP_DEBUG"))
|
||||
g_at_ppp_set_debug(gcd->ppp, ppp_debug, "PPP");
|
||||
|
||||
g_at_ppp_set_auth_method(gcd->ppp, gcd->auth_method);
|
||||
g_at_ppp_set_credentials(gcd->ppp, gcd->username, gcd->password);
|
||||
|
||||
/* set connect and disconnect callbacks */
|
||||
@@ -243,6 +245,18 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
memcpy(gcd->username, ctx->username, sizeof(ctx->username));
|
||||
memcpy(gcd->password, ctx->password, sizeof(ctx->password));
|
||||
|
||||
/* We only support CHAP and PAP */
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
gcd->auth_method = G_AT_PPP_AUTH_METHOD_PAP;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
gcd->state = STATE_ENABLING;
|
||||
|
||||
if (gcd->vendor == OFONO_VENDOR_ZTE) {
|
||||
@@ -268,9 +282,34 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid);
|
||||
|
||||
if (ctx->apn)
|
||||
snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
|
||||
ctx->apn);
|
||||
if (ctx->apn) {
|
||||
switch (gcd->vendor) {
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
/*
|
||||
* U-blox modems require a magic prefix to the APN to
|
||||
* specify the authentication method to use in the
|
||||
* network. See UBX-13002752 - R21.
|
||||
*
|
||||
* As the response of the read command omits this magic
|
||||
* prefix, this is the least invasive place to set it.
|
||||
*/
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
snprintf(buf + len, sizeof(buf) - len - 3,
|
||||
",\"CHAP:%s\"", ctx->apn);
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
snprintf(buf + len, sizeof(buf) - len - 3,
|
||||
",\"PAP:%s\"", ctx->apn);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
|
||||
ctx->apn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
at_cgdcont_cb, gc, NULL) > 0)
|
||||
|
||||
@@ -49,6 +49,7 @@ static const char *none_prefix[] = { NULL };
|
||||
struct gprs_data {
|
||||
GAtChat *chat;
|
||||
unsigned int vendor;
|
||||
unsigned int last_auto_context_id;
|
||||
};
|
||||
|
||||
static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
@@ -141,6 +142,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;
|
||||
@@ -157,6 +200,7 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
|
||||
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;
|
||||
|
||||
@@ -172,6 +216,11 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
g_str_equal(event, "ME DETACH")) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,6 +331,40 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
|
||||
ofono_gprs_bearer_notify(gprs, bearer);
|
||||
}
|
||||
|
||||
static void ublox_ureg_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
GAtResultIter iter;
|
||||
gint state, bearer;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+UREG:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &state))
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
case 4:
|
||||
bearer = 5;
|
||||
break;
|
||||
case 5:
|
||||
bearer = 4;
|
||||
break;
|
||||
case 8:
|
||||
bearer = 1;
|
||||
break;
|
||||
case 9:
|
||||
bearer = 2;
|
||||
break;
|
||||
default:
|
||||
bearer = state;
|
||||
}
|
||||
|
||||
ofono_gprs_bearer_notify(gprs, bearer);
|
||||
}
|
||||
|
||||
static void cpsb_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
@@ -316,6 +399,13 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
|
||||
FALSE, gprs, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
g_at_chat_register(gd->chat, "+UREG:", ublox_ureg_notify,
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_send(gd->chat, "AT+UREG=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_TELIT:
|
||||
g_at_chat_register(gd->chat, "#PSNT:", telit_mode_notify,
|
||||
FALSE, gprs, NULL);
|
||||
|
||||
@@ -838,6 +838,39 @@ static void telit_ciev_notify(GAtResult *result, gpointer user_data)
|
||||
ofono_netreg_strength_notify(netreg, strength);
|
||||
}
|
||||
|
||||
static void cinterion_ciev_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
const char *signal_identifier = "rssi";
|
||||
const char *ind_str;
|
||||
int strength;
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CIEV:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_unquoted_string(&iter, &ind_str))
|
||||
return;
|
||||
|
||||
if (!g_str_equal(signal_identifier, ind_str))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &strength))
|
||||
return;
|
||||
|
||||
DBG("rssi %d", strength);
|
||||
|
||||
if (strength == nd->signal_invalid)
|
||||
strength = -1;
|
||||
else
|
||||
strength = (strength * 100) / (nd->signal_max - nd->signal_min);
|
||||
|
||||
ofono_netreg_strength_notify(netreg, strength);
|
||||
}
|
||||
|
||||
static void ctzv_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
@@ -1547,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 */
|
||||
@@ -1574,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;
|
||||
}
|
||||
|
||||
@@ -1590,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;
|
||||
@@ -1915,6 +1959,27 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
g_at_chat_send(nd->chat, "AT*TLTS=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
/*
|
||||
* We can't set rssi bounds from Cinterion responses
|
||||
* so set them up to specified values here
|
||||
*
|
||||
* Cinterion rssi signal strength specified as:
|
||||
* 0 <= -112dBm
|
||||
* 1 - 4 signal strengh in 15 dB steps
|
||||
* 5 >= -51 dBm
|
||||
* 99 not known or undetectable
|
||||
*/
|
||||
nd->signal_min = 0;
|
||||
nd->signal_max = 5;
|
||||
nd->signal_invalid = 99;
|
||||
|
||||
/* Register for specific signal strength reports */
|
||||
g_at_chat_send(nd->chat, "AT^SIND=\"rssi\",1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
g_at_chat_register(nd->chat, "+CIEV:",
|
||||
cinterion_ciev_notify, FALSE, netreg, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_NOKIA:
|
||||
case OFONO_VENDOR_SAMSUNG:
|
||||
/* Signal strength reporting via CIND is not supported */
|
||||
|
||||
@@ -67,6 +67,8 @@ static const char *epin_prefix[] = { "*EPIN:", NULL };
|
||||
static const char *spic_prefix[] = { "+SPIC:", NULL };
|
||||
static const char *pct_prefix[] = { "#PCT:", NULL };
|
||||
static const char *pnnm_prefix[] = { "+PNNM:", NULL };
|
||||
static const char *qpinc_prefix[] = { "+QPINC:", NULL };
|
||||
static const char *upincnt_prefix[] = { "+UPINCNT:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
@@ -825,7 +827,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if (!strcmp(name, at_sim_name[i].name)) {
|
||||
retries[i] = val;
|
||||
retries[at_sim_name[i].type] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -967,6 +969,90 @@ error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void at_qpinc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
const char *final = g_at_result_final_response(result);
|
||||
GAtResultIter iter;
|
||||
struct ofono_error error;
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
size_t i;
|
||||
|
||||
decode_at_error(&error, final);
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
||||
retries[i] = -1;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+QPINC:")) {
|
||||
const char *name;
|
||||
int pin, puk;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &name))
|
||||
continue;
|
||||
if (!g_at_result_iter_next_number(&iter, &pin))
|
||||
continue;
|
||||
if (!g_at_result_iter_next_number(&iter, &puk))
|
||||
continue;
|
||||
|
||||
if (!strcmp(name, "SC")) {
|
||||
retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin;
|
||||
retries[OFONO_SIM_PASSWORD_SIM_PUK] = puk;
|
||||
} else if (!strcmp(name, "P2")) {
|
||||
retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin;
|
||||
retries[OFONO_SIM_PASSWORD_SIM_PUK2] = puk;
|
||||
}
|
||||
}
|
||||
|
||||
cb(&error, retries, cbd->data);
|
||||
}
|
||||
|
||||
static void upincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
||||
const char *final = g_at_result_final_response(result);
|
||||
GAtResultIter iter;
|
||||
struct ofono_error error;
|
||||
int retries[OFONO_SIM_PASSWORD_INVALID];
|
||||
size_t i;
|
||||
static enum ofono_sim_password_type password_types[] = {
|
||||
OFONO_SIM_PASSWORD_SIM_PIN,
|
||||
OFONO_SIM_PASSWORD_SIM_PIN2,
|
||||
OFONO_SIM_PASSWORD_SIM_PUK,
|
||||
OFONO_SIM_PASSWORD_SIM_PUK2,
|
||||
};
|
||||
|
||||
decode_at_error(&error, final);
|
||||
|
||||
if (!ok) {
|
||||
cb(&error, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+UPINCNT:"))
|
||||
goto error;
|
||||
|
||||
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
||||
retries);
|
||||
|
||||
cb(&error, retries, cbd->data);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb,
|
||||
void *data)
|
||||
@@ -1028,6 +1114,17 @@ static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
at_pnnm_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_QUECTEL:
|
||||
if (g_at_chat_send(sd->chat, "AT+QPINC?", qpinc_prefix,
|
||||
at_qpinc_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
|
||||
upincnt_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
|
||||
at_cpinr_cb, cbd, g_free) > 0)
|
||||
@@ -1254,6 +1351,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
case OFONO_VENDOR_ALCATEL:
|
||||
case OFONO_VENDOR_HUAWEI:
|
||||
case OFONO_VENDOR_SIMCOM:
|
||||
case OFONO_VENDOR_SIERRA:
|
||||
/*
|
||||
* On ZTE modems, after pin is entered, SIM state is checked
|
||||
* by polling CPIN as their modem doesn't provide unsolicited
|
||||
@@ -1419,7 +1517,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;
|
||||
|
||||
@@ -1444,9 +1542,9 @@ 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);
|
||||
@@ -1529,7 +1627,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 = {
|
||||
@@ -1543,7 +1641,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)
|
||||
|
||||
@@ -42,5 +42,9 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_SIMCOM_SIM900,
|
||||
OFONO_VENDOR_ICERA,
|
||||
OFONO_VENDOR_WAVECOM_Q2XXX,
|
||||
OFONO_VENDOR_ALCATEL
|
||||
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);
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
static const char *binp_prefix[] = { "+BINP:", NULL };
|
||||
static const char *bvra_prefix[] = { "+BVRA:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct hf_data {
|
||||
GAtChat *chat;
|
||||
@@ -197,7 +198,7 @@ static void hfp_cnum_query(struct ofono_handsfree *hf,
|
||||
struct hf_data *hd = ofono_handsfree_get_data(hf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(hd->chat, "AT+CNUM", NULL,
|
||||
if (g_at_chat_send(hd->chat, "AT+CNUM", none_prefix,
|
||||
cnum_query_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
@@ -206,6 +207,27 @@ static void hfp_cnum_query(struct ofono_handsfree *hf,
|
||||
CALLBACK_WITH_FAILURE(cb, -1, NULL, data);
|
||||
}
|
||||
|
||||
static void bind_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_handsfree *hf = user_data;
|
||||
int hf_indicator;
|
||||
int active;
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+BIND:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &hf_indicator))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &active))
|
||||
return;
|
||||
|
||||
ofono_handsfree_hf_indicator_active_notify(hf, hf_indicator, active);
|
||||
}
|
||||
|
||||
static gboolean hfp_handsfree_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_handsfree *hf = user_data;
|
||||
@@ -216,6 +238,7 @@ static gboolean hfp_handsfree_register(gpointer user_data)
|
||||
g_at_chat_register(hd->chat, "+BSIR:", bsir_notify, FALSE, hf, NULL);
|
||||
g_at_chat_register(hd->chat, "+BVRA:", bvra_notify, FALSE, hf, NULL);
|
||||
g_at_chat_register(hd->chat, "+CIEV:", ciev_notify, FALSE, hf, NULL);
|
||||
g_at_chat_register(hd->chat, "+BIND:", bind_notify, FALSE, hf, NULL);
|
||||
|
||||
if (hd->ag_features & HFP_AG_FEATURE_IN_BAND_RING_TONE)
|
||||
ofono_handsfree_set_inband_ringing(hf, TRUE);
|
||||
@@ -232,6 +255,7 @@ static int hfp_handsfree_probe(struct ofono_handsfree *hf,
|
||||
{
|
||||
struct hfp_slc_info *info = data;
|
||||
struct hf_data *hd;
|
||||
unsigned int i;
|
||||
|
||||
DBG("");
|
||||
hd = g_new0(struct hf_data, 1);
|
||||
@@ -245,6 +269,14 @@ static int hfp_handsfree_probe(struct ofono_handsfree *hf,
|
||||
ofono_handsfree_battchg_notify(hf,
|
||||
info->cind_val[HFP_INDICATOR_BATTCHG]);
|
||||
|
||||
ofono_handsfree_set_hf_indicators(hf, info->hf_indicators,
|
||||
info->num_hf_indicators);
|
||||
|
||||
for (i = 0; i < info->num_hf_indicators; i++)
|
||||
ofono_handsfree_hf_indicator_active_notify(hf,
|
||||
info->hf_indicators[i],
|
||||
info->hf_indicator_active_map & (1 << i));
|
||||
|
||||
hd->register_source = g_idle_add(hfp_handsfree_register, hf);
|
||||
|
||||
return 0;
|
||||
@@ -351,8 +383,27 @@ static void hfp_disable_nrec(struct ofono_handsfree *hf,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
const char *buf = "AT+NREC=0";
|
||||
|
||||
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
|
||||
cbd, g_free) > 0)
|
||||
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||
hf_generic_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void hfp_hf_indicator(struct ofono_handsfree *hf,
|
||||
unsigned short indicator, unsigned int value,
|
||||
ofono_handsfree_cb_t cb, void *data)
|
||||
{
|
||||
struct hf_data *hd = ofono_handsfree_get_data(hf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[128];
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+BIEV=%u,%u", indicator, value);
|
||||
|
||||
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||
hf_generic_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
@@ -368,6 +419,7 @@ static struct ofono_handsfree_driver driver = {
|
||||
.request_phone_number = hfp_request_phone_number,
|
||||
.voice_recognition = hfp_voice_recognition,
|
||||
.disable_nrec = hfp_disable_nrec,
|
||||
.hf_indicator = hfp_hf_indicator,
|
||||
};
|
||||
|
||||
void hfp_handsfree_init(void)
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
static const char *cops_prefix[] = { "+COPS:", NULL };
|
||||
static const char *cind_prefix[] = { "+CIND:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct netreg_data {
|
||||
GAtChat *chat;
|
||||
@@ -263,7 +264,7 @@ static void hfp_current_operator(struct ofono_netreg *netreg,
|
||||
|
||||
cbd->user = netreg;
|
||||
|
||||
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", NULL,
|
||||
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
|
||||
NULL, cbd, NULL);
|
||||
|
||||
if (ok)
|
||||
|
||||
@@ -41,10 +41,12 @@
|
||||
#include "hfp.h"
|
||||
#include "slc.h"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *brsf_prefix[] = { "+BRSF:", NULL };
|
||||
static const char *cind_prefix[] = { "+CIND:", NULL };
|
||||
static const char *cmer_prefix[] = { "+CMER:", NULL };
|
||||
static const char *chld_prefix[] = { "+CHLD:", NULL };
|
||||
static const char *bind_prefix[] = { "+BIND:", NULL };
|
||||
|
||||
struct slc_establish_data {
|
||||
gint ref_count;
|
||||
@@ -76,6 +78,14 @@ void hfp_slc_info_init(struct hfp_slc_info *info, guint16 version)
|
||||
|
||||
info->hf_features |= HFP_HF_FEATURE_CODEC_NEGOTIATION;
|
||||
|
||||
if (version < HFP_VERSION_1_7)
|
||||
goto done;
|
||||
|
||||
info->hf_features |= HFP_HF_FEATURE_HF_INDICATORS;
|
||||
memset(info->hf_indicators, 0, sizeof(info->hf_indicators));
|
||||
info->num_hf_indicators = 0;
|
||||
info->hf_indicator_active_map = 0;
|
||||
|
||||
done:
|
||||
memset(info->cind_val, 0, sizeof(info->cind_val));
|
||||
memset(info->cind_pos, 0, sizeof(info->cind_pos));
|
||||
@@ -103,10 +113,109 @@ static void slc_established(struct slc_establish_data *sed)
|
||||
{
|
||||
struct hfp_slc_info *info = sed->info;
|
||||
|
||||
g_at_chat_send(info->chat, "AT+CMEE=1", NULL, NULL, NULL, NULL);
|
||||
g_at_chat_send(info->chat, "AT+CMEE=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
sed->connect_cb(sed->userdata);
|
||||
}
|
||||
|
||||
static void bind_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct slc_establish_data *sed = user_data;
|
||||
struct hfp_slc_info *info = sed->info;
|
||||
GAtResultIter iter;
|
||||
int hf_indicator;
|
||||
int enabled;
|
||||
unsigned int i;
|
||||
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+BIND:")) {
|
||||
if (!g_at_result_iter_next_number(&iter, &hf_indicator))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &enabled))
|
||||
goto error;
|
||||
|
||||
ofono_info("AG wants indicator %d %s",
|
||||
hf_indicator, enabled ? "enabled" : "disabled");
|
||||
|
||||
for (i = 0; i < info->num_hf_indicators; i++) {
|
||||
if (info->hf_indicators[i] != hf_indicator)
|
||||
continue;
|
||||
|
||||
info->hf_indicator_active_map |= enabled << i;
|
||||
}
|
||||
|
||||
ofono_info("Active map: %02x", info->hf_indicator_active_map);
|
||||
}
|
||||
|
||||
slc_established(sed);
|
||||
return;
|
||||
|
||||
error:
|
||||
slc_failed(sed);
|
||||
}
|
||||
|
||||
static void bind_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct slc_establish_data *sed = user_data;
|
||||
struct hfp_slc_info *info = sed->info;
|
||||
GAtResultIter iter;
|
||||
int hf_indicator;
|
||||
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+BIND:"))
|
||||
goto error;
|
||||
|
||||
if (!g_at_result_iter_open_list(&iter))
|
||||
goto error;
|
||||
|
||||
while (g_at_result_iter_next_number(&iter, &hf_indicator)) {
|
||||
if (info->num_hf_indicators >= 20)
|
||||
goto error;
|
||||
|
||||
ofono_info("AG supports the following HF indicator: %d",
|
||||
hf_indicator);
|
||||
|
||||
info->hf_indicators[info->num_hf_indicators] = hf_indicator;
|
||||
info->num_hf_indicators += 1;
|
||||
}
|
||||
|
||||
if (!g_at_result_iter_close_list(&iter))
|
||||
goto error;
|
||||
|
||||
slc_establish_data_ref(sed);
|
||||
g_at_chat_send(info->chat, "AT+BIND?", bind_prefix,
|
||||
bind_query_cb, sed, slc_establish_data_unref);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
slc_failed(sed);
|
||||
}
|
||||
|
||||
static void bind_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct slc_establish_data *sed = user_data;
|
||||
struct hfp_slc_info *info = sed->info;
|
||||
|
||||
if (!ok) {
|
||||
slc_failed(sed);
|
||||
return;
|
||||
}
|
||||
|
||||
slc_establish_data_ref(sed);
|
||||
g_at_chat_send(info->chat, "AT+BIND=?", bind_prefix,
|
||||
bind_support_cb, sed, slc_establish_data_unref);
|
||||
}
|
||||
|
||||
static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct slc_establish_data *sed = user_data;
|
||||
@@ -148,7 +257,14 @@ static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
info->ag_mpty_features = ag_mpty_feature;
|
||||
|
||||
slc_established(sed);
|
||||
if ((info->ag_features & HFP_AG_FEATURE_HF_INDICATORS) &&
|
||||
(info->hf_features & HFP_HF_FEATURE_HF_INDICATORS)) {
|
||||
slc_establish_data_ref(sed);
|
||||
g_at_chat_send(info->chat, "AT+BIND=1", none_prefix,
|
||||
bind_set_cb, sed, slc_establish_data_unref);
|
||||
} else
|
||||
slc_established(sed);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -319,8 +435,8 @@ static void brsf_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
sprintf(str, "AT+BAC=%d", HFP_CODEC_CVSD);
|
||||
|
||||
slc_establish_data_ref(sed);
|
||||
g_at_chat_send(info->chat, str, NULL, bac_cb, sed,
|
||||
slc_establish_data_unref);
|
||||
g_at_chat_send(info->chat, str, none_prefix, bac_cb,
|
||||
sed, slc_establish_data_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ struct hfp_slc_info {
|
||||
unsigned int hf_features;
|
||||
unsigned char cind_pos[HFP_INDICATOR_LAST];
|
||||
unsigned int cind_val[HFP_INDICATOR_LAST];
|
||||
unsigned short hf_indicators[20];
|
||||
unsigned char num_hf_indicators;
|
||||
unsigned int hf_indicator_active_map;
|
||||
};
|
||||
|
||||
void hfp_slc_info_init(struct hfp_slc_info *info, guint16 version);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#define POLL_CLCC_DELAY 50
|
||||
#define EXPECT_RELEASE_DELAY 50
|
||||
#define CLIP_TIMEOUT 500
|
||||
#define EXPECT_RING_DELAY 200
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *clcc_prefix[] = { "+CLCC:", NULL };
|
||||
@@ -285,8 +286,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||
|
||||
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;
|
||||
|
||||
@@ -294,7 +294,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
* we won't get indicator update if any of them is released by CHLD=1x.
|
||||
* So we have to poll it.
|
||||
*/
|
||||
if (num_active > 1 || num_held > 1)
|
||||
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc,
|
||||
vc);
|
||||
}
|
||||
@@ -332,6 +332,10 @@ static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok && vd->calls)
|
||||
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
|
||||
clcc_poll_cb, req->vc, NULL);
|
||||
|
||||
req->cb(&error, req->data);
|
||||
}
|
||||
|
||||
@@ -499,6 +503,19 @@ static gboolean expect_release(gpointer user_data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean expect_ring(gpointer user_data)
|
||||
{
|
||||
struct ofono_voicecall *vc = user_data;
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
|
||||
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
|
||||
clcc_poll_cb, vc, NULL);
|
||||
|
||||
vd->clip_source = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void release_all_active_cb(gboolean ok, GAtResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
@@ -640,8 +657,10 @@ static void hfp_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
struct change_state_req *req = g_try_new0(struct change_state_req, 1);
|
||||
int len = strlen(dtmf);
|
||||
char *buf;
|
||||
int s;
|
||||
int i;
|
||||
|
||||
if (req == NULL)
|
||||
goto error;
|
||||
@@ -651,12 +670,15 @@ static void hfp_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
|
||||
req->data = data;
|
||||
req->affected_types = 0;
|
||||
|
||||
/* strlen("AT+VTS=) = 7 + NULL */
|
||||
buf = g_try_new(char, strlen(dtmf) + 8);
|
||||
/* strlen("AT") + (n-1) * strlen("+VTS=T;") + strlen(+VTS=T) + null */
|
||||
buf = g_try_new(char, len * 7 + 2);
|
||||
if (buf == NULL)
|
||||
goto error;
|
||||
|
||||
sprintf(buf, "AT+VTS=%s", dtmf);
|
||||
s = sprintf(buf, "AT+VTS=%c", dtmf[0]);
|
||||
|
||||
for (i = 1; i < len; i++)
|
||||
s += sprintf(buf + s, ";+VTS=%c", dtmf[i]);
|
||||
|
||||
s = g_at_chat_send(vd->chat, buf, none_prefix,
|
||||
generic_cb, req, g_free);
|
||||
@@ -686,12 +708,31 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
|
||||
int num_type, validity;
|
||||
struct ofono_call *call;
|
||||
|
||||
/* Waiting call notification makes no sense, when there are
|
||||
* no calls at all. This can happen when a phone already has
|
||||
* waiting and active calls and is being connected over HFP
|
||||
* but it first sends +CCWA before we manage to synchronize
|
||||
* calls with AT+CLCC.
|
||||
*/
|
||||
if (!vd->calls)
|
||||
return;
|
||||
|
||||
/* CCWA can repeat, ignore if we already have an waiting call */
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_WAITING),
|
||||
at_util_call_compare_by_status))
|
||||
return;
|
||||
|
||||
/* some phones may send extra CCWA after active call is ended
|
||||
* this would trigger creation of second call in state 'WAITING'
|
||||
* as our previous WAITING call has been promoted to INCOMING
|
||||
*/
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_INCOMING),
|
||||
at_util_call_compare_by_status))
|
||||
return;
|
||||
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CCWA:"))
|
||||
@@ -752,6 +793,11 @@ static void ring_notify(GAtResult *result, gpointer user_data)
|
||||
struct ofono_call *call;
|
||||
GSList *waiting;
|
||||
|
||||
if (vd->clip_source) {
|
||||
g_source_remove(vd->clip_source);
|
||||
vd->clip_source = 0;
|
||||
}
|
||||
|
||||
/* RING can repeat, ignore if we already have an incoming call */
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_INCOMING),
|
||||
@@ -976,7 +1022,15 @@ static void ciev_callsetup_notify(struct ofono_voicecall *vc,
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Handled in RING/CCWA */
|
||||
/*
|
||||
* Handled in RING/CCWA most of the time, however sometimes
|
||||
* the call is answered before the RING unsolicited
|
||||
* notification has a chance to be generated on the device.
|
||||
* In this case, we use a failsafe CLCC poll in expect_ring
|
||||
* callback.
|
||||
* */
|
||||
vd->clip_source = g_timeout_add(EXPECT_RING_DELAY,
|
||||
expect_ring, vc);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -1064,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1102,6 +1167,10 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
struct ofono_voicecall *vc = user_data;
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
unsigned int mpty_ids;
|
||||
GSList *n;
|
||||
struct ofono_call *nc;
|
||||
unsigned int num_active = 0;
|
||||
unsigned int num_held = 0;
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
@@ -1110,6 +1179,22 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
g_slist_foreach(vd->calls, voicecall_notify, vc);
|
||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||
|
||||
n = vd->calls;
|
||||
|
||||
while (n) {
|
||||
nc = n->data;
|
||||
|
||||
if (nc->status == CALL_STATUS_ACTIVE)
|
||||
num_active++;
|
||||
else if (nc->status == CALL_STATUS_HELD)
|
||||
num_held++;
|
||||
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc, vc);
|
||||
}
|
||||
|
||||
static void hfp_voicecall_initialized(gboolean ok, GAtResult *result,
|
||||
@@ -1151,8 +1236,8 @@ static int hfp_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
|
||||
ofono_voicecall_set_data(vc, vd);
|
||||
|
||||
g_at_chat_send(vd->chat, "AT+CLIP=1", NULL, NULL, NULL, NULL);
|
||||
g_at_chat_send(vd->chat, "AT+CCWA=1", NULL,
|
||||
g_at_chat_send(vd->chat, "AT+CLIP=1", none_prefix, NULL, NULL, NULL);
|
||||
g_at_chat_send(vd->chat, "AT+CCWA=1", none_prefix,
|
||||
hfp_voicecall_initialized, vc, NULL);
|
||||
return 0;
|
||||
}
|
||||
@@ -1170,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);
|
||||
|
||||
284
ofono/drivers/ril/ril_call_barring.c
Normal file
284
ofono/drivers/ril/ril_call_barring.c
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* See 3GPP 27.007 7.4 for possible values */
|
||||
#define RIL_MAX_SERVICE_LENGTH 3
|
||||
|
||||
/*
|
||||
* ril.h does not state that string count must be given, but that is
|
||||
* still expected by the modem
|
||||
*/
|
||||
#define RIL_QUERY_STRING_COUNT 4
|
||||
#define RIL_SET_STRING_COUNT 5
|
||||
#define RIL_SET_PW_STRING_COUNT 3
|
||||
|
||||
struct ril_call_barring {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_barring_cbd {
|
||||
struct ril_call_barring *bd;
|
||||
union _ofono_call_barring_cb {
|
||||
ofono_call_barring_query_cb_t query;
|
||||
ofono_call_barring_set_cb_t set;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_barring_cbd_free g_free
|
||||
|
||||
static inline struct ril_call_barring *ril_call_barring_get_data(
|
||||
struct ofono_call_barring *b)
|
||||
{
|
||||
return ofono_call_barring_get_data(b);
|
||||
}
|
||||
|
||||
static struct ril_call_barring_cbd *ril_call_barring_cbd_new(
|
||||
struct ril_call_barring *bd, void *cb, void *data)
|
||||
{
|
||||
struct ril_call_barring_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_call_barring_cbd, 1);
|
||||
cbd->bd = bd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_barring_submit_request(struct ril_call_barring *bd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
{
|
||||
grilio_queue_send_request_full(bd->q, req, code, response,
|
||||
ril_call_barring_cbd_free,
|
||||
ril_call_barring_cbd_new(bd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_call_barring_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_query_cb_t cb = cbd->cb.query;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int bearer_class = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
/*
|
||||
* Services for which the specified barring facility is active.
|
||||
* "0" means "disabled for all, -1 if unknown"
|
||||
*/
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* count */
|
||||
grilio_parser_get_int32(&rilp, &bearer_class);
|
||||
DBG("Active services: %d", bearer_class);
|
||||
cb(ril_error_ok(&error), bearer_class, cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring query error %d", status);
|
||||
cb(ril_error_failure(&error), 0, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
const char *lock, int cls,
|
||||
ofono_call_barring_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("lock: %s, services to query: %d", lock, cls);
|
||||
|
||||
/*
|
||||
* RIL modems do not support 7 as default bearer class. According to
|
||||
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||
* "All tele and bearer services"
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/*
|
||||
* See 3GPP 27.007 7.4 for parameter descriptions.
|
||||
* According to ril.h password should be empty string "" when not
|
||||
* needed, but in reality we only need to give string length as 0
|
||||
*/
|
||||
grilio_request_append_int32(req, RIL_QUERY_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_int32(req, 0); /* Password length */
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_call_barring_query_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring Set error %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_set(struct ofono_call_barring *b,
|
||||
const char *lock, int enable, const char *passwd, int cls,
|
||||
ofono_call_barring_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("lock: %s, enable: %i, bearer class: %i", lock, enable, cls);
|
||||
|
||||
/*
|
||||
* RIL modem does not support 7 as default bearer class. According to
|
||||
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||
* "All tele and bearer services"
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/* See 3GPP 27.007 7.4 for parameter descriptions */
|
||||
grilio_request_append_int32(req, RIL_SET_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_utf8(req, enable ?
|
||||
RIL_FACILITY_LOCK :
|
||||
RIL_FACILITY_UNLOCK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
ril_call_barring_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring Set PW error %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd(struct ofono_call_barring *b,
|
||||
const char *lock, const char *old_passwd,
|
||||
const char *new_passwd, ofono_call_barring_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("");
|
||||
grilio_request_append_int32(req, RIL_SET_PW_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_utf8(req, old_passwd);
|
||||
grilio_request_append_utf8(req, new_passwd);
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_CHANGE_BARRING_PASSWORD,
|
||||
ril_call_barring_set_passwd_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_barring_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_barring *b = user_data;
|
||||
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||
|
||||
GASSERT(bd->timer_id);
|
||||
bd->timer_id = 0;
|
||||
ofono_call_barring_register(b);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_barring_probe(struct ofono_call_barring *b,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
|
||||
|
||||
DBG("");
|
||||
bd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
bd->timer_id = g_idle_add(ril_call_barring_register, b);
|
||||
ofono_call_barring_set_data(b, bd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_barring_remove(struct ofono_call_barring *b)
|
||||
{
|
||||
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||
|
||||
DBG("");
|
||||
ofono_call_barring_set_data(b, NULL);
|
||||
|
||||
if (bd->timer_id > 0) {
|
||||
g_source_remove(bd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(bd->q, FALSE);
|
||||
grilio_queue_unref(bd->q);
|
||||
g_free(bd);
|
||||
}
|
||||
|
||||
const struct ofono_call_barring_driver ril_call_barring_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_barring_probe,
|
||||
.remove = ril_call_barring_remove,
|
||||
.query = ril_call_barring_query,
|
||||
.set = ril_call_barring_set,
|
||||
.set_passwd = ril_call_barring_set_passwd
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
275
ofono/drivers/ril/ril_call_forward.c
Normal file
275
ofono/drivers/ril/ril_call_forward.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct ril_call_forward {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
enum ril_call_forward_action {
|
||||
CF_ACTION_DISABLE,
|
||||
CF_ACTION_ENABLE,
|
||||
CF_ACTION_INTERROGATE,
|
||||
CF_ACTION_REGISTRATION,
|
||||
CF_ACTION_ERASURE
|
||||
};
|
||||
|
||||
#define CF_TIME_DEFAULT (0)
|
||||
|
||||
struct ril_call_forward_cbd {
|
||||
struct ril_call_forward *fd;
|
||||
union _ofono_call_forward_cb {
|
||||
ofono_call_forwarding_query_cb_t query;
|
||||
ofono_call_forwarding_set_cb_t set;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static inline struct ril_call_forward *ril_call_forward_get_data(
|
||||
struct ofono_call_forwarding *cf)
|
||||
{
|
||||
return ofono_call_forwarding_get_data(cf);
|
||||
}
|
||||
|
||||
static void ril_call_forward_cbd_free(gpointer cbd)
|
||||
{
|
||||
g_slice_free(struct ril_call_forward_cbd, cbd);
|
||||
}
|
||||
|
||||
static struct ril_call_forward_cbd *ril_call_forward_cbd_new(void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_forward_cbd *cbd;
|
||||
|
||||
cbd = g_slice_new0(struct ril_call_forward_cbd);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
|
||||
int type, int cls, const struct ofono_phone_number *number, int time)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
/*
|
||||
* Modem seems to respond with error to all requests
|
||||
* made with bearer class BEARER_CLASS_DEFAULT.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, action);
|
||||
grilio_request_append_int32(req, type);
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
if (number) {
|
||||
grilio_request_append_int32(req, number->type);
|
||||
grilio_request_append_utf8(req, number->number);
|
||||
} else {
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, NULL); /* No number */
|
||||
}
|
||||
grilio_request_append_int32(req, time);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_forward_cbd *cbd = user_data;
|
||||
ofono_call_forwarding_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("CF setting failed");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_forward_set(struct ofono_call_forwarding *cf,
|
||||
enum ril_call_forward_action cmd, int type, int cls,
|
||||
const struct ofono_phone_number *number, int time,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = ril_call_forward_req(cmd, type, cls, number, time);
|
||||
|
||||
grilio_queue_send_request_full(fd->q, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_call_forward_set_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, const struct ofono_phone_number *number,
|
||||
int time, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf registration");
|
||||
ril_call_forward_set(cf, CF_ACTION_REGISTRATION, type, cls,
|
||||
number, time, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_erasure(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf erasure");
|
||||
ril_call_forward_set(cf, CF_ACTION_ERASURE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_deactivate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf disable");
|
||||
ril_call_forward_set(cf, CF_ACTION_DISABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_activate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf enable");
|
||||
ril_call_forward_set(cf, CF_ACTION_ENABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_forward_cbd *cbd = user_data;
|
||||
ofono_call_forwarding_query_cb_t cb = cbd->cb.query;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ofono_call_forwarding_condition *list = NULL;
|
||||
GRilIoParser rilp;
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, &count);
|
||||
|
||||
list = g_new0(struct ofono_call_forwarding_condition, count);
|
||||
for (i = 0; i < count; i++) {
|
||||
struct ofono_call_forwarding_condition *fw = list + i;
|
||||
char *str;
|
||||
|
||||
grilio_parser_get_int32(&rilp, &fw->status);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &fw->cls);
|
||||
grilio_parser_get_int32(&rilp, &fw->phone_number.type);
|
||||
str = grilio_parser_get_utf8(&rilp);
|
||||
if (str) {
|
||||
strncpy(fw->phone_number.number, str,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
fw->phone_number.number[
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH] = 0;
|
||||
g_free(str);
|
||||
}
|
||||
grilio_parser_get_int32(&rilp, &fw->time);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), count, list, cbd->data);
|
||||
g_free(list);
|
||||
} else {
|
||||
ofono_error("CF query failed");
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_forward_query(struct ofono_call_forwarding *cf, int type,
|
||||
int cls, ofono_call_forwarding_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = ril_call_forward_req(CF_ACTION_INTERROGATE,
|
||||
type, cls, NULL, CF_TIME_DEFAULT);
|
||||
|
||||
ofono_info("cf query");
|
||||
grilio_queue_send_request_full(fd->q, req,
|
||||
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
ril_call_forward_query_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_forward_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_forwarding *cf = user_data;
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
|
||||
fd->timer_id = 0;
|
||||
ofono_call_forwarding_register(cf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_forward_probe(struct ofono_call_forwarding *cf,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_forward *fd = g_try_new0(struct ril_call_forward, 1);
|
||||
|
||||
DBG("");
|
||||
fd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
fd->timer_id = g_idle_add(ril_call_forward_register, cf);
|
||||
ofono_call_forwarding_set_data(cf, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_forward_remove(struct ofono_call_forwarding *cf)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
|
||||
DBG("");
|
||||
ofono_call_forwarding_set_data(cf, NULL);
|
||||
|
||||
if (fd->timer_id) {
|
||||
g_source_remove(fd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(fd->q, FALSE);
|
||||
grilio_queue_unref(fd->q);
|
||||
g_free(fd);
|
||||
}
|
||||
|
||||
const struct ofono_call_forwarding_driver ril_call_forwarding_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_forward_probe,
|
||||
.remove = ril_call_forward_remove,
|
||||
.erasure = ril_call_forward_erasure,
|
||||
.deactivation = ril_call_forward_deactivate,
|
||||
.query = ril_call_forward_query,
|
||||
.registration = ril_call_forward_registration,
|
||||
.activation = ril_call_forward_activate
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
309
ofono/drivers/ril/ril_call_settings.c
Normal file
309
ofono/drivers/ril/ril_call_settings.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct ril_call_settings {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_settings_cbd {
|
||||
union _ofono_call_settings_cb {
|
||||
ofono_call_settings_status_cb_t status;
|
||||
ofono_call_settings_set_cb_t set;
|
||||
ofono_call_settings_clir_cb_t clir;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_settings_cbd_free g_free
|
||||
|
||||
static inline struct ril_call_settings *ril_call_settings_get_data(
|
||||
struct ofono_call_settings *b)
|
||||
{
|
||||
return ofono_call_settings_get_data(b);
|
||||
}
|
||||
|
||||
static struct ril_call_settings_cbd *ril_call_settings_cbd_new(void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_settings_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_call_settings_cbd, 1);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_settings_submit_req(struct ril_call_settings *sd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
{
|
||||
grilio_queue_send_request_full(sd->q, req, code, response,
|
||||
ril_call_settings_cbd_free,
|
||||
ril_call_settings_cbd_new(cb, data));
|
||||
}
|
||||
|
||||
static void ril_call_settings_clip_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int res = 0;
|
||||
|
||||
/* data length of the response */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &res) && res > 0) {
|
||||
grilio_parser_get_int32(&rilp, &res);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), res, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_set(struct ofono_call_settings *cs, int mode,
|
||||
int cls, ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(12);
|
||||
|
||||
grilio_request_append_int32(req, 2); /* Number of params */
|
||||
grilio_request_append_int32(req, mode); /* on/off */
|
||||
|
||||
/* Modem seems to respond with error to all queries
|
||||
* or settings made with bearer class
|
||||
* BEARER_CLASS_DEFAULT. Design decision: If given
|
||||
* class is BEARER_CLASS_DEFAULT let's map it to
|
||||
* SERVICE_CLASS_VOICE effectively making it the
|
||||
* default bearer. This in line with API which is
|
||||
* contains only voice anyways.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CALL_WAITING,
|
||||
ril_call_settings_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int res = 0;
|
||||
int sv = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* first value in int[] is len so let's skip that */
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
|
||||
/* status of call waiting service, disabled is returned only if
|
||||
* service is not active for any service class */
|
||||
grilio_parser_get_int32(&rilp, &res);
|
||||
DBG("CW enabled/disabled: %d", res);
|
||||
|
||||
if (res > 0) {
|
||||
/* services for which call waiting is enabled,
|
||||
27.007 7.12 */
|
||||
grilio_parser_get_int32(&rilp, &sv);
|
||||
DBG("CW enabled for: %d", sv);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), sv, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_query(struct ofono_call_settings *cs, int cls,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
|
||||
/*
|
||||
* RILD expects service class to be 0 as certain carriers can reject
|
||||
* the query with specific service class
|
||||
*/
|
||||
grilio_request_append_int32(req, 0);
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_QUERY_CALL_WAITING,
|
||||
ril_call_settings_cw_query_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clip_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_QUERY_CLIP,
|
||||
ril_call_settings_clip_query_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_clir_cb_t cb = cbd->cb.clir;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int override = -1, network = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
/*first value in int[] is len so let's skip that*/
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
/* Set HideCallerId property from network */
|
||||
grilio_parser_get_int32(&rilp, &override);
|
||||
/* CallingLineRestriction indicates the state of
|
||||
the CLIR supplementary service in the network */
|
||||
grilio_parser_get_int32(&rilp, &network);
|
||||
|
||||
cb(ril_error_ok(&error), override, network, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_clir_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_GET_CLIR,
|
||||
ril_call_settings_clir_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_set(struct ofono_call_settings *cs,
|
||||
int mode, ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, mode); /* for outgoing calls */
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CLIR,
|
||||
ril_call_settings_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_settings_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_settings *cs = user_data;
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
DBG("");
|
||||
GASSERT(sd->timer_id);
|
||||
sd->timer_id = 0;
|
||||
ofono_call_settings_register(cs);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_settings_probe(struct ofono_call_settings *cs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_settings *sd = g_try_new0(struct ril_call_settings, 1);
|
||||
|
||||
DBG("");
|
||||
sd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
sd->timer_id = g_idle_add(ril_call_settings_register, cs);
|
||||
ofono_call_settings_set_data(cs, sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_settings_remove(struct ofono_call_settings *cs)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
DBG("");
|
||||
ofono_call_settings_set_data(cs, NULL);
|
||||
|
||||
if (sd->timer_id > 0) {
|
||||
g_source_remove(sd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_unref(sd->q);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
const struct ofono_call_settings_driver ril_call_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_settings_probe,
|
||||
.remove = ril_call_settings_remove,
|
||||
.clip_query = ril_call_settings_clip_query,
|
||||
.cw_query = ril_call_settings_cw_query,
|
||||
.cw_set = ril_call_settings_cw_set,
|
||||
.clir_query = ril_call_settings_clir_query,
|
||||
.clir_set = ril_call_settings_clir_set
|
||||
|
||||
/*
|
||||
* Not supported in RIL API
|
||||
* .colp_query = ril_call_settings_colp_query,
|
||||
* .colr_query = ril_call_settings_colr_query
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
151
ofono/drivers/ril/ril_call_volume.c
Normal file
151
ofono/drivers/ril/ril_call_volume.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#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;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_volume_req {
|
||||
ofono_call_volume_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static inline struct ril_call_volume *ril_call_volume_get_data(
|
||||
struct ofono_call_volume *v)
|
||||
{
|
||||
return ofono_call_volume_get_data(v);
|
||||
}
|
||||
|
||||
static void ril_call_volume_mute_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_volume_req *cbd = user_data;
|
||||
ofono_call_volume_cb_t cb = cbd->cb;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Could not set the ril mute state");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_volume_mute(struct ofono_call_volume *v, int muted,
|
||||
ofono_call_volume_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||
struct ril_call_volume_req *cbd;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
cbd = g_new(struct ril_call_volume_req, 1);
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
|
||||
DBG("%d", muted);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, muted);
|
||||
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_SET_MUTE,
|
||||
ril_call_volume_mute_cb, g_free, cbd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_volume_query_mute_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_call_volume *vd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int muted = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* Array length */
|
||||
grilio_parser_get_int32(&rilp, &muted);
|
||||
DBG("{%d}", muted);
|
||||
ofono_call_volume_set_muted(vd->v, muted);
|
||||
} else {
|
||||
ofono_error("Could not retrive the ril mute state");
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_call_volume_register(gpointer user_data)
|
||||
{
|
||||
struct ril_call_volume *vd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(vd->timer_id);
|
||||
vd->timer_id = 0;
|
||||
ofono_call_volume_register(vd->v);
|
||||
|
||||
/* Probe the mute state */
|
||||
grilio_queue_send_request_full(vd->q, NULL,
|
||||
RIL_REQUEST_GET_MUTE, ril_call_volume_query_mute_cb, NULL, vd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_volume_probe(struct ofono_call_volume *v,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_volume *vd = g_new0(struct ril_call_volume, 1);
|
||||
|
||||
DBG("");
|
||||
vd->v = v;
|
||||
vd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
vd->timer_id = g_idle_add(ril_call_volume_register, vd);
|
||||
ofono_call_volume_set_data(v, vd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_volume_remove(struct ofono_call_volume *v)
|
||||
{
|
||||
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||
|
||||
DBG("");
|
||||
ofono_call_volume_set_data(v, NULL);
|
||||
|
||||
if (vd->timer_id) {
|
||||
g_source_remove(vd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
const struct ofono_call_volume_driver ril_call_volume_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_volume_probe,
|
||||
.remove = ril_call_volume_remove,
|
||||
.mute = ril_call_volume_mute,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
227
ofono/drivers/ril/ril_cbs.c
Normal file
227
ofono/drivers/ril/ril_cbs.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct ril_cbs {
|
||||
struct ofono_cbs *cbs;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
struct ril_cbs_cbd {
|
||||
struct ril_cbs *cd;
|
||||
ofono_cbs_set_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define RIL_CBS_CHECK_RETRY_MS 1000
|
||||
#define RIL_CBS_CHECK_RETRY_COUNT 30
|
||||
|
||||
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
|
||||
|
||||
#define ril_cbs_cbd_free g_free
|
||||
|
||||
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
|
||||
|
||||
cbd->cd = cd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
GRilIoRequest* req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, activate ? 0 :1);
|
||||
|
||||
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||
GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
|
||||
int i, n = gutil_strv_length(list);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *entry = list[i];
|
||||
const char *delim = strchr(entry, '-');
|
||||
int from, to;
|
||||
if (delim) {
|
||||
char **range = g_strsplit(topics, "-", 0);
|
||||
from = atoi(range[0]);
|
||||
to = atoi(range[1]);
|
||||
g_strfreev(range);
|
||||
} else {
|
||||
from = to = atoi(entry);
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, from);
|
||||
grilio_request_append_int32(req, to);
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_append_int32(req, 0xff);
|
||||
grilio_request_append_int32(req, 1);
|
||||
}
|
||||
|
||||
DBG_(cd, "configuring CB");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
g_strfreev(list);
|
||||
}
|
||||
|
||||
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = user_data;
|
||||
|
||||
if (cbd->cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "%s", topics);
|
||||
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
DBG_(cd, "%u bytes", len);
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
|
||||
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||
cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
} else {
|
||||
DBG_(cd, "failed to query CB config");
|
||||
ofono_cbs_remove(cd->cbs);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
cd->cbs = cbs;
|
||||
|
||||
DBG_(cd, "");
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
|
||||
/*
|
||||
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup.
|
||||
* We may have to retry a few times.
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
|
||||
ril_cbs_probe_done_cb, NULL, cd);
|
||||
grilio_request_unref(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
grilio_queue_cancel_all(cd->q, FALSE);
|
||||
grilio_queue_unref(cd->q);
|
||||
g_free(cd->log_prefix);
|
||||
g_free(cd);
|
||||
}
|
||||
|
||||
const struct ofono_cbs_driver ril_cbs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
536
ofono/drivers/ril/ril_cell_info.c
Normal file
536
ofono/drivers/ril/ril_cell_info.c
Normal file
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* 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_cell_info.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
|
||||
struct ril_cell_info_priv {
|
||||
GRilIoChannel *io;
|
||||
MceDisplay *display;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
gulong display_state_event_id;
|
||||
gulong radio_state_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gboolean sim_card_ready;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
guint set_rate_id;
|
||||
};
|
||||
|
||||
enum ril_cell_info_signal {
|
||||
SIGNAL_CELLS_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_CELLS_CHANGED_NAME "ril-cell-info-cells-changed"
|
||||
|
||||
static guint ril_cell_info_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||
#define RIL_CELL_INFO_TYPE (ril_cell_info_get_type())
|
||||
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
return ril_cell_compare_location(v1, v2);
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
l2 = l2->next;
|
||||
}
|
||||
return !l1 && !l2;
|
||||
}
|
||||
|
||||
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||
{
|
||||
if (!ril_cell_info_list_identical(self->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);
|
||||
} else {
|
||||
g_slist_free_full(l, g_free);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
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) &&
|
||||
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;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
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) &&
|
||||
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->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
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) &&
|
||||
grilio_parser_get_int32(rilp, <e->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrp) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrq) &&
|
||||
grilio_parser_get_int32(rilp, <e->rssnr) &&
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=0x%x,rssnr=0x%x,cqi=%d,"
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
cell->type = RIL_CELL_INFO_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
struct ril_cell **cell_ptr)
|
||||
{
|
||||
int type, reg;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &type) &&
|
||||
grilio_parser_get_int32(rilp, ®) &&
|
||||
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||
int skip = 0;
|
||||
struct ril_cell *cell = NULL;
|
||||
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
skip = 10;
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
skip = 6;
|
||||
break;
|
||||
default:
|
||||
skip = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cell) {
|
||||
*cell_ptr = cell;
|
||||
return type;
|
||||
}
|
||||
|
||||
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||
*cell_ptr = NULL;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
*cell_ptr = NULL;
|
||||
return RIL_CELL_INFO_TYPE_NONE;
|
||||
}
|
||||
|
||||
static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
{
|
||||
GSList *l = NULL;
|
||||
GRilIoParser rilp;
|
||||
int i, n;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct ril_cell *c;
|
||||
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, &c); i++) {
|
||||
if (c) {
|
||||
l = g_slist_insert_sorted(l, c,
|
||||
ril_cell_compare_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
{
|
||||
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,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
ril_cell_info_set_rate_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
ril_cell_info_set_rate(self,
|
||||
(priv->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
}
|
||||
|
||||
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
|
||||
DBG_(self, "%s", ril_radio_state_to_string(radio->state));
|
||||
ril_cell_info_refresh(self);
|
||||
}
|
||||
|
||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
|
||||
ril_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_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;
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->display = mce_display_ref(display);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
priv->display_state_event_id =
|
||||
mce_display_add_state_changed_handler(display,
|
||||
ril_cell_info_display_state_cb, self);
|
||||
priv->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,
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (priv->set_rate_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
|
||||
FALSE);
|
||||
priv->set_rate_id = 0;
|
||||
}
|
||||
gutil_disconnect_handlers(priv->display,
|
||||
&priv->display_state_event_id, 1);
|
||||
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);
|
||||
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);
|
||||
mce_display_unref(priv->display);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
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,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
64
ofono/drivers/ril/ril_cell_info.h
Normal file
64
ofono/drivers/ril/ril_cell_info.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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_CELL_INFO_H
|
||||
#define RIL_CELL_INFO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include <mce_display.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, 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 */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
586
ofono/drivers/ril/ril_cell_info_dbus.c
Normal file
586
ofono/drivers/ril/ril_cell_info_dbus.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
115
ofono/drivers/ril/ril_config.c
Normal file
115
ofono/drivers/ril/ril_config.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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_config.h"
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
{
|
||||
char *val = g_key_file_get_string(file, group, key, NULL);
|
||||
|
||||
if (!val && strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||
/* Check the common section */
|
||||
val = g_key_file_get_string(file, RILCONF_SETTINGS_GROUP, key,
|
||||
NULL);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *out_value)
|
||||
{
|
||||
GError *error = NULL;
|
||||
int value = g_key_file_get_integer(file, group, key, &error);
|
||||
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
g_error_free(error);
|
||||
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||
/* Check the common section */
|
||||
error = NULL;
|
||||
value = g_key_file_get_integer(file,
|
||||
RILCONF_SETTINGS_GROUP, key, &error);
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
g_error_free(error);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||
const char *key, gboolean *out_value)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean value = g_key_file_get_boolean(file, group, key, &error);
|
||||
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
g_error_free(error);
|
||||
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
|
||||
/* Check the common section */
|
||||
error = NULL;
|
||||
value = g_key_file_get_boolean(file,
|
||||
RILCONF_SETTINGS_GROUP, key, &error);
|
||||
if (!error) {
|
||||
if (out_value) {
|
||||
*out_value = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
g_error_free(error);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags)
|
||||
{
|
||||
gboolean value;
|
||||
|
||||
if (ril_config_get_boolean(file, group, key, &value)) {
|
||||
if (value) {
|
||||
*flags |= flag;
|
||||
} else {
|
||||
*flags &= ~flag;
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
41
ofono/drivers/ril/ril_config.h
Normal file
41
ofono/drivers/ril/ril_config.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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_CONFIG_H
|
||||
#define RIL_CONFIG_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
|
||||
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);
|
||||
|
||||
#endif /* RIL_CONFIG_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
521
ofono/drivers/ril/ril_constants.h
Normal file
521
ofono/drivers/ril/ril_constants.h
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
*
|
||||
* RIL constants adopted from AOSP's header:
|
||||
*
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-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_CONSTANTS_H
|
||||
#define __RIL_CONSTANTS_H 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* call states */
|
||||
enum ril_call_state {
|
||||
RIL_CALL_ACTIVE = 0,
|
||||
RIL_CALL_HOLDING = 1,
|
||||
RIL_CALL_DIALING = 2,
|
||||
RIL_CALL_ALERTING = 3,
|
||||
RIL_CALL_INCOMING = 4,
|
||||
RIL_CALL_WAITING = 5
|
||||
};
|
||||
|
||||
/* Radio state */
|
||||
enum ril_radio_state {
|
||||
RADIO_STATE_OFF = 0,
|
||||
RADIO_STATE_UNAVAILABLE = 1,
|
||||
RADIO_STATE_SIM_NOT_READY = 2,
|
||||
RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3,
|
||||
RADIO_STATE_SIM_READY = 4,
|
||||
RADIO_STATE_RUIM_NOT_READY = 5,
|
||||
RADIO_STATE_RUIM_READY = 6,
|
||||
RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7,
|
||||
RADIO_STATE_NV_NOT_READY = 8,
|
||||
RADIO_STATE_NV_READY = 9,
|
||||
RADIO_STATE_ON = 10
|
||||
};
|
||||
|
||||
/* Preferred network types */
|
||||
enum ril_pref_net_type {
|
||||
PREF_NET_TYPE_GSM_WCDMA = 0,
|
||||
PREF_NET_TYPE_GSM_ONLY = 1,
|
||||
PREF_NET_TYPE_WCDMA = 2,
|
||||
PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,
|
||||
PREF_NET_TYPE_CDMA_EVDO_AUTO = 4,
|
||||
PREF_NET_TYPE_CDMA_ONLY = 5,
|
||||
PREF_NET_TYPE_EVDO_ONLY = 6,
|
||||
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7,
|
||||
PREF_NET_TYPE_LTE_CDMA_EVDO = 8,
|
||||
PREF_NET_TYPE_LTE_GSM_WCDMA = 9,
|
||||
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10,
|
||||
PREF_NET_TYPE_LTE_ONLY = 11,
|
||||
PREF_NET_TYPE_LTE_WCDMA = 12
|
||||
};
|
||||
|
||||
/* Radio technologies */
|
||||
enum ril_radio_tech {
|
||||
RADIO_TECH_UNKNOWN = 0,
|
||||
RADIO_TECH_GPRS = 1,
|
||||
RADIO_TECH_EDGE = 2,
|
||||
RADIO_TECH_UMTS = 3,
|
||||
RADIO_TECH_IS95A = 4,
|
||||
RADIO_TECH_IS95B = 5,
|
||||
RADIO_TECH_1xRTT = 6,
|
||||
RADIO_TECH_EVDO_0 = 7,
|
||||
RADIO_TECH_EVDO_A = 8,
|
||||
RADIO_TECH_HSDPA = 9,
|
||||
RADIO_TECH_HSUPA = 10,
|
||||
RADIO_TECH_HSPA = 11,
|
||||
RADIO_TECH_EVDO_B = 12,
|
||||
RADIO_TECH_EHRPD = 13,
|
||||
RADIO_TECH_LTE = 14,
|
||||
RADIO_TECH_HSPAP = 15,
|
||||
RADIO_TECH_GSM = 16,
|
||||
RADIO_TECH_TD_SCDMA = 17,
|
||||
RADIO_TECH_IWLAN = 18
|
||||
};
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
|
||||
enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_NONE = 0,
|
||||
PDP_FAIL_OPERATOR_BARRED = 0x08,
|
||||
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
|
||||
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
|
||||
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
|
||||
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
|
||||
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
|
||||
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
|
||||
PDP_FAIL_RADIO_POWER_OFF = -5,
|
||||
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
|
||||
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
|
||||
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
|
||||
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
|
||||
|
||||
/* RIL_REQUEST_SETUP_DATA_CALL */
|
||||
enum ril_data_profile {
|
||||
RIL_DATA_PROFILE_DEFAULT = 0,
|
||||
RIL_DATA_PROFILE_TETHERED = 1,
|
||||
RIL_DATA_PROFILE_IMS = 2,
|
||||
RIL_DATA_PROFILE_FOTA = 3,
|
||||
RIL_DATA_PROFILE_CBS = 4,
|
||||
RIL_DATA_PROFILE_OEM_BASE = 1000,
|
||||
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum ril_auth {
|
||||
RIL_AUTH_NONE = 0,
|
||||
RIL_AUTH_PAP = 1,
|
||||
RIL_AUTH_CHAP = 2,
|
||||
RIL_AUTH_BOTH = 3
|
||||
};
|
||||
|
||||
#define RIL_CARD_MAX_APPS 8
|
||||
|
||||
/* SIM card states */
|
||||
enum ril_card_state {
|
||||
RIL_CARDSTATE_UNKNOWN = -1,
|
||||
RIL_CARDSTATE_ABSENT = 0,
|
||||
RIL_CARDSTATE_PRESENT = 1,
|
||||
RIL_CARDSTATE_ERROR = 2
|
||||
};
|
||||
|
||||
/* SIM personalization substates */
|
||||
enum ril_perso_substate {
|
||||
RIL_PERSOSUBSTATE_UNKNOWN = 0,
|
||||
RIL_PERSOSUBSTATE_IN_PROGRESS = 1,
|
||||
RIL_PERSOSUBSTATE_READY = 2,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK = 3,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE = 5,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM = 7,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_PUK = 8,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM_PUK = 12,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1 = 13,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2 = 14,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD = 15,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE = 16,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM = 18,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD_PUK = 21,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM_PUK = 24
|
||||
};
|
||||
|
||||
/* SIM - App states */
|
||||
enum ril_app_state {
|
||||
RIL_APPSTATE_ILLEGAL = -1,
|
||||
RIL_APPSTATE_UNKNOWN = 0,
|
||||
RIL_APPSTATE_DETECTED = 1,
|
||||
RIL_APPSTATE_PIN = 2,
|
||||
RIL_APPSTATE_PUK = 3,
|
||||
RIL_APPSTATE_SUBSCRIPTION_PERSO = 4,
|
||||
RIL_APPSTATE_READY = 5
|
||||
};
|
||||
|
||||
/* SIM - PIN states */
|
||||
enum ril_pin_state {
|
||||
RIL_PINSTATE_UNKNOWN = 0,
|
||||
RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
|
||||
RIL_PINSTATE_ENABLED_VERIFIED = 2,
|
||||
RIL_PINSTATE_DISABLED = 3,
|
||||
RIL_PINSTATE_ENABLED_BLOCKED = 4,
|
||||
RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
|
||||
};
|
||||
|
||||
/* SIM - App types */
|
||||
enum ril_app_type {
|
||||
RIL_APPTYPE_UNKNOWN = 0,
|
||||
RIL_APPTYPE_SIM = 1,
|
||||
RIL_APPTYPE_USIM = 2,
|
||||
RIL_APPTYPE_RUIM = 3,
|
||||
RIL_APPTYPE_CSIM = 4,
|
||||
RIL_APPTYPE_ISIM = 5
|
||||
};
|
||||
|
||||
/* Cell info */
|
||||
enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_NONE = 0,
|
||||
RIL_CELL_INFO_TYPE_GSM = 1,
|
||||
RIL_CELL_INFO_TYPE_CDMA = 2,
|
||||
RIL_CELL_INFO_TYPE_LTE = 3,
|
||||
RIL_CELL_INFO_TYPE_WCDMA = 4,
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
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 */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK 3
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN2 4
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK2 5
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN 6
|
||||
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
|
||||
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
|
||||
#define RIL_REQUEST_GET_CURRENT_CALLS 9
|
||||
#define RIL_REQUEST_DIAL 10
|
||||
#define RIL_REQUEST_GET_IMSI 11
|
||||
#define RIL_REQUEST_HANGUP 12
|
||||
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
|
||||
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
|
||||
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
|
||||
#define RIL_REQUEST_CONFERENCE 16
|
||||
#define RIL_REQUEST_UDUB 17
|
||||
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
|
||||
#define RIL_REQUEST_SIGNAL_STRENGTH 19
|
||||
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
|
||||
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
|
||||
#define RIL_REQUEST_OPERATOR 22
|
||||
#define RIL_REQUEST_RADIO_POWER 23
|
||||
#define RIL_REQUEST_DTMF 24
|
||||
#define RIL_REQUEST_SEND_SMS 25
|
||||
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
|
||||
#define RIL_REQUEST_SETUP_DATA_CALL 27
|
||||
#define RIL_REQUEST_SIM_IO 28
|
||||
#define RIL_REQUEST_SEND_USSD 29
|
||||
#define RIL_REQUEST_CANCEL_USSD 30
|
||||
#define RIL_REQUEST_GET_CLIR 31
|
||||
#define RIL_REQUEST_SET_CLIR 32
|
||||
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
|
||||
#define RIL_REQUEST_SET_CALL_FORWARD 34
|
||||
#define RIL_REQUEST_QUERY_CALL_WAITING 35
|
||||
#define RIL_REQUEST_SET_CALL_WAITING 36
|
||||
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
|
||||
#define RIL_REQUEST_GET_IMEI 38
|
||||
#define RIL_REQUEST_GET_IMEISV 39
|
||||
#define RIL_REQUEST_ANSWER 40
|
||||
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
|
||||
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
|
||||
#define RIL_REQUEST_SET_FACILITY_LOCK 43
|
||||
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
|
||||
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
|
||||
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
|
||||
#define RIL_REQUEST_DTMF_START 49
|
||||
#define RIL_REQUEST_DTMF_STOP 50
|
||||
#define RIL_REQUEST_BASEBAND_VERSION 51
|
||||
#define RIL_REQUEST_SEPARATE_CONNECTION 52
|
||||
#define RIL_REQUEST_SET_MUTE 53
|
||||
#define RIL_REQUEST_GET_MUTE 54
|
||||
#define RIL_REQUEST_QUERY_CLIP 55
|
||||
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
|
||||
#define RIL_REQUEST_DATA_CALL_LIST 57
|
||||
#define RIL_REQUEST_RESET_RADIO 58
|
||||
#define RIL_REQUEST_OEM_HOOK_RAW 59
|
||||
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
|
||||
#define RIL_REQUEST_SCREEN_STATE 61
|
||||
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
|
||||
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
|
||||
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
|
||||
#define RIL_REQUEST_SET_BAND_MODE 65
|
||||
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
|
||||
#define RIL_REQUEST_STK_GET_PROFILE 67
|
||||
#define RIL_REQUEST_STK_SET_PROFILE 68
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
|
||||
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
|
||||
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
|
||||
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
|
||||
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
|
||||
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
|
||||
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
|
||||
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
|
||||
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
|
||||
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
|
||||
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
|
||||
#define RIL_REQUEST_SET_TTY_MODE 80
|
||||
#define RIL_REQUEST_QUERY_TTY_MODE 81
|
||||
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
|
||||
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
|
||||
#define RIL_REQUEST_CDMA_FLASH 84
|
||||
#define RIL_REQUEST_CDMA_BURST_DTMF 85
|
||||
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
|
||||
#define RIL_REQUEST_CDMA_SEND_SMS 87
|
||||
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
|
||||
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
|
||||
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
|
||||
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
|
||||
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
|
||||
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
|
||||
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
|
||||
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
|
||||
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
|
||||
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
|
||||
#define RIL_REQUEST_DEVICE_IDENTITY 98
|
||||
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
|
||||
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
|
||||
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
|
||||
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
|
||||
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
|
||||
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
|
||||
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
|
||||
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
|
||||
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
|
||||
#define RIL_REQUEST_VOICE_RADIO_TECH 108
|
||||
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
|
||||
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
|
||||
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
|
||||
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
|
||||
#define RIL_REQUEST_IMS_SEND_SMS 113
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
|
||||
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
|
||||
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
|
||||
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
|
||||
#define RIL_REQUEST_NV_READ_ITEM 118
|
||||
#define RIL_REQUEST_NV_WRITE_ITEM 119
|
||||
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
|
||||
#define RIL_REQUEST_NV_RESET_CONFIG 121
|
||||
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
|
||||
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
|
||||
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
|
||||
#define RIL_REQUEST_ALLOW_DATA 123
|
||||
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
|
||||
#define RIL_REQUEST_SIM_AUTHENTICATION 125
|
||||
#define RIL_REQUEST_GET_DC_RT_INFO 126
|
||||
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
|
||||
#define RIL_REQUEST_SET_DATA_PROFILE 128
|
||||
#define RIL_REQUEST_SHUTDOWN 129
|
||||
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
|
||||
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
|
||||
|
||||
/* RIL Unsolicited Messages */
|
||||
#define RIL_UNSOL_RESPONSE_BASE 1000
|
||||
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
|
||||
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
|
||||
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
|
||||
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
|
||||
#define RIL_UNSOL_ON_USSD 1006
|
||||
#define RIL_UNSOL_ON_USSD_REQUEST 1007
|
||||
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
|
||||
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
|
||||
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
|
||||
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
|
||||
#define RIL_UNSOL_STK_SESSION_END 1012
|
||||
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
|
||||
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
|
||||
#define RIL_UNSOL_STK_CALL_SETUP 1015
|
||||
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
|
||||
#define RIL_UNSOL_SIM_REFRESH 1017
|
||||
#define RIL_UNSOL_CALL_RING 1018
|
||||
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
|
||||
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
|
||||
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
|
||||
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
|
||||
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
|
||||
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
|
||||
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
|
||||
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
|
||||
#define RIL_UNSOL_CDMA_INFO_REC 1027
|
||||
#define RIL_UNSOL_OEM_HOOK_RAW 1028
|
||||
#define RIL_UNSOL_RINGBACK_TONE 1029
|
||||
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
|
||||
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
|
||||
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
|
||||
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
|
||||
#define RIL_UNSOL_RIL_CONNECTED 1034
|
||||
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
|
||||
#define RIL_UNSOL_CELL_INFO_LIST 1036
|
||||
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
|
||||
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
|
||||
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
|
||||
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
|
||||
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
|
||||
#define RIL_UNSOL_RADIO_CAPABILITY 1042
|
||||
#define RIL_UNSOL_ON_SS 1043
|
||||
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
/* RIL_FACILITY_LOCK parameters */
|
||||
#define RIL_FACILITY_UNLOCK "0"
|
||||
#define RIL_FACILITY_LOCK "1"
|
||||
|
||||
#endif /*__RIL_CONSTANTS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
1572
ofono/drivers/ril/ril_data.c
Normal file
1572
ofono/drivers/ril/ril_data.c
Normal file
File diff suppressed because it is too large
Load Diff
133
ofono/drivers/ril/ril_data.h
Normal file
133
ofono/drivers/ril/ril_data.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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_DATA_H
|
||||
#define RIL_DATA_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
enum ril_data_call_active {
|
||||
RIL_DATA_CALL_INACTIVE = 0,
|
||||
RIL_DATA_CALL_LINK_DOWN = 1,
|
||||
RIL_DATA_CALL_ACTIVE = 2
|
||||
};
|
||||
|
||||
struct ril_data_call {
|
||||
int cid;
|
||||
enum ril_data_call_fail_cause status;
|
||||
enum ril_data_call_active active;
|
||||
enum ofono_gprs_proto prot;
|
||||
int retry_time;
|
||||
int mtu;
|
||||
char *ifname;
|
||||
char **dnses;
|
||||
char **gateways;
|
||||
char **addresses;
|
||||
};
|
||||
|
||||
struct ril_data_call_list {
|
||||
guint version;
|
||||
guint num;
|
||||
GSList *calls;
|
||||
};
|
||||
|
||||
struct ril_data {
|
||||
GObject object;
|
||||
struct ril_data_priv *priv;
|
||||
struct ril_data_call_list *data_calls;
|
||||
};
|
||||
|
||||
enum ril_data_manager_flags {
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
|
||||
};
|
||||
|
||||
enum ril_data_allow_data_opt {
|
||||
RIL_ALLOW_DATA_AUTO,
|
||||
RIL_ALLOW_DATA_ON,
|
||||
RIL_ALLOW_DATA_OFF
|
||||
};
|
||||
|
||||
enum ril_data_call_format {
|
||||
RIL_DATA_CALL_FORMAT_AUTO,
|
||||
RIL_DATA_CALL_FORMAT_6 = 6,
|
||||
RIL_DATA_CALL_FORMAT_9 = 9,
|
||||
RIL_DATA_CALL_FORMAT_11 = 11
|
||||
};
|
||||
|
||||
struct ril_data_options {
|
||||
enum ril_data_allow_data_opt allow_data;
|
||||
enum ril_data_call_format data_call_format;
|
||||
unsigned int data_call_retry_limit;
|
||||
unsigned int data_call_retry_delay_ms;
|
||||
};
|
||||
|
||||
enum ril_data_role {
|
||||
RIL_DATA_ROLE_NONE, /* Data not allowed */
|
||||
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
|
||||
RIL_DATA_ROLE_INTERNET /* Data is allowed at full speed */
|
||||
};
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
|
||||
int ril_status, const struct ril_data_call *call,
|
||||
void *arg);
|
||||
typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
||||
int ril_status, void *arg);
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config);
|
||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||
void ril_data_unref(struct ril_data *data);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
gulong ril_data_add_calls_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
void ril_data_remove_handler(struct ril_data *data, gulong id);
|
||||
|
||||
void ril_data_allow(struct ril_data *data, enum ril_data_role role);
|
||||
|
||||
struct ril_data_request;
|
||||
struct ril_data_request *ril_data_call_setup(struct ril_data *data,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ril_data_call_setup_cb_t cb, void *arg);
|
||||
struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
|
||||
int cid, ril_data_call_deactivate_cb_t cb, void *arg);
|
||||
void ril_data_request_detach(struct ril_data_request *req);
|
||||
void ril_data_request_cancel(struct ril_data_request *req);
|
||||
|
||||
void ril_data_call_free(struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
int cid);
|
||||
|
||||
#endif /* RIL_DATA_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
193
ofono/drivers/ril/ril_devinfo.c
Normal file
193
ofono/drivers/ril/ril_devinfo.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.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?
|
||||
*/
|
||||
|
||||
struct ril_devinfo {
|
||||
struct ofono_devinfo *info;
|
||||
GRilIoQueue *q;
|
||||
guint register_id;
|
||||
guint imei_id;
|
||||
char *imei;
|
||||
};
|
||||
|
||||
struct ril_devinfo_cbd {
|
||||
struct ril_devinfo *di;
|
||||
ofono_devinfo_query_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_devinfo_cbd_free g_free
|
||||
|
||||
static inline struct ril_devinfo *ril_devinfo_get_data(
|
||||
struct ofono_devinfo *info)
|
||||
{
|
||||
return ofono_devinfo_get_data(info);
|
||||
}
|
||||
|
||||
struct ril_devinfo_cbd *ril_devinfo_cbd_new(struct ril_devinfo *di,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = g_new0(struct ril_devinfo_cbd, 1);
|
||||
|
||||
cbd->di = di;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_failure(&error), "", data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
char *res;
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
res = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", res);
|
||||
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
|
||||
g_free(res);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG("");
|
||||
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
|
||||
ril_devinfo_query_cb, ril_devinfo_cbd_free,
|
||||
ril_devinfo_cbd_new(di, cb, data));
|
||||
}
|
||||
|
||||
static gboolean ril_devinfo_query_serial_cb(void *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;
|
||||
|
||||
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static gboolean ril_devinfo_register(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo *di = user_data;
|
||||
|
||||
DBG("");
|
||||
di->register_id = 0;
|
||||
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,
|
||||
void *data)
|
||||
{
|
||||
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);
|
||||
GASSERT(modem->imei);
|
||||
di->q = grilio_queue_new(ril_modem_io(modem));
|
||||
di->info = info;
|
||||
di->imei = g_strdup(modem->imei);
|
||||
|
||||
di->register_id = g_idle_add(ril_devinfo_register, di);
|
||||
ofono_devinfo_set_data(info, di);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG("%p", 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);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(di->q, FALSE);
|
||||
grilio_queue_unref(di->q);
|
||||
g_free(di->imei);
|
||||
g_free(di);
|
||||
}
|
||||
|
||||
const struct ofono_devinfo_driver ril_devinfo_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_devinfo_probe,
|
||||
.remove = ril_devinfo_remove,
|
||||
.query_manufacturer = ril_devinfo_query_unsupported,
|
||||
.query_model = ril_devinfo_query_unsupported,
|
||||
.query_revision = ril_devinfo_query_revision,
|
||||
.query_serial = ril_devinfo_query_serial
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
258
ofono/drivers/ril/ril_ecclist.c
Normal file
258
ofono/drivers/ril/ril_ecclist.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_inotify.h>
|
||||
|
||||
#include <sys/inotify.h>
|
||||
|
||||
typedef GObjectClass RilEccListClass;
|
||||
typedef struct ril_ecclist RilEccList;
|
||||
|
||||
struct ril_ecclist_priv {
|
||||
struct ofono_sim *sim;
|
||||
GUtilInotifyWatchCallback *dir_watch;
|
||||
GUtilInotifyWatchCallback *file_watch;
|
||||
char *dir;
|
||||
char *path;
|
||||
char *name;
|
||||
};
|
||||
|
||||
enum ril_ecclist_signal {
|
||||
SIGNAL_LIST_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_LIST_CHANGED_NAME "ril-ecclist-changed"
|
||||
|
||||
static guint ril_ecclist_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
|
||||
#define RIL_ECCLIST_TYPE (ril_ecclist_get_type())
|
||||
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_ECCLIST_TYPE, RilEccList))
|
||||
|
||||
static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
char **list = NULL;
|
||||
|
||||
if (g_file_test(priv->path, G_FILE_TEST_EXISTS)) {
|
||||
gsize len = 0;
|
||||
gchar *content = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (g_file_get_contents(priv->path, &content, &len, &error)) {
|
||||
char **ptr;
|
||||
|
||||
DBG("%s = %s", priv->name, content);
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
|
||||
gutil_strv_sort(list, TRUE);
|
||||
} else if (error) {
|
||||
DBG("%s: %s", priv->path, GERRMSG(error));
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
g_free (content);
|
||||
} else {
|
||||
DBG("%s doesn't exist", priv->path);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void ril_ecclist_update(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
char **list = ril_ecclist_read(self);
|
||||
|
||||
if (!gutil_strv_equal(self->list, list)) {
|
||||
DBG("%s changed", priv->name);
|
||||
g_strfreev(self->list);
|
||||
self->list = list;
|
||||
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0);
|
||||
} else {
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
guint cookie, const char *name, void *user_data)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
ril_ecclist_update(self);
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
DBG("file %s is gone", priv->path);
|
||||
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||
priv->file_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
guint cookie, const char *name, void *user_data)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
DBG("0x%04x %s", mask, name);
|
||||
if (!priv->file_watch && !g_strcmp0(name, priv->name)) {
|
||||
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||
IN_MODIFY | IN_CLOSE_WRITE,
|
||||
ril_ecclist_changed, self);
|
||||
if (priv->file_watch) {
|
||||
DBG("watching %s", priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
DBG("%s is gone", priv->dir);
|
||||
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||
priv->dir_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *self,
|
||||
ril_ecclist_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_LIST_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_ecclist_remove_handler(struct ril_ecclist *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_ecclist *ril_ecclist_new(const char *path)
|
||||
{
|
||||
if (path) {
|
||||
struct ril_ecclist *self = g_object_new(RIL_ECCLIST_TYPE, 0);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", path);
|
||||
priv->path = g_strdup(path);
|
||||
priv->name = g_path_get_basename(path);
|
||||
priv->dir = g_path_get_dirname(path);
|
||||
priv->dir_watch = gutil_inotify_watch_callback_new(priv->dir,
|
||||
IN_MODIFY|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|
|
||||
IN_CREATE|IN_DELETE_SELF|IN_CLOSE_WRITE,
|
||||
ril_ecclist_dir_changed, self);
|
||||
if (priv->dir_watch) {
|
||||
DBG("watching %s", priv->dir);
|
||||
}
|
||||
|
||||
self->list = ril_ecclist_read(self);
|
||||
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||
IN_MODIFY | IN_CLOSE_WRITE,
|
||||
ril_ecclist_changed, self);
|
||||
if (priv->file_watch) {
|
||||
DBG("watching %s", priv->path);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_ECCLIST(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_ecclist_unref(struct ril_ecclist *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_ECCLIST(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_init(struct ril_ecclist *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_ECCLIST_TYPE,
|
||||
struct ril_ecclist_priv);
|
||||
}
|
||||
|
||||
static void ril_ecclist_dispose(GObject *object)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
if (priv->dir_watch) {
|
||||
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||
priv->dir_watch = NULL;
|
||||
}
|
||||
|
||||
if (priv->file_watch) {
|
||||
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||
priv->file_watch = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(ril_ecclist_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_ecclist_finalize(GObject *object)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
GASSERT(!priv->dir_watch);
|
||||
GASSERT(!priv->file_watch);
|
||||
g_free(priv->dir);
|
||||
g_free(priv->path);
|
||||
g_free(priv->name);
|
||||
g_strfreev(self->list);
|
||||
|
||||
G_OBJECT_CLASS(ril_ecclist_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_ecclist_class_init(RilEccListClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_ecclist_dispose;
|
||||
object_class->finalize = ril_ecclist_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_ecclist_priv));
|
||||
ril_ecclist_signals[SIGNAL_LIST_CHANGED] =
|
||||
g_signal_new(SIGNAL_LIST_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
46
ofono/drivers/ril/ril_ecclist.h
Normal file
46
ofono/drivers/ril/ril_ecclist.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_ECCLIST_H
|
||||
#define RIL_ECCLIST_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_ecclist_priv;
|
||||
|
||||
struct ril_ecclist {
|
||||
GObject object;
|
||||
struct ril_ecclist_priv *priv;
|
||||
char **list;
|
||||
};
|
||||
|
||||
typedef void (*ril_ecclist_cb_t)(struct ril_ecclist *ecc, void *arg);
|
||||
|
||||
struct ril_ecclist *ril_ecclist_new(const char *path);
|
||||
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *ecc);
|
||||
void ril_ecclist_unref(struct ril_ecclist *ecc);
|
||||
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *ecc,
|
||||
ril_ecclist_cb_t cb, void *arg);
|
||||
void ril_ecclist_remove_handler(struct ril_ecclist *ecc, gulong id);
|
||||
|
||||
#endif /* RIL_ECCLIST_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
283
ofono/drivers/ril/ril_gprs.c
Normal file
283
ofono/drivers/ril/ril_gprs.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* This module is the ofono_gprs_driver implementation for rilmodem.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* 1. ofono_gprs_suspend/resume() are not used by this module, as
|
||||
* the concept of suspended GPRS is not exposed by RILD.
|
||||
*
|
||||
* 2. ofono_gprs_bearer_notify() is never called as RILD does not
|
||||
* expose an unsolicited event equivalent to +CPSB ( see 27.007
|
||||
* 7.29 ), and the tech values returned by REQUEST_DATA/VOICE
|
||||
* _REGISTRATION requests do not match the values defined for
|
||||
* <AcT> in the +CPSB definition. Note, the values returned by
|
||||
* the *REGISTRATION commands are aligned with those defined by
|
||||
* +CREG ( see 27.003 7.2 ).
|
||||
*/
|
||||
|
||||
struct ril_gprs {
|
||||
struct ofono_gprs *gprs;
|
||||
struct ril_modem *md;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean attached;
|
||||
int max_cids;
|
||||
enum network_registration_status registration_status;
|
||||
guint register_id;
|
||||
gulong network_event_id;
|
||||
gulong data_event_id;
|
||||
guint set_attached_id;
|
||||
};
|
||||
|
||||
struct ril_gprs_cbd {
|
||||
struct ril_gprs *gd;
|
||||
ofono_gprs_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_gprs_cbd_free g_free
|
||||
|
||||
static struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *ofono)
|
||||
{
|
||||
return ofono ? ofono_gprs_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_cbd *cbd = g_new0(struct ril_gprs_cbd, 1);
|
||||
|
||||
cbd->gd = gd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static enum network_registration_status ril_gprs_fix_registration_status(
|
||||
struct ril_gprs *gd, enum network_registration_status status)
|
||||
{
|
||||
if (!ril_data_allowed(gd->data)) {
|
||||
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
} else {
|
||||
/* TODO: need a way to make sure that SPDI information has
|
||||
* already been read from the SIM (i.e. sim_spdi_read_cb in
|
||||
* network.c has been called) */
|
||||
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gd->md);
|
||||
return ril_netreg_check_if_really_roaming(netreg, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
|
||||
{
|
||||
const enum network_registration_status status =
|
||||
ril_gprs_fix_registration_status(gd, gd->network->data.status);
|
||||
|
||||
if (gd->registration_status != status) {
|
||||
ofono_info("data reg changed %d -> %d (%s), attached %d",
|
||||
gd->registration_status, status,
|
||||
registration_status_to_string(status),
|
||||
gd->attached);
|
||||
gd->registration_status = status;
|
||||
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_check_data_allowed(struct ril_gprs *gd)
|
||||
{
|
||||
DBG("%s %d %d", ril_modem_get_path(gd->md), ril_data_allowed(gd->data),
|
||||
gd->attached);
|
||||
if (!ril_data_allowed(gd->data) && gd->attached) {
|
||||
gd->attached = FALSE;
|
||||
if (gd->gprs) {
|
||||
ofono_gprs_detached_notify(gd->gprs);
|
||||
}
|
||||
}
|
||||
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_set_attached_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_gprs_cbd *cbd = user_data;
|
||||
struct ril_gprs *gd = cbd->gd;
|
||||
|
||||
GASSERT(gd->set_attached_id);
|
||||
gd->set_attached_id = 0;
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
|
||||
if (ril_data_allowed(gd->data) || !attached) {
|
||||
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
gd->attached = attached;
|
||||
gd->set_attached_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_gprs_set_attached_cb,
|
||||
ril_gprs_cbd_new(gd, cb, data),
|
||||
ril_gprs_cbd_free);
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
DBG("%s not allowed to attach", ril_modem_get_path(gd->md));
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_allow_data_changed(struct ril_data *data, void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
|
||||
GASSERT(gd->data == data);
|
||||
DBG("%s %d", ril_modem_get_path(gd->md), ril_data_allowed(data));
|
||||
if (!gd->set_attached_id) {
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_data_registration_state_changed(struct ril_network *net,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
const struct ril_registration_state *data = &net->data;
|
||||
|
||||
GASSERT(gd->network == net);
|
||||
if (data->max_calls > gd->max_cids) {
|
||||
DBG("Setting max cids to %d", data->max_calls);
|
||||
gd->max_cids = data->max_calls;
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
ofono_gprs_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
struct ofono_error error;
|
||||
const enum network_registration_status status = gd->attached ?
|
||||
gd->registration_status :
|
||||
NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
|
||||
|
||||
DBG("%d (%s)", status, registration_status_to_string(status));
|
||||
cb(ril_error_ok(&error), status, data);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_register(gpointer user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
|
||||
gd->register_id = 0;
|
||||
gd->network_event_id = ril_network_add_data_state_changed_handler(
|
||||
gd->network, ril_gprs_data_registration_state_changed, gd);
|
||||
gd->data_event_id = ril_data_add_allow_changed_handler(gd->data,
|
||||
ril_gprs_allow_data_changed, gd);
|
||||
gd->registration_status = ril_gprs_fix_registration_status(gd,
|
||||
gd->network->data.status);
|
||||
|
||||
gd->max_cids = gd->network->data.max_calls;
|
||||
if (gd->max_cids > 0) {
|
||||
DBG("Setting max cids to %d", gd->max_cids);
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
ofono_gprs_register(gd->gprs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_gprs *gd = g_new0(struct ril_gprs, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
gd->md = modem;
|
||||
gd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
gd->q = grilio_queue_new(gd->io);
|
||||
gd->data = ril_data_ref(modem->data);
|
||||
gd->network = ril_network_ref(modem->network);
|
||||
gd->gprs = gprs;
|
||||
ofono_gprs_set_data(gprs, gd);
|
||||
|
||||
/* ofono crashes if we register right away */
|
||||
gd->register_id = g_idle_add(ril_gprs_register, gd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_remove(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
|
||||
DBG("%s", ril_modem_get_path(gd->md));
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
|
||||
if (gd->register_id) {
|
||||
g_source_remove(gd->register_id);
|
||||
}
|
||||
|
||||
ril_network_remove_handler(gd->network, gd->network_event_id);
|
||||
ril_network_unref(gd->network);
|
||||
|
||||
ril_data_remove_handler(gd->data, gd->data_event_id);
|
||||
ril_data_unref(gd->data);
|
||||
|
||||
grilio_channel_unref(gd->io);
|
||||
grilio_queue_cancel_all(gd->q, FALSE);
|
||||
grilio_queue_unref(gd->q);
|
||||
g_free(gd);
|
||||
}
|
||||
|
||||
const struct ofono_gprs_driver ril_gprs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_gprs_probe,
|
||||
.remove = ril_gprs_remove,
|
||||
.set_attached = ril_gprs_set_attached,
|
||||
.attached_status = ril_gprs_registration_status,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
597
ofono/drivers/ril/ril_gprs_context.c
Normal file
597
ofono/drivers/ril/ril_gprs_context.c
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_mtu.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define CTX_ID_NONE ((unsigned int)(-1))
|
||||
|
||||
#define MAX_MTU 1280
|
||||
|
||||
struct ril_gprs_context_call {
|
||||
struct ril_data_request *req;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct ril_gprs_context {
|
||||
struct ofono_gprs_context *gc;
|
||||
struct ril_modem *modem;
|
||||
struct ril_network *network;
|
||||
struct ril_data *data;
|
||||
guint active_ctx_cid;
|
||||
gulong calls_changed_id;
|
||||
struct ril_mtu_watch *mtu_watch;
|
||||
struct ril_data_call *active_call;
|
||||
struct ril_gprs_context_call activate;
|
||||
struct ril_gprs_context_call deactivate;
|
||||
};
|
||||
|
||||
static inline struct ril_gprs_context *ril_gprs_context_get_data(
|
||||
struct ofono_gprs_context *gprs)
|
||||
{
|
||||
return ofono_gprs_context_get_data(gprs);
|
||||
}
|
||||
|
||||
static char *ril_gprs_context_netmask(const char *bits)
|
||||
{
|
||||
if (bits) {
|
||||
int nbits = atoi(bits);
|
||||
if (nbits > 0 && nbits < 33) {
|
||||
const char* str;
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||
((1 << nbits)-1) << (32-nbits));
|
||||
str = inet_ntoa(in);
|
||||
if (str) {
|
||||
return g_strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ril_gprs_context_address_family(const char *addr)
|
||||
{
|
||||
if (strchr(addr, ':')) {
|
||||
return AF_INET6;
|
||||
} else if (strchr(addr, '.')) {
|
||||
return AF_INET;
|
||||
} else {
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = NULL;
|
||||
}
|
||||
if (gcd->calls_changed_id) {
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id = 0;
|
||||
}
|
||||
if (gcd->mtu_watch) {
|
||||
ril_mtu_watch_free(gcd->mtu_watch);
|
||||
gcd->mtu_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
if (call) {
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = ril_data_call_dup(call);
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = ril_mtu_watch_new(MAX_MTU);
|
||||
}
|
||||
ril_mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
} else {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
if (gcd->deactivate.req) {
|
||||
struct ril_gprs_context_call deact = gcd->deactivate;
|
||||
|
||||
/*
|
||||
* Complete the deactivate request. We need to
|
||||
* clear gcd->deactivate first because cancelling
|
||||
* the deactivation request will probably result
|
||||
* in ril_gprs_context_deactivate_primary_cb() being
|
||||
* invoked with GRILIO_CANCELLED status. And we don't
|
||||
* want to fail the disconnect request because this
|
||||
* is a success (we wanted to disconnect the data
|
||||
* call and it's gone).
|
||||
*
|
||||
* Additionally, we need to make sure that we don't
|
||||
* complete the same request twice - that would crash
|
||||
* the core.
|
||||
*/
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
ril_data_request_cancel(deact.req);
|
||||
if (deact.cb) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Deactivated data call");
|
||||
deact.cb(ril_error_ok(&error), deact.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gcd->active_ctx_cid != CTX_ID_NONE) {
|
||||
guint id = gcd->active_ctx_cid;
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
DBG("ofono context %u deactivated", id);
|
||||
ofono_gprs_context_deactivated(gcd->gc, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_address(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const char *ip_addr = NULL;
|
||||
char *ip_mask = NULL;
|
||||
const char *ipv6_addr = NULL;
|
||||
unsigned char ipv6_prefix_length = 0;
|
||||
char *tmp_ip_addr = NULL;
|
||||
char *tmp_ipv6_addr = NULL;
|
||||
char * const *list = call->addresses;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n && (!ipv6_addr || !ip_addr); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
tmp_ip_addr = g_strndup(addr, len);
|
||||
ip_addr = tmp_ip_addr;
|
||||
ip_mask = ril_gprs_context_netmask(s+1);
|
||||
} else {
|
||||
ip_addr = addr;
|
||||
}
|
||||
if (!ip_mask) {
|
||||
ip_mask = g_strdup("255.255.255.0");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
const int prefix = atoi(s + 1);
|
||||
tmp_ipv6_addr = g_strndup(addr, len);
|
||||
ipv6_addr = tmp_ipv6_addr;
|
||||
if (prefix >= 0 && prefix <= 128) {
|
||||
ipv6_prefix_length = prefix;
|
||||
}
|
||||
} else {
|
||||
ipv6_addr = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_address(gc, ip_addr, TRUE);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, ip_mask);
|
||||
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr);
|
||||
ofono_gprs_context_set_ipv6_prefix_length(gc, ipv6_prefix_length);
|
||||
|
||||
if (!ip_addr && !ipv6_addr) {
|
||||
ofono_error("GPRS context: No IP address");
|
||||
}
|
||||
|
||||
/* Allocate temporary strings */
|
||||
g_free(ip_mask);
|
||||
g_free(tmp_ip_addr);
|
||||
g_free(tmp_ipv6_addr);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const char *ip_gw = NULL;
|
||||
const char *ipv6_gw = NULL;
|
||||
char * const *list = call->gateways;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
/* Pick 1 gw for each protocol*/
|
||||
for (i = 0; i < n && (!ipv6_gw || !ip_gw); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_gw) ip_gw = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_gw) ipv6_gw = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
int i;
|
||||
char * const *list = call->dnses;
|
||||
const int n = gutil_strv_length(list);
|
||||
const char **ip_dns = g_new0(const char *, n+1);
|
||||
const char **ipv6_dns = g_new0(const char *, n+1);
|
||||
const char **ip_ptr = ip_dns;
|
||||
const char **ipv6_ptr = ipv6_dns;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
*ipv6_ptr++ = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
|
||||
|
||||
g_free(ip_dns);
|
||||
g_free(ipv6_dns);
|
||||
}
|
||||
|
||||
/* Only compares the stuff that's important to us */
|
||||
#define DATA_CALL_IFNAME_CHANGED (0x01)
|
||||
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||
#define DATA_CALL_ALL_CHANGED (0x0f)
|
||||
static int ril_gprs_context_data_call_change(
|
||||
const struct ril_data_call *c1,
|
||||
const struct ril_data_call *c2)
|
||||
{
|
||||
if (!c1 && !c2) {
|
||||
return 0;
|
||||
} else if (c1 && c2) {
|
||||
int changes = 0;
|
||||
|
||||
if (g_strcmp0(c1->ifname, c2->ifname)) {
|
||||
changes |= DATA_CALL_IFNAME_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->addresses, c2->addresses)) {
|
||||
changes |= DATA_CALL_ADDRESS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->gateways, c2->gateways)) {
|
||||
changes |= DATA_CALL_GATEWAY_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->dnses, c2->dnses)) {
|
||||
changes |= DATA_CALL_DNS_CHANGED;
|
||||
}
|
||||
|
||||
return changes;
|
||||
} else {
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
{
|
||||
struct ril_gprs_context *gcd = arg;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
|
||||
/*
|
||||
* gcd->active_call can't be NULL here because this callback
|
||||
* is only registered when we have the active call and released
|
||||
* when active call is dropped.
|
||||
*/
|
||||
struct ril_data_call *prev_call = gcd->active_call;
|
||||
const struct ril_data_call *call =
|
||||
ril_data_call_find(data->data_calls, prev_call->cid);
|
||||
int change = 0;
|
||||
|
||||
if (call && call->active != RIL_DATA_CALL_INACTIVE) {
|
||||
/* Compare it against the last known state */
|
||||
change = ril_gprs_context_data_call_change(call, prev_call);
|
||||
} else {
|
||||
ofono_error("Clearing active context");
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
call = NULL;
|
||||
}
|
||||
|
||||
if (!call) {
|
||||
/* We are not interested */
|
||||
return;
|
||||
} else if (!change) {
|
||||
DBG("call %u didn't change", call->cid);
|
||||
return;
|
||||
} else {
|
||||
DBG("call %u changed", call->cid);
|
||||
}
|
||||
|
||||
/*
|
||||
* prev_call points to the previous active call, and it will
|
||||
* be deallocated at the end of the this function. Clear the
|
||||
* gcd->active_call pointer so that we don't deallocate it twice.
|
||||
*/
|
||||
gcd->active_call = NULL;
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
|
||||
if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_info("data call status: %d", call->status);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_IFNAME_CHANGED) {
|
||||
DBG("interface changed");
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_ADDRESS_CHANGED) {
|
||||
DBG("address changed");
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_GATEWAY_CHANGED) {
|
||||
DBG("gateway changed");
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_DNS_CHANGED) {
|
||||
DBG("name server(s) changed");
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
int ril_status, const struct ril_data_call *call,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer cb_data;
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("GPRS context: Reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
} else if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_error("Unexpected data call status %d", call->status);
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
error.error = call->status;
|
||||
} else if (!call->ifname) {
|
||||
/* Must have interface */
|
||||
ofono_error("GPRS context: No interface");
|
||||
} else {
|
||||
ofono_info("setting up data call");
|
||||
|
||||
GASSERT(!gcd->calls_changed_id);
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id =
|
||||
ril_data_add_calls_changed_handler(gcd->data,
|
||||
ril_gprs_context_call_list_changed, gcd);
|
||||
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
ril_error_init_ok(&error);
|
||||
}
|
||||
|
||||
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
}
|
||||
|
||||
cb = gcd->activate.cb;
|
||||
cb_data = gcd->activate.data;
|
||||
GASSERT(gcd->activate.req);
|
||||
memset(&gcd->activate, 0, sizeof(gcd->activate));
|
||||
|
||||
if (cb) {
|
||||
cb(&error, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
|
||||
const int rs = ofono_netreg_get_status(netreg);
|
||||
|
||||
/* Let's make sure that we aren't connecting when roaming not allowed */
|
||||
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
|
||||
if (!ofono_gprs_get_roaming_allowed(gprs) &&
|
||||
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Can't activate context %u (roaming)",
|
||||
ctx->cid);
|
||||
cb(ril_error_failure(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Activating context: %u", ctx->cid);
|
||||
GASSERT(!gcd->activate.req);
|
||||
GASSERT(ctx->cid != CTX_ID_NONE);
|
||||
|
||||
gcd->active_ctx_cid = ctx->cid;
|
||||
gcd->activate.cb = cb;
|
||||
gcd->activate.data = data;
|
||||
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
|
||||
ril_gprs_context_activate_primary_cb, gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
|
||||
int ril_status, void *user_data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
|
||||
/*
|
||||
* Data call list may change before the completion of the deactivate
|
||||
* request, in that case ril_gprs_context_set_disconnected will be
|
||||
* invoked and gcd->deactivate.req will be NULL.
|
||||
*/
|
||||
if (gcd->deactivate.req) {
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
|
||||
gpointer cb_data = gcd->deactivate.data;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
GASSERT(gcd->active_call);
|
||||
ril_error_init_ok(&error);
|
||||
ofono_info("Deactivated data call");
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
ofono_error("Deactivate failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
if (cb) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(&error, cb_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure we are in the disconnected state */
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
unsigned int id, ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
gcd->deactivate.cb = cb;
|
||||
gcd->deactivate.data = data;
|
||||
gcd->deactivate.req = ril_data_call_deactivate(gcd->data,
|
||||
gcd->active_call->cid,
|
||||
ril_gprs_context_deactivate_primary_cb, gcd);
|
||||
} else if (cb) {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int id)
|
||||
{
|
||||
DBG("%u", id);
|
||||
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||
}
|
||||
|
||||
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_gprs_context *gcd = g_new0(struct ril_gprs_context, 1);
|
||||
|
||||
DBG("");
|
||||
gcd->gc = gc;
|
||||
gcd->modem = modem;
|
||||
gcd->network = ril_network_ref(modem->network);
|
||||
gcd->data = ril_data_ref(modem->data);
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
if (gcd->activate.req) {
|
||||
/*
|
||||
* The core has already completed its pending D-Bus
|
||||
* request, invoking the completion callback will
|
||||
* cause libdbus to panic.
|
||||
*/
|
||||
ril_data_request_detach(gcd->activate.req);
|
||||
ril_data_request_cancel(gcd->activate.req);
|
||||
}
|
||||
|
||||
if (gcd->deactivate.req) {
|
||||
/* Let it complete but we won't be around to be notified. */
|
||||
ril_data_request_detach(gcd->deactivate.req);
|
||||
} else if (gcd->active_call) {
|
||||
ril_data_call_deactivate(gcd->data, gcd->active_call->cid,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
ril_data_unref(gcd->data);
|
||||
ril_network_unref(gcd->network);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
ril_mtu_watch_free(gcd->mtu_watch);
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
const struct ofono_gprs_context_driver ril_gprs_context_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_gprs_context_probe,
|
||||
.remove = ril_gprs_context_remove,
|
||||
.activate_primary = ril_gprs_context_activate_primary,
|
||||
.deactivate_primary = ril_gprs_context_deactivate_primary,
|
||||
.detach_shutdown = ril_gprs_context_detach_shutdown,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
31
ofono/drivers/ril/ril_log.h
Normal file
31
ofono/drivers/ril/ril_log.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_LOG_H
|
||||
#define RIL_LOG_H
|
||||
|
||||
#define GLOG_MODULE_NAME ril_log
|
||||
#include <gutil_log.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#endif /* RIL_LOG_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
551
ofono/drivers/ril/ril_modem.c
Normal file
551
ofono/drivers/ril/ril_modem.c
Normal file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_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"
|
||||
|
||||
#define MAX_PDP_CONTEXTS (2)
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
enum ril_modem_power_state {
|
||||
POWERED_OFF,
|
||||
POWERED_ON,
|
||||
POWERING_OFF
|
||||
};
|
||||
|
||||
enum ril_modem_online_state {
|
||||
OFFLINE,
|
||||
GOING_ONLINE,
|
||||
ONLINE,
|
||||
GOING_OFFLINE
|
||||
};
|
||||
|
||||
struct ril_modem_online_request {
|
||||
ofono_modem_online_cb_t cb;
|
||||
struct ril_modem_data *md;
|
||||
void *data;
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gboolean pre_sim_done;
|
||||
gboolean allow_data;
|
||||
gulong sim_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);
|
||||
GASSERT(md->modem.ofono == 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)
|
||||
{
|
||||
if (modem && modem->ofono) {
|
||||
struct ofono_atom *atom =
|
||||
__ofono_modem_find_atom(modem->ofono, type);
|
||||
|
||||
if (atom) {
|
||||
return __ofono_atom_get_data(atom);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
|
||||
}
|
||||
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
|
||||
}
|
||||
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
|
||||
}
|
||||
|
||||
static inline struct ofono_radio_settings *ril_modem_radio_settings(
|
||||
struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
|
||||
}
|
||||
|
||||
void ril_modem_delete(struct ril_modem *md)
|
||||
{
|
||||
if (md && md->ofono) {
|
||||
ofono_modem_remove(md->ofono);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
g_source_remove(req->timeout_id);
|
||||
req->timeout_id = 0;
|
||||
}
|
||||
|
||||
if (req->cb) {
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *data = req->data;
|
||||
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||
{
|
||||
switch (md->modem.radio->state) {
|
||||
case RADIO_STATE_ON:
|
||||
DBG("online");
|
||||
ril_modem_online_request_ok(&md->set_online);
|
||||
break;
|
||||
|
||||
case RADIO_STATE_OFF:
|
||||
case RADIO_STATE_UNAVAILABLE:
|
||||
DBG("offline");
|
||||
ril_modem_online_request_ok(&md->set_offline);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
|
||||
md->power_state == POWERING_OFF) {
|
||||
md->power_state = POWERED_OFF;
|
||||
if (md->modem.ofono) {
|
||||
ofono_modem_set_powered(md->modem.ofono, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_request_timeout(gpointer data)
|
||||
{
|
||||
struct ril_modem_online_request *req = data;
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *cb_data = req->data;
|
||||
|
||||
GASSERT(req->timeout_id);
|
||||
GASSERT(cb);
|
||||
|
||||
req->timeout_id = 0;
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_failure(&error), cb_data);
|
||||
ril_modem_update_online_state(req->md);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_check(gpointer data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->online_check_id);
|
||||
md->online_check_id = 0;
|
||||
ril_modem_update_online_state(md);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
{
|
||||
if (!md->online_check_id) {
|
||||
md->online_check_id = g_idle_add(ril_modem_online_check, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
struct ril_modem *m = &md->modem;
|
||||
if (m->radio->state == RADIO_STATE_ON && m->sim_settings->imsi) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!ril_modem_radio_settings(m)) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
ofono_radio_settings_create(m->ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
} else {
|
||||
/* ofono core may remove radio settings atom internally */
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.radio == radio);
|
||||
ril_modem_update_radio_settings(md);
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
static void ril_modem_imsi_cb(struct ril_sim_settings *settings, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.sim_settings == settings);
|
||||
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);
|
||||
if (!md->radio_state_event_id) {
|
||||
md->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||
ril_modem_radio_state_cb, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (gprs) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
|
||||
struct ofono_gprs_context *gc =
|
||||
ofono_gprs_context_create(modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
if (gc == NULL)
|
||||
break;
|
||||
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
}
|
||||
|
||||
ofono_phonebook_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_call_volume_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_settings_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_netmon_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
|
||||
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ril_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);
|
||||
}
|
||||
|
||||
if (online) {
|
||||
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_online;
|
||||
} else {
|
||||
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_offline;
|
||||
}
|
||||
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
}
|
||||
req->timeout_id = g_timeout_add_seconds(ONLINE_TIMEOUT_SECS,
|
||||
ril_modem_online_request_timeout, req);
|
||||
ril_modem_schedule_online_check(md);
|
||||
}
|
||||
|
||||
static int ril_modem_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->power_state = POWERED_ON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ril_modem_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
if (md->set_online.timeout_id || md->set_offline.timeout_id) {
|
||||
md->power_state = POWERING_OFF;
|
||||
return -EINPROGRESS;
|
||||
} else {
|
||||
md->power_state = POWERED_OFF;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_modem_probe(struct ofono_modem *modem)
|
||||
{
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(ofono);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
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_remove_handler(modem->sim_settings,
|
||||
md->sim_imsi_event_id);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
}
|
||||
|
||||
if (md->set_online.timeout_id) {
|
||||
g_source_remove(md->set_online.timeout_id);
|
||||
}
|
||||
|
||||
if (md->set_offline.timeout_id) {
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_cell_info_unref(modem->cell_info);
|
||||
ril_data_unref(modem->data);
|
||||
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->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,
|
||||
struct ril_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,
|
||||
RILMODEM_DRIVER);
|
||||
if (ofono) {
|
||||
int err;
|
||||
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
/*
|
||||
* ril_plugin.c must wait until IMEI becomes known before
|
||||
* creating the modem
|
||||
*/
|
||||
GASSERT(slot->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);
|
||||
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 = ril_cell_info_ref(cell_info);
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
|
||||
/*
|
||||
* modem->sim_settings->imsi follows IMSI known to the ofono
|
||||
* core, unlike ril_sim_info->imsi which may point to the
|
||||
* cached IMSI even before the PIN code is entered.
|
||||
*/
|
||||
md->sim_imsi_event_id =
|
||||
ril_sim_settings_add_imsi_changed_handler(settings,
|
||||
ril_modem_imsi_cb, md);
|
||||
|
||||
md->set_online.md = md;
|
||||
md->set_offline.md = md;
|
||||
ofono_modem_set_data(ofono, md);
|
||||
err = ofono_modem_register(ofono);
|
||||
if (!err) {
|
||||
ril_radio_power_cycle(modem->radio);
|
||||
GASSERT(io->connected);
|
||||
|
||||
/*
|
||||
* ofono_modem_reset sets Powered to TRUE without
|
||||
* issuing PropertyChange signal.
|
||||
*/
|
||||
ofono_modem_set_powered(modem->ofono, FALSE);
|
||||
ofono_modem_set_powered(modem->ofono, TRUE);
|
||||
md->power_state = POWERED_ON;
|
||||
|
||||
/*
|
||||
* With some RIL implementations, querying available
|
||||
* band modes causes some magic Android properties to
|
||||
* appear. Otherwise this request is pretty harmless
|
||||
* and useless.
|
||||
*/
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
} else {
|
||||
ofono_error("Error %d registering %s",
|
||||
err, RILMODEM_DRIVER);
|
||||
|
||||
/*
|
||||
* If ofono_modem_register() failed, then
|
||||
* ofono_modem_remove() won't invoke
|
||||
* ril_modem_remove() callback.
|
||||
*/
|
||||
ril_modem_remove(ofono);
|
||||
}
|
||||
|
||||
ofono_modem_remove(ofono);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct ofono_modem_driver ril_modem_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_modem_probe,
|
||||
.remove = ril_modem_remove,
|
||||
.enable = ril_modem_enable,
|
||||
.disable = ril_modem_disable,
|
||||
.pre_sim = ril_modem_pre_sim,
|
||||
.post_sim = ril_modem_post_sim,
|
||||
.post_online = ril_modem_post_online,
|
||||
.set_online = ril_modem_set_online
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
223
ofono/drivers/ril/ril_mtu.c
Normal file
223
ofono/drivers/ril/ril_mtu.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* 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_mtu.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
struct ril_mtu_watch {
|
||||
int max_mtu;
|
||||
char *ifname;
|
||||
void *buf;
|
||||
int bufsize;
|
||||
GIOChannel *channel;
|
||||
guint io_watch;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
|
||||
{
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fd >= 0) {
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, self->ifname, IFNAMSIZ);
|
||||
if (ioctl(fd, SIOCGIFMTU, &ifr) < 0 ||
|
||||
ifr.ifr_mtu > self->max_mtu) {
|
||||
DBG("%s mtu %d => %d", self->ifname, ifr.ifr_mtu,
|
||||
self->max_mtu);
|
||||
ifr.ifr_mtu = self->max_mtu;
|
||||
if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
|
||||
ofono_error("Failed to set MTU");
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
|
||||
const struct rtattr *rta, int len)
|
||||
{
|
||||
int mtu = 0;
|
||||
const char *ifname = NULL;
|
||||
while (len > 0 && RTA_OK(rta, len) && (!mtu || !ifname)) {
|
||||
switch (rta->rta_type) {
|
||||
case IFLA_IFNAME:
|
||||
ifname = RTA_DATA(rta);
|
||||
break;
|
||||
case IFLA_MTU:
|
||||
mtu = *((int*)RTA_DATA(rta));
|
||||
break;
|
||||
}
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
if (mtu > self->max_mtu && !g_strcmp0(ifname, self->ifname)) {
|
||||
DBG("%s %d", ifname, mtu);
|
||||
ril_mtu_watch_limit_mtu(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_handle_ifinfomsg(struct ril_mtu_watch *self,
|
||||
const struct ifinfomsg *ifi, int len)
|
||||
{
|
||||
if (ifi->ifi_flags & IFF_UP) {
|
||||
const struct rtattr *rta = IFLA_RTA(ifi);
|
||||
ril_mtu_watch_handle_rtattr(self, rta,
|
||||
len - ((char*)rta - (char*)ifi));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_handle_nlmsg(struct ril_mtu_watch *self,
|
||||
const struct nlmsghdr *hdr, int len)
|
||||
{
|
||||
while (len > 0 && NLMSG_OK(hdr, len)) {
|
||||
if (hdr->nlmsg_type == RTM_NEWLINK) {
|
||||
ril_mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
|
||||
IFLA_PAYLOAD(hdr));
|
||||
}
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
|
||||
gpointer data)
|
||||
{
|
||||
struct ril_mtu_watch *self = data;
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
ssize_t result = recvfrom(self->fd, self->buf, self->bufsize, 0,
|
||||
(struct sockaddr *)&addr, &addrlen);
|
||||
if (result > 0) {
|
||||
if (!addr.nl_pid) {
|
||||
ril_mtu_watch_handle_nlmsg(self, self->buf, result);
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
} else if (result == 0 || errno == EINTR || errno == EAGAIN) {
|
||||
return G_SOURCE_CONTINUE;
|
||||
} else {
|
||||
DBG("%s error %d", self->ifname, errno);
|
||||
self->io_watch = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
|
||||
{
|
||||
GASSERT(self->fd < 0);
|
||||
self->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (self->fd >= 0) {
|
||||
struct sockaddr_nl nl;
|
||||
memset(&nl, 0, sizeof(nl));
|
||||
nl.nl_pid = getpid();
|
||||
nl.nl_family = AF_NETLINK;
|
||||
nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
|
||||
RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
|
||||
RTMGRP_LINK;
|
||||
|
||||
if (bind(self->fd, (struct sockaddr*)&nl, sizeof(nl)) >= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
close(self->fd);
|
||||
self->fd = -1;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
|
||||
{
|
||||
if (self->fd >= 0) {
|
||||
return TRUE;
|
||||
} else if (ril_mtu_watch_open_socket(self)) {
|
||||
GASSERT(!self->channel);
|
||||
GASSERT(!self->io_watch);
|
||||
self->channel = g_io_channel_unix_new(self->fd);
|
||||
if (self->channel) {
|
||||
g_io_channel_set_encoding(self->channel, NULL, NULL);
|
||||
g_io_channel_set_buffered(self->channel, FALSE);
|
||||
self->io_watch = g_io_add_watch(self->channel,
|
||||
G_IO_IN | G_IO_NVAL | G_IO_HUP,
|
||||
ril_mtu_watch_event, self);
|
||||
return TRUE;
|
||||
}
|
||||
close(self->fd);
|
||||
self->fd = -1;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
|
||||
{
|
||||
if (self->io_watch) {
|
||||
g_source_remove(self->io_watch);
|
||||
self->io_watch = 0;
|
||||
}
|
||||
if (self->channel) {
|
||||
g_io_channel_shutdown(self->channel, TRUE, NULL);
|
||||
g_io_channel_unref(self->channel);
|
||||
self->channel = NULL;
|
||||
}
|
||||
if (self->fd >= 0) {
|
||||
close(self->fd);
|
||||
self->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
|
||||
{
|
||||
struct ril_mtu_watch *self = g_new0(struct ril_mtu_watch, 1);
|
||||
self->fd = -1;
|
||||
self->max_mtu = max_mtu;
|
||||
self->bufsize = 4096;
|
||||
self->buf = g_malloc(self->bufsize);
|
||||
return self;
|
||||
}
|
||||
|
||||
void ril_mtu_watch_free(struct ril_mtu_watch *self)
|
||||
{
|
||||
if (self) {
|
||||
ril_mtu_watch_stop(self);
|
||||
g_free(self->ifname);
|
||||
g_free(self->buf);
|
||||
g_free(self);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *self, const char *ifname)
|
||||
{
|
||||
if (self && g_strcmp0(self->ifname, ifname)) {
|
||||
g_free(self->ifname);
|
||||
if (ifname) {
|
||||
self->ifname = g_strdup(ifname);
|
||||
ril_mtu_watch_limit_mtu(self);
|
||||
ril_mtu_watch_start(self);
|
||||
} else {
|
||||
self->ifname = NULL;
|
||||
ril_mtu_watch_stop(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
33
ofono/drivers/ril/ril_mtu.h
Normal file
33
ofono/drivers/ril/ril_mtu.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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_MTU_H
|
||||
#define RIL_MTU_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu);
|
||||
void ril_mtu_watch_free(struct ril_mtu_watch *mw);
|
||||
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *mw, const char *ifname);
|
||||
|
||||
#endif /* RIL_MTU_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
202
ofono/drivers/ril/ril_netmon.c
Normal file
202
ofono/drivers/ril/ril_netmon.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
struct ril_netmon {
|
||||
struct ofono_netmon *netmon;
|
||||
struct ril_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 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 ril_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 ril_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 ril_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 ril_cell *cell = l->data;
|
||||
|
||||
if (cell->registered) {
|
||||
switch (cell->type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
ril_netmon_notify_gsm(netmon,
|
||||
&cell->info.gsm);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
ril_netmon_notify_wcdma(netmon,
|
||||
&cell->info.wcdma);
|
||||
break;
|
||||
case RIL_CELL_INFO_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 = ril_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);
|
||||
}
|
||||
|
||||
ril_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:
|
||||
*/
|
||||
552
ofono/drivers/ril/ril_netreg.c
Normal file
552
ofono/drivers/ril/ril_netreg.c
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "simutil.h"
|
||||
|
||||
enum ril_netreg_events {
|
||||
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||
NETREG_RIL_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_netreg_network_events {
|
||||
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
|
||||
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
|
||||
NETREG_NETWORK_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_netreg *netreg;
|
||||
struct ril_network *network;
|
||||
char *log_prefix;
|
||||
guint timer_id;
|
||||
guint notify_id;
|
||||
guint current_operator_id;
|
||||
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
|
||||
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
|
||||
};
|
||||
|
||||
struct ril_netreg_cbd {
|
||||
struct ril_netreg *nd;
|
||||
union {
|
||||
ofono_netreg_status_cb_t status;
|
||||
ofono_netreg_operator_cb_t operator;
|
||||
ofono_netreg_operator_list_cb_t operator_list;
|
||||
ofono_netreg_register_cb_t reg;
|
||||
ofono_netreg_strength_cb_t strength;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_netreg_cbd_free g_free
|
||||
|
||||
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
|
||||
{
|
||||
return ofono ? ofono_netreg_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
|
||||
void *cb, void *data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = g_new0(struct ril_netreg_cbd, 1);
|
||||
|
||||
cbd->nd = nd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
|
||||
gint status)
|
||||
{
|
||||
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
/* These functions tolerate NULL argument */
|
||||
const char *net_mcc = ofono_netreg_get_mcc(netreg);
|
||||
const char *net_mnc = ofono_netreg_get_mnc(netreg);
|
||||
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
|
||||
|
||||
if (spdi && net_mcc && net_mnc) {
|
||||
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
|
||||
ofono_info("not roaming based on spdi");
|
||||
return NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ril_netreg_check_status(struct ril_netreg *nd, int status)
|
||||
{
|
||||
return (nd && nd->netreg) ?
|
||||
ril_netreg_check_if_really_roaming(nd->netreg, status) :
|
||||
status;
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_status_notify_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
GASSERT(nd->notify_id);
|
||||
nd->notify_id = 0;
|
||||
ofono_netreg_status_notify(nd->netreg,
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
/* Coalesce multiple notifications into one */
|
||||
if (nd->notify_id) {
|
||||
DBG("%snotification aready queued", nd->log_prefix);
|
||||
} else {
|
||||
DBG("%squeuing notification", nd->log_prefix);
|
||||
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_registration_status(struct ofono_netreg *netreg,
|
||||
ofono_netreg_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
cb(ril_error_ok(&error),
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech, data);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_current_operator_cb(void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
GASSERT(nd->current_operator_id);
|
||||
nd->current_operator_id = 0;
|
||||
|
||||
cb(ril_error_ok(&error), nd->network->operator, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
ofono_netreg_operator_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
/*
|
||||
* Calling ofono_netreg_status_notify() may result in
|
||||
* ril_netreg_current_operator() being invoked even if one
|
||||
* is already pending. Since ofono core doesn't associate
|
||||
* any context with individual calls, we can safely assume
|
||||
* that such a call essentially cancels the previous one.
|
||||
*/
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
nd->current_operator_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_netreg_current_operator_cb,
|
||||
ril_netreg_cbd_new(nd, cb, data),
|
||||
ril_netreg_cbd_free);
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list;
|
||||
struct ofono_network_operator *list;
|
||||
struct ofono_error error;
|
||||
int noperators = 0, i;
|
||||
GRilIoParser rilp;
|
||||
gboolean ok = TRUE;
|
||||
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("Failed to retrive the list of operators: %s",
|
||||
ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* Number of operators at the list (4 strings for every operator) */
|
||||
grilio_parser_get_int32(&rilp, &noperators);
|
||||
GASSERT(!(noperators % 4));
|
||||
noperators /= 4;
|
||||
ofono_info("noperators = %d", noperators);
|
||||
|
||||
list = g_new0(struct ofono_network_operator, noperators);
|
||||
for (i = 0; i < noperators && ok; i++) {
|
||||
struct ofono_network_operator *op = list + i;
|
||||
char *lalpha = grilio_parser_get_utf8(&rilp);
|
||||
char *salpha = grilio_parser_get_utf8(&rilp);
|
||||
char *numeric = grilio_parser_get_utf8(&rilp);
|
||||
char *status = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
/* Try to use long by default */
|
||||
if (lalpha) {
|
||||
strncpy(op->name, lalpha,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else if (salpha) {
|
||||
strncpy(op->name, salpha,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else {
|
||||
op->name[0] = 0;
|
||||
}
|
||||
|
||||
/* Set the proper status */
|
||||
if (!strcmp(status, "available")) {
|
||||
list[i].status = OPERATOR_STATUS_AVAILABLE;
|
||||
} else if (!strcmp(status, "current")) {
|
||||
list[i].status = OPERATOR_STATUS_CURRENT;
|
||||
} else if (!strcmp(status, "forbidden")) {
|
||||
list[i].status = OPERATOR_STATUS_FORBIDDEN;
|
||||
} else {
|
||||
list[i].status = OPERATOR_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
op->tech = -1;
|
||||
ok = ril_parse_mcc_mnc(numeric, op);
|
||||
if (ok) {
|
||||
if (op->tech < 0) {
|
||||
op->tech = cbd->nd->network->voice.access_tech;
|
||||
}
|
||||
DBG("[operator=%s, %s, %s, status: %s]", op->name,
|
||||
op->mcc, op->mnc, status);
|
||||
} else {
|
||||
DBG("failed to parse operator list");
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
g_free(status);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
cb(ril_error_ok(&error), noperators, list, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
}
|
||||
|
||||
g_free(list);
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators(struct ofono_netreg *netreg,
|
||||
ofono_netreg_operator_list_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS,
|
||||
ril_netreg_list_operators_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_netreg_register_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_register_cb_t cb = cbd->cb.reg;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("registration failed, ril result %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_register_auto(struct ofono_netreg *netreg,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
ofono_info("nw select automatic");
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
const char *mcc, const char *mnc,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("nw select manual: %s%s", mcc, mnc);
|
||||
grilio_request_append_format(req, "%s%s+0", mcc, mnc);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* RIL_SignalStrength_v6 */
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &gw_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &cdma_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &evdo_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, <e_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rsrp */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* cqi */
|
||||
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
|
||||
evdo_dbm, lte_signal);
|
||||
|
||||
/* Return the first valid one */
|
||||
if (gw_signal != 99 && gw_signal != -1) {
|
||||
return (gw_signal * 100) / 31;
|
||||
}
|
||||
|
||||
if (lte_signal != 99 && lte_signal != -1) {
|
||||
return (lte_signal * 100) / 31;
|
||||
}
|
||||
|
||||
/* In case of dbm, return the value directly */
|
||||
if (cdma_dbm != -1) {
|
||||
return MIN(cdma_dbm, 100);
|
||||
}
|
||||
|
||||
if (evdo_dbm != -1) {
|
||||
return MIN(evdo_dbm, 100);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
int strength;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
|
||||
strength = ril_netreg_get_signal_strength(data, len);
|
||||
DBG("%d", strength);
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_strength_cb_t cb = cbd->cb.strength;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int strength = ril_netreg_get_signal_strength(data, len);
|
||||
cb(ril_error_ok(&error), strength, cbd->data);
|
||||
} else {
|
||||
ofono_error("Failed to retrive the signal strength: %s",
|
||||
ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength(struct ofono_netreg *netreg,
|
||||
ofono_netreg_strength_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SIGNAL_STRENGTH, ril_netreg_strength_cb,
|
||||
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
GRilIoParser rilp;
|
||||
struct ofono_network_time time;
|
||||
int year, mon, mday, hour, min, sec, dst, tzi;
|
||||
char tzs, tz[4];
|
||||
gchar *nitz;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
nitz = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
DBG("%s", nitz);
|
||||
sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday,
|
||||
&hour, &min, &sec, &tzs, &tzi, &dst);
|
||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||
|
||||
time.utcoff = atoi(tz) * 15 * 60;
|
||||
time.dst = dst;
|
||||
time.sec = sec;
|
||||
time.min = min;
|
||||
time.hour = hour;
|
||||
time.mday = mday;
|
||||
time.mon = mon;
|
||||
time.year = 2000 + year;
|
||||
|
||||
ofono_netreg_time_notify(nd->netreg, &time);
|
||||
g_free(nitz);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_register(gpointer user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
GASSERT(nd->timer_id);
|
||||
nd->timer_id = 0;
|
||||
ofono_netreg_register(nd->netreg);
|
||||
|
||||
/* Register for network state changes */
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_OPERATOR_CHANGED] =
|
||||
ril_network_add_operator_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED] =
|
||||
ril_network_add_voice_state_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
|
||||
/* Register for network time updates */
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_NITZ_TIME_RECEIVED] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_nitz_notify,
|
||||
RIL_UNSOL_NITZ_TIME_RECEIVED, nd);
|
||||
|
||||
/* Register for signal strength changes */
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_SIGNAL_STRENGTH] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_strength_notify,
|
||||
RIL_UNSOL_SIGNAL_STRENGTH, nd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
|
||||
guint slot = ril_modem_slot(modem);
|
||||
|
||||
DBG("[%u] %p", slot, netreg);
|
||||
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
int i;
|
||||
|
||||
DBG("%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
ofono_netreg_set_data(netreg, NULL);
|
||||
|
||||
if (nd->timer_id > 0) {
|
||||
g_source_remove(nd->timer_id);
|
||||
}
|
||||
|
||||
if (nd->notify_id) {
|
||||
g_source_remove(nd->notify_id);
|
||||
}
|
||||
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
|
||||
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
|
||||
}
|
||||
ril_network_unref(nd->network);
|
||||
|
||||
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
|
||||
G_N_ELEMENTS(nd->ril_event_id));
|
||||
|
||||
grilio_channel_unref(nd->io);
|
||||
grilio_queue_unref(nd->q);
|
||||
g_free(nd->log_prefix);
|
||||
g_free(nd);
|
||||
}
|
||||
|
||||
const struct ofono_netreg_driver ril_netreg_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_netreg_probe,
|
||||
.remove = ril_netreg_remove,
|
||||
.registration_status = ril_netreg_registration_status,
|
||||
.current_operator = ril_netreg_current_operator,
|
||||
.list_operators = ril_netreg_list_operators,
|
||||
.register_auto = ril_netreg_register_auto,
|
||||
.register_manual = ril_netreg_register_manual,
|
||||
.strength = ril_netreg_strength
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
902
ofono/drivers/ril/ril_network.c
Normal file
902
ofono/drivers/ril/ril_network.c
Normal file
@@ -0,0 +1,902 @@
|
||||
/*
|
||||
* 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_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SET_PREF_MODE_HOLDOFF_SEC RIL_RETRY_SECS
|
||||
|
||||
typedef GObjectClass RilNetworkClass;
|
||||
typedef struct ril_network RilNetwork;
|
||||
|
||||
enum ril_network_timer {
|
||||
TIMER_SET_RAT_HOLDOFF,
|
||||
TIMER_FORCE_CHECK_PREF_MODE,
|
||||
TIMER_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_radio_event {
|
||||
RADIO_EVENT_STATE_CHANGED,
|
||||
RADIO_EVENT_ONLINE_CHANGED,
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
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;
|
||||
guint voice_poll_id;
|
||||
guint data_poll_id;
|
||||
guint timer[TIMER_COUNT];
|
||||
gulong query_rat_id;
|
||||
gulong set_rat_id;
|
||||
gulong ril_event_id;
|
||||
gulong settings_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
struct ofono_network_operator operator;
|
||||
};
|
||||
|
||||
enum ril_network_signal {
|
||||
SIGNAL_OPERATOR_CHANGED,
|
||||
SIGNAL_VOICE_STATE_CHANGED,
|
||||
SIGNAL_DATA_STATE_CHANGED,
|
||||
SIGNAL_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"
|
||||
|
||||
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilNetwork, ril_network, G_TYPE_OBJECT)
|
||||
#define RIL_NETWORK_TYPE (ril_network_get_type())
|
||||
#define RIL_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,\
|
||||
RIL_NETWORK_TYPE,RilNetwork))
|
||||
|
||||
#define RIL_NETWORK_SIGNAL(klass,name) \
|
||||
ril_network_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
/* Some assumptions: */
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_ANY == 0);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_GSM > OFONO_RADIO_ACCESS_MODE_ANY);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
|
||||
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self);
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat);
|
||||
|
||||
static void ril_network_emit(struct ril_network *self,
|
||||
enum ril_network_signal sig)
|
||||
{
|
||||
g_signal_emit(self, ril_network_signals[sig], 0);
|
||||
}
|
||||
|
||||
static void ril_network_stop_timer(struct ril_network *self,
|
||||
enum ril_network_timer tid)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->timer[tid]) {
|
||||
g_source_remove(priv->timer[tid]);
|
||||
priv->timer[tid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_reset_state(struct ril_registration_state *reg)
|
||||
{
|
||||
memset(reg, 0, sizeof(*reg));
|
||||
reg->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
reg->access_tech = -1;
|
||||
reg->ril_tech = -1;
|
||||
reg->lac = -1;
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
const void *data, guint len, struct ril_registration_state *reg)
|
||||
{
|
||||
int nparams, ril_status;
|
||||
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
|
||||
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
ril_network_reset_state(reg);
|
||||
|
||||
/* Size of response string array. The minimum seen in the wild is 3 */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (!grilio_parser_get_int32(&rilp, &nparams) || nparams < 3) {
|
||||
DBG_(self, "broken response");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sstatus = grilio_parser_get_utf8(&rilp); /* response[0] */
|
||||
if (!sstatus) {
|
||||
DBG_(self, "No sstatus value returned!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
slac = grilio_parser_get_utf8(&rilp); /* response[1] */
|
||||
sci = grilio_parser_get_utf8(&rilp); /* response[2] */
|
||||
|
||||
if (nparams > 3) {
|
||||
stech = grilio_parser_get_utf8(&rilp); /* response[3] */
|
||||
}
|
||||
|
||||
ril_status = atoi(sstatus);
|
||||
if (ril_status > 10) {
|
||||
reg->status = ril_status - 10;
|
||||
} else {
|
||||
reg->status = ril_status;
|
||||
}
|
||||
|
||||
/* FIXME: need to review VOICE_REGISTRATION response
|
||||
* as it returns up to 15 parameters ( vs. 6 for DATA ).
|
||||
*
|
||||
* The first four parameters are the same for both
|
||||
* responses ( although status includes values for
|
||||
* emergency calls for VOICE response ).
|
||||
*
|
||||
* Parameters 5 & 6 have different meanings for
|
||||
* voice & data response.
|
||||
*/
|
||||
if (nparams > 4) {
|
||||
/* TODO: different use for CDMA */
|
||||
sreason = grilio_parser_get_utf8(&rilp); /* response[4] */
|
||||
if (nparams > 5) {
|
||||
/* TODO: different use for CDMA */
|
||||
smax = grilio_parser_get_utf8(&rilp); /* response[5] */
|
||||
if (smax) {
|
||||
reg->max_calls = atoi(smax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some older RILs don't provide max calls, in that case let's
|
||||
* supply some reasonable default. We don't need more than 2
|
||||
* simultaneous data calls anyway.
|
||||
*/
|
||||
if (reg->max_calls < 1) {
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
|
||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
||||
registration_status_to_string(reg->status),
|
||||
slac, sci, reg->ril_tech,
|
||||
registration_tech_to_string(reg->access_tech),
|
||||
sreason, smax);
|
||||
|
||||
g_free(sstatus);
|
||||
g_free(slac);
|
||||
g_free(sci);
|
||||
g_free(stech);
|
||||
g_free(sreason);
|
||||
g_free(smax);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ril_network_op_copy(struct ofono_network_operator *dest,
|
||||
const struct ofono_network_operator *src)
|
||||
{
|
||||
strncpy(dest->mcc, src->mcc, sizeof(dest->mcc));
|
||||
strncpy(dest->mnc, src->mnc, sizeof(dest->mnc));
|
||||
strncpy(dest->name, src->name, sizeof(dest->name));
|
||||
dest->mcc[sizeof(dest->mcc)-1] = 0;
|
||||
dest->mnc[sizeof(dest->mnc)-1] = 0;
|
||||
dest->name[sizeof(dest->name)-1] = 0;
|
||||
dest->status = src->status;
|
||||
dest->tech = src->tech;
|
||||
}
|
||||
|
||||
static gboolean ril_network_op_equal(const struct ofono_network_operator *op1,
|
||||
const struct ofono_network_operator *op2)
|
||||
{
|
||||
if (op1 == op2) {
|
||||
return TRUE;
|
||||
} else if (!op1 || !op2) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return op1->status == op2->status &&
|
||||
op1->tech == op2->tech &&
|
||||
!strncmp(op1->mcc, op2->mcc, sizeof(op2->mcc)) &&
|
||||
!strncmp(op1->mnc, op2->mnc, sizeof(op2->mnc)) &&
|
||||
!strncmp(op1->name, op2->name, sizeof(op2->name));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->operator_poll_id);
|
||||
priv->operator_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ofono_network_operator op;
|
||||
gboolean changed = FALSE;
|
||||
gchar *lalpha;
|
||||
char *salpha;
|
||||
char *numeric;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
lalpha = grilio_parser_get_utf8(&rilp);
|
||||
salpha = grilio_parser_get_utf8(&rilp);
|
||||
numeric = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
op.tech = -1;
|
||||
if (ril_parse_mcc_mnc(numeric, &op)) {
|
||||
if (op.tech < 0) op.tech = self->voice.access_tech;
|
||||
op.status = OPERATOR_STATUS_CURRENT;
|
||||
op.name[0] = 0;
|
||||
if (lalpha) {
|
||||
strncpy(op.name, lalpha, sizeof(op.name));
|
||||
} else if (salpha) {
|
||||
strncpy(op.name, salpha, sizeof(op.name));
|
||||
} else {
|
||||
strncpy(op.name, numeric, sizeof(op.name));
|
||||
}
|
||||
op.name[sizeof(op.name)-1] = 0;
|
||||
if (!self->operator) {
|
||||
self->operator = &priv->operator;
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
} else if (!ril_network_op_equal(&op, &priv->operator)) {
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
}
|
||||
} else if (self->operator) {
|
||||
self->operator = NULL;
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (self->operator) {
|
||||
DBG_(self, "lalpha=%s, salpha=%s, numeric=%s, "
|
||||
"%s, mcc=%s, mnc=%s, %s",
|
||||
lalpha, salpha, numeric,
|
||||
op.name, op.mcc, op.mnc,
|
||||
registration_tech_to_string(op.tech));
|
||||
} else {
|
||||
DBG_(self, "no operator");
|
||||
}
|
||||
ril_network_emit(self, SIGNAL_OPERATOR_CHANGED);
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_voice_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->voice_poll_id);
|
||||
priv->voice_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->voice, sizeof(state))) {
|
||||
DBG_(self, "voice registration changed");
|
||||
self->voice = state;
|
||||
ril_network_emit(self, SIGNAL_VOICE_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->data_poll_id);
|
||||
priv->data_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->data, sizeof(state))) {
|
||||
DBG_(self, "data registration changed");
|
||||
self->data = state;
|
||||
ril_network_emit(self, SIGNAL_DATA_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
|
||||
int code, GRilIoChannelResponseFunc fn)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, id);
|
||||
} else {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
id = grilio_queue_send_request_full(priv->q, req, code, fn,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_network_poll_state(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
||||
ril_network_poll_operator_cb);
|
||||
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||
ril_network_poll_voice_state_cb);
|
||||
priv->data_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_network_poll_data_state_cb);
|
||||
}
|
||||
|
||||
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
|
||||
{
|
||||
switch (rat) {
|
||||
case PREF_NET_TYPE_LTE_CDMA_EVDO:
|
||||
case PREF_NET_TYPE_LTE_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_LTE_ONLY:
|
||||
case PREF_NET_TYPE_LTE_WCDMA:
|
||||
return OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
case PREF_NET_TYPE_GSM_WCDMA_AUTO:
|
||||
case PREF_NET_TYPE_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA:
|
||||
return OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
default:
|
||||
DBG("unexpected rat mode %d", rat);
|
||||
case PREF_NET_TYPE_GSM_ONLY:
|
||||
return OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (self->settings->enable_4g) {
|
||||
return PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
return PREF_NET_TYPE_GSM_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_pref_mode_expected(struct ril_network *self)
|
||||
{
|
||||
struct ril_sim_settings *settings = self->settings;
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* On dual-SIM phones such as Jolla C only one slot at a time
|
||||
* is allowed to use LTE. Even if the slot which has been using
|
||||
* LTE gets powered off, we still need to explicitely set its
|
||||
* preferred mode to GSM, to make LTE machinery available to
|
||||
* the other slot. This sort of behaviour might not be necessary
|
||||
* on some hardware and can (should) be made configurable when
|
||||
* it becomes necessary.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? priv->max_pref_mode :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
|
||||
/*
|
||||
* OFONO_RADIO_ACCESS_MODE_ANY is zero. If both pref_mode
|
||||
* and max_pref_mode are not ANY, we pick the smallest value.
|
||||
* Otherwise we take any non-zero value if there is one.
|
||||
*/
|
||||
const enum ofono_radio_access_mode pref_mode =
|
||||
(settings->pref_mode && max_pref_mode) ?
|
||||
MIN(settings->pref_mode, max_pref_mode) :
|
||||
settings->pref_mode ? settings->pref_mode :
|
||||
max_pref_mode;
|
||||
return ril_network_mode_to_rat(self, pref_mode);
|
||||
}
|
||||
|
||||
static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
|
||||
}
|
||||
|
||||
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
|
||||
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
|
||||
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
|
||||
|
||||
/*
|
||||
* Don't retry the request if modem is offline or SIM card isn't
|
||||
* ready, to avoid spamming system log with error messages. Radio
|
||||
* and SIM card state change callbacks will schedule a new check
|
||||
* when it's appropriate.
|
||||
*/
|
||||
if (priv->rat != rat) {
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
DBG_(self, "giving up");
|
||||
}
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->set_rat_id);
|
||||
priv->set_rat_id = 0;
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("failed to set rat mode");
|
||||
}
|
||||
|
||||
ril_network_query_pref_mode(self);
|
||||
}
|
||||
|
||||
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG_(self, "setting rat mode %d", rat);
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, rat);
|
||||
|
||||
grilio_queue_cancel_request(priv->q, priv->set_rat_id, FALSE);
|
||||
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_set_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Don't do it too often */
|
||||
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
|
||||
ril_network_set_rat_holdoff_cb, self);
|
||||
}
|
||||
|
||||
static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean force)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const int rat = ril_network_pref_mode_expected(self);
|
||||
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
force = TRUE;
|
||||
}
|
||||
|
||||
if (priv->rat == rat || force) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (priv->rat != rat) {
|
||||
/* Something isn't right, we need to fix it */
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_network_parse_pref_resp(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int pref = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &pref);
|
||||
return pref;
|
||||
}
|
||||
|
||||
static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
|
||||
int status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike ril_network_query_pref_mode_cb, this one always
|
||||
* checks the preferred mode.
|
||||
*/
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
/* This request never fails because in case of error it gets retried */
|
||||
GASSERT(status == RIL_E_SUCCESS);
|
||||
GASSERT(priv->query_rat_id);
|
||||
|
||||
priv->query_rat_id = 0;
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_query_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE);
|
||||
priv->query_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_query_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
void ril_network_set_max_pref_mode(struct ril_network *self,
|
||||
enum ofono_radio_access_mode max_mode,
|
||||
gboolean force_check)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
if (priv->max_pref_mode != max_mode || force_check) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_OPERATOR_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_VOICE_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_data_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_DATA_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_network_remove_handler(struct ril_network *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, n);
|
||||
}
|
||||
|
||||
static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_radio_online_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_network_check_pref_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->timer[TIMER_FORCE_CHECK_PREF_MODE]);
|
||||
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] = 0;
|
||||
|
||||
DBG_(self, "checking pref mode");
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_network_pref_mode_changed_cb(struct ril_sim_settings *settings,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* Postpone ril_network_check_pref_mode because other pref_mode
|
||||
* listeners (namely, ril_data) may want to tweak max_pref_mode
|
||||
*/
|
||||
if (!priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
DBG_(self, "scheduling pref mode check");
|
||||
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] =
|
||||
g_idle_add(ril_network_check_pref_mode_cb, self);
|
||||
} else {
|
||||
DBG_(self, "pref mode check already scheduled");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings)
|
||||
{
|
||||
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
self->settings = ril_sim_settings_ref(settings);
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->ril_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_voice_state_changed_cb,
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
|
||||
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
|
||||
ril_radio_add_state_changed_handler(priv->radio,
|
||||
ril_network_radio_state_cb, self);
|
||||
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
|
||||
ril_radio_add_online_changed_handler(priv->radio,
|
||||
ril_network_radio_online_cb, self);
|
||||
priv->settings_event_id =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(settings,
|
||||
ril_network_pref_mode_changed_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
ril_network_sim_status_changed_cb, self);
|
||||
|
||||
/*
|
||||
* Query the initial state. Querying network state before the radio
|
||||
* has been turned on makes RIL unhappy.
|
||||
*/
|
||||
grilio_queue_send_request_full(priv->q, NULL,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_network_startup_query_pref_mode_cb, NULL, self);
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_ref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_NETWORK(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_unref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_NETWORK(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_init(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_NETWORK_TYPE, struct ril_network_priv);
|
||||
|
||||
self->priv = priv;
|
||||
ril_network_reset_state(&self->voice);
|
||||
ril_network_reset_state(&self->data);
|
||||
priv->rat = -1;
|
||||
}
|
||||
|
||||
static void ril_network_dispose(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);
|
||||
|
||||
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;
|
||||
|
||||
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_unref(priv->radio);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
ril_sim_settings_unref(self->settings);
|
||||
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_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
75
ofono/drivers/ril/ril_network.h
Normal file
75
ofono/drivers/ril/ril_network.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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_NETWORK_H
|
||||
#define RIL_NETWORK_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
int status; /* enum network_registration_status */
|
||||
int access_tech; /* enum access_technology or -1 if none */
|
||||
int ril_tech;
|
||||
int max_calls;
|
||||
int lac;
|
||||
int ci;
|
||||
};
|
||||
|
||||
struct ril_network {
|
||||
GObject object;
|
||||
struct ril_network_priv *priv;
|
||||
struct ril_registration_state voice;
|
||||
struct ril_registration_state data;
|
||||
const struct ofono_network_operator *operator;
|
||||
enum ofono_radio_access_mode pref_mode;
|
||||
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_sim_settings *settings);
|
||||
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
|
||||
void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||
enum ofono_radio_access_mode max_pref_mode,
|
||||
gboolean force_check);
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||
|
||||
#endif /* RIL_NETWORK_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
166
ofono/drivers/ril/ril_oem_raw.c
Normal file
166
ofono/drivers/ril/ril_oem_raw.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "gdbus.h"
|
||||
#include "ofono.h"
|
||||
|
||||
#define RIL_OEM_RAW_INTERFACE "org.ofono.OemRaw"
|
||||
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
|
||||
|
||||
struct ril_oem_raw {
|
||||
struct ril_modem *modem;
|
||||
GRilIoQueue *q;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
char *log_prefix;
|
||||
};
|
||||
|
||||
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
|
||||
|
||||
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DBusMessage *msg = user_data;
|
||||
DBusMessage *reply;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBusMessageIter it, array;
|
||||
const guchar* bytes = data;
|
||||
guint i;
|
||||
|
||||
reply = dbus_message_new_method_return(msg);
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_BYTE_AS_STRING, &array);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
guchar byte = bytes[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
|
||||
&byte);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
|
||||
DBG("Timed out");
|
||||
reply = __ofono_error_timed_out(msg);
|
||||
} else {
|
||||
DBG("Error %s", ril_error_to_string(ril_status));
|
||||
reply = __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, reply);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
void *user_data)
|
||||
{
|
||||
DBusMessageIter it;
|
||||
struct ril_oem_raw *oem = user_data;
|
||||
|
||||
dbus_message_iter_init(msg, &it);
|
||||
if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY &&
|
||||
dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) {
|
||||
char *data;
|
||||
int data_len;
|
||||
DBusMessageIter array;
|
||||
GRilIoRequest *req;
|
||||
|
||||
/* Fetch the data */
|
||||
dbus_message_iter_recurse(&it, &array);
|
||||
dbus_message_iter_get_fixed_array(&array, &data, &data_len);
|
||||
DBG_(oem, "%d bytes", data_len);
|
||||
|
||||
/*
|
||||
* And forward it to rild. Set a timeout because rild may
|
||||
* never respond to invalid requests.
|
||||
*/
|
||||
req = grilio_request_sized_new(data_len);
|
||||
grilio_request_set_timeout(req, RIL_OEM_RAW_TIMEOUT);
|
||||
grilio_request_append_bytes(req, data, data_len);
|
||||
grilio_queue_send_request_full(oem->q, req,
|
||||
RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb,
|
||||
NULL, dbus_message_ref(msg));
|
||||
grilio_request_unref(req);
|
||||
return NULL;
|
||||
} else {
|
||||
DBG_(oem, "Unexpected signature");
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_oem_raw_methods[] = {
|
||||
{ GDBUS_ASYNC_METHOD("Send",
|
||||
GDBUS_ARGS({ "request", "ay" }),
|
||||
GDBUS_ARGS({ "response", "ay" }),
|
||||
ril_oem_raw_send) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
const char *log_prefix)
|
||||
{
|
||||
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
oem->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));
|
||||
oem->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE, ril_oem_raw_methods,
|
||||
NULL, NULL, oem, NULL)) {
|
||||
ofono_modem_add_interface(modem->ofono, RIL_OEM_RAW_INTERFACE);
|
||||
return oem;
|
||||
} else {
|
||||
ofono_error("OemRaw D-Bus register failed");
|
||||
ril_oem_raw_free(oem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_oem_raw_free(struct ril_oem_raw *oem)
|
||||
{
|
||||
if (oem) {
|
||||
DBG("%s", oem->path);
|
||||
g_dbus_unregister_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
ofono_modem_remove_interface(oem->modem->ofono,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
dbus_connection_unref(oem->conn);
|
||||
|
||||
grilio_queue_cancel_all(oem->q, TRUE);
|
||||
grilio_queue_unref(oem->q);
|
||||
|
||||
g_free(oem->log_prefix);
|
||||
g_free(oem->path);
|
||||
g_free(oem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
1067
ofono/drivers/ril/ril_phonebook.c
Normal file
1067
ofono/drivers/ril/ril_phonebook.c
Normal file
File diff suppressed because it is too large
Load Diff
1813
ofono/drivers/ril/ril_plugin.c
Normal file
1813
ofono/drivers/ril/ril_plugin.c
Normal file
File diff suppressed because it is too large
Load Diff
176
ofono/drivers/ril/ril_plugin.h
Normal file
176
ofono/drivers/ril/ril_plugin.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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_PLUGIN_H
|
||||
#define RIL_PLUGIN_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-barring.h>
|
||||
#include <ofono/call-forwarding.h>
|
||||
#include <ofono/call-settings.h>
|
||||
#include <ofono/call-volume.h>
|
||||
#include <ofono/cbs.h>
|
||||
#include <ofono/devinfo.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/phonebook.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/sms.h>
|
||||
#include <ofono/stk.h>
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/voicecall.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#define RILMODEM_DRIVER "ril"
|
||||
|
||||
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 *log_prefix;
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
struct ril_cell_info *cell_info;
|
||||
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,
|
||||
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,
|
||||
struct ril_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)
|
||||
#define ril_modem_slot(modem) ((modem)->config.slot)
|
||||
#define ril_modem_io(modem) ((modem)->io)
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
|
||||
|
||||
extern const struct ofono_call_barring_driver ril_call_barring_driver;
|
||||
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
|
||||
extern const struct ofono_call_settings_driver ril_call_settings_driver;
|
||||
extern const struct ofono_call_volume_driver ril_call_volume_driver;
|
||||
extern const struct ofono_cbs_driver ril_cbs_driver;
|
||||
extern const struct ofono_devinfo_driver ril_devinfo_driver;
|
||||
extern const struct ofono_gprs_context_driver ril_gprs_context_driver;
|
||||
extern const struct ofono_gprs_driver ril_gprs_driver;
|
||||
extern const struct ofono_modem_driver ril_modem_driver;
|
||||
extern const struct ofono_netreg_driver ril_netreg_driver;
|
||||
extern const struct ofono_phonebook_driver ril_phonebook_driver;
|
||||
extern const struct ofono_radio_settings_driver ril_radio_settings_driver;
|
||||
extern const struct ofono_sim_driver ril_sim_driver;
|
||||
extern const struct ofono_sms_driver ril_sms_driver;
|
||||
extern const struct ofono_stk_driver ril_stk_driver;
|
||||
extern const struct ofono_ussd_driver ril_ussd_driver;
|
||||
extern const struct ofono_voicecall_driver ril_voicecall_driver;
|
||||
extern const struct ofono_netmon_driver ril_netmon_driver;
|
||||
|
||||
#endif /* RIL_PLUGIN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
851
ofono/drivers/ril/ril_plugin_dbus.c
Normal file
851
ofono/drivers/ril/ril_plugin_dbus.c
Normal file
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
450
ofono/drivers/ril/ril_radio.c
Normal file
450
ofono/drivers/ril/ril_radio.c
Normal file
@@ -0,0 +1,450 @@
|
||||
/*
|
||||
* 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_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
typedef GObjectClass RilRadioClass;
|
||||
typedef struct ril_radio RilRadio;
|
||||
|
||||
/*
|
||||
* Object states:
|
||||
*
|
||||
* 1. Idle (!pending && !retry)
|
||||
* 2. Power on/off request pending (pending)
|
||||
* 3. Power on retry has been scheduled (retry)
|
||||
*/
|
||||
struct ril_radio_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gulong state_event_id;
|
||||
char *log_prefix;
|
||||
GHashTable *req_table;
|
||||
guint pending_id;
|
||||
guint retry_id;
|
||||
guint state_changed_while_request_pending;
|
||||
enum ril_radio_state last_known_state;
|
||||
gboolean power_cycle;
|
||||
gboolean next_state_valid;
|
||||
gboolean next_state;
|
||||
};
|
||||
|
||||
enum ril_radio_signal {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_ONLINE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define POWER_RETRY_SECS (1)
|
||||
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
|
||||
#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
|
||||
|
||||
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_radio_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
|
||||
#define RIL_RADIO_TYPE (ril_radio_get_type())
|
||||
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
|
||||
|
||||
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
return self->online && !priv->power_cycle &&
|
||||
g_hash_table_size(priv->req_table) > 0;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
{
|
||||
return radio_state == RADIO_STATE_OFF;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_on(enum ril_radio_state radio_state)
|
||||
{
|
||||
return !ril_radio_state_off(radio_state);
|
||||
}
|
||||
|
||||
static inline void ril_radio_emit_signal(struct ril_radio *self,
|
||||
enum ril_radio_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_radio_signals[id], 0);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_cancel_retry(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->retry_id) {
|
||||
DBG("%sretry cancelled", priv->log_prefix);
|
||||
g_source_remove(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_check_state(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (!priv->pending_id) {
|
||||
const gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
if (ril_radio_state_on(self->priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
/* All is good, cancel pending retry if there is one */
|
||||
ril_radio_cancel_retry(self);
|
||||
} else if (priv->state_changed_while_request_pending) {
|
||||
/* Hmm... RIL's reaction was inadequate, repeat */
|
||||
ril_radio_submit_power_request(self, should_be_on);
|
||||
} else if (!priv->retry_id) {
|
||||
/* There has been no reaction so far, wait a bit */
|
||||
DBG("%sretry scheduled", priv->log_prefix);
|
||||
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
|
||||
ril_radio_power_request_retry_cb, self);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't update public state while something is pending */
|
||||
if (!priv->pending_id && !priv->retry_id &&
|
||||
self->state != priv->last_known_state) {
|
||||
DBG("%s%s -> %s", priv->log_prefix,
|
||||
ril_radio_state_to_string(self->state),
|
||||
ril_radio_state_to_string(priv->last_known_state));
|
||||
self->state = priv->last_known_state;
|
||||
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
priv->pending_id = 0;
|
||||
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("Power request failed: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
if (priv->next_state_valid) {
|
||||
ril_radio_submit_power_request(self, priv->next_state);
|
||||
} else {
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
{
|
||||
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;
|
||||
priv->state_changed_while_request_pending = 0;
|
||||
ril_radio_cancel_retry(self);
|
||||
|
||||
GASSERT(!priv->pending_id);
|
||||
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||
gboolean allow_repeat)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
const char *on_off = on ? "on" : "off";
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (allow_repeat || priv->next_state != on) {
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = on;
|
||||
DBG("%s%s (queued)", priv->log_prefix, on_off);
|
||||
} else {
|
||||
DBG("%s%s (ignored)", priv->log_prefix, on_off);
|
||||
}
|
||||
} else {
|
||||
DBG("%s%s", priv->log_prefix, on_off);
|
||||
ril_radio_submit_power_request(self, on);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_confirm_power_on(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_cycle(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (ril_radio_state_off(priv->last_known_state)) {
|
||||
DBG("%spower is already off", priv->log_prefix);
|
||||
GASSERT(!priv->power_cycle);
|
||||
} else if (priv->power_cycle) {
|
||||
DBG("%salready in progress", priv->log_prefix);
|
||||
} else {
|
||||
DBG("%sinitiated", priv->log_prefix);
|
||||
priv->power_cycle = TRUE;
|
||||
if (!priv->pending_id) {
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (!g_hash_table_contains(priv->req_table, tag)) {
|
||||
gboolean was_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
g_hash_table_insert(priv->req_table, tag, tag);
|
||||
if (!was_on && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (g_hash_table_remove(priv->req_table, tag)) {
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
if (!ril_radio_power_should_be_on(self)) {
|
||||
/* The last one turns the lights off */
|
||||
ril_radio_power_request(self, FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_set_online(struct ril_radio *self, gboolean online)
|
||||
{
|
||||
if (G_LIKELY(self) && self->online != online) {
|
||||
gboolean on, was_on = ril_radio_power_should_be_on(self);
|
||||
self->online = online;
|
||||
on = ril_radio_power_should_be_on(self);
|
||||
if (was_on != on) {
|
||||
ril_radio_power_request(self, on, FALSE);
|
||||
}
|
||||
ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_remove_handlers(struct ril_radio *self, gulong *ids, int count)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int radio_state;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &radio_state)) {
|
||||
return radio_state;
|
||||
} else {
|
||||
ofono_error("Error parsing radio state");
|
||||
return RADIO_STATE_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
|
||||
if (radio_state != RADIO_STATE_UNAVAILABLE) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s%s", priv->log_prefix,
|
||||
ril_radio_state_to_string(radio_state));
|
||||
GASSERT(!priv->pending_id || !priv->retry_id);
|
||||
|
||||
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
|
||||
DBG("%sswitched off for power cycle", priv->log_prefix);
|
||||
priv->power_cycle = FALSE;
|
||||
}
|
||||
|
||||
if (priv->pending_id) {
|
||||
priv->state_changed_while_request_pending++;
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io)
|
||||
{
|
||||
struct ril_radio *self = g_object_new(RIL_RADIO_TYPE, NULL);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->log_prefix =
|
||||
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
|
||||
g_strconcat(io->name, " ", NULL) : g_strdup("");
|
||||
DBG("%s", priv->log_prefix);
|
||||
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_RADIO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_unref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_RADIO(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_init(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_RADIO_TYPE, struct ril_radio_priv);
|
||||
self->priv = priv;
|
||||
priv->req_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static void ril_radio_dispose(GObject *object)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->state_event_id) {
|
||||
grilio_channel_remove_handler(priv->io, priv->state_event_id);
|
||||
priv->state_event_id = 0;
|
||||
}
|
||||
if (priv->pending_id) {
|
||||
grilio_queue_cancel_request(priv->q, priv->pending_id, FALSE);
|
||||
priv->pending_id = 0;
|
||||
}
|
||||
priv->next_state_valid = FALSE;
|
||||
ril_radio_cancel_retry(self);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_radio_finalize(GObject *object)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
g_hash_table_unref(priv->req_table);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_radio_class_init(RilRadioClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_radio_dispose;
|
||||
object_class->finalize = ril_radio_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
|
||||
NEW_SIGNAL(klass, STATE);
|
||||
NEW_SIGNAL(klass, ONLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
55
ofono/drivers/ril/ril_radio.h
Normal file
55
ofono/drivers/ril/ril_radio.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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_RADIO_H
|
||||
#define RIL_RADIO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_radio {
|
||||
GObject object;
|
||||
struct ril_radio_priv *priv;
|
||||
enum ril_radio_state state;
|
||||
gboolean online;
|
||||
};
|
||||
|
||||
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io);
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *radio);
|
||||
void ril_radio_unref(struct ril_radio *radio);
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_cycle(struct ril_radio *radio);
|
||||
void ril_radio_confirm_power_on(struct ril_radio *radio);
|
||||
void ril_radio_set_online(struct ril_radio *radio, gboolean online);
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
|
||||
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
|
||||
|
||||
#endif /* RIL_RADIO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
199
ofono/drivers/ril/ril_radio_settings.c
Normal file
199
ofono/drivers/ril/ril_radio_settings.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ril_radio_settings {
|
||||
struct ofono_radio_settings *rs;
|
||||
struct ril_sim_settings *settings;
|
||||
const char *log_prefix;
|
||||
char *allocated_log_prefix;
|
||||
guint source_id;
|
||||
};
|
||||
|
||||
struct ril_radio_settings_cbd {
|
||||
struct ril_radio_settings *rsd;
|
||||
union _ofono_radio_settings_cb {
|
||||
ofono_radio_settings_rat_mode_set_cb_t rat_mode_set;
|
||||
ofono_radio_settings_rat_mode_query_cb_t rat_mode_query;
|
||||
ofono_radio_settings_available_rats_query_cb_t available_rats;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define DBG_(rsd,fmt,args...) DBG("%s" fmt, (rsd)->log_prefix, ##args)
|
||||
|
||||
static inline struct ril_radio_settings *ril_radio_settings_get_data(
|
||||
struct ofono_radio_settings *rs)
|
||||
{
|
||||
return ofono_radio_settings_get_data(rs);
|
||||
}
|
||||
|
||||
static void ril_radio_settings_later(struct ril_radio_settings *rsd,
|
||||
GSourceFunc fn, void *cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_radio_settings_cbd, 1);
|
||||
cbd->rsd = rsd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
|
||||
GASSERT(!rsd->source_id);
|
||||
rsd->source_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
fn, cbd, g_free);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_set_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_set(ril_error_ok(&error), cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
DBG_(rsd, "%s", ofono_radio_access_mode_to_string(mode));
|
||||
ril_sim_settings_set_pref_mode(rsd->settings, mode);
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_set_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
enum ofono_radio_access_mode mode = rsd->settings->pref_mode;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(rsd, "rat mode %s", ofono_radio_access_mode_to_string(mode));
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_query(ril_error_ok(&error), mode, cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_query_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
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);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_available_rats(
|
||||
struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_query_available_rats_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = user_data;
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
ofono_radio_settings_register(rsd->rs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
|
||||
|
||||
DBG("%s", modem->log_prefix);
|
||||
rsd->rs = rs;
|
||||
rsd->settings = ril_sim_settings_ref(modem->sim_settings);
|
||||
rsd->source_id = g_idle_add(ril_radio_settings_register, rsd);
|
||||
|
||||
if (modem->log_prefix && modem->log_prefix[0]) {
|
||||
rsd->log_prefix = rsd->allocated_log_prefix =
|
||||
g_strconcat(modem->log_prefix, " ", NULL);
|
||||
} else {
|
||||
rsd->log_prefix = "";
|
||||
}
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
if (rsd->source_id) {
|
||||
g_source_remove(rsd->source_id);
|
||||
}
|
||||
ril_sim_settings_unref(rsd->settings);
|
||||
g_free(rsd->allocated_log_prefix);
|
||||
g_free(rsd);
|
||||
}
|
||||
|
||||
const struct ofono_radio_settings_driver ril_radio_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.query_rat_mode = ril_radio_settings_query_rat_mode,
|
||||
.set_rat_mode = ril_radio_settings_set_rat_mode,
|
||||
.query_available_rats = ril_radio_settings_query_available_rats
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
1319
ofono/drivers/ril/ril_sim.c
Normal file
1319
ofono/drivers/ril/ril_sim.c
Normal file
File diff suppressed because it is too large
Load Diff
547
ofono/drivers/ril/ril_sim_card.c
Normal file
547
ofono/drivers/ril/ril_sim_card.c
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* 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_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
typedef GObjectClass RilSimCardClass;
|
||||
typedef struct ril_sim_card RilSimCard;
|
||||
|
||||
enum ril_sim_card_event {
|
||||
EVENT_SIM_STATUS_CHANGED,
|
||||
EVENT_UICC_SUBSCRIPTION_STATUS_CHANGED,
|
||||
EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_card_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
int flags;
|
||||
guint status_req_id;
|
||||
gulong event_id[EVENT_COUNT];
|
||||
};
|
||||
|
||||
enum ril_sim_card_signal {
|
||||
SIGNAL_STATUS_RECEIVED,
|
||||
SIGNAL_STATUS_CHANGED,
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_APP_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"
|
||||
|
||||
static guint ril_sim_card_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
|
||||
#define RIL_SIMCARD_TYPE (ril_sim_card_get_type())
|
||||
#define RIL_SIMCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_SIMCARD_TYPE, RilSimCard))
|
||||
|
||||
#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)
|
||||
{
|
||||
if (a1 == a2) {
|
||||
return TRUE;
|
||||
} else if (!a1 || !a2) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return a1->app_type == a2->app_type &&
|
||||
a1->app_state == a2->app_state &&
|
||||
a1->perso_substate == a2->perso_substate &&
|
||||
a1->pin_replaced == a2->pin_replaced &&
|
||||
a1->pin1_state == a2->pin1_state &&
|
||||
a1->pin2_state == a2->pin2_state &&
|
||||
!g_strcmp0(a1->aid, a2->aid) &&
|
||||
!g_strcmp0(a1->label, a2->label);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_sim_card_status_compare(const struct ril_sim_card_status *s1,
|
||||
const struct ril_sim_card_status *s2)
|
||||
{
|
||||
if (s1 == s2) {
|
||||
return 0;
|
||||
} else if (!s1 || !s2) {
|
||||
return RIL_SIMCARD_STATE_CHANGED | RIL_SIMCARD_STATUS_CHANGED;
|
||||
} else {
|
||||
int diff = 0;
|
||||
|
||||
if (s1->card_state != s2->card_state) {
|
||||
diff |= RIL_SIMCARD_STATE_CHANGED;
|
||||
}
|
||||
|
||||
if (s1->pin_state != s2->pin_state ||
|
||||
s1->gsm_umts_index != s2->gsm_umts_index ||
|
||||
s1->cdma_index != s2->cdma_index ||
|
||||
s1->ims_index != s2->ims_index ||
|
||||
s1->num_apps != s2->num_apps) {
|
||||
diff |= RIL_SIMCARD_STATUS_CHANGED;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s1->num_apps; i++) {
|
||||
if (!ril_sim_card_app_equal(s1->apps + i,
|
||||
s2->apps + i)) {
|
||||
diff |= RIL_SIMCARD_STATUS_CHANGED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_status_free(struct ril_sim_card_status *status)
|
||||
{
|
||||
if (status) {
|
||||
if (status->apps) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < status->num_apps; i++) {
|
||||
g_free(status->apps[i].aid);
|
||||
g_free(status->apps[i].label);
|
||||
}
|
||||
g_free(status->apps);
|
||||
}
|
||||
g_free(status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self,
|
||||
int app_index, int sub_status)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||
const guint sub_id = self->slot;
|
||||
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_status);
|
||||
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 &&
|
||||
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
|
||||
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
|
||||
RIL_REQUEST_SET_UICC_SUBSCRIPTION);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
|
||||
{
|
||||
int selected_app = -1;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < status->num_apps; i++) {
|
||||
const int type = status->apps[i].app_type;
|
||||
if (type == RIL_APPTYPE_USIM || type == RIL_APPTYPE_RUIM) {
|
||||
selected_app = i;
|
||||
break;
|
||||
} else if (type != RIL_APPTYPE_UNKNOWN && selected_app == -1) {
|
||||
selected_app = i;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("%d", selected_app);
|
||||
return selected_app;
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
{
|
||||
const struct ril_sim_card_app *old_app = self->app;
|
||||
const struct ril_sim_card_status *status = self->status;
|
||||
int app_index;
|
||||
|
||||
if (status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
if (status->gsm_umts_index >= 0 &&
|
||||
status->gsm_umts_index < status->num_apps) {
|
||||
app_index = status->gsm_umts_index;
|
||||
} else {
|
||||
app_index = ril_sim_card_select_app(status);
|
||||
if (app_index >= 0) {
|
||||
ril_sim_card_subscribe(self, app_index, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app_index = -1;
|
||||
}
|
||||
|
||||
if (app_index >= 0 &&
|
||||
status->apps[app_index].app_type != RIL_APPTYPE_UNKNOWN) {
|
||||
self->app = status->apps + app_index;
|
||||
} else {
|
||||
self->app = NULL;
|
||||
}
|
||||
|
||||
if (!ril_sim_card_app_equal(old_app, self->app)) {
|
||||
g_signal_emit(self,
|
||||
ril_sim_card_signals[SIGNAL_APP_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
struct ril_sim_card_status *status)
|
||||
{
|
||||
const int diff = ril_sim_card_status_compare(self->status, status);
|
||||
|
||||
if (diff) {
|
||||
struct ril_sim_card_status *old_status = self->status;
|
||||
|
||||
self->status = status;
|
||||
ril_sim_card_update_app(self);
|
||||
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);
|
||||
}
|
||||
if (diff & RIL_SIMCARD_STATE_CHANGED) {
|
||||
DBG("state changed");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_card_app_parse(GRilIoParser *rilp,
|
||||
struct ril_sim_card_app *app)
|
||||
{
|
||||
gint32 app_type, app_state, perso_substate;
|
||||
gint32 pin_replaced, pin1_state, pin2_state;
|
||||
|
||||
grilio_parser_get_int32(rilp, &app_type);
|
||||
grilio_parser_get_int32(rilp, &app_state);
|
||||
|
||||
/*
|
||||
* Consider RIL_APPSTATE_ILLEGAL also READY. Even if app state is
|
||||
* RIL_APPSTATE_ILLEGAL (-1), ICC operations must be permitted.
|
||||
* Network access requests will anyway be rejected and ME will be
|
||||
* in limited service.
|
||||
*/
|
||||
if (app_state == RIL_APPSTATE_ILLEGAL) {
|
||||
DBG("RIL_APPSTATE_ILLEGAL => RIL_APPSTATE_READY");
|
||||
app_state = RIL_APPSTATE_READY;
|
||||
}
|
||||
|
||||
grilio_parser_get_int32(rilp, &perso_substate);
|
||||
app->aid = grilio_parser_get_utf8(rilp);
|
||||
app->label = grilio_parser_get_utf8(rilp);
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &pin_replaced) &&
|
||||
grilio_parser_get_int32(rilp, &pin1_state) &&
|
||||
grilio_parser_get_int32(rilp, &pin2_state)) {
|
||||
|
||||
app->app_type = app_type;
|
||||
app->app_state = app_state;
|
||||
app->perso_substate = perso_substate;
|
||||
app->pin_replaced = pin_replaced;
|
||||
app->pin1_state = pin1_state;
|
||||
app->pin2_state = pin2_state;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
gint32 card_state, pin_state, gsm_umts_index, cdma_index;
|
||||
gint32 ims_index, num_apps;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
if (!grilio_parser_get_int32(&rilp, &card_state) ||
|
||||
!grilio_parser_get_int32(&rilp, &pin_state) ||
|
||||
!grilio_parser_get_int32(&rilp, &gsm_umts_index) ||
|
||||
!grilio_parser_get_int32(&rilp, &cdma_index) ||
|
||||
!grilio_parser_get_int32(&rilp, &ims_index) ||
|
||||
!grilio_parser_get_int32(&rilp, &num_apps)) {
|
||||
ofono_error("Failed to parse SIM card status request");
|
||||
return NULL;
|
||||
} else if (num_apps < 0 || num_apps > RIL_CARD_MAX_APPS) {
|
||||
ofono_error("Invalid SIM app count %d", num_apps);
|
||||
return NULL;
|
||||
} else {
|
||||
int i;
|
||||
struct ril_sim_card_status *status =
|
||||
g_new0(struct ril_sim_card_status, 1);
|
||||
|
||||
DBG("card_state=%d, universal_pin_state=%d, gsm_umts_index=%d, "
|
||||
"cdma_index=%d, ims_index=%d, num_apps=%d",
|
||||
card_state, pin_state, gsm_umts_index, cdma_index,
|
||||
ims_index, num_apps);
|
||||
|
||||
status->card_state = card_state;
|
||||
status->pin_state = pin_state;
|
||||
status->gsm_umts_index = gsm_umts_index;
|
||||
status->cdma_index = cdma_index;
|
||||
status->ims_index = ims_index;
|
||||
status->num_apps = num_apps;
|
||||
|
||||
if (num_apps > 0) {
|
||||
status->apps = g_new0(struct ril_sim_card_app, num_apps);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_apps; i++) {
|
||||
struct ril_sim_card_app *app = status->apps + i;
|
||||
|
||||
if (ril_sim_card_app_parse(&rilp, app)) {
|
||||
DBG("app[%d]: type=%d, state=%d, "
|
||||
"perso_substate=%d, aid_ptr=%s, "
|
||||
"label=%s, pin1_replaced=%d, pin1=%d, "
|
||||
"pin2=%d", i, app->app_type,
|
||||
app->app_state, app->perso_substate,
|
||||
app->aid, app->label,
|
||||
app->pin_replaced, app->pin1_state,
|
||||
app->pin2_state);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == num_apps) {
|
||||
return status;
|
||||
} else {
|
||||
ril_sim_card_status_free(status);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->status_req_id);
|
||||
priv->status_req_id = 0;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
struct ril_sim_card_status *status =
|
||||
ril_sim_card_status_parse(data, len);
|
||||
|
||||
if (status) {
|
||||
ril_sim_card_update_status(self, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *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();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags)
|
||||
{
|
||||
struct ril_sim_card *self = g_object_new(RIL_SIMCARD_TYPE, NULL);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* We need to know the RIL version (for UICC subscription hack),
|
||||
* so we must be connected. The caller is supposed to make sure
|
||||
* that we get connected first.
|
||||
*/
|
||||
DBG("%u", slot);
|
||||
GASSERT(io->connected);
|
||||
|
||||
self->slot = slot;
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(io);
|
||||
priv->flags = flags;
|
||||
|
||||
priv->event_id[EVENT_SIM_STATUS_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_sim_card_status_changed,
|
||||
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, self);
|
||||
priv->event_id[EVENT_UICC_SUBSCRIPTION_STATUS_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_sim_card_status_changed,
|
||||
RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, self);
|
||||
ril_sim_card_request_status(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIMCARD(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_unref(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIMCARD(self));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_sim_card_ready(struct ril_sim_card *self)
|
||||
{
|
||||
return self && self->app &&
|
||||
((self->app->app_state == RIL_APPSTATE_READY) ||
|
||||
(self->app->app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO &&
|
||||
self->app->perso_substate == RIL_PERSOSUBSTATE_READY));
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_status_received_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_STATUS_RECEIVED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_status_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_STATUS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_state_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_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_app_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_APP_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)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_remove_handlers(struct ril_sim_card *self, gulong *ids, int n)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, 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);
|
||||
}
|
||||
|
||||
static void ril_sim_card_dispose(GObject *object)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(object);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, priv->event_id, EVENT_COUNT);
|
||||
grilio_queue_cancel_all(priv->q, TRUE);
|
||||
G_OBJECT_CLASS(ril_sim_card_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_sim_card_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(object);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_sim_card_status_free(self->status);
|
||||
G_OBJECT_CLASS(ril_sim_card_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_card_class_init(RilSimCardClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
83
ofono/drivers/ril/ril_sim_card.h
Normal file
83
ofono/drivers/ril/ril_sim_card.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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_SIM_CARD_H
|
||||
#define RIL_SIM_CARD_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_sim_card_app {
|
||||
enum ril_app_type app_type;
|
||||
enum ril_app_state app_state;
|
||||
enum ril_perso_substate perso_substate;
|
||||
char *aid;
|
||||
char *label;
|
||||
guint pin_replaced;
|
||||
enum ril_pin_state pin1_state;
|
||||
enum ril_pin_state pin2_state;
|
||||
};
|
||||
|
||||
struct ril_sim_card_status {
|
||||
enum ril_card_state card_state;
|
||||
enum ril_pin_state pin_state;
|
||||
int gsm_umts_index;
|
||||
int cdma_index;
|
||||
int ims_index;
|
||||
int num_apps;
|
||||
struct ril_sim_card_app *apps;
|
||||
};
|
||||
|
||||
struct ril_sim_card {
|
||||
GObject object;
|
||||
struct ril_sim_card_priv *priv;
|
||||
struct ril_sim_card_status *status;
|
||||
const struct ril_sim_card_app *app;
|
||||
guint slot;
|
||||
};
|
||||
|
||||
typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
||||
|
||||
/* Flags for ril_sim_card_new */
|
||||
#define RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND (0x01)
|
||||
|
||||
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);
|
||||
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);
|
||||
gulong ril_sim_card_add_status_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
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);
|
||||
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);
|
||||
|
||||
/* Inline wrappers */
|
||||
static inline enum ril_app_type
|
||||
ril_sim_card_app_type(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
|
||||
|
||||
#endif /* RIL_SIM_CARD_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
668
ofono/drivers/ril/ril_sim_info.c
Normal file
668
ofono/drivers/ril/ril_sim_info.c
Normal file
@@ -0,0 +1,668 @@
|
||||
/*
|
||||
* 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];
|
||||
int public_spn_block;
|
||||
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;
|
||||
|
||||
GASSERT(priv->public_spn_block >= 0);
|
||||
if (!priv->public_spn_block) {
|
||||
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)) {
|
||||
g_free(priv->cached_spn);
|
||||
if (spn) {
|
||||
DBG_(self, "cached spn \"%s\"", spn);
|
||||
priv->cached_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
} else {
|
||||
priv->cached_spn = NULL;
|
||||
}
|
||||
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) {
|
||||
priv->public_spn_block++;
|
||||
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));
|
||||
} else {
|
||||
DBG_(self, "detached from sim");
|
||||
ril_sim_info_update_default_spn(self);
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
priv->public_spn_block--;
|
||||
ril_sim_info_update_public_spn(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:
|
||||
*/
|
||||
53
ofono/drivers/ril/ril_sim_info.h
Normal file
53
ofono/drivers/ril/ril_sim_info.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
243
ofono/drivers/ril/ril_sim_info_dbus.c
Normal file
243
ofono/drivers/ril/ril_sim_info_dbus.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
319
ofono/drivers/ril/ril_sim_settings.c
Normal file
319
ofono/drivers/ril/ril_sim_settings.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* 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_settings.h"
|
||||
#include "ril_log.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)
|
||||
|
||||
typedef GObjectClass RilSimSettingsClass;
|
||||
typedef struct ril_sim_settings RilSimSettings;
|
||||
|
||||
struct ril_sim_settings_priv {
|
||||
struct ofono_sim *sim;
|
||||
guint imsi_watch_id;
|
||||
guint state_watch_id;
|
||||
GKeyFile *storage;
|
||||
char *imsi;
|
||||
};
|
||||
|
||||
enum ril_sim_settings_signal {
|
||||
SIGNAL_IMSI_CHANGED,
|
||||
SIGNAL_PREF_MODE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-settings-imsi-changed"
|
||||
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-sim-settings-pref-mode-changed"
|
||||
|
||||
static guint ril_sim_settings_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilSimSettings, ril_sim_settings, G_TYPE_OBJECT)
|
||||
#define RIL_SIM_SETTINGS_TYPE (ril_sim_settings_get_type())
|
||||
#define RIL_SIM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_SIM_SETTINGS_TYPE, RilSimSettings))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_sim_settings_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)
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_state_check(struct ril_sim_settings *self,
|
||||
enum ofono_sim_state new_state)
|
||||
{
|
||||
if (new_state != OFONO_SIM_STATE_READY) {
|
||||
ril_sim_settings_set_imsi(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
|
||||
void *user_data)
|
||||
{
|
||||
ril_sim_settings_state_check(RIL_SIM_SETTINGS(user_data), new_state);
|
||||
}
|
||||
|
||||
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);
|
||||
ril_sim_settings_state_check(self,
|
||||
ofono_sim_get_state(sim));
|
||||
/*
|
||||
* ofono_sim_add_imsi_watch immediately
|
||||
* calls the event callback if IMSI is
|
||||
* already known. It's useless though
|
||||
* because we still have to check the
|
||||
* current state in case if IMSI is not
|
||||
* available yet.
|
||||
*/
|
||||
priv->imsi_watch_id =
|
||||
ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_settings_imsi_watch_cb, self,
|
||||
ril_sim_settings_imsi_watch_done);
|
||||
GASSERT(priv->state_watch_id);
|
||||
}
|
||||
/* Luckily, ofono_sim_get_imsi handles NULL pointer */
|
||||
ril_sim_settings_set_imsi(self,
|
||||
ofono_sim_get_imsi(sim));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
|
||||
ril_sim_settings_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_settings_add_pref_mode_changed_handler(
|
||||
struct ril_sim_settings *self,
|
||||
ril_sim_settings_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_settings_remove_handler(struct ril_sim_settings *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_remove_handlers(struct ril_sim_settings *self,
|
||||
gulong *ids, int count)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
|
||||
|
||||
ril_sim_settings_set_ofono_sim(self, NULL);
|
||||
G_OBJECT_CLASS(ril_sim_settings_parent_class)->dispose(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_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, PREF_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
59
ofono/drivers/ril/ril_sim_settings.h
Normal file
59
ofono/drivers/ril/ril_sim_settings.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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_SETTINGS_H
|
||||
#define RIL_SIM_SETTINGS_H
|
||||
|
||||
#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 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_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,
|
||||
ril_sim_settings_cb_t cb, void *arg);
|
||||
gulong ril_sim_settings_add_pref_mode_changed_handler(struct ril_sim_settings *s,
|
||||
ril_sim_settings_cb_t cb, void *arg);
|
||||
void ril_sim_settings_remove_handler(struct ril_sim_settings *s, gulong id);
|
||||
void ril_sim_settings_remove_handlers(struct ril_sim_settings *s, gulong *ids,
|
||||
int count);
|
||||
|
||||
#endif /* RIL_SIM_SETTINGS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
516
ofono/drivers/ril/ril_sms.c
Normal file
516
ofono/drivers/ril/ril_sms.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
#include "simutil.h"
|
||||
|
||||
#define RIL_SMS_ACK_RETRY_MS 1000
|
||||
#define RIL_SMS_ACK_RETRY_COUNT 10
|
||||
|
||||
#define SIM_EFSMS_FILEID 0x6F3C
|
||||
#define EFSMS_LENGTH 176
|
||||
|
||||
#define TYPE_LOCAL 129
|
||||
#define TYPE_INTERNATIONAL 145
|
||||
|
||||
static unsigned char sim_path[4] = {0x3F, 0x00, 0x7F, 0x10};
|
||||
|
||||
enum ril_sms_events {
|
||||
SMS_EVENT_NEW_SMS,
|
||||
SMS_EVENT_NEW_STATUS_REPORT,
|
||||
SMS_EVENT_NEW_SMS_ON_SIM,
|
||||
SMS_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sms {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_modem *modem;
|
||||
struct ofono_sms *sms;
|
||||
struct ofono_sim_context *sim_context;
|
||||
gulong event_id[SMS_EVENT_COUNT];
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_sms_cbd {
|
||||
union _ofono_sms_cb {
|
||||
ofono_sms_sca_set_cb_t sca_set;
|
||||
ofono_sms_sca_query_cb_t sca_query;
|
||||
ofono_sms_submit_cb_t submit;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct ril_sms_on_sim_req {
|
||||
struct ril_sms *sd;
|
||||
int record;
|
||||
};
|
||||
|
||||
#define ril_sms_cbd_free g_free
|
||||
#define ril_sms_on_sim_req_free g_free
|
||||
|
||||
static inline struct ril_sms *ril_sms_get_data(struct ofono_sms *sms)
|
||||
{
|
||||
return ofono_sms_get_data(sms);
|
||||
}
|
||||
|
||||
struct ril_sms_cbd *ril_sms_cbd_new(struct ril_sms *sd, void *cb, void *data)
|
||||
{
|
||||
struct ril_sms_cbd *cbd = g_new0(struct ril_sms_cbd, 1);
|
||||
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
struct ril_sms_on_sim_req *ril_sms_on_sim_req_new(struct ril_sms *sd, int rec)
|
||||
{
|
||||
struct ril_sms_on_sim_req *cbd = g_new0(struct ril_sms_on_sim_req, 1);
|
||||
|
||||
cbd->sd = sd;
|
||||
cbd->record = rec;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_sms_sca_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_sms_cbd *cbd = user_data;
|
||||
ofono_sms_sca_set_cb_t cb = cbd->cb.sca_set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("csca setting failed");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sms_sca_set(struct ofono_sms *sms,
|
||||
const struct ofono_phone_number *sca,
|
||||
ofono_sms_sca_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 4];
|
||||
|
||||
if (sca->type == TYPE_LOCAL) {
|
||||
snprintf(number, sizeof(number), "\"%s\"", sca->number);
|
||||
} else {
|
||||
snprintf(number, sizeof(number), "\"+%s\"", sca->number);
|
||||
}
|
||||
|
||||
DBG("Setting sca: %s", number);
|
||||
grilio_request_append_utf8(req, number);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SET_SMSC_ADDRESS, ril_sms_sca_set_cb,
|
||||
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_sca_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms_cbd *cbd = user_data;
|
||||
ofono_sms_sca_query_cb_t cb = cbd->cb.sca_query;
|
||||
struct ofono_error error;
|
||||
GRilIoParser rilp;
|
||||
gchar *temp_buf;
|
||||
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("csca query failed");
|
||||
cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
temp_buf = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
if (temp_buf) {
|
||||
/* RIL gives address in quotes */
|
||||
gchar *number = strtok(temp_buf, "\"");
|
||||
struct ofono_phone_number sca;
|
||||
|
||||
strncpy(sca.number, number, OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
if (sca.number[0] == '+') {
|
||||
number = number + 1;
|
||||
sca.type = TYPE_INTERNATIONAL;
|
||||
} else {
|
||||
sca.type = TYPE_LOCAL;
|
||||
}
|
||||
|
||||
DBG("csca_query_cb: %s, %d", sca.number, sca.type);
|
||||
cb(ril_error_ok(&error), &sca, cbd->data);
|
||||
g_free(temp_buf);
|
||||
} else {
|
||||
ofono_error("return value invalid");
|
||||
cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sms_sca_query(struct ofono_sms *sms,
|
||||
ofono_sms_sca_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
|
||||
DBG("Sending csca_query");
|
||||
grilio_queue_send_request_full(sd->q, NULL,
|
||||
RIL_REQUEST_GET_SMSC_ADDRESS, ril_sms_sca_query_cb,
|
||||
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_sms_submit_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms_cbd *cbd = user_data;
|
||||
ofono_sms_submit_cb_t cb = cbd->cb.submit;
|
||||
struct ofono_error error;
|
||||
int mr = 0;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int err = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* TP-Message-Reference for GSM/
|
||||
* BearerData MessageId for CDMA
|
||||
*/
|
||||
grilio_parser_get_int32(&rilp, &mr);
|
||||
grilio_parser_skip_string(&rilp);
|
||||
|
||||
/* error: 3GPP 27.005, 3.2.5, -1 if unknown or not applicable */
|
||||
grilio_parser_get_int32(&rilp, &err);
|
||||
DBG("sms msg ref: %d, error: %d", mr, err);
|
||||
ril_error_init_ok(&error);
|
||||
} else if (status == RIL_E_GENERIC_FAILURE) {
|
||||
ofono_info("not allowed by MO SMS control, do not retry");
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
error.error = 500;
|
||||
} else {
|
||||
ofono_error("sms sending failed, retry");
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
cb(&error, mr, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sms_submit(struct ofono_sms *sms, const unsigned char *pdu,
|
||||
int pdu_len, int tpdu_len, int mms,
|
||||
ofono_sms_submit_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
int smsc_len;
|
||||
char *tpdu;
|
||||
|
||||
DBG("pdu_len: %d, tpdu_len: %d mms: %d", pdu_len, tpdu_len, mms);
|
||||
|
||||
grilio_request_append_int32(req, 2); /* Number of strings */
|
||||
|
||||
/* SMSC address:
|
||||
*
|
||||
* smsc_len == 1, then zero-length SMSC was spec'd
|
||||
* RILD expects a NULL string in this case instead
|
||||
* of a zero-length string.
|
||||
*/
|
||||
smsc_len = pdu_len - tpdu_len;
|
||||
if (smsc_len > 1) {
|
||||
/* TODO: encode SMSC & write to parcel */
|
||||
DBG("SMSC address specified (smsc_len %d); NOT-IMPLEMENTED",
|
||||
smsc_len);
|
||||
}
|
||||
|
||||
grilio_request_append_utf8(req, NULL); /* default SMSC address */
|
||||
|
||||
/* TPDU:
|
||||
*
|
||||
* 'pdu' is a raw hexadecimal string
|
||||
* encode_hex() turns it into an ASCII/hex UTF8 buffer
|
||||
* grilio_request_append_utf8() encodes utf8 -> utf16
|
||||
*/
|
||||
tpdu = encode_hex(pdu + smsc_len, tpdu_len, 0);
|
||||
grilio_request_append_utf8(req, tpdu);
|
||||
|
||||
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));
|
||||
grilio_request_unref(req);
|
||||
g_free(tpdu);
|
||||
}
|
||||
|
||||
static void ril_ack_delivery_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("SMS acknowledgement failed: "
|
||||
"Further SMS reception is not guaranteed");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ack_delivery(struct ril_sms *sd, gboolean error)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(12);
|
||||
const int code = (error ? 0 : 0xff);
|
||||
|
||||
DBG("(%d,%d)", error, code);
|
||||
grilio_request_append_int32(req, 2); /* Array size*/
|
||||
grilio_request_append_int32(req, error); /* Success (1)/Failure (0) */
|
||||
grilio_request_append_int32(req, code); /* error code */
|
||||
|
||||
/* ACK the incoming NEW_SMS */
|
||||
grilio_request_set_retry(req, RIL_SMS_ACK_RETRY_MS,
|
||||
RIL_SMS_ACK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SMS_ACKNOWLEDGE, ril_ack_delivery_cb, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms *sd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *ril_pdu;
|
||||
int ril_pdu_len;
|
||||
unsigned int smsc_len;
|
||||
long ril_buf_len;
|
||||
guchar *ril_data;
|
||||
|
||||
ril_pdu = NULL;
|
||||
ril_data = NULL;
|
||||
|
||||
DBG("event: %d; data_len: %d", ril_event, len);
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
ril_pdu = grilio_parser_get_utf8(&rilp);
|
||||
if (ril_pdu == NULL)
|
||||
goto error;
|
||||
|
||||
ril_pdu_len = strlen(ril_pdu);
|
||||
|
||||
DBG("ril_pdu_len is %d", ril_pdu_len);
|
||||
ril_data = decode_hex(ril_pdu, ril_pdu_len, &ril_buf_len, -1);
|
||||
if (ril_data == NULL)
|
||||
goto error;
|
||||
|
||||
/* The first octect in the pdu contains the SMSC address length
|
||||
* which is the X following octects it reads. We add 1 octet to
|
||||
* the read length to take into account this read octet in order
|
||||
* to calculate the proper tpdu length.
|
||||
*/
|
||||
smsc_len = ril_data[0] + 1;
|
||||
ofono_info("sms received, smsc_len is %d", smsc_len);
|
||||
DBG("(%s)", ril_pdu);
|
||||
|
||||
if (ril_event == RIL_UNSOL_RESPONSE_NEW_SMS) {
|
||||
/* Last parameter is 'tpdu_len' ( substract SMSC length ) */
|
||||
ofono_sms_deliver_notify(sd->sms, ril_data, ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
} else {
|
||||
GASSERT(ril_event == RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT);
|
||||
ofono_sms_status_notify(sd->sms, ril_data, ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
}
|
||||
|
||||
g_free(ril_pdu);
|
||||
g_free(ril_data);
|
||||
ril_ack_delivery(sd, TRUE);
|
||||
return;
|
||||
|
||||
error:
|
||||
g_free(ril_pdu);
|
||||
g_free(ril_data);
|
||||
ril_ack_delivery(sd, FALSE);
|
||||
ofono_error("Unable to parse NEW_SMS notification");
|
||||
}
|
||||
|
||||
static void ril_new_sms_on_sim_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DBG("%d", status);
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ofono_info("sms deleted from sim");
|
||||
} else {
|
||||
ofono_error("deleting sms from sim failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_request_delete_sms_om_sim(struct ril_sms *sd, int record)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG("Deleting record: %d", record);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Array length */
|
||||
grilio_request_append_int32(req, record);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_DELETE_SMS_ON_SIM,
|
||||
ril_new_sms_on_sim_cb, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_on_sim_cb(int ok, int total_length, int record,
|
||||
const unsigned char *sdata, int length, void *userdata)
|
||||
{
|
||||
struct ril_sms_on_sim_req *cbd = userdata;
|
||||
struct ril_sms *sd = cbd->sd;
|
||||
|
||||
/*
|
||||
* It seems when reading EFsms RIL returns the whole record including
|
||||
* the first status byte therefore we ignore that as we are only
|
||||
* interested of the following pdu
|
||||
*/
|
||||
/* The first octect in the pdu contains the SMSC address length
|
||||
* which is the X following octects it reads. We add 1 octet to
|
||||
* the read length to take into account this read octet in order
|
||||
* to calculate the proper tpdu length.
|
||||
*/
|
||||
if (ok) {
|
||||
unsigned int smsc_len = sdata[1] + 1;
|
||||
ofono_sms_deliver_notify(sd->sms, sdata + 1, length - 1,
|
||||
length - smsc_len - 1);
|
||||
ril_request_delete_sms_om_sim(sd, cbd->record);
|
||||
} else {
|
||||
ofono_error("cannot read sms from sim");
|
||||
}
|
||||
|
||||
ril_sms_on_sim_req_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_sms_on_sim(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms *sd = user_data;
|
||||
struct ofono_sim *sim = ril_modem_ofono_sim(sd->modem);
|
||||
int data_len = 0, rec = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
ofono_info("new sms on sim");
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (sim &&
|
||||
grilio_parser_get_int32(&rilp, &data_len) && data_len > 0 &&
|
||||
grilio_parser_get_int32(&rilp, &rec)) {
|
||||
DBG("rec %d", rec);
|
||||
if (sd->sim_context) {
|
||||
ofono_sim_read_record(sd->sim_context,
|
||||
SIM_EFSMS_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
rec, EFSMS_LENGTH,
|
||||
sim_path, sizeof(sim_path),
|
||||
ril_sms_on_sim_cb,
|
||||
ril_sms_on_sim_req_new(sd,rec));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sms_register(gpointer user_data)
|
||||
{
|
||||
struct ril_sms *sd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(sd->timer_id);
|
||||
sd->timer_id = 0;
|
||||
ofono_sms_register(sd->sms);
|
||||
|
||||
/* Register event handlers */
|
||||
sd->event_id[SMS_EVENT_NEW_SMS] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_notify,
|
||||
RIL_UNSOL_RESPONSE_NEW_SMS, sd);
|
||||
sd->event_id[SMS_EVENT_NEW_STATUS_REPORT] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_notify,
|
||||
RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, sd);
|
||||
sd->event_id[SMS_EVENT_NEW_SMS_ON_SIM] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_on_sim,
|
||||
RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, sd);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ofono_sim *sim = ril_modem_ofono_sim(modem);
|
||||
struct ril_sms *sd = g_new0(struct ril_sms, 1);
|
||||
|
||||
sd->modem = modem;
|
||||
sd->sms = sms;
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->sim_context = ofono_sim_context_create(sim);
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
sd->timer_id = g_idle_add(ril_sms_register, sd);
|
||||
ofono_sms_set_data(sms, sd);
|
||||
|
||||
GASSERT(sd->sim_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_sms_remove(struct ofono_sms *sms)
|
||||
{
|
||||
int i;
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
|
||||
DBG("");
|
||||
ofono_sms_set_data(sms, NULL);
|
||||
|
||||
if (sd->sim_context) {
|
||||
ofono_sim_context_free(sd->sim_context);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(sd->event_id); i++) {
|
||||
grilio_channel_remove_handler(sd->io, sd->event_id[i]);
|
||||
|
||||
}
|
||||
|
||||
if (sd->timer_id > 0) {
|
||||
g_source_remove(sd->timer_id);
|
||||
}
|
||||
|
||||
grilio_channel_unref(sd->io);
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_unref(sd->q);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
const struct ofono_sms_driver ril_sms_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_sms_probe,
|
||||
.remove = ril_sms_remove,
|
||||
.sca_query = ril_sms_sca_query,
|
||||
.sca_set = ril_sms_sca_set,
|
||||
.submit = ril_sms_submit,
|
||||
.bearer_query = NULL, /* FIXME: needs investigation. */
|
||||
.bearer_set = NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
303
ofono/drivers/ril/ril_stk.c
Normal file
303
ofono/drivers/ril/ril_stk.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#ifndef UI_LANG
|
||||
# define UI_LANG "/var/lib/environment/nemo/locale.conf"
|
||||
#endif
|
||||
|
||||
enum ril_stk_events {
|
||||
STK_EVENT_PROACTIVE_COMMAND,
|
||||
STK_EVENT_SESSION_END,
|
||||
STK_EVENT_NOTIFY,
|
||||
STK_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_stk {
|
||||
struct ofono_stk *stk;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gulong event_id[STK_EVENT_COUNT];
|
||||
};
|
||||
|
||||
struct ril_stk_cbd {
|
||||
union _ofono_stk_cb {
|
||||
ofono_stk_envelope_cb_t envelope;
|
||||
ofono_stk_generic_cb_t generic;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_stk_cbd_free g_free
|
||||
|
||||
static inline struct ril_stk *ril_stk_get_data(struct ofono_stk *stk)
|
||||
{
|
||||
return ofono_stk_get_data(stk);
|
||||
}
|
||||
|
||||
struct ril_stk_cbd *ril_stk_cbd_new(void *cb, void *data)
|
||||
{
|
||||
struct ril_stk_cbd *cbd = g_new0(struct ril_stk_cbd, 1);
|
||||
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_stk_envelope_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_stk_cbd *cbd = user_data;
|
||||
ofono_stk_envelope_cb_t cb = cbd->cb.envelope;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
DBG("%u bytes(s)", len);
|
||||
cb(ril_error_ok(&error), NULL, 0, cbd->data);
|
||||
} else {
|
||||
DBG("Envelope reply failure: %s", ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), NULL, 0, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_stk_envelope(struct ofono_stk *stk, int length,
|
||||
const unsigned char *cmd, ofono_stk_envelope_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char *hex_envelope = encode_hex(cmd, length, 0);
|
||||
|
||||
DBG("%s", hex_envelope);
|
||||
grilio_request_append_utf8(req, hex_envelope);
|
||||
g_free(hex_envelope);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND,
|
||||
ril_stk_envelope_cb, ril_stk_cbd_free,
|
||||
ril_stk_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_stk_terminal_response_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_stk_cbd *cbd = user_data;
|
||||
ofono_stk_generic_cb_t cb = cbd->cb.generic;
|
||||
|
||||
DBG("");
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Error in sending terminal response");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_stk_terminal_response(struct ofono_stk *stk, int length,
|
||||
const unsigned char *resp,
|
||||
ofono_stk_generic_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char *hex_tr = encode_hex(resp, length, 0);
|
||||
|
||||
DBG("rilmodem terminal response: %s", hex_tr);
|
||||
grilio_request_append_utf8(req, hex_tr);
|
||||
g_free(hex_tr);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE,
|
||||
ril_stk_terminal_response_cb,
|
||||
ril_stk_cbd_free, ril_stk_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_stk_user_confirmation(struct ofono_stk *stk,
|
||||
ofono_bool_t confirm)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG("%d", confirm);
|
||||
grilio_request_append_int32(req, 1); /* size of array */
|
||||
grilio_request_append_int32(req, confirm); /* yes/no */
|
||||
|
||||
grilio_queue_send_request(sd->q, req,
|
||||
RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_stk_pcmd_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint data_len, void *user_data)
|
||||
{
|
||||
struct ril_stk *sd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *pcmd;
|
||||
guchar *pdu;
|
||||
long len = 0;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_STK_PROACTIVE_COMMAND);
|
||||
grilio_parser_init(&rilp, data, data_len);
|
||||
pcmd = grilio_parser_get_utf8(&rilp);
|
||||
DBG("pcmd: %s", pcmd);
|
||||
|
||||
pdu = decode_hex(pcmd, strlen(pcmd), &len, -1);
|
||||
g_free(pcmd);
|
||||
|
||||
ofono_stk_proactive_command_notify(sd->stk, len, pdu);
|
||||
g_free(pdu);
|
||||
}
|
||||
|
||||
static void ril_stk_event_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint data_len, void *user_data)
|
||||
{
|
||||
struct ril_stk *sd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *pcmd = NULL;
|
||||
guchar *pdu = NULL;
|
||||
long len;
|
||||
|
||||
/* Proactive command has been handled by the modem. */
|
||||
GASSERT(code == RIL_UNSOL_STK_EVENT_NOTIFY);
|
||||
grilio_parser_init(&rilp, data, data_len);
|
||||
pcmd = grilio_parser_get_utf8(&rilp);
|
||||
DBG("pcmd: %s", pcmd);
|
||||
pdu = decode_hex(pcmd, strlen(pcmd), &len, -1);
|
||||
g_free(pcmd);
|
||||
|
||||
ofono_stk_proactive_command_handled_notify(sd->stk, len, pdu);
|
||||
g_free(pdu);
|
||||
}
|
||||
|
||||
static void ril_stk_session_end_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_stk *sd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(code == RIL_UNSOL_STK_SESSION_END);
|
||||
ofono_stk_proactive_session_end_notify(sd->stk);
|
||||
}
|
||||
|
||||
static void ril_stk_agent_ready(struct ofono_stk *stk)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
|
||||
DBG("");
|
||||
if (!sd->event_id[STK_EVENT_PROACTIVE_COMMAND]) {
|
||||
DBG("Subscribing notifications");
|
||||
sd->event_id[STK_EVENT_PROACTIVE_COMMAND] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_stk_pcmd_notify,
|
||||
RIL_UNSOL_STK_PROACTIVE_COMMAND, sd);
|
||||
|
||||
GASSERT(!sd->event_id[STK_EVENT_SESSION_END]);
|
||||
sd->event_id[STK_EVENT_SESSION_END] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_stk_session_end_notify,
|
||||
RIL_UNSOL_STK_SESSION_END, sd);
|
||||
|
||||
GASSERT(!sd->event_id[STK_EVENT_NOTIFY]);
|
||||
sd->event_id[STK_EVENT_NOTIFY] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_stk_event_notify,
|
||||
RIL_UNSOL_STK_EVENT_NOTIFY, sd);
|
||||
|
||||
grilio_queue_send_request(sd->q, NULL,
|
||||
RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_stk_set_lang()
|
||||
{
|
||||
GError *error = NULL;
|
||||
GIOChannel* chan = g_io_channel_new_file(UI_LANG, "r", &error);
|
||||
if (chan) {
|
||||
GString* buf = g_string_new(NULL);
|
||||
gsize term;
|
||||
while (g_io_channel_read_line_string(chan, buf, &term, NULL) ==
|
||||
G_IO_STATUS_NORMAL) {
|
||||
char* lang;
|
||||
g_string_set_size(buf, term);
|
||||
lang = strstr(buf->str, "LANG=");
|
||||
if (lang) {
|
||||
setenv("LANG", lang + 5, TRUE);
|
||||
}
|
||||
}
|
||||
g_string_free(buf, TRUE);
|
||||
g_io_channel_unref(chan);
|
||||
} else {
|
||||
DBG("%s: %s", UI_LANG, error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_stk *sd = g_new0(struct ril_stk, 1);
|
||||
|
||||
DBG("");
|
||||
sd->stk = stk;
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
|
||||
ofono_stk_set_data(stk, sd);
|
||||
ofono_stk_register(stk);
|
||||
ril_stk_set_lang();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_stk_remove(struct ofono_stk *stk)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
ofono_stk_set_data(stk, NULL);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(sd->event_id); i++) {
|
||||
grilio_channel_remove_handler(sd->io, sd->event_id[i]);
|
||||
}
|
||||
|
||||
grilio_channel_unref(sd->io);
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_unref(sd->q);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
const struct ofono_stk_driver ril_stk_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_stk_probe,
|
||||
.remove = ril_stk_remove,
|
||||
.envelope = ril_stk_envelope,
|
||||
.terminal_response = ril_stk_terminal_response,
|
||||
.user_confirmation = ril_stk_user_confirmation,
|
||||
.ready = ril_stk_agent_ready
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
144
ofono/drivers/ril/ril_subscription.conf
Normal file
144
ofono/drivers/ril/ril_subscription.conf
Normal file
@@ -0,0 +1,144 @@
|
||||
# This is a sample configuration file for Jolla ril driver
|
||||
#
|
||||
# This file is expected to be installed in /etc/ofono
|
||||
#
|
||||
# Configuration for each modem is defined in its own [ril_x] section,
|
||||
# common settings are in the [Settings] section, all other sections
|
||||
# are ignored.
|
||||
#
|
||||
# If any value from [ril_x] section (except "socket") is defined
|
||||
# in the [Settings] section, it becomes the default for all modems.
|
||||
# Default values can still be redefined at [ril_x] level.
|
||||
#
|
||||
|
||||
[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
|
||||
|
||||
# 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
|
||||
# currently using 3G/LTE has to drop to GSM, release 3G/LTE module
|
||||
# and only then 3G/LTE can be used by the other modem. This setting
|
||||
# allows to disable this behaviour (say, if your phone has independent
|
||||
# 3G/LTE modules for each slot or you don't need 4G for both slots).
|
||||
# Obviously, it only has any effect if you have more than one SIM.
|
||||
#
|
||||
# Default is true (switch the current data modem to 2G when changing
|
||||
# the data modems)
|
||||
#
|
||||
#3GLTEHandover=true
|
||||
|
||||
[ril_0]
|
||||
|
||||
# Required entry, defines the RIL socket path
|
||||
socket=/dev/socket/rild
|
||||
|
||||
# Subscription string. Some (mostly, older) RILs require that 4 bytes
|
||||
# (usually SUB1 or SUB2) are written to the socket before rild starts
|
||||
# talking to us.
|
||||
#
|
||||
# Not sent by default.
|
||||
#
|
||||
#sub=SUB1
|
||||
|
||||
# RIL logging prefix, to tell one socket from another in the log.
|
||||
# Makes sense if you have more than one modem configured.
|
||||
#
|
||||
# No prefix by default.
|
||||
#
|
||||
#name=RIL1
|
||||
|
||||
# Slot id for SET_UICC_SUBSCRIPTION request.
|
||||
#
|
||||
# By default the first modem becomes slot 0, the next one slot 1 and so on.
|
||||
#
|
||||
#slot=0
|
||||
|
||||
# RIL request timeout, in milliseconds.
|
||||
#
|
||||
# The default is zero (no timeout)
|
||||
#
|
||||
#timeout=0
|
||||
|
||||
# Setting this one to false would disable 4G technology selection.
|
||||
#
|
||||
# By default 4G is enabled
|
||||
#
|
||||
#enable4G=true
|
||||
|
||||
# RIL_REQUEST_SET_UICC_SUBSCRIPTION is 115 in RIL version 9 (or earlier)
|
||||
# and 122 in RIL version 10 and later. Since ofono doesn't know in advance
|
||||
# which RIL version it's dealing with, it makes the decision at runtime.
|
||||
# Settings it to false disables the workaround and always sends 122.
|
||||
#
|
||||
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
|
||||
#
|
||||
#uiccWorkaround=true
|
||||
|
||||
# Points to the file containing comma-separated ECC (Emergency List Codes)
|
||||
# list, e.g. 911,112,*911,#911. The file is tracked by ofono and when its
|
||||
# contents changes, it's reflected in the EmergencyNumbers property of
|
||||
# org.ofono.VoiceCallManager.
|
||||
#
|
||||
# If necessary, the contents of the file can be synchronized with the
|
||||
# Android system property by adding something like this to /init.rc:
|
||||
#
|
||||
# on property:ril.ecclist=*
|
||||
# write /var/lib/ofono/ril.ecclist ${ril.ecclist}
|
||||
# chmod 0644 /var/lib/ofono/ril.ecclist
|
||||
#
|
||||
#ecclistFile=/var/lib/ofono/ril.ecclist
|
||||
|
||||
# RIL_REQUEST_ALLOW_DATA may or may not be supported by your RIL.
|
||||
# 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)
|
||||
#
|
||||
#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
|
||||
66
ofono/drivers/ril/ril_types.h
Normal file
66
ofono/drivers/ril/ril_types.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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_TYPES_H
|
||||
#define RIL_TYPES_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <grilio_types.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ril_constants.h"
|
||||
|
||||
#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;
|
||||
gboolean empty_pin_query;
|
||||
};
|
||||
|
||||
#endif /* RIL_TYPES_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
222
ofono/drivers/ril/ril_ussd.c
Normal file
222
ofono/drivers/ril/ril_ussd.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
|
||||
struct ril_ussd {
|
||||
struct ofono_ussd *ussd;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
struct ril_ussd_cbd {
|
||||
ofono_ussd_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_ussd_cbd_free g_free
|
||||
|
||||
static inline struct ril_ussd *ril_ussd_get_data(struct ofono_ussd *ussd)
|
||||
{
|
||||
return ofono_ussd_get_data(ussd);
|
||||
}
|
||||
|
||||
static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd_cbd *cbd = g_new0(struct ril_ussd_cbd, 1);
|
||||
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* 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,
|
||||
const unsigned char *pdu, int len, ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
enum sms_charset charset;
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
|
||||
ofono_info("send ussd, len:%d", len);
|
||||
if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) {
|
||||
if (charset == SMS_CHARSET_7BIT) {
|
||||
unsigned char unpacked_buf[182];
|
||||
long written = 0;
|
||||
|
||||
unpack_7bit_own_buf(pdu, len, 0, TRUE,
|
||||
sizeof(unpacked_buf)-1, &written, 0,
|
||||
unpacked_buf);
|
||||
|
||||
unpacked_buf[written] = 0;
|
||||
if (written >= 1) {
|
||||
/*
|
||||
* When USSD was packed, additional CR
|
||||
* might have been added (according to
|
||||
* 23.038 6.1.2.3.1). So if the last
|
||||
* character is CR, it should be removed
|
||||
* here.
|
||||
*
|
||||
* Over 2 characters long USSD string must
|
||||
* end with # (checked in valid_ussd_string),
|
||||
* so it should be safe to remove extra CR.
|
||||
*/
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
int length = strlen((char *)unpacked_buf);
|
||||
while (length > 2 &&
|
||||
unpacked_buf[length-1] == '\r') {
|
||||
unpacked_buf[--length] = 0;
|
||||
}
|
||||
grilio_request_append_utf8_chars(req, (char*)
|
||||
unpacked_buf, length);
|
||||
grilio_queue_send_request(ud->q, req,
|
||||
RIL_REQUEST_SEND_USSD);
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
|
||||
static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
|
||||
ril_ussd_cancel_cb, ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(cb, data));
|
||||
}
|
||||
|
||||
static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_ussd *ud = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *type;
|
||||
guint32 n = 0;
|
||||
|
||||
ofono_info("ussd received");
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_uint32(&rilp, &n);
|
||||
type = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
if (type) {
|
||||
int ussdtype = g_ascii_xdigit_value(*type);
|
||||
char *msg = (n > 1) ? grilio_parser_get_utf8(&rilp) : NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_ussd_register(gpointer user_data)
|
||||
{
|
||||
struct ril_ussd *ud = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(ud->timer_id);
|
||||
ud->timer_id = 0;
|
||||
ofono_ussd_register(ud->ussd);
|
||||
|
||||
/* Register for USSD events */
|
||||
ud->event_id = grilio_channel_add_unsol_event_handler(ud->io,
|
||||
ril_ussd_notify, RIL_UNSOL_ON_USSD, ud);
|
||||
|
||||
/* Single-shot */
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_ussd *ud = g_try_new0(struct ril_ussd, 1);
|
||||
|
||||
DBG("");
|
||||
ud->ussd = ussd;
|
||||
ud->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
ud->q = grilio_queue_new(ud->io);
|
||||
ud->timer_id = g_idle_add(ril_ussd_register, ud);
|
||||
ofono_ussd_set_data(ussd, ud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_ussd_remove(struct ofono_ussd *ussd)
|
||||
{
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
|
||||
DBG("");
|
||||
ofono_ussd_set_data(ussd, NULL);
|
||||
|
||||
if (ud->timer_id > 0) {
|
||||
g_source_remove(ud->timer_id);
|
||||
}
|
||||
|
||||
grilio_channel_remove_handler(ud->io, ud->event_id);
|
||||
grilio_channel_unref(ud->io);
|
||||
grilio_queue_cancel_all(ud->q, FALSE);
|
||||
grilio_queue_unref(ud->q);
|
||||
g_free(ud);
|
||||
}
|
||||
|
||||
const struct ofono_ussd_driver ril_ussd_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_ussd_probe,
|
||||
.remove = ril_ussd_remove,
|
||||
.request = ril_ussd_request,
|
||||
.cancel = ril_ussd_cancel
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
388
ofono/drivers/ril/ril_util.c
Normal file
388
ofono/drivers/ril/ril_util.c
Normal file
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
* 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_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "netreg.h"
|
||||
|
||||
const char *ril_error_to_string(int error)
|
||||
{
|
||||
#define RIL_E_(name) case RIL_E_##name: return #name
|
||||
#define GRILIO_E_(name) case GRILIO_STATUS_##name: return "GRILIO_" #name
|
||||
static char unknown[12];
|
||||
switch (error) {
|
||||
case RIL_E_SUCCESS: return "OK";
|
||||
GRILIO_E_(TIMEOUT);
|
||||
GRILIO_E_(CANCELLED);
|
||||
RIL_E_(RADIO_NOT_AVAILABLE);
|
||||
RIL_E_(GENERIC_FAILURE);
|
||||
RIL_E_(PASSWORD_INCORRECT);
|
||||
RIL_E_(SIM_PIN2);
|
||||
RIL_E_(SIM_PUK2);
|
||||
RIL_E_(REQUEST_NOT_SUPPORTED);
|
||||
RIL_E_(CANCELLED);
|
||||
RIL_E_(OP_NOT_ALLOWED_DURING_VOICE_CALL);
|
||||
RIL_E_(OP_NOT_ALLOWED_BEFORE_REG_TO_NW);
|
||||
RIL_E_(SMS_SEND_FAIL_RETRY);
|
||||
RIL_E_(SIM_ABSENT);
|
||||
RIL_E_(SUBSCRIPTION_NOT_AVAILABLE);
|
||||
RIL_E_(MODE_NOT_SUPPORTED);
|
||||
RIL_E_(FDN_CHECK_FAILURE);
|
||||
RIL_E_(ILLEGAL_SIM_OR_ME);
|
||||
RIL_E_(UNUSED);
|
||||
RIL_E_(DIAL_MODIFIED_TO_USSD);
|
||||
RIL_E_(DIAL_MODIFIED_TO_SS);
|
||||
RIL_E_(DIAL_MODIFIED_TO_DIAL);
|
||||
RIL_E_(USSD_MODIFIED_TO_DIAL);
|
||||
RIL_E_(USSD_MODIFIED_TO_SS);
|
||||
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);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "%d", error);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_request_to_string(guint request)
|
||||
{
|
||||
#define RIL_REQUEST_(name) case RIL_REQUEST_##name: return #name
|
||||
static char unknown[24];
|
||||
switch (request) {
|
||||
RIL_REQUEST_(GET_SIM_STATUS);
|
||||
RIL_REQUEST_(ENTER_SIM_PIN);
|
||||
RIL_REQUEST_(ENTER_SIM_PUK);
|
||||
RIL_REQUEST_(ENTER_SIM_PIN2);
|
||||
RIL_REQUEST_(ENTER_SIM_PUK2);
|
||||
RIL_REQUEST_(CHANGE_SIM_PIN);
|
||||
RIL_REQUEST_(CHANGE_SIM_PIN2);
|
||||
RIL_REQUEST_(ENTER_NETWORK_DEPERSONALIZATION);
|
||||
RIL_REQUEST_(GET_CURRENT_CALLS);
|
||||
RIL_REQUEST_(DIAL);
|
||||
RIL_REQUEST_(GET_IMSI);
|
||||
RIL_REQUEST_(HANGUP);
|
||||
RIL_REQUEST_(HANGUP_WAITING_OR_BACKGROUND);
|
||||
RIL_REQUEST_(HANGUP_FOREGROUND_RESUME_BACKGROUND);
|
||||
RIL_REQUEST_(SWITCH_HOLDING_AND_ACTIVE);
|
||||
RIL_REQUEST_(CONFERENCE);
|
||||
RIL_REQUEST_(UDUB);
|
||||
RIL_REQUEST_(LAST_CALL_FAIL_CAUSE);
|
||||
RIL_REQUEST_(SIGNAL_STRENGTH);
|
||||
RIL_REQUEST_(VOICE_REGISTRATION_STATE);
|
||||
RIL_REQUEST_(DATA_REGISTRATION_STATE);
|
||||
RIL_REQUEST_(OPERATOR);
|
||||
RIL_REQUEST_(RADIO_POWER);
|
||||
RIL_REQUEST_(DTMF);
|
||||
RIL_REQUEST_(SEND_SMS);
|
||||
RIL_REQUEST_(SEND_SMS_EXPECT_MORE);
|
||||
RIL_REQUEST_(SETUP_DATA_CALL);
|
||||
RIL_REQUEST_(SIM_IO);
|
||||
RIL_REQUEST_(SEND_USSD);
|
||||
RIL_REQUEST_(CANCEL_USSD);
|
||||
RIL_REQUEST_(GET_CLIR);
|
||||
RIL_REQUEST_(SET_CLIR);
|
||||
RIL_REQUEST_(QUERY_CALL_FORWARD_STATUS);
|
||||
RIL_REQUEST_(SET_CALL_FORWARD);
|
||||
RIL_REQUEST_(QUERY_CALL_WAITING);
|
||||
RIL_REQUEST_(SET_CALL_WAITING);
|
||||
RIL_REQUEST_(SMS_ACKNOWLEDGE);
|
||||
RIL_REQUEST_(GET_IMEI);
|
||||
RIL_REQUEST_(GET_IMEISV);
|
||||
RIL_REQUEST_(ANSWER);
|
||||
RIL_REQUEST_(DEACTIVATE_DATA_CALL);
|
||||
RIL_REQUEST_(QUERY_FACILITY_LOCK);
|
||||
RIL_REQUEST_(SET_FACILITY_LOCK);
|
||||
RIL_REQUEST_(CHANGE_BARRING_PASSWORD);
|
||||
RIL_REQUEST_(QUERY_NETWORK_SELECTION_MODE);
|
||||
RIL_REQUEST_(SET_NETWORK_SELECTION_AUTOMATIC);
|
||||
RIL_REQUEST_(SET_NETWORK_SELECTION_MANUAL);
|
||||
RIL_REQUEST_(QUERY_AVAILABLE_NETWORKS);
|
||||
RIL_REQUEST_(DTMF_START);
|
||||
RIL_REQUEST_(DTMF_STOP);
|
||||
RIL_REQUEST_(BASEBAND_VERSION);
|
||||
RIL_REQUEST_(SEPARATE_CONNECTION);
|
||||
RIL_REQUEST_(SET_MUTE);
|
||||
RIL_REQUEST_(GET_MUTE);
|
||||
RIL_REQUEST_(QUERY_CLIP);
|
||||
RIL_REQUEST_(LAST_DATA_CALL_FAIL_CAUSE);
|
||||
RIL_REQUEST_(DATA_CALL_LIST);
|
||||
RIL_REQUEST_(RESET_RADIO);
|
||||
RIL_REQUEST_(OEM_HOOK_RAW);
|
||||
RIL_REQUEST_(OEM_HOOK_STRINGS);
|
||||
RIL_REQUEST_(SCREEN_STATE);
|
||||
RIL_REQUEST_(SET_SUPP_SVC_NOTIFICATION);
|
||||
RIL_REQUEST_(WRITE_SMS_TO_SIM);
|
||||
RIL_REQUEST_(DELETE_SMS_ON_SIM);
|
||||
RIL_REQUEST_(SET_BAND_MODE);
|
||||
RIL_REQUEST_(QUERY_AVAILABLE_BAND_MODE);
|
||||
RIL_REQUEST_(STK_GET_PROFILE);
|
||||
RIL_REQUEST_(STK_SET_PROFILE);
|
||||
RIL_REQUEST_(STK_SEND_ENVELOPE_COMMAND);
|
||||
RIL_REQUEST_(STK_SEND_TERMINAL_RESPONSE);
|
||||
RIL_REQUEST_(STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM);
|
||||
RIL_REQUEST_(EXPLICIT_CALL_TRANSFER);
|
||||
RIL_REQUEST_(SET_PREFERRED_NETWORK_TYPE);
|
||||
RIL_REQUEST_(GET_PREFERRED_NETWORK_TYPE);
|
||||
RIL_REQUEST_(GET_NEIGHBORING_CELL_IDS);
|
||||
RIL_REQUEST_(SET_LOCATION_UPDATES);
|
||||
RIL_REQUEST_(CDMA_SET_SUBSCRIPTION_SOURCE);
|
||||
RIL_REQUEST_(CDMA_SET_ROAMING_PREFERENCE);
|
||||
RIL_REQUEST_(CDMA_QUERY_ROAMING_PREFERENCE);
|
||||
RIL_REQUEST_(SET_TTY_MODE);
|
||||
RIL_REQUEST_(QUERY_TTY_MODE);
|
||||
RIL_REQUEST_(CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE);
|
||||
RIL_REQUEST_(CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE);
|
||||
RIL_REQUEST_(CDMA_FLASH);
|
||||
RIL_REQUEST_(CDMA_BURST_DTMF);
|
||||
RIL_REQUEST_(CDMA_VALIDATE_AND_WRITE_AKEY);
|
||||
RIL_REQUEST_(CDMA_SEND_SMS);
|
||||
RIL_REQUEST_(CDMA_SMS_ACKNOWLEDGE);
|
||||
RIL_REQUEST_(GSM_GET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(GSM_SET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(GSM_SMS_BROADCAST_ACTIVATION);
|
||||
RIL_REQUEST_(CDMA_GET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(CDMA_SET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(CDMA_SMS_BROADCAST_ACTIVATION);
|
||||
RIL_REQUEST_(CDMA_SUBSCRIPTION);
|
||||
RIL_REQUEST_(CDMA_WRITE_SMS_TO_RUIM);
|
||||
RIL_REQUEST_(CDMA_DELETE_SMS_ON_RUIM);
|
||||
RIL_REQUEST_(DEVICE_IDENTITY);
|
||||
RIL_REQUEST_(EXIT_EMERGENCY_CALLBACK_MODE);
|
||||
RIL_REQUEST_(GET_SMSC_ADDRESS);
|
||||
RIL_REQUEST_(SET_SMSC_ADDRESS);
|
||||
RIL_REQUEST_(REPORT_SMS_MEMORY_STATUS);
|
||||
RIL_REQUEST_(REPORT_STK_SERVICE_IS_RUNNING);
|
||||
RIL_REQUEST_(CDMA_GET_SUBSCRIPTION_SOURCE);
|
||||
RIL_REQUEST_(ISIM_AUTHENTICATION);
|
||||
RIL_REQUEST_(ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU);
|
||||
RIL_REQUEST_(STK_SEND_ENVELOPE_WITH_STATUS);
|
||||
RIL_REQUEST_(VOICE_RADIO_TECH);
|
||||
RIL_REQUEST_(GET_CELL_INFO_LIST);
|
||||
RIL_REQUEST_(SET_UNSOL_CELL_INFO_LIST_RATE);
|
||||
RIL_REQUEST_(SET_INITIAL_ATTACH_APN);
|
||||
RIL_REQUEST_(IMS_REGISTRATION_STATE);
|
||||
RIL_REQUEST_(IMS_SEND_SMS);
|
||||
RIL_REQUEST_(SIM_TRANSMIT_APDU_BASIC);
|
||||
RIL_REQUEST_(SIM_OPEN_CHANNEL);
|
||||
RIL_REQUEST_(SIM_CLOSE_CHANNEL);
|
||||
RIL_REQUEST_(SIM_TRANSMIT_APDU_CHANNEL);
|
||||
RIL_REQUEST_(NV_READ_ITEM);
|
||||
RIL_REQUEST_(NV_WRITE_ITEM);
|
||||
RIL_REQUEST_(NV_WRITE_CDMA_PRL);
|
||||
RIL_REQUEST_(NV_RESET_CONFIG);
|
||||
RIL_REQUEST_(SET_UICC_SUBSCRIPTION);
|
||||
RIL_REQUEST_(ALLOW_DATA);
|
||||
RIL_REQUEST_(GET_HARDWARE_CONFIG);
|
||||
RIL_REQUEST_(SIM_AUTHENTICATION);
|
||||
RIL_REQUEST_(GET_DC_RT_INFO);
|
||||
RIL_REQUEST_(SET_DC_RT_INFO_RATE);
|
||||
RIL_REQUEST_(SET_DATA_PROFILE);
|
||||
RIL_REQUEST_(SHUTDOWN);
|
||||
RIL_REQUEST_(GET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(SET_RADIO_CAPABILITY);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "RIL_REQUEST_%d", request);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_unsol_event_to_string(guint event)
|
||||
{
|
||||
#define RIL_UNSOL_(name) case RIL_UNSOL_##name: return #name
|
||||
static char unknown[24];
|
||||
switch (event) {
|
||||
RIL_UNSOL_(RESPONSE_RADIO_STATE_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_CALL_STATE_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_VOICE_NETWORK_STATE_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_NEW_SMS);
|
||||
RIL_UNSOL_(RESPONSE_NEW_SMS_STATUS_REPORT);
|
||||
RIL_UNSOL_(RESPONSE_NEW_SMS_ON_SIM);
|
||||
RIL_UNSOL_(ON_USSD);
|
||||
RIL_UNSOL_(ON_USSD_REQUEST);
|
||||
RIL_UNSOL_(NITZ_TIME_RECEIVED);
|
||||
RIL_UNSOL_(SIGNAL_STRENGTH);
|
||||
RIL_UNSOL_(DATA_CALL_LIST_CHANGED);
|
||||
RIL_UNSOL_(SUPP_SVC_NOTIFICATION);
|
||||
RIL_UNSOL_(STK_SESSION_END);
|
||||
RIL_UNSOL_(STK_PROACTIVE_COMMAND);
|
||||
RIL_UNSOL_(STK_EVENT_NOTIFY);
|
||||
RIL_UNSOL_(STK_CALL_SETUP);
|
||||
RIL_UNSOL_(SIM_SMS_STORAGE_FULL);
|
||||
RIL_UNSOL_(SIM_REFRESH);
|
||||
RIL_UNSOL_(CALL_RING);
|
||||
RIL_UNSOL_(RESPONSE_SIM_STATUS_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_CDMA_NEW_SMS);
|
||||
RIL_UNSOL_(RESPONSE_NEW_BROADCAST_SMS);
|
||||
RIL_UNSOL_(CDMA_RUIM_SMS_STORAGE_FULL);
|
||||
RIL_UNSOL_(RESTRICTED_STATE_CHANGED);
|
||||
RIL_UNSOL_(ENTER_EMERGENCY_CALLBACK_MODE);
|
||||
RIL_UNSOL_(CDMA_CALL_WAITING);
|
||||
RIL_UNSOL_(CDMA_OTA_PROVISION_STATUS);
|
||||
RIL_UNSOL_(CDMA_INFO_REC);
|
||||
RIL_UNSOL_(OEM_HOOK_RAW);
|
||||
RIL_UNSOL_(RINGBACK_TONE);
|
||||
RIL_UNSOL_(RESEND_INCALL_MUTE);
|
||||
RIL_UNSOL_(CDMA_SUBSCRIPTION_SOURCE_CHANGED);
|
||||
RIL_UNSOL_(CDMA_PRL_CHANGED);
|
||||
RIL_UNSOL_(EXIT_EMERGENCY_CALLBACK_MODE);
|
||||
RIL_UNSOL_(RIL_CONNECTED);
|
||||
RIL_UNSOL_(VOICE_RADIO_TECH_CHANGED);
|
||||
RIL_UNSOL_(CELL_INFO_LIST);
|
||||
RIL_UNSOL_(RESPONSE_IMS_NETWORK_STATE_CHANGED);
|
||||
RIL_UNSOL_(UICC_SUBSCRIPTION_STATUS_CHANGED);
|
||||
RIL_UNSOL_(SRVCC_STATE_NOTIFY);
|
||||
RIL_UNSOL_(HARDWARE_CONFIG_CHANGED);
|
||||
RIL_UNSOL_(DC_RT_INFO_CHANGED);
|
||||
RIL_UNSOL_(RADIO_CAPABILITY);
|
||||
RIL_UNSOL_(ON_SS);
|
||||
RIL_UNSOL_(STK_CC_ALPHA_NOTIFY);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "RIL_UNSOL_%d", event);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_radio_state_to_string(int radio_state)
|
||||
{
|
||||
#define RADIO_STATE_(name) case RADIO_STATE_##name: return #name
|
||||
static char unknown[16];
|
||||
switch (radio_state) {
|
||||
RADIO_STATE_(OFF);
|
||||
RADIO_STATE_(UNAVAILABLE);
|
||||
RADIO_STATE_(SIM_NOT_READY);
|
||||
RADIO_STATE_(SIM_LOCKED_OR_ABSENT);
|
||||
RADIO_STATE_(SIM_READY);
|
||||
RADIO_STATE_(RUIM_NOT_READY);
|
||||
RADIO_STATE_(RUIM_READY);
|
||||
RADIO_STATE_(RUIM_LOCKED_OR_ABSENT);
|
||||
RADIO_STATE_(NV_NOT_READY);
|
||||
RADIO_STATE_(NV_READY);
|
||||
RADIO_STATE_(ON);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "%d (?)", radio_state);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
switch (tech) {
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
access_tech = ACCESS_TECHNOLOGY_GSM;
|
||||
break;
|
||||
case RADIO_TECH_EDGE:
|
||||
access_tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
|
||||
break;
|
||||
case RADIO_TECH_UMTS:
|
||||
access_tech = ACCESS_TECHNOLOGY_UTRAN;
|
||||
break;
|
||||
case RADIO_TECH_HSDPA:
|
||||
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
|
||||
break;
|
||||
case RADIO_TECH_HSUPA:
|
||||
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_HSPA:
|
||||
case RADIO_TECH_HSPAP:
|
||||
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_LTE:
|
||||
access_tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
break;
|
||||
default:
|
||||
DBG("Unknown RIL tech %s", stech);
|
||||
/* no break */
|
||||
case RADIO_TECH_IWLAN:
|
||||
case RADIO_TECH_UNKNOWN:
|
||||
tech = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (ril_tech) {
|
||||
*ril_tech = tech;
|
||||
}
|
||||
return access_tech;
|
||||
}
|
||||
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
{
|
||||
if (str) {
|
||||
int i;
|
||||
const char *ptr = str;
|
||||
|
||||
/* Three digit country code */
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MCC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mcc[i] = *ptr++;
|
||||
}
|
||||
op->mcc[i] = 0;
|
||||
|
||||
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);
|
||||
i++) {
|
||||
op->mnc[i] = *ptr++;
|
||||
}
|
||||
op->mnc[i] = 0;
|
||||
|
||||
if (i > 0) {
|
||||
|
||||
/*
|
||||
* Sometimes MCC/MNC are followed by + and
|
||||
* what looks like the technology code. This
|
||||
* is of course completely undocumented.
|
||||
*/
|
||||
if (*ptr == '+') {
|
||||
int tech = ril_parse_tech(ptr+1, NULL);
|
||||
if (tech >= 0) {
|
||||
op->tech = tech;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
49
ofono/drivers/ril/ril_util.h
Normal file
49
ofono/drivers/ril/ril_util.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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_UTIL_H
|
||||
#define RIL_UTIL_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
const char *ril_error_to_string(int error);
|
||||
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);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
|
||||
#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 */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
872
ofono/drivers/ril/ril_voicecall.c
Normal file
872
ofono/drivers/ril/ril_voicecall.c
Normal file
@@ -0,0 +1,872 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <gutil_ring.h>
|
||||
|
||||
#define FLAG_NEED_CLIP 1
|
||||
|
||||
enum ril_voicecall_events {
|
||||
VOICECALL_EVENT_CALL_STATE_CHANGED,
|
||||
VOICECALL_EVENT_SUPP_SVC_NOTIFICATION,
|
||||
VOICECALL_EVENT_RINGBACK_TONE,
|
||||
VOICECALL_EVENT_COUNT,
|
||||
};
|
||||
|
||||
struct ril_voicecall {
|
||||
GSList *calls;
|
||||
GRilIoChannel *io;
|
||||
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;
|
||||
guint send_dtmf_id;
|
||||
guint clcc_poll_id;
|
||||
gulong event_id[VOICECALL_EVENT_COUNT];
|
||||
gulong supp_svc_notification_id;
|
||||
gulong ringback_tone_event_id;
|
||||
gulong ecclist_change_id;
|
||||
};
|
||||
|
||||
struct ril_voicecall_change_state_req {
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
gpointer data;
|
||||
int affected_types;
|
||||
};
|
||||
|
||||
struct lastcause_req {
|
||||
struct ofono_voicecall *vc;
|
||||
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 voicecall {
|
||||
struct ofono_call *call;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
static inline struct ril_voicecall *ril_voicecall_get_data(
|
||||
struct ofono_voicecall *vc)
|
||||
{
|
||||
return ofono_voicecall_get_data(vc);
|
||||
}
|
||||
|
||||
static gint ril_voicecall_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ofono_call *ca = a;
|
||||
const struct ofono_call *cb = b;
|
||||
|
||||
if (ca->id < cb->id)
|
||||
return -1;
|
||||
|
||||
if (ca->id > cb->id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
GSList *l = NULL;
|
||||
int num = 0, i;
|
||||
gchar *number, *name;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* Number of RIL_Call structs */
|
||||
|
||||
grilio_parser_get_int32(&rilp, &num);
|
||||
for (i = 0; i < num; i++) {
|
||||
struct ofono_call *call = g_new(struct ofono_call, 1);
|
||||
gint tmp;
|
||||
|
||||
ofono_call_init(call);
|
||||
grilio_parser_get_int32(&rilp, &call->status);
|
||||
grilio_parser_get_uint32(&rilp, &call->id);
|
||||
grilio_parser_get_int32(&rilp, &call->phone_number.type);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* isMpty */
|
||||
|
||||
tmp = 0;
|
||||
grilio_parser_get_int32(&rilp, &tmp);
|
||||
call->direction = (tmp ? /* isMT */
|
||||
CALL_DIRECTION_MOBILE_TERMINATED :
|
||||
CALL_DIRECTION_MOBILE_ORIGINATED);
|
||||
|
||||
grilio_parser_get_int32(&rilp, NULL); /* als */
|
||||
grilio_parser_get_int32(&rilp, &call->type); /* isVoice */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* isVoicePrivacy */
|
||||
number = grilio_parser_get_utf8(&rilp);
|
||||
if (number) {
|
||||
strncpy(call->phone_number.number, number,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
g_free(number);
|
||||
}
|
||||
grilio_parser_get_int32(&rilp, NULL); /* numberPresentation */
|
||||
name = grilio_parser_get_utf8(&rilp);
|
||||
if (name) {
|
||||
strncpy(call->name, name, OFONO_MAX_CALLER_NAME_LENGTH);
|
||||
g_free(name);
|
||||
}
|
||||
grilio_parser_get_int32(&rilp, NULL); /* namePresentation */
|
||||
grilio_parser_get_int32(&rilp, &tmp); /* uusInfo */
|
||||
GASSERT(!tmp);
|
||||
|
||||
if (strlen(call->phone_number.number) > 0) {
|
||||
call->clip_validity = 0;
|
||||
} else {
|
||||
call->clip_validity = 2;
|
||||
}
|
||||
|
||||
DBG("[id=%d,status=%d,type=%d,number=%s,name=%s]",
|
||||
call->id, call->status, call->type,
|
||||
call->phone_number.number, call->name);
|
||||
|
||||
l = g_slist_insert_sorted(l, call, ril_voicecall_compare);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Valid call statuses have value >= 0 */
|
||||
static int call_status_with_id(struct ofono_voicecall *vc, int id)
|
||||
{
|
||||
GSList *l;
|
||||
struct voicecall *v;
|
||||
|
||||
GASSERT(vc);
|
||||
|
||||
for (l = vc->call_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
if (v->call->id == id) {
|
||||
return v->call->status;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Not all call control cause values specified in 3GPP TS 24.008
|
||||
* "Mobile radio interface Layer 3 specification; Core network
|
||||
* protocols", Annex H, are properly reflected in the RIL API.
|
||||
* For example, cause #21 "call rejected" is mapped to
|
||||
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
|
||||
* from a network failure.
|
||||
*/
|
||||
switch (last_cause) {
|
||||
case CALL_FAIL_UNOBTAINABLE_NUMBER:
|
||||
case CALL_FAIL_NORMAL:
|
||||
case CALL_FAIL_BUSY:
|
||||
case CALL_FAIL_NO_ROUTE_TO_DESTINATION:
|
||||
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_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_FACILITY_REJECTED:
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
break;
|
||||
|
||||
case CALL_FAIL_NORMAL_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_ACTIVE ||
|
||||
call_status == CALL_STATUS_HELD ||
|
||||
call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
} else if (call_status == CALL_STATUS_INCOMING) {
|
||||
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
|
||||
}
|
||||
break;
|
||||
|
||||
case CALL_FAIL_ERROR_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
|
||||
id, last_cause, reason);
|
||||
|
||||
ofono_voicecall_disconnected(vc, id, reason, NULL);
|
||||
}
|
||||
|
||||
static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall *vd = user_data;
|
||||
GSList *calls;
|
||||
GSList *n, *o;
|
||||
struct ofono_error error;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
calls = ril_voicecall_parse_clcc(data, len);
|
||||
|
||||
n = calls;
|
||||
o = vd->calls;
|
||||
|
||||
while (n || o) {
|
||||
struct ofono_call *nc = n ? n->data : NULL;
|
||||
struct ofono_call *oc = o ? o->data : NULL;
|
||||
|
||||
if (oc && (nc == NULL || (nc->id > oc->id))) {
|
||||
if (vd->local_release & (1 << oc->id)) {
|
||||
ofono_voicecall_disconnected(vd->vc, oc->id,
|
||||
OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
|
||||
NULL);
|
||||
} else {
|
||||
/* Get disconnect cause before informing
|
||||
* oFono core */
|
||||
struct lastcause_req *reqdata =
|
||||
g_new0(struct lastcause_req, 1);
|
||||
|
||||
reqdata->vc = vd->vc;
|
||||
reqdata->id = oc->id;
|
||||
grilio_queue_send_request_full(vd->q, NULL,
|
||||
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
|
||||
ril_voicecall_lastcause_cb,
|
||||
g_free, reqdata);
|
||||
}
|
||||
|
||||
ril_voicecall_clear_dtmf_queue(vd);
|
||||
o = o->next;
|
||||
|
||||
} else if (nc && (oc == NULL || (nc->id < oc->id))) {
|
||||
/* new call, signal it */
|
||||
if (nc->type) {
|
||||
ofono_voicecall_notify(vd->vc, nc);
|
||||
if (vd->cb) {
|
||||
ofono_voicecall_cb_t cb = vd->cb;
|
||||
void *cbdata = vd->data;
|
||||
vd->cb = NULL;
|
||||
vd->data = NULL;
|
||||
cb(ril_error_ok(&error), cbdata);
|
||||
}
|
||||
}
|
||||
|
||||
n = n->next;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Always use the clip_validity from old call
|
||||
* the only place this is truly told to us is
|
||||
* in the CLIP notify, the rest are fudged
|
||||
* anyway. Useful when RING, CLIP is used,
|
||||
* and we're forced to use CLCC and clip_validity
|
||||
* is 1
|
||||
*/
|
||||
if (oc->clip_validity == 1) {
|
||||
nc->clip_validity = oc->clip_validity;
|
||||
}
|
||||
|
||||
nc->cnap_validity = oc->cnap_validity;
|
||||
|
||||
/*
|
||||
* CDIP doesn't arrive as part of CLCC, always
|
||||
* re-use from the old call
|
||||
*/
|
||||
memcpy(&nc->called_number, &oc->called_number,
|
||||
sizeof(oc->called_number));
|
||||
|
||||
/*
|
||||
* If the CLIP is not provided and the CLIP never
|
||||
* arrives, or RING is used, then signal the call
|
||||
* here
|
||||
*/
|
||||
if (nc->status == CALL_STATUS_INCOMING &&
|
||||
(vd->flags & FLAG_NEED_CLIP)) {
|
||||
if (nc->type) {
|
||||
ofono_voicecall_notify(vd->vc, nc);
|
||||
}
|
||||
|
||||
vd->flags &= ~FLAG_NEED_CLIP;
|
||||
} else if (memcmp(nc, oc, sizeof(*nc)) && nc->type) {
|
||||
ofono_voicecall_notify(vd->vc, nc);
|
||||
}
|
||||
|
||||
n = n->next;
|
||||
o = o->next;
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
vd->local_release = 0;
|
||||
}
|
||||
|
||||
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
{
|
||||
GASSERT(vd);
|
||||
if (!vd->clcc_poll_id) {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
vd->clcc_poll_id = grilio_queue_send_request_full(vd->q,
|
||||
req, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||
ril_voicecall_clcc_poll_cb, NULL, vd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
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 *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) {
|
||||
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)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall_change_state_req *req;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall *vd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
if (vd->cb) {
|
||||
/* CLCC will update the oFono call list with
|
||||
* proper ids if it's not done yet */
|
||||
ril_voicecall_clcc_poll(vd);
|
||||
}
|
||||
} else {
|
||||
ofono_error("call failed.");
|
||||
|
||||
/*
|
||||
* Even though this dial request may have already been
|
||||
* completed (successfully) by ril_voicecall_clcc_poll_cb,
|
||||
* RIL_REQUEST_DIAL may still fail.
|
||||
*/
|
||||
if (vd->cb) {
|
||||
struct ofono_error error;
|
||||
ofono_voicecall_cb_t cb = vd->cb;
|
||||
void *cbdata = vd->data;
|
||||
vd->cb = NULL;
|
||||
vd->data = NULL;
|
||||
cb(ril_error_failure(&error), cbdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_dial(struct ofono_voicecall *vc,
|
||||
const struct ofono_phone_number *ph,
|
||||
enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
const char *phstr = phone_number_to_string(ph);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("dialing \"%s\"", phstr);
|
||||
|
||||
DBG("%s,%d,0", phstr, clir);
|
||||
GASSERT(!vd->cb);
|
||||
vd->cb = cb;
|
||||
vd->data = data;
|
||||
|
||||
grilio_request_append_utf8(req, phstr); /* Number to dial */
|
||||
grilio_request_append_int32(req, clir); /* CLIR mode */
|
||||
grilio_request_append_int32(req, 0); /* UUS information (absent) */
|
||||
|
||||
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_DIAL,
|
||||
ril_voicecall_dial_cb, NULL, vd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Send request to RIL */
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req,
|
||||
NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
int id, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
struct ofono_error error;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void ril_voicecall_call_state_changed_event(GRilIoChannel *io,
|
||||
guint ril_event, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall *vd = user_data;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);
|
||||
|
||||
/* Just need to request the call list again */
|
||||
ril_voicecall_clcc_poll(vd);
|
||||
}
|
||||
|
||||
static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
|
||||
guint ril_event, const void *data, guint len, void *user_data)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
struct ril_voicecall *vd = user_data;
|
||||
struct ofono_phone_number phone;
|
||||
int type = 0, code = 0, index = 0;
|
||||
char *tmp = NULL;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_SUPP_SVC_NOTIFICATION);
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, &type);
|
||||
grilio_parser_get_int32(&rilp, &code);
|
||||
grilio_parser_get_int32(&rilp, &index);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
tmp = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
if (tmp) {
|
||||
strncpy(phone.number, tmp, OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
phone.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = 0;
|
||||
g_free(tmp);
|
||||
} else {
|
||||
phone.number[0] = 0;
|
||||
}
|
||||
|
||||
DBG("RIL data: MT/MO: %i, code: %i, index: %i", type, code, index);
|
||||
|
||||
/* 0 stands for MO intermediate (support TBD), 1 for MT unsolicited */
|
||||
if (type == 1) {
|
||||
ofono_voicecall_ssn_mt_notify(vd->vc, 0, code, index, &phone);
|
||||
} else {
|
||||
ofono_error("Unknown SS notification");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_answer(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
/* Send request to RIL */
|
||||
DBG("Answering current call");
|
||||
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, 0, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall *vd = user_data;
|
||||
|
||||
GASSERT(vd->send_dtmf_id);
|
||||
vd->send_dtmf_id = 0;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
/* Send the next one */
|
||||
ril_voicecall_send_one_dtmf(vd);
|
||||
} else {
|
||||
DBG("error=%d", status);
|
||||
ril_voicecall_clear_dtmf_queue(vd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd)
|
||||
{
|
||||
if (!vd->send_dtmf_id && gutil_ring_size(vd->dtmf_queue) > 0) {
|
||||
GRilIoRequest *req = grilio_request_sized_new(4);
|
||||
const char dtmf_char = (char)
|
||||
GPOINTER_TO_UINT(gutil_ring_get(vd->dtmf_queue));
|
||||
|
||||
/* RIL wants just one character */
|
||||
GASSERT(dtmf_char);
|
||||
DBG("%c", dtmf_char);
|
||||
grilio_request_append_utf8_chars(req, &dtmf_char, 1);
|
||||
vd->send_dtmf_id = grilio_queue_send_request_full(vd->q, req,
|
||||
RIL_REQUEST_DTMF, ril_voicecall_send_dtmf_cb, NULL, vd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_send_dtmf(struct ofono_voicecall *vc,
|
||||
const char *dtmf, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ofono_error error;
|
||||
|
||||
/*
|
||||
* Queue any incoming DTMF, send them to RIL one-by-one,
|
||||
* immediately call back core with no error
|
||||
*/
|
||||
DBG("Queue '%s'", dtmf);
|
||||
while (*dtmf) {
|
||||
gutil_ring_put(vd->dtmf_queue, GUINT_TO_POINTER(*dtmf));
|
||||
dtmf++;
|
||||
}
|
||||
|
||||
ril_voicecall_send_one_dtmf(vd);
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd)
|
||||
{
|
||||
gutil_ring_clear(vd->dtmf_queue);
|
||||
if (vd->send_dtmf_id) {
|
||||
grilio_channel_cancel_request(vd->io, vd->send_dtmf_id, FALSE);
|
||||
vd->send_dtmf_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_CONFERENCE,
|
||||
vc, 0, 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);
|
||||
}
|
||||
|
||||
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("Private chat with id %d", id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, id);
|
||||
|
||||
ril_voicecall_request(RIL_REQUEST_SEPARATE_CONNECTION,
|
||||
vc, 0, 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)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
|
||||
vc, 0, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hold_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
|
||||
vc, 0, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_all_held(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
}
|
||||
|
||||
static gboolean 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 */
|
||||
|
||||
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,
|
||||
guint code, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall *vd = user_data;
|
||||
GRilIoParser rilp;
|
||||
guint32 playTone = FALSE;
|
||||
int tmp;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RINGBACK_TONE);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
|
||||
grilio_parser_get_uint32(&rilp, &playTone);
|
||||
}
|
||||
|
||||
DBG("play ringback tone: %d", playTone);
|
||||
ofono_voicecall_ringback_tone_notify(vd->vc, playTone);
|
||||
}
|
||||
|
||||
static void ril_voicecall_ecclist_changed(struct ril_ecclist *list, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = data;
|
||||
|
||||
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_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 */
|
||||
if (vd->ecclist) {
|
||||
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
|
||||
vd->ecclist_change_id =
|
||||
ril_ecclist_add_list_changed_handler(vd->ecclist,
|
||||
ril_voicecall_ecclist_changed, vd);
|
||||
}
|
||||
|
||||
/* Initialize call list */
|
||||
ril_voicecall_clcc_poll(vd);
|
||||
|
||||
/* request supplementary service notifications*/
|
||||
ril_voicecall_enable_supp_svc(vd);
|
||||
|
||||
/* Unsol when call state changes */
|
||||
vd->event_id[VOICECALL_EVENT_CALL_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(vd->io,
|
||||
ril_voicecall_call_state_changed_event,
|
||||
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, vd);
|
||||
|
||||
/* Unsol when call set in hold */
|
||||
vd->event_id[VOICECALL_EVENT_SUPP_SVC_NOTIFICATION] =
|
||||
grilio_channel_add_unsol_event_handler(vd->io,
|
||||
ril_voicecall_supp_svc_notification_event,
|
||||
RIL_UNSOL_SUPP_SVC_NOTIFICATION, vd);
|
||||
|
||||
/* Register for ringback tone notifications */
|
||||
vd->event_id[VOICECALL_EVENT_RINGBACK_TONE] =
|
||||
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;
|
||||
struct ril_voicecall *vd;
|
||||
|
||||
DBG("");
|
||||
vd = g_new0(struct ril_voicecall, 1);
|
||||
vd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
vd->q = grilio_queue_new(vd->io);
|
||||
vd->dtmf_queue = gutil_ring_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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
|
||||
DBG("");
|
||||
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);
|
||||
|
||||
grilio_channel_remove_handlers(vd->io, vd->event_id,
|
||||
G_N_ELEMENTS(vd->event_id));
|
||||
grilio_channel_unref(vd->io);
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
gutil_ring_unref(vd->dtmf_queue);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
const struct ofono_voicecall_driver ril_voicecall_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_voicecall_probe,
|
||||
.remove = ril_voicecall_remove,
|
||||
.dial = ril_voicecall_dial,
|
||||
.answer = ril_voicecall_answer,
|
||||
.hangup_all = ril_voicecall_hangup_all,
|
||||
.release_specific = ril_voicecall_hangup_specific,
|
||||
.send_tones = ril_voicecall_send_dtmf,
|
||||
.create_multiparty = ril_voicecall_create_multiparty,
|
||||
.transfer = ril_voicecall_transfer,
|
||||
.private_chat = ril_voicecall_private_chat,
|
||||
.swap_without_accept = ril_voicecall_swap_without_accept,
|
||||
.hold_all_active = ril_voicecall_hold_all_active,
|
||||
.release_all_held = ril_voicecall_release_all_held,
|
||||
.set_udub = ril_voicecall_set_udub,
|
||||
.release_all_active = ril_voicecall_release_all_active
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -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
@@ -39,14 +39,22 @@
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/types.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "grilutil.h"
|
||||
#include <gril/gril.h>
|
||||
#include <gril/grilutil.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "rilmodem.h"
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/sim.h>
|
||||
#include "storage.h"
|
||||
/* Time between get data status retries */
|
||||
#define GET_STATUS_TIMER_MS 5000
|
||||
|
||||
struct ril_gprs_data {
|
||||
GRil *ril;
|
||||
struct ofono_modem *modem;
|
||||
gboolean ofono_attached;
|
||||
int rild_status;
|
||||
int pending_deact_req;
|
||||
};
|
||||
|
||||
/*
|
||||
* This module is the ofono_gprs_driver implementation for rilmodem.
|
||||
@@ -55,128 +63,67 @@
|
||||
*
|
||||
* 1. ofono_gprs_suspend/resume() are not used by this module, as
|
||||
* the concept of suspended GPRS is not exposed by RILD.
|
||||
*
|
||||
* 2. ofono_gprs_bearer_notify() is never called as RILD does not
|
||||
* expose an unsolicited event equivalent to +CPSB ( see 27.007
|
||||
* 7.29 ), and the tech values returned by REQUEST_DATA/VOICE
|
||||
* _REGISTRATION requests do not match the values defined for
|
||||
* <AcT> in the +CPSB definition. Note, the values returned by
|
||||
* the *REGISTRATION commands are aligned with those defined by
|
||||
* +CREG ( see 27.003 7.2 ).
|
||||
*/
|
||||
|
||||
struct gprs_data {
|
||||
GRil *ril;
|
||||
gboolean ofono_attached;
|
||||
int max_cids;
|
||||
int rild_status; /* Driver Status */
|
||||
guint registerid;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
/* Following constants are purely to improve readability */
|
||||
static const int roaming = NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||
static const int registered = NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
|
||||
/*if we have called ofono_gprs_register or not*/
|
||||
static gboolean ofono_registered;
|
||||
|
||||
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
ofono_gprs_status_cb_t cb,
|
||||
void *data);
|
||||
|
||||
static void ril_gprs_state_change(struct ril_msg *message, gpointer user_data)
|
||||
static int ril_tech_to_bearer_tech(int ril_tech)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
/*
|
||||
* This code handles the mapping between the RIL_RadioTechnology
|
||||
* and packet bearer values ( see <curr_bearer> values - 27.007
|
||||
* Section 7.29 ).
|
||||
*/
|
||||
|
||||
g_assert(message->req ==
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
|
||||
|
||||
DBG("");
|
||||
|
||||
/* We need to notify core always to cover situations when
|
||||
* connection drops temporarily for example when user is
|
||||
* taking CS voice call from LTE or changing technology
|
||||
* preference */
|
||||
ril_gprs_registration_status(gprs, NULL, NULL);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_set_attached_callback(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_gprs_cb_t cb = cbd->cb;
|
||||
struct ofono_gprs *gprs = cbd->user;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
DBG("");
|
||||
|
||||
gd->timer_id = 0;
|
||||
|
||||
decode_ril_error(&error, "OK");
|
||||
|
||||
cb(&error, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
return FALSE;
|
||||
switch (ril_tech) {
|
||||
case RADIO_TECH_GSM:
|
||||
case RADIO_TECH_UNKNOWN:
|
||||
return PACKET_BEARER_NONE;
|
||||
case RADIO_TECH_GPRS:
|
||||
return PACKET_BEARER_GPRS;
|
||||
case RADIO_TECH_EDGE:
|
||||
return PACKET_BEARER_EGPRS;
|
||||
case RADIO_TECH_UMTS:
|
||||
return PACKET_BEARER_UMTS;
|
||||
case RADIO_TECH_HSDPA:
|
||||
return PACKET_BEARER_HSDPA;
|
||||
case RADIO_TECH_HSUPA:
|
||||
return PACKET_BEARER_HSUPA;
|
||||
case RADIO_TECH_HSPAP:
|
||||
case RADIO_TECH_HSPA:
|
||||
/*
|
||||
* HSPAP is HSPA+; which ofono doesn't define;
|
||||
* so, if differentiating HSPA and HSPA+ is
|
||||
* important, then ofono needs to be patched,
|
||||
* and we probably also need to introduce a
|
||||
* new indicator icon.
|
||||
*/
|
||||
return PACKET_BEARER_HSUPA_HSDPA;
|
||||
case RADIO_TECH_LTE:
|
||||
return PACKET_BEARER_EPS;
|
||||
default:
|
||||
return PACKET_BEARER_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
DBG("attached: %d", attached);
|
||||
/*
|
||||
* As RIL offers no actual control over the GPRS 'attached'
|
||||
* state, we save the desired state, and use it to override
|
||||
* the actual modem's state in the 'attached_status' function.
|
||||
* This is similar to the way the core ofono gprs code handles
|
||||
* data roaming ( see src/gprs.c gprs_netreg_update().
|
||||
*
|
||||
* The core gprs code calls driver->set_attached() when a netreg
|
||||
* notification is received and any configured roaming conditions
|
||||
* are met.
|
||||
*/
|
||||
|
||||
/*
|
||||
* As RIL offers no actual control over the GPRS 'attached'
|
||||
* state, we save the desired state, and use it to override
|
||||
* the actual modem's state in the 'attached_status' function.
|
||||
* This is similar to the way the core ofono gprs code handles
|
||||
* data roaming ( see src/gprs.c gprs_netreg_update().
|
||||
*
|
||||
* The core gprs code calls driver->set_attached() when a netreg
|
||||
* notificaiton is received and any configured roaming conditions
|
||||
* are met.
|
||||
*/
|
||||
gd->ofono_attached = attached;
|
||||
|
||||
cbd->user = gprs;
|
||||
|
||||
/*
|
||||
* However we cannot respond immediately, since core sets the
|
||||
* value of driver_attached after calling set_attached and that
|
||||
* leads to comparison failure in gprs_attached_update in
|
||||
* connection drop phase
|
||||
*/
|
||||
gd->timer_id = g_timeout_add_seconds(1, ril_gprs_set_attached_callback,
|
||||
cbd);
|
||||
}
|
||||
|
||||
gboolean ril_roaming_allowed()
|
||||
{
|
||||
GError *error;
|
||||
error = NULL;
|
||||
GKeyFile *settings;
|
||||
struct ofono_sim *sim;
|
||||
|
||||
sim = get_sim();
|
||||
const char *imsi = ofono_sim_get_imsi(sim);
|
||||
settings = storage_open(imsi, "gprs");
|
||||
gboolean roaming_allowed = g_key_file_get_boolean(settings,
|
||||
"Settings",
|
||||
"RoamingAllowed",
|
||||
&error);
|
||||
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
storage_close(imsi, "gprs", settings, FALSE);
|
||||
|
||||
DBG("roaming_allowed: %d", roaming_allowed);
|
||||
return roaming_allowed;
|
||||
CALLBACK_WITH_SUCCESS(cb, data);
|
||||
}
|
||||
|
||||
static void ril_data_reg_cb(struct ril_msg *message, gpointer user_data)
|
||||
@@ -184,245 +131,392 @@ static void ril_data_reg_cb(struct ril_msg *message, gpointer user_data)
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_gprs_status_cb_t cb = cbd->cb;
|
||||
struct ofono_gprs *gprs = cbd->user;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct ofono_error error;
|
||||
int lac, ci, tech;
|
||||
int max_cids = 1;
|
||||
int status = -1;
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct ofono_modem *modem;
|
||||
struct parcel rilp;
|
||||
int num_str;
|
||||
char **strv;
|
||||
char *debug_str;
|
||||
char *end;
|
||||
int status;
|
||||
int tech = -1;
|
||||
gboolean attached = FALSE;
|
||||
gboolean notify_status = FALSE;
|
||||
int old_status;
|
||||
|
||||
if (gd && message->error == RIL_E_SUCCESS) {
|
||||
decode_ril_error(&error, "OK");
|
||||
} else {
|
||||
ofono_error("ril_data_reg_cb: reply failure: %s",
|
||||
old_status = gd->rild_status;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: DATA_REGISTRATION_STATE reply failure: %s",
|
||||
__func__,
|
||||
ril_error_to_string(message->error));
|
||||
decode_ril_error(&error, "FAIL");
|
||||
error.error = message->error;
|
||||
goto exit;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ril_util_parse_reg(gd->ril, message, &status,
|
||||
&lac, &ci, &tech, &max_cids) == FALSE) {
|
||||
ofono_error("Failure parsing data registration response.");
|
||||
decode_ril_error(&error, "FAIL");
|
||||
goto exit;
|
||||
}
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
strv = parcel_r_strv(&rilp);
|
||||
num_str = g_strv_length(strv);
|
||||
|
||||
if (status > 10)
|
||||
status = status - 10;
|
||||
if (strv == NULL)
|
||||
goto error;
|
||||
|
||||
if (!ofono_registered) {
|
||||
ofono_gprs_register(gprs);
|
||||
ofono_registered = TRUE;
|
||||
}
|
||||
debug_str = g_strjoinv(",", strv);
|
||||
g_ril_append_print_buf(gd->ril, "{%d,%s}", num_str, debug_str);
|
||||
g_free(debug_str);
|
||||
g_ril_print_response(gd->ril, message);
|
||||
|
||||
if (max_cids > gd->max_cids) {
|
||||
DBG("Setting max cids to %d", max_cids);
|
||||
gd->max_cids = max_cids;
|
||||
ofono_gprs_set_cid_range(gprs, 1, max_cids);
|
||||
}
|
||||
status = strtoul(strv[0], &end, 10);
|
||||
if (end == strv[0] || *end != '\0')
|
||||
goto error_free;
|
||||
|
||||
if (status == roaming)
|
||||
status = check_if_really_roaming(status);
|
||||
status = ril_util_registration_state_to_status(status);
|
||||
if (status < 0)
|
||||
goto error_free;
|
||||
|
||||
/* Let's minimize logging */
|
||||
if (status != gd->rild_status)
|
||||
ofono_info("data reg changes %d (%d), attached %d",
|
||||
status, gd->rild_status, gd->ofono_attached);
|
||||
if (num_str >= 4) {
|
||||
tech = strtoul(strv[3], &end, 10);
|
||||
if (end == strv[3] || *end != '\0')
|
||||
tech = -1;
|
||||
|
||||
/* Must be attached if registered or roaming */
|
||||
if ((gd->rild_status != registered) && (gd->rild_status != roaming)) {
|
||||
if (status == registered)
|
||||
gd->ofono_attached = TRUE;
|
||||
else if ((status == roaming) && (ril_roaming_allowed() == TRUE))
|
||||
gd->ofono_attached = TRUE;
|
||||
}
|
||||
|
||||
if (!ofono_modem_get_online(ofono_gprs_get_modem(gprs)))
|
||||
gd->ofono_attached = FALSE;
|
||||
|
||||
/* if unsolicitated and no state change let's not notify core */
|
||||
if ((status == gd->rild_status) && gd->ofono_attached)
|
||||
goto cb_out;
|
||||
|
||||
if (!gd->ofono_attached) {
|
||||
if (!cb) {
|
||||
if (status == roaming) {
|
||||
if (ril_roaming_allowed() == FALSE)
|
||||
ofono_gprs_detached_notify(gprs);
|
||||
|
||||
/*
|
||||
* This prevents core ending
|
||||
* into eternal loop with driver
|
||||
*/
|
||||
decode_ril_error(&error, "FAIL");
|
||||
if (g_ril_vendor(gd->ril) == OFONO_RIL_VENDOR_MTK) {
|
||||
switch (tech) {
|
||||
case MTK_RADIO_TECH_HSDPAP:
|
||||
case MTK_RADIO_TECH_HSDPAP_UPA:
|
||||
case MTK_RADIO_TECH_HSUPAP:
|
||||
case MTK_RADIO_TECH_HSUPAP_DPA:
|
||||
tech = RADIO_TECH_HSPAP;
|
||||
break;
|
||||
case MTK_RADIO_TECH_DC_DPA:
|
||||
tech = RADIO_TECH_HSDPA;
|
||||
break;
|
||||
case MTK_RADIO_TECH_DC_UPA:
|
||||
tech = RADIO_TECH_HSUPA;
|
||||
break;
|
||||
case MTK_RADIO_TECH_DC_HSDPAP:
|
||||
case MTK_RADIO_TECH_DC_HSDPAP_UPA:
|
||||
case MTK_RADIO_TECH_DC_HSDPAP_DPA:
|
||||
case MTK_RADIO_TECH_DC_HSPAP:
|
||||
tech = RADIO_TECH_HSPAP;
|
||||
break;
|
||||
}
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This prevents core ending
|
||||
* into eternal loop with driver
|
||||
*/
|
||||
decode_ril_error(&error, "FAIL");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There are two cases that can result in this callback
|
||||
* running:
|
||||
*
|
||||
* 1) ril_gprs_state_change() is called due to an unsolicited
|
||||
* event from RILD. No ofono cb exists.
|
||||
*
|
||||
* 2) The ofono code code calls the driver's attached_status()
|
||||
* function. A valid ofono cb exists.
|
||||
*/
|
||||
|
||||
if (gd->rild_status != status) {
|
||||
gd->rild_status = status;
|
||||
goto exit;
|
||||
|
||||
if (cb == NULL)
|
||||
notify_status = TRUE;
|
||||
}
|
||||
|
||||
if (!cb)
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
/*
|
||||
* Override the actual status based upon the desired
|
||||
* attached status set by the core GPRS code ( controlled
|
||||
* by the ConnnectionManager's 'Powered' property ).
|
||||
*/
|
||||
attached = status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
|
||||
status == NETWORK_REGISTRATION_STATUS_ROAMING;
|
||||
|
||||
gd->rild_status = status;
|
||||
if (attached && gd->ofono_attached == FALSE) {
|
||||
DBG("attached=true; ofono_attached=false; return !REGISTERED");
|
||||
status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
|
||||
/*
|
||||
* Further optimization so that if ril_status ==
|
||||
* NOT_REGISTERED, ofono_attached == false, and status ==
|
||||
* ROAMING | REGISTERED, then notify gets cleared...
|
||||
*
|
||||
* As is, this results in unecessary status notify calls
|
||||
* when nothing has changed.
|
||||
*/
|
||||
if (notify_status && status == old_status)
|
||||
notify_status = FALSE;
|
||||
}
|
||||
|
||||
/* Just need to notify ofono if it's already attached */
|
||||
if (notify_status) {
|
||||
/*
|
||||
* If network disconnect has occurred, call detached_notify()
|
||||
* instead of status_notify().
|
||||
*/
|
||||
if (!attached &&
|
||||
(old_status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
|
||||
old_status ==
|
||||
NETWORK_REGISTRATION_STATUS_ROAMING)) {
|
||||
DBG("calling ofono_gprs_detached_notify()");
|
||||
ofono_gprs_detached_notify(gprs);
|
||||
tech = RADIO_TECH_UNKNOWN;
|
||||
} else {
|
||||
DBG("calling ofono_gprs_status_notify()");
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
}
|
||||
|
||||
modem = ofono_gprs_get_modem(gprs);
|
||||
ofono_modem_set_integer(modem, "RilDataRadioTechnology", tech);
|
||||
ofono_gprs_bearer_notify(gprs, ril_tech_to_bearer_tech(tech));
|
||||
|
||||
exit:
|
||||
DBG("data reg status %d, rild_status %d, attached %d",
|
||||
status, gd->rild_status, gd->ofono_attached);
|
||||
cb_out:
|
||||
if (cb)
|
||||
cb(&error, status, cbd->data);
|
||||
}
|
||||
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
|
||||
|
||||
static void ril_data_probe_reg_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_gprs *gprs = cbd->user;
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct ofono_error error;
|
||||
int status, lac, ci, tech;
|
||||
int max_cids = 1;
|
||||
int id = RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED;
|
||||
return;
|
||||
|
||||
DBG("");
|
||||
error_free:
|
||||
g_strfreev(strv);
|
||||
|
||||
if (!(gd && message->error == RIL_E_SUCCESS)) {
|
||||
ofono_error("ril_data_reg_cb: reply failure: %s",
|
||||
ril_error_to_string(message->error));
|
||||
decode_ril_error(&error, "FAIL");
|
||||
error.error = message->error;
|
||||
status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
decode_ril_error(&error, "OK");
|
||||
status = -1;
|
||||
|
||||
if (ril_util_parse_reg(gd->ril, message, &status,
|
||||
&lac, &ci, &tech, &max_cids) == FALSE) {
|
||||
ofono_error("Failure parsing data registration response.");
|
||||
decode_ril_error(&error, "FAIL");
|
||||
|
||||
if (status == -1)
|
||||
status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status > 10)
|
||||
status = status - 10;
|
||||
|
||||
ofono_gprs_register(gprs);
|
||||
|
||||
ofono_registered = TRUE;
|
||||
|
||||
if (max_cids > gd->max_cids) {
|
||||
DBG("Setting max cids to %d", max_cids);
|
||||
gd->max_cids = max_cids;
|
||||
ofono_gprs_set_cid_range(gprs, 1, max_cids);
|
||||
}
|
||||
|
||||
if (status == roaming)
|
||||
status = check_if_really_roaming(status);
|
||||
|
||||
out:
|
||||
ofono_info("data reg status probed %d", status);
|
||||
|
||||
gd->registerid = g_ril_register(gd->ril,
|
||||
id, ril_gprs_state_change, gprs);
|
||||
|
||||
gd->rild_status = status;
|
||||
error:
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
ofono_gprs_status_cb_t cb,
|
||||
void *data)
|
||||
ofono_gprs_status_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int request = RIL_REQUEST_DATA_REGISTRATION_STATE;
|
||||
guint ret;
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, gprs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (gd == NULL || cbd == NULL)
|
||||
return;
|
||||
|
||||
cbd->user = gprs;
|
||||
|
||||
ret = g_ril_send(gd->ril, request,
|
||||
NULL, 0,
|
||||
((gd->rild_status == -1)
|
||||
? ril_data_probe_reg_cb
|
||||
: ril_data_reg_cb), cbd, g_free);
|
||||
|
||||
g_ril_print_request_no_args(gd->ril, ret, request);
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("Send RIL_REQUEST_DATA_RESTISTRATION_STATE fail.");
|
||||
if (g_ril_send(gd->ril, RIL_REQUEST_DATA_REGISTRATION_STATE, NULL,
|
||||
ril_data_reg_cb, cbd, g_free) == 0) {
|
||||
ofono_error("%s: send "
|
||||
"RIL_REQUEST_DATA_REGISTRATION_STATE failed",
|
||||
__func__);
|
||||
g_free(cbd);
|
||||
|
||||
if (cb)
|
||||
if (cb != NULL)
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_gprs_probe(struct ofono_gprs *gprs,
|
||||
unsigned int vendor, void *data)
|
||||
static void query_max_cids_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
GRil *ril = data;
|
||||
struct gprs_data *gd;
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct parcel rilp;
|
||||
int num_str;
|
||||
char **strv;
|
||||
char *debug_str;
|
||||
char *end;
|
||||
int max_calls = 2;
|
||||
|
||||
gd = g_try_new0(struct gprs_data, 1);
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: DATA_REGISTRATION_STATE reply failure: %s",
|
||||
__func__,
|
||||
ril_error_to_string(message->error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
strv = parcel_r_strv(&rilp);
|
||||
|
||||
if (strv == NULL)
|
||||
goto error;
|
||||
|
||||
num_str = g_strv_length(strv);
|
||||
debug_str = g_strjoinv(",", strv);
|
||||
g_ril_append_print_buf(gd->ril, "{%d,%s}", num_str, debug_str);
|
||||
g_free(debug_str);
|
||||
g_ril_print_response(gd->ril, message);
|
||||
|
||||
if (num_str < 6)
|
||||
goto reg_atom;
|
||||
|
||||
max_calls = strtoul(strv[5], &end, 10);
|
||||
if (end == strv[5] || *end != '\0')
|
||||
goto error_free;
|
||||
|
||||
reg_atom:
|
||||
g_strfreev(strv);
|
||||
ofono_gprs_set_cid_range(gprs, 1, max_calls);
|
||||
ofono_gprs_register(gprs);
|
||||
return;
|
||||
|
||||
error_free:
|
||||
g_strfreev(strv);
|
||||
|
||||
error:
|
||||
ofono_error("Unable to query max CIDs");
|
||||
ofono_gprs_remove(gprs);
|
||||
}
|
||||
|
||||
static void ril_gprs_state_change(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
g_ril_print_unsol_no_args(gd->ril, message);
|
||||
|
||||
/*
|
||||
* We just want to track network data status if ofono
|
||||
* itself is attached, so we avoid unnecessary data state requests.
|
||||
*/
|
||||
if (gd->ofono_attached == TRUE)
|
||||
ril_gprs_registration_status(gprs, NULL, NULL);
|
||||
}
|
||||
|
||||
static void query_max_cids(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
g_ril_register(gd->ril, RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
|
||||
ril_gprs_state_change, gprs);
|
||||
|
||||
/*
|
||||
* MTK modem does not return max_cids, string, so hard-code it
|
||||
* here
|
||||
*/
|
||||
if (g_ril_vendor(gd->ril) == OFONO_RIL_VENDOR_MTK) {
|
||||
ofono_gprs_set_cid_range(gprs, 1, 3);
|
||||
ofono_gprs_register(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_ril_send(gd->ril, RIL_REQUEST_DATA_REGISTRATION_STATE, NULL,
|
||||
query_max_cids_cb, gprs, NULL) < 0)
|
||||
ofono_gprs_remove(gprs);
|
||||
}
|
||||
|
||||
static void drop_data_call_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
g_ril_print_response_no_args(gd->ril, message);
|
||||
else
|
||||
ofono_error("%s: RIL error %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
|
||||
if (--(gd->pending_deact_req) == 0)
|
||||
query_max_cids(gprs);
|
||||
}
|
||||
|
||||
static int drop_data_call(struct ofono_gprs *gprs, int cid)
|
||||
{
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct parcel rilp;
|
||||
|
||||
ril_util_build_deactivate_data_call(gd->ril, &rilp, cid,
|
||||
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
|
||||
|
||||
if (g_ril_send(gd->ril, RIL_REQUEST_DEACTIVATE_DATA_CALL,
|
||||
&rilp, drop_data_call_cb, gprs, NULL) > 0)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void get_active_data_calls_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct parcel rilp;
|
||||
int num_calls;
|
||||
int cid;
|
||||
int i;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s: RIL error %s", __func__,
|
||||
ril_error_to_string(message->error));
|
||||
goto end;
|
||||
}
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
/* Version */
|
||||
parcel_r_int32(&rilp);
|
||||
num_calls = parcel_r_int32(&rilp);
|
||||
|
||||
/*
|
||||
* We disconnect from previous calls here, which might be needed
|
||||
* because of a previous ofono abort, as some rild implementations do
|
||||
* not disconnect the calls even after the ril socket is closed.
|
||||
*/
|
||||
for (i = 0; i < num_calls; i++) {
|
||||
parcel_r_int32(&rilp); /* status */
|
||||
parcel_r_int32(&rilp); /* ignore */
|
||||
cid = parcel_r_int32(&rilp);
|
||||
parcel_r_int32(&rilp); /* active */
|
||||
parcel_skip_string(&rilp); /* type */
|
||||
parcel_skip_string(&rilp); /* ifname */
|
||||
parcel_skip_string(&rilp); /* addresses */
|
||||
parcel_skip_string(&rilp); /* dns */
|
||||
parcel_skip_string(&rilp); /* gateways */
|
||||
|
||||
/* malformed check */
|
||||
if (rilp.malformed) {
|
||||
ofono_error("%s: malformed parcel received", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
DBG("Standing data call with cid %d", cid);
|
||||
|
||||
if (drop_data_call(gprs, cid) == 0)
|
||||
++(gd->pending_deact_req);
|
||||
}
|
||||
|
||||
end:
|
||||
if (gd->pending_deact_req == 0)
|
||||
query_max_cids(gprs);
|
||||
}
|
||||
|
||||
static void get_active_data_calls(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
if (g_ril_send(gd->ril, RIL_REQUEST_DATA_CALL_LIST, NULL,
|
||||
get_active_data_calls_cb, gprs, NULL) == 0)
|
||||
ofono_error("%s: send failed", __func__);
|
||||
}
|
||||
|
||||
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||
void *userdata)
|
||||
{
|
||||
GRil *ril = userdata;
|
||||
struct ril_gprs_data *gd;
|
||||
|
||||
gd = g_try_new0(struct ril_gprs_data, 1);
|
||||
if (gd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gd->ril = g_ril_clone(ril);
|
||||
gd->ofono_attached = FALSE;
|
||||
gd->max_cids = 0;
|
||||
gd->rild_status = -1;
|
||||
gd->registerid = -1;
|
||||
gd->timer_id = 0;
|
||||
|
||||
ofono_registered = FALSE;
|
||||
|
||||
ofono_gprs_set_data(gprs, gd);
|
||||
|
||||
ril_gprs_registration_status(gprs, NULL, NULL);
|
||||
get_active_data_calls(gprs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_remove(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
if (gd->registerid != -1)
|
||||
g_ril_unregister(gd->ril, gd->registerid);
|
||||
|
||||
if (gd->timer_id > 0)
|
||||
g_source_remove(gd->timer_id);
|
||||
|
||||
g_ril_unref(gd->ril);
|
||||
g_free(gd);
|
||||
}
|
||||
|
||||
static struct ofono_gprs_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.name = RILMODEM,
|
||||
.probe = ril_gprs_probe,
|
||||
.remove = ril_gprs_remove,
|
||||
.set_attached = ril_gprs_set_attached,
|
||||
|
||||
282
ofono/drivers/rilmodem/netmon.c
Normal file
282
ofono/drivers/rilmodem/netmon.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include "gril.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
|
||||
/*
|
||||
* Defined below are copy of
|
||||
* RIL_CellInfoType defined in Ril.h
|
||||
*/
|
||||
#define NETMON_RIL_CELLINFO_TYPE_GSM 1
|
||||
#define NETMON_RIL_CELLINFO_TYPE_CDMA 2
|
||||
#define NETMON_RIL_CELLINFO_TYPE_LTE 3
|
||||
#define NETMON_RIL_CELLINFO_TYPE_UMTS 4
|
||||
#define NETMON_RIL_CELLINFO_TYPE_TDSCDMA 5
|
||||
|
||||
/* size of RIL_CellInfoGsm */
|
||||
#define NETMON_RIL_CELLINFO_SIZE_GSM 24
|
||||
/* size of RIL_CellInfoCDMA */
|
||||
#define NETMON_RIL_CELLINFO_SIZE_CDMA 40
|
||||
/* size of RIL_CellInfoLte */
|
||||
#define NETMON_RIL_CELLINFO_SIZE_LTE 44
|
||||
/* size of RIL_CellInfoWcdma */
|
||||
#define NETMON_RIL_CELLINFO_SIZE_UMTS 28
|
||||
/* size of RIL_CellInfoTdscdma */
|
||||
#define NETMON_RIL_CELLINFO_SIZE_TDSCDMA 24
|
||||
|
||||
struct netmon_data {
|
||||
GRil *ril;
|
||||
};
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_netmon *netmon = user_data;
|
||||
|
||||
ofono_netmon_register(netmon);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_cell_type_to_size(int cell_type)
|
||||
{
|
||||
switch (cell_type) {
|
||||
case NETMON_RIL_CELLINFO_TYPE_GSM:
|
||||
return NETMON_RIL_CELLINFO_SIZE_GSM;
|
||||
|
||||
case NETMON_RIL_CELLINFO_TYPE_CDMA:
|
||||
return NETMON_RIL_CELLINFO_SIZE_CDMA;
|
||||
|
||||
case NETMON_RIL_CELLINFO_TYPE_LTE:
|
||||
return NETMON_RIL_CELLINFO_SIZE_LTE;
|
||||
|
||||
case NETMON_RIL_CELLINFO_TYPE_UMTS:
|
||||
return NETMON_RIL_CELLINFO_SIZE_UMTS;
|
||||
|
||||
case NETMON_RIL_CELLINFO_TYPE_TDSCDMA:
|
||||
return NETMON_RIL_CELLINFO_SIZE_TDSCDMA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_netmon_cb_t cb = cbd->cb;
|
||||
struct ofono_netmon *netmon = cbd->data;
|
||||
struct parcel rilp;
|
||||
int skip_len;
|
||||
int cell_info_cnt;
|
||||
int cell_type;
|
||||
int registered = 0;
|
||||
int mcc, mnc;
|
||||
int lac, cid, psc;
|
||||
int rssi, ber;
|
||||
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
int i, j;
|
||||
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
cell_info_cnt = parcel_r_int32(&rilp);
|
||||
|
||||
for (i = 0; i < cell_info_cnt; i++) {
|
||||
cell_type = parcel_r_int32(&rilp);
|
||||
|
||||
registered = parcel_r_int32(&rilp);
|
||||
|
||||
/* skipping unneeded timeStampType in Ril cell info */
|
||||
(void)parcel_r_int32(&rilp);
|
||||
|
||||
/*skipping timeStamp which is a uint64_t type */
|
||||
(void)parcel_r_int32(&rilp);
|
||||
(void)parcel_r_int32(&rilp);
|
||||
|
||||
if (registered)
|
||||
break;
|
||||
|
||||
/*
|
||||
* not serving cell,
|
||||
* skip remainder of current cell info
|
||||
*/
|
||||
skip_len = ril_cell_type_to_size(cell_type)/sizeof(int);
|
||||
|
||||
for (j = 0; j < skip_len; j++)
|
||||
(void)parcel_r_int32(&rilp);
|
||||
}
|
||||
|
||||
if (!registered)
|
||||
goto error;
|
||||
|
||||
if (cell_type == NETMON_RIL_CELLINFO_TYPE_GSM) {
|
||||
mcc = parcel_r_int32(&rilp);
|
||||
mnc = parcel_r_int32(&rilp);
|
||||
lac = parcel_r_int32(&rilp);
|
||||
cid = parcel_r_int32(&rilp);
|
||||
rssi = parcel_r_int32(&rilp);
|
||||
ber = parcel_r_int32(&rilp);
|
||||
|
||||
if (mcc >= 0 && mcc <= 999)
|
||||
snprintf(s_mcc, sizeof(s_mcc), "%03d", mcc);
|
||||
else
|
||||
strcpy(s_mcc, "");
|
||||
|
||||
if (mnc >= 0 && mnc <= 999)
|
||||
snprintf(s_mnc, sizeof(s_mnc), "%03d", mnc);
|
||||
else
|
||||
strcpy(s_mnc, "");
|
||||
|
||||
lac = (lac >= 0 && lac <= 65535) ? lac : -1;
|
||||
cid = (cid >= 0 && cid <= 65535) ? cid : -1;
|
||||
rssi = (rssi >= 0 && rssi <= 31) ? rssi : -1;
|
||||
ber = (ber >= 0 && ber <= 7) ? ber : -1;
|
||||
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_GSM,
|
||||
OFONO_NETMON_INFO_MCC, s_mcc,
|
||||
OFONO_NETMON_INFO_MNC, s_mnc,
|
||||
OFONO_NETMON_INFO_LAC, lac,
|
||||
OFONO_NETMON_INFO_CI, cid,
|
||||
OFONO_NETMON_INFO_RSSI, rssi,
|
||||
OFONO_NETMON_INFO_BER, ber,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
} else if (cell_type == NETMON_RIL_CELLINFO_TYPE_UMTS) {
|
||||
mcc = parcel_r_int32(&rilp);
|
||||
mnc = parcel_r_int32(&rilp);
|
||||
lac = parcel_r_int32(&rilp);
|
||||
cid = parcel_r_int32(&rilp);
|
||||
psc = parcel_r_int32(&rilp);
|
||||
rssi = parcel_r_int32(&rilp);
|
||||
ber = parcel_r_int32(&rilp);
|
||||
|
||||
if (mcc >= 0 && mcc <= 999)
|
||||
snprintf(s_mcc, sizeof(s_mcc), "%03d", mcc);
|
||||
else
|
||||
strcpy(s_mcc, "");
|
||||
|
||||
if (mnc >= 0 && mnc <= 999)
|
||||
snprintf(s_mnc, sizeof(s_mnc), "%03d", mnc);
|
||||
else
|
||||
strcpy(s_mnc, "");
|
||||
|
||||
lac = (lac >= 0 && lac <= 65535) ? lac : -1;
|
||||
cid = (cid >= 0 && cid <= 268435455) ? cid : -1;
|
||||
psc = (psc >= 0 && rssi <= 511) ? psc : -1;
|
||||
rssi = (rssi >= 0 && rssi <= 31) ? rssi : -1;
|
||||
ber = (ber >= 0 && ber <= 7) ? ber : -1;
|
||||
|
||||
ofono_netmon_serving_cell_notify(netmon,
|
||||
OFONO_NETMON_CELL_TYPE_UMTS,
|
||||
OFONO_NETMON_INFO_MCC, s_mcc,
|
||||
OFONO_NETMON_INFO_MNC, s_mnc,
|
||||
OFONO_NETMON_INFO_LAC, lac,
|
||||
OFONO_NETMON_INFO_CI, cid,
|
||||
OFONO_NETMON_INFO_PSC, psc,
|
||||
OFONO_NETMON_INFO_RSSI, rssi,
|
||||
OFONO_NETMON_INFO_BER, ber,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static int ril_netmon_probe(struct ofono_netmon *netmon,
|
||||
unsigned int vendor, void *user)
|
||||
{
|
||||
GRil *ril = user;
|
||||
struct netmon_data *ud = g_new0(struct netmon_data, 1);
|
||||
|
||||
ud->ril = g_ril_clone(ril);
|
||||
|
||||
ofono_netmon_set_data(netmon, ud);
|
||||
|
||||
g_idle_add(ril_delayed_register, netmon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
g_ril_unref(nmd->ril);
|
||||
}
|
||||
|
||||
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb, void *data)
|
||||
{
|
||||
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, nmd);
|
||||
|
||||
if (g_ril_send(nmd->ril, RIL_REQUEST_GET_CELL_INFO_LIST, NULL,
|
||||
ril_netmon_update_cb, cbd, NULL) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static struct ofono_netmon_driver driver = {
|
||||
.name = RILMODEM,
|
||||
.probe = ril_netmon_probe,
|
||||
.remove = ril_netmon_remove,
|
||||
.request_update = ril_netmon_request_update,
|
||||
};
|
||||
|
||||
void ril_netmon_init(void)
|
||||
{
|
||||
ofono_netmon_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ril_netmon_exit(void)
|
||||
{
|
||||
ofono_netmon_driver_unregister(&driver);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2013 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.
|
||||
*
|
||||
* 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 <glib.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/oemraw.h>
|
||||
#include "common.h"
|
||||
#include "gril.h"
|
||||
#include "rilmodem.h"
|
||||
|
||||
struct oem_raw_data {
|
||||
GRil *ril;
|
||||
unsigned int vendor;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
static gboolean ril_oemraw_delayed_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_oem_raw *raw = user_data;
|
||||
struct oem_raw_data *od = ofono_oem_raw_get_data(raw);
|
||||
|
||||
DBG("");
|
||||
|
||||
od->timer_id = 0;
|
||||
|
||||
ofono_oem_raw_dbus_register(raw);
|
||||
return FALSE; /* This makes the timeout a single-shot */
|
||||
}
|
||||
|
||||
static int ril_oemraw_probe(struct ofono_oem_raw *raw, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
GRil *ril = data;
|
||||
struct oem_raw_data *od;
|
||||
|
||||
DBG("");
|
||||
|
||||
od = g_new0(struct oem_raw_data, 1);
|
||||
|
||||
od->ril = g_ril_clone(ril);
|
||||
od->vendor = vendor;
|
||||
ofono_oem_raw_set_data(raw, od);
|
||||
|
||||
od->timer_id = g_timeout_add_seconds(1, ril_oemraw_delayed_register,
|
||||
raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_oemraw_remove(struct ofono_oem_raw *raw)
|
||||
{
|
||||
struct oem_raw_data *od;
|
||||
|
||||
DBG("");
|
||||
|
||||
od = ofono_oem_raw_get_data(raw);
|
||||
|
||||
ofono_oem_raw_set_data(raw, NULL);
|
||||
|
||||
if (od->timer_id)
|
||||
g_source_remove(od->timer_id);
|
||||
|
||||
g_ril_unref(od->ril);
|
||||
g_free(od);
|
||||
}
|
||||
|
||||
static void ril_oemraw_request_cb(struct ril_msg *msg,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ofono_oem_raw_results result;
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_oem_raw_query_cb_t cb = cbd->cb;
|
||||
|
||||
if (msg && msg->error == RIL_E_SUCCESS) {
|
||||
decode_ril_error(&error, "OK");
|
||||
} else {
|
||||
DBG("error:%d len:%d unsol:%d req:%d serial_no:%d",
|
||||
msg->error, msg->buf_len, msg->unsolicited,
|
||||
msg->req, msg->serial_no);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
result.data = msg->buf;
|
||||
result.length = msg->buf_len;
|
||||
|
||||
cb(&error, &result, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_oemraw_request(struct ofono_oem_raw *raw,
|
||||
const struct ofono_oem_raw_request *request,
|
||||
ofono_oem_raw_query_cb_t cb, void *data)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct cb_data *cbd;
|
||||
struct oem_raw_data *od;
|
||||
struct parcel parcel;
|
||||
|
||||
cbd = cb_data_new(cb, data);
|
||||
od = ofono_oem_raw_get_data(raw);
|
||||
parcel_init(&parcel);
|
||||
|
||||
for (i = 0; i < request->length; i++) {
|
||||
/*DBG("Byte: 0x%x", request->data[i]); Enable for debugging*/
|
||||
parcel_w_byte(&parcel, request->data[i]);
|
||||
}
|
||||
|
||||
ret = g_ril_send(od->ril, RIL_REQUEST_OEM_HOOK_RAW, parcel.data,
|
||||
parcel.size, ril_oemraw_request_cb, cbd,
|
||||
g_free);
|
||||
|
||||
parcel_free(&parcel);
|
||||
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
DBG("Failed to issue an OEM RAW request to RIL: result=%d ",
|
||||
ret);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static struct ofono_oem_raw_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.probe = ril_oemraw_probe,
|
||||
.remove = ril_oemraw_remove,
|
||||
.request = ril_oemraw_request,
|
||||
};
|
||||
|
||||
void ril_oemraw_init(void)
|
||||
{
|
||||
DBG("");
|
||||
ofono_oem_raw_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ril_oemraw_exit(void)
|
||||
{
|
||||
DBG("");
|
||||
ofono_oem_raw_driver_unregister(&driver);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* 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,296 +36,410 @@
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "grilutil.h"
|
||||
#include "storage.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
|
||||
#include "ril_constants.h"
|
||||
/* Preferred network types */
|
||||
#define PREF_NET_TYPE_GSM_WCDMA 0
|
||||
#define PREF_NET_TYPE_GSM_ONLY 1
|
||||
#define PREF_NET_TYPE_WCDMA 2
|
||||
#define PREF_NET_TYPE_GSM_WCDMA_AUTO 3
|
||||
#define PREF_NET_TYPE_CDMA_EVDO_AUTO 4
|
||||
#define PREF_NET_TYPE_CDMA_ONLY 5
|
||||
#define PREF_NET_TYPE_EVDO_ONLY 6
|
||||
#define PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO 7
|
||||
#define PREF_NET_TYPE_LTE_CDMA_EVDO 8
|
||||
#define PREF_NET_TYPE_LTE_GSM_WCDMA 9
|
||||
#define PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA 10
|
||||
#define PREF_NET_TYPE_LTE_ONLY 11
|
||||
#define PREF_NET_TYPE_LTE_WCDMA 12
|
||||
/* MTK specific network types */
|
||||
#define MTK_PREF_NET_TYPE_BASE 30
|
||||
#define MTK_PREF_NET_TYPE_LTE_GSM_WCDMA (MTK_PREF_NET_TYPE_BASE + 1)
|
||||
#define MTK_PREF_NET_TYPE_LTE_GSM_WCDMA_MMDC (MTK_PREF_NET_TYPE_BASE + 2)
|
||||
#define MTK_PREF_NET_TYPE_GSM_WCDMA_LTE (MTK_PREF_NET_TYPE_BASE + 3)
|
||||
#define MTK_PREF_NET_TYPE_GSM_WCDMA_LTE_MMDC (MTK_PREF_NET_TYPE_BASE + 4)
|
||||
#define MTK_PREF_NET_TYPE_LTE_GSM_TYPE (MTK_PREF_NET_TYPE_BASE + 5)
|
||||
#define MTK_PREF_NET_TYPE_LTE_GSM_MMDC_TYPE (MTK_PREF_NET_TYPE_BASE + 6)
|
||||
|
||||
/*GSM Band*/
|
||||
#define PREF_NET_BAND_GSM_AUTOMATIC 255
|
||||
#define PREF_NET_BAND_GSM850 6
|
||||
#define PREF_NET_BAND_GSM900_P 1
|
||||
#define PREF_NET_BAND_GSM900_E 2
|
||||
#define PREF_NET_BAND_GSM1800 4
|
||||
#define PREF_NET_BAND_GSM1900 5
|
||||
|
||||
/*UMTS Band*/
|
||||
#define PREF_NET_BAND_UMTS_AUTOMATIC 255
|
||||
#define PREF_NET_BAND_UMTS_V 54
|
||||
#define PREF_NET_BAND_UMTS_VIII 57
|
||||
#define PREF_NET_BAND_UMTS_IV 53
|
||||
#define PREF_NET_BAND_UMTS_II 51
|
||||
#define PREF_NET_BAND_UMTS_I 50
|
||||
|
||||
struct radio_data {
|
||||
GRil *ril;
|
||||
guint timer_id;
|
||||
int ratmode;
|
||||
gboolean fast_dormancy;
|
||||
gboolean pending_fd;
|
||||
unsigned int vendor;
|
||||
};
|
||||
|
||||
static void ril_set_rat_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_radio_settings *rs = cbd->user;
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
g_ril_print_response_no_args(rd->ril, message);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else {
|
||||
ofono_error("rat mode setting failed");
|
||||
} else {
|
||||
ofono_error("%s: rat mode setting failed", __func__);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, rs);
|
||||
struct parcel rilp;
|
||||
int pref = rd->ratmode;
|
||||
int ret = 0;
|
||||
|
||||
ofono_info("rat mode set %d", mode);
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1); /* Number of params */
|
||||
int pref = PREF_NET_TYPE_GSM_WCDMA;
|
||||
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
pref = PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
pref = PREF_NET_TYPE_GSM_ONLY;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
pref = PREF_NET_TYPE_GSM_WCDMA_AUTO; /* according to UI design */
|
||||
pref = PREF_NET_TYPE_GSM_WCDMA;
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
pref = PREF_NET_TYPE_LTE_ONLY;
|
||||
default:
|
||||
pref = PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
break;
|
||||
}
|
||||
|
||||
parcel_init(&rilp);
|
||||
|
||||
parcel_w_int32(&rilp, 1); /* Number of params */
|
||||
parcel_w_int32(&rilp, pref);
|
||||
|
||||
ret = g_ril_send(rd->ril, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
rilp.data, rilp.size, ril_set_rat_cb,
|
||||
cbd, g_free);
|
||||
g_ril_append_print_buf(rd->ril, "(%d)", pref);
|
||||
|
||||
parcel_free(&rilp);
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("unable to set rat mode");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_force_rat_mode(struct radio_data *rd, int pref)
|
||||
{
|
||||
struct parcel rilp;
|
||||
|
||||
if (pref == rd->ratmode)
|
||||
if (g_ril_send(rd->ril, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
&rilp, ril_set_rat_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
DBG("pref ril rat mode %d, ril current %d", pref, rd->ratmode);
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1);
|
||||
parcel_w_int32(&rilp, rd->ratmode);
|
||||
g_ril_send(rd->ril,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
rilp.data, rilp.size, NULL,
|
||||
NULL, g_free);
|
||||
parcel_free(&rilp);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ril_rat_mode_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
DBG("");
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
|
||||
struct ofono_radio_settings *rs = cbd->user;
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
int mode;
|
||||
struct parcel rilp;
|
||||
int mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
int pref;
|
||||
int net_type;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
/* first item in int[] is len so let's skip that */
|
||||
parcel_r_int32(&rilp);
|
||||
pref = parcel_r_int32(&rilp);
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
switch (pref) {
|
||||
case PREF_NET_TYPE_LTE_ONLY:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
case PREF_NET_TYPE_GSM_ONLY:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
if (parcel_r_int32(&rilp) != 1)
|
||||
goto error;
|
||||
|
||||
net_type = parcel_r_int32(&rilp);
|
||||
|
||||
if (rilp.malformed)
|
||||
goto error;
|
||||
|
||||
g_ril_append_print_buf(rd->ril, "{%d}", net_type);
|
||||
g_ril_print_response(rd->ril, message);
|
||||
|
||||
/* Try to translate special MTK settings */
|
||||
if (g_ril_vendor(rd->ril) == OFONO_RIL_VENDOR_MTK) {
|
||||
switch (net_type) {
|
||||
/* 4G preferred */
|
||||
case MTK_PREF_NET_TYPE_LTE_GSM_WCDMA:
|
||||
case MTK_PREF_NET_TYPE_LTE_GSM_WCDMA_MMDC:
|
||||
case MTK_PREF_NET_TYPE_LTE_GSM_TYPE:
|
||||
case MTK_PREF_NET_TYPE_LTE_GSM_MMDC_TYPE:
|
||||
net_type = PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
break;
|
||||
case PREF_NET_TYPE_GSM_WCDMA_AUTO:/* according to UI design */
|
||||
if (!cb)
|
||||
ril_force_rat_mode(cbd->user, pref);
|
||||
case PREF_NET_TYPE_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA: /* according to UI design */
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case PREF_NET_TYPE_LTE_CDMA_EVDO:
|
||||
case PREF_NET_TYPE_LTE_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
|
||||
if (!cb)
|
||||
ril_force_rat_mode(cbd->user, pref);
|
||||
break;
|
||||
case PREF_NET_TYPE_CDMA_EVDO_AUTO:
|
||||
case PREF_NET_TYPE_CDMA_ONLY:
|
||||
case PREF_NET_TYPE_EVDO_ONLY:
|
||||
case PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO:
|
||||
default:
|
||||
/* 3G or 2G preferred over LTE */
|
||||
case MTK_PREF_NET_TYPE_GSM_WCDMA_LTE:
|
||||
case MTK_PREF_NET_TYPE_GSM_WCDMA_LTE_MMDC:
|
||||
net_type = PREF_NET_TYPE_GSM_WCDMA;
|
||||
break;
|
||||
}
|
||||
ofono_info("rat mode %d (ril %d)", mode, pref);
|
||||
if (cb)
|
||||
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||
} else {
|
||||
if (cb)
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
ofono_error("rat mode query failed");
|
||||
}
|
||||
|
||||
if (net_type < 0 || net_type > PREF_NET_TYPE_LTE_ONLY) {
|
||||
ofono_error("%s: unknown network type", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* GSM_WCDMA_AUTO -> ril.h: GSM/WCDMA (auto mode, according to PRL)
|
||||
* PRL: preferred roaming list.
|
||||
* This value is returned when selecting the slot as having 3G
|
||||
* capabilities, so it is sort of the default for MTK modems.
|
||||
*/
|
||||
switch (net_type) {
|
||||
case PREF_NET_TYPE_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA:
|
||||
case PREF_NET_TYPE_GSM_WCDMA_AUTO:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
break;
|
||||
case PREF_NET_TYPE_GSM_ONLY:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
break;
|
||||
case PREF_NET_TYPE_LTE_GSM_WCDMA:
|
||||
mode = OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
break;
|
||||
default:
|
||||
ofono_error("%s: Unexpected preferred network type (%d)",
|
||||
__func__, net_type);
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
break;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||
void *data){
|
||||
DBG("");
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
int ret = 0;
|
||||
|
||||
ofono_info("rat mode query");
|
||||
|
||||
ret = g_ril_send(rd->ril, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
NULL, 0, ril_rat_mode_cb, cbd, g_free);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
ofono_error("unable to send rat mode query");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_get_net_config(struct radio_data *rsd)
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
GKeyFile *keyfile;
|
||||
GError *err = NULL;
|
||||
char *config_path = RIL_CONFIG_DIR;
|
||||
char **alreadyset = NULL;
|
||||
gboolean needsconfig = FALSE;
|
||||
gboolean value = FALSE;
|
||||
gboolean found = FALSE;
|
||||
rsd->ratmode = PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
GDir *config_dir;
|
||||
const gchar *config_file;
|
||||
gsize length;
|
||||
gchar **codes = NULL;
|
||||
int i;
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, rs);
|
||||
|
||||
/*
|
||||
* First we need to check should the LTE be on
|
||||
* or not
|
||||
*/
|
||||
if (g_ril_send(rd->ril, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
NULL, ril_rat_mode_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
keyfile = g_key_file_new();
|
||||
|
||||
g_key_file_set_list_separator(keyfile, ',');
|
||||
|
||||
config_dir = g_dir_open(config_path, 0, NULL);
|
||||
while ((config_file = g_dir_read_name(config_dir)) != NULL) {
|
||||
char *path = g_strconcat(RIL_CONFIG_DIR "/", config_file, NULL);
|
||||
DBG("Rilconfig handling %s", path);
|
||||
gboolean ok = g_key_file_load_from_file(keyfile, path, 0, &err);
|
||||
|
||||
g_free(path);
|
||||
if (!ok) {
|
||||
g_error_free(err);
|
||||
DBG("Rilconfig file skipped");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_key_file_has_group(keyfile, LTE_FLAG))
|
||||
found = TRUE;
|
||||
else if (g_key_file_has_group(keyfile, MCC_LIST)) {
|
||||
codes = g_key_file_get_string_list(keyfile, MCC_LIST,
|
||||
MCC_KEY, &length, NULL);
|
||||
if (codes) {
|
||||
for (i = 0; codes[i]; i++) {
|
||||
if (g_str_equal(codes[i],
|
||||
ofono_sim_get_mcc(get_sim()))
|
||||
== TRUE) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_strfreev(codes);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
rsd->ratmode = PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_key_file_free(keyfile);
|
||||
g_dir_close(config_dir);
|
||||
|
||||
/* Then we need to check if it already set */
|
||||
|
||||
keyfile = storage_open(NULL, RIL_STORE);
|
||||
alreadyset = g_key_file_get_groups(keyfile, NULL);
|
||||
|
||||
if (alreadyset[0])
|
||||
value = g_key_file_get_boolean(
|
||||
keyfile, alreadyset[0], LTE_FLAG, NULL);
|
||||
else if (rsd->ratmode == PREF_NET_TYPE_GSM_WCDMA_AUTO)
|
||||
value = TRUE;
|
||||
|
||||
if (!value && rsd->ratmode == PREF_NET_TYPE_LTE_GSM_WCDMA) {
|
||||
g_key_file_set_boolean(keyfile,
|
||||
LTE_FLAG, LTE_FLAG, TRUE);
|
||||
needsconfig = TRUE;
|
||||
} else if (value && rsd->ratmode == PREF_NET_TYPE_GSM_WCDMA_AUTO) {
|
||||
g_key_file_set_boolean(keyfile,
|
||||
LTE_FLAG, LTE_FLAG, FALSE);
|
||||
needsconfig = TRUE;
|
||||
}
|
||||
|
||||
g_strfreev(alreadyset);
|
||||
|
||||
storage_close(NULL, RIL_STORE, keyfile, TRUE);
|
||||
|
||||
DBG("needsconfig %d, rat mode %d", needsconfig, rsd->ratmode);
|
||||
return needsconfig;
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
static void ril_query_fast_dormancy(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_fast_dormancy_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, rd->fast_dormancy, data);
|
||||
}
|
||||
|
||||
static void ril_display_state_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_radio_settings *rs = cbd->user;
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
ofono_radio_settings_fast_dormancy_set_cb_t cb = cbd->cb;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
g_ril_print_response_no_args(rd->ril, message);
|
||||
|
||||
rd->fast_dormancy = rd->pending_fd;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
} else {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_set_fast_dormancy(struct ofono_radio_settings *rs,
|
||||
ofono_bool_t enable,
|
||||
ofono_radio_settings_fast_dormancy_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, rs);
|
||||
struct parcel rilp;
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1); /* Number of params */
|
||||
parcel_w_int32(&rilp, enable);
|
||||
|
||||
g_ril_append_print_buf(rd->ril, "(%d)", enable);
|
||||
|
||||
rd->pending_fd = enable;
|
||||
|
||||
if (g_ril_send(rd->ril, RIL_REQUEST_SCREEN_STATE, &rilp,
|
||||
ril_display_state_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ril_query_available_rats(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
unsigned int available_rats;
|
||||
struct ofono_modem *modem = ofono_radio_settings_get_modem(rs);
|
||||
|
||||
available_rats = OFONO_RADIO_ACCESS_MODE_GSM
|
||||
| OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
|
||||
if (ofono_modem_get_boolean(modem, MODEM_PROP_LTE_CAPABLE))
|
||||
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, available_rats, data);
|
||||
}
|
||||
|
||||
static void ril_set_band_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_radio_settings *rs = cbd->user;
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
ofono_radio_settings_band_set_cb_t cb = cbd->cb;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
g_ril_print_response_no_args(rd->ril, message);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
} else {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sofia3gr_set_band(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
struct cb_data *cbd = cb_data_new(cb, data, rs);
|
||||
struct parcel rilp;
|
||||
char cmd_buf[9], gsm_band[4], umts_band[4];
|
||||
/* RIL_OEM_HOOK_STRING_SET_BAND_PREFERENCE = 0x000000CE */
|
||||
int cmd_id = 0x000000CE;
|
||||
sprintf(cmd_buf, "%d", cmd_id);
|
||||
|
||||
switch (band_gsm) {
|
||||
case OFONO_RADIO_BAND_GSM_ANY:
|
||||
sprintf(gsm_band, "%d", PREF_NET_BAND_GSM_AUTOMATIC);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_GSM_850:
|
||||
sprintf(gsm_band, "%d", PREF_NET_BAND_GSM850);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_GSM_900P:
|
||||
sprintf(gsm_band, "%d", PREF_NET_BAND_GSM900_P);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_GSM_900E:
|
||||
sprintf(gsm_band, "%d", PREF_NET_BAND_GSM900_E);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_GSM_1800:
|
||||
sprintf(gsm_band, "%d", PREF_NET_BAND_GSM1800);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_GSM_1900:
|
||||
sprintf(gsm_band, "%d", PREF_NET_BAND_GSM1900);
|
||||
break;
|
||||
default:
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (band_umts) {
|
||||
case OFONO_RADIO_BAND_UMTS_ANY:
|
||||
sprintf(umts_band, "%d", PREF_NET_BAND_UMTS_AUTOMATIC);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_UMTS_850:
|
||||
sprintf(umts_band, "%d", PREF_NET_BAND_UMTS_V);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_UMTS_900:
|
||||
sprintf(umts_band, "%d", PREF_NET_BAND_UMTS_VIII);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_UMTS_1700AWS:
|
||||
sprintf(umts_band, "%d", PREF_NET_BAND_UMTS_IV);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_UMTS_1900:
|
||||
sprintf(umts_band, "%d", PREF_NET_BAND_UMTS_II);
|
||||
break;
|
||||
case OFONO_RADIO_BAND_UMTS_2100:
|
||||
sprintf(umts_band, "%d", PREF_NET_BAND_UMTS_I);
|
||||
break;
|
||||
default:
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
return;
|
||||
}
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 3); /* Number of params */
|
||||
parcel_w_string(&rilp, cmd_buf);
|
||||
parcel_w_string(&rilp, gsm_band);
|
||||
parcel_w_string(&rilp, umts_band);
|
||||
|
||||
if (g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
|
||||
ril_set_band_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ril_set_band(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_band_gsm band_gsm,
|
||||
enum ofono_radio_band_umts band_umts,
|
||||
ofono_radio_settings_band_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
switch (rd->vendor) {
|
||||
case OFONO_RIL_VENDOR_IMC_SOFIA3GR:
|
||||
ril_sofia3gr_set_band(rs, band_gsm, band_umts, cb, data);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ril_delayed_register(const struct ofono_error *error,
|
||||
void *user_data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
|
||||
rd->timer_id = 0;
|
||||
|
||||
ofono_radio_settings_register(rs);
|
||||
return FALSE;
|
||||
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
|
||||
ofono_radio_settings_register(rs);
|
||||
else
|
||||
ofono_error("%s: cannot set default fast dormancy", __func__);
|
||||
}
|
||||
|
||||
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor,
|
||||
void *user)
|
||||
unsigned int vendor, void *user)
|
||||
{
|
||||
GRil *ril = user;
|
||||
struct cb_data *cbd = NULL;
|
||||
int ret;
|
||||
struct radio_data *rsd = g_try_new0(struct radio_data, 1);
|
||||
struct radio_data *rsd = g_new0(struct radio_data, 1);
|
||||
|
||||
rsd->ril = g_ril_clone(ril);
|
||||
if (ril_get_net_config(rsd)) {
|
||||
cbd = cb_data_new2(rsd, NULL, NULL);
|
||||
ret = g_ril_send(rsd->ril,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
NULL, 0, ril_rat_mode_cb, cbd, g_free);
|
||||
if (ret <= 0)
|
||||
g_free(cbd);
|
||||
}
|
||||
rsd->vendor = vendor;
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
rsd->timer_id = g_timeout_add_seconds(2, ril_delayed_register, rs);
|
||||
|
||||
ril_set_fast_dormancy(rs, FALSE, ril_delayed_register, rs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -334,19 +449,20 @@ static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
struct radio_data *rd = ofono_radio_settings_get_data(rs);
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
|
||||
if (rd->timer_id > 0)
|
||||
g_source_remove(rd->timer_id);
|
||||
|
||||
g_ril_unref(rd->ril);
|
||||
g_free(rd);
|
||||
}
|
||||
|
||||
static struct ofono_radio_settings_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.name = RILMODEM,
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.query_rat_mode = ril_query_rat_mode,
|
||||
.set_rat_mode = ril_set_rat_mode,
|
||||
.set_band = ril_set_band,
|
||||
.query_fast_dormancy = ril_query_fast_dormancy,
|
||||
.set_fast_dormancy = ril_set_fast_dormancy,
|
||||
.query_available_rats = ril_query_available_rats
|
||||
};
|
||||
|
||||
void ril_radio_settings_init(void)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012 Canonical, Ltd. All rights reserved.
|
||||
* Copyright (C) 2013 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
|
||||
@@ -45,18 +44,16 @@ static int rilmodem_init(void)
|
||||
ril_sms_init();
|
||||
ril_netreg_init();
|
||||
ril_call_volume_init();
|
||||
|
||||
ril_gprs_init();
|
||||
ril_gprs_context_init();
|
||||
ril_radio_settings_init();
|
||||
ril_phonebook_init();
|
||||
ril_ussd_init();
|
||||
ril_call_settings_init();
|
||||
ril_call_forwarding_init();
|
||||
ril_radio_settings_init();
|
||||
ril_call_barring_init();
|
||||
ril_cbs_init();
|
||||
ril_oemraw_init();
|
||||
ril_netmon_init();
|
||||
ril_stk_init();
|
||||
ril_cbs_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -73,15 +70,14 @@ static void rilmodem_exit(void)
|
||||
ril_call_volume_exit();
|
||||
ril_gprs_exit();
|
||||
ril_gprs_context_exit();
|
||||
ril_radio_settings_exit();
|
||||
ril_phonebook_exit();
|
||||
ril_ussd_exit();
|
||||
ril_call_settings_exit();
|
||||
ril_call_forwarding_exit();
|
||||
ril_radio_settings_exit();
|
||||
ril_call_barring_exit();
|
||||
ril_cbs_exit();
|
||||
ril_oemraw_exit();
|
||||
ril_netmon_exit();
|
||||
ril_stk_exit();
|
||||
ril_cbs_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012 Canonical Ltd.
|
||||
* Copyright (C) 2013 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
|
||||
@@ -28,14 +27,6 @@
|
||||
/* Shared constants */
|
||||
#define EF_STATUS_INVALIDATED 0
|
||||
#define EF_STATUS_VALID 1
|
||||
#define RIL_HW_CONFIG "/etc/ofono/ril_subscription.conf"
|
||||
#define RIL_CONFIG_DIR "/etc/ofono/"
|
||||
#define RIL_STORE "rilmodem"
|
||||
#define LTE_FLAG "4gOn"
|
||||
#define MCC_LIST "MCC-whitelist"
|
||||
#define MCC_KEY "Countries"
|
||||
#define UI_LANG "/var/lib/environment/nemo/locale.conf"
|
||||
#define CFG_LANG "LANG="
|
||||
|
||||
extern void ril_devinfo_init(void);
|
||||
extern void ril_devinfo_exit(void);
|
||||
@@ -61,9 +52,6 @@ extern void ril_gprs_exit(void);
|
||||
extern void ril_gprs_context_init(void);
|
||||
extern void ril_gprs_context_exit(void);
|
||||
|
||||
extern void ril_radio_settings_init(void);
|
||||
extern void ril_radio_settings_exit(void);
|
||||
|
||||
extern void ril_ussd_init(void);
|
||||
extern void ril_ussd_exit(void);
|
||||
|
||||
@@ -73,18 +61,20 @@ extern void ril_call_settings_exit(void);
|
||||
extern void ril_call_forwarding_init(void);
|
||||
extern void ril_call_forwarding_exit(void);
|
||||
|
||||
extern void ril_radio_settings_init(void);
|
||||
extern void ril_radio_settings_exit(void);
|
||||
|
||||
extern void ril_call_barring_init(void);
|
||||
extern void ril_call_barring_exit(void);
|
||||
|
||||
extern void ril_cbs_init(void);
|
||||
extern void ril_cbs_exit(void);
|
||||
|
||||
extern void ril_phonebook_init(void);
|
||||
extern void ril_phonebook_exit(void);
|
||||
|
||||
extern void ril_oemraw_init(void);
|
||||
extern void ril_oemraw_exit(void);
|
||||
extern void ril_netmon_init(void);
|
||||
extern void ril_netmon_exit(void);
|
||||
|
||||
extern void ril_stk_init(void);
|
||||
extern void ril_stk_exit(void);
|
||||
|
||||
extern void ril_cbs_init(void);
|
||||
extern void ril_cbs_exit(void);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user