forked from sailfishos/ofono
Compare commits
620 Commits
mer/1.17+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 |
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
|
||||
|
||||
@@ -104,3 +104,15 @@ 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,34 @@
|
||||
ver 1.19:
|
||||
Fix issue with DHCP parsing and Huawei modems.
|
||||
Fix issue with detecting Huawei E3372 modem.
|
||||
Fix issue with handling serving cell info.
|
||||
Fix issue with handling SIM SC facility lock.
|
||||
Fix issue with Android RIL PIN retry logic.
|
||||
Fix issue with Android RIL and RAT handling.
|
||||
Add support for Android RIL cell broadcast.
|
||||
Add support for SoFIA 3GR thermal management.
|
||||
|
||||
ver 1.18:
|
||||
Fix issue with cell broadcast and use-after-fee.
|
||||
Fix issue with repeated held call indicator.
|
||||
Fix issue with +CCWA and connection setup.
|
||||
Fix issue with empty operator scan results.
|
||||
Fix issue with persistent RAT mode handling.
|
||||
Fix issue with multiparty call introspection.
|
||||
Fix issue with GRPS context introspection.
|
||||
Fix issue with stale context deactivation.
|
||||
Add support for automatic context activation.
|
||||
Add support for SIM service provider names.
|
||||
Add support for handling allowed APN lists.
|
||||
Add support for network monitoring interface.
|
||||
Add support for U-Blox TOBY-L2 modem series.
|
||||
Add support for Sierra MC73xx QMI modems.
|
||||
Add support for SoFIA 3GR modem series.
|
||||
Add support for upower battery monitoring.
|
||||
Add support for gateway audio card types.
|
||||
Add support for Handsfree audio driver.
|
||||
Add support for Android RIL integration.
|
||||
|
||||
ver 1.17:
|
||||
Fix issue with alphanumeric TP-OA handling.
|
||||
Fix issue with push notification origin port.
|
||||
|
||||
@@ -113,3 +113,5 @@ doc/coding-style.txt.
|
||||
a feature that touches files under 'include/', 'src/' and 'drivers/'
|
||||
directories, split in three separated patches, taking care not to
|
||||
break compilation.
|
||||
|
||||
4) Submit patches using git send-email to ofono@ofono.org
|
||||
|
||||
@@ -21,9 +21,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
|
||||
|
||||
@@ -97,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
|
||||
|
||||
@@ -120,19 +118,24 @@ 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_mce.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_mtu.c \
|
||||
drivers/ril/ril_netmon.c \
|
||||
drivers/ril/ril_netreg.c \
|
||||
drivers/ril/ril_network.c \
|
||||
drivers/ril/ril_oem_raw.c \
|
||||
@@ -143,9 +146,9 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_radio_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_dbus.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 \
|
||||
@@ -157,20 +160,29 @@ dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
builtin_modules += rildev
|
||||
builtin_sources += plugins/rildev.c
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += plugins/ril.c
|
||||
builtin_sources += plugins/ril.c plugins/ril.h
|
||||
|
||||
builtin_modules += infineon
|
||||
builtin_sources += plugins/infineon.c
|
||||
|
||||
builtin_modules += ril_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 \
|
||||
@@ -178,20 +190,15 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/sms.c \
|
||||
drivers/rilmodem/rilutil.c \
|
||||
drivers/rilmodem/rilutil.h \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/phonebook.c \
|
||||
drivers/rilmodem/ussd.c \
|
||||
drivers/rilmodem/call-settings.c \
|
||||
drivers/rilmodem/call-forwarding.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/rilmodem/oemraw-messages.c \
|
||||
drivers/rilmodem/radio-settings.c \
|
||||
drivers/rilmodem/call-barring.c \
|
||||
drivers/rilmodem/stk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += gril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
drivers/rilmodem/netmon.c \
|
||||
drivers/rilmodem/stk.c \
|
||||
drivers/rilmodem/cbs.c \
|
||||
drivers/infineonmodem/infineon_constants.h
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -279,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 \
|
||||
@@ -418,6 +424,13 @@ 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
|
||||
@@ -524,9 +537,6 @@ builtin_sources += plugins/connman.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
|
||||
|
||||
@@ -536,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@
|
||||
@@ -549,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
|
||||
|
||||
@@ -615,7 +637,7 @@ builtin_cflags += @WSPCODEC_CFLAGS@
|
||||
builtin_libadd += @WSPCODEC_LIBS@
|
||||
endif
|
||||
|
||||
if LOGCONTROL
|
||||
if DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/debuglog.c
|
||||
endif
|
||||
@@ -623,9 +645,12 @@ 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 \
|
||||
@@ -650,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/sim-mnclength.c src/oemraw.c src/voicecallagent.c \
|
||||
src/hfp.h src/siri.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
|
||||
@@ -697,7 +723,9 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/location-reporting-api.txt \
|
||||
doc/smshistory-api.txt doc/oemraw-api.txt \
|
||||
doc/certification.txt doc/siri-api.txt \
|
||||
doc/telit-modem.txt
|
||||
doc/telit-modem.txt \
|
||||
doc/networkmonitor-api.txt \
|
||||
doc/allowed-apns-api.txt
|
||||
|
||||
|
||||
test_scripts = test/backtrace \
|
||||
@@ -731,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 \
|
||||
@@ -795,7 +824,15 @@ test_scripts = test/backtrace \
|
||||
test/set-msisdn \
|
||||
test/test-voicecallagent \
|
||||
test/get-network-time \
|
||||
test/set-ddr
|
||||
test/set-ddr \
|
||||
test/register-auto \
|
||||
test/register-operator \
|
||||
test/set-sms-smsc \
|
||||
test/set-sms-bearer \
|
||||
test/get-serving-cell-info \
|
||||
test/list-allowed-access-points \
|
||||
test/enable-throttling \
|
||||
test/disable-throttling
|
||||
|
||||
if TEST
|
||||
testdir = $(pkglibdir)/test
|
||||
@@ -813,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
|
||||
|
||||
@@ -869,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 \
|
||||
@@ -891,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
|
||||
===========
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.17)
|
||||
AC_INIT(ofono, 1.19)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -64,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)
|
||||
|
||||
@@ -175,10 +175,12 @@ 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, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS"
|
||||
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],
|
||||
@@ -236,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}])
|
||||
@@ -252,10 +259,16 @@ if (test "${enable_pushforwarder}" != "no"); then
|
||||
AC_SUBST(WSPCODEC_LIBS)
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(logcontrol,
|
||||
AC_HELP_STRING([--enable-logcontrol], [enable log control plugin]),
|
||||
[enable_logcontrol=${enableval}], [enable_logcontrol="no"])
|
||||
AM_CONDITIONAL(LOGCONTROL, test "${enable_logcontrol}" != "no")
|
||||
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
|
||||
|
||||
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.
|
||||
@@ -106,7 +106,7 @@ Properties boolean Attached [readonly]
|
||||
GPRS service registration (if known).
|
||||
|
||||
Possible values are:
|
||||
"none", "gsm", "edge", "umts", "hsdpa", "hsupa",
|
||||
"none", "gprs", "edge", "umts", "hsdpa", "hsupa",
|
||||
"hspa" (HSDPA and HSUPA at the same time) and
|
||||
"lte"
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
Debug log control
|
||||
=================
|
||||
|
||||
Service org.ofono
|
||||
Interface org.ofono.DebugLog
|
||||
Object path /
|
||||
|
||||
Methods void Enable(string pattern)
|
||||
|
||||
Enables all logs that match the pattern.
|
||||
|
||||
void Disable(string pattern)
|
||||
|
||||
Disables all logs that match the pattern.
|
||||
|
||||
array(string,boolean) List()
|
||||
|
||||
Returns all available log names and their current
|
||||
states.
|
||||
|
||||
In order for Enable or Disable call to have any
|
||||
effect, the pattern must match one or more of
|
||||
these strings.
|
||||
|
||||
Signals Changed(string name, boolean enabled)
|
||||
|
||||
This signal indicates a changed log status of the
|
||||
given log module.
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,10 +352,6 @@ static void ublox_ureg_notify(GAtResult *result, gpointer user_data)
|
||||
case 5:
|
||||
bearer = 4;
|
||||
break;
|
||||
case 7:
|
||||
/* XXX: reserved - assume none. */
|
||||
bearer = 0;
|
||||
break;
|
||||
case 8:
|
||||
bearer = 1;
|
||||
break;
|
||||
@@ -355,6 +400,7 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
FALSE, gprs, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
g_at_chat_register(gd->chat, "+UREG:", ublox_ureg_notify,
|
||||
FALSE, gprs, NULL);
|
||||
g_at_chat_send(gd->chat, "AT+UREG=1", none_prefix,
|
||||
|
||||
@@ -1580,17 +1580,28 @@ static inline ofono_bool_t append_cmer_element(char *buf, int *len, int cap,
|
||||
static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
struct netreg_data *nd)
|
||||
{
|
||||
const char *mode;
|
||||
const char *ind;
|
||||
int len = sprintf(buf, "AT+CMER=");
|
||||
const char *mode;
|
||||
|
||||
DBG("");
|
||||
|
||||
switch (nd->vendor) {
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
/* UBX-13002752 R33: TOBY L2 doesn't support mode 2 and 3 */
|
||||
mode = "1";
|
||||
break;
|
||||
default:
|
||||
mode = "3";
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward unsolicited result codes directly to the TE;
|
||||
* TA‑TE link specific inband technique used to embed result codes and
|
||||
* data when TA is in on‑line data mode
|
||||
*/
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], "3", FALSE))
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[0], mode, FALSE))
|
||||
return FALSE;
|
||||
|
||||
/* No keypad event reporting */
|
||||
@@ -1607,14 +1618,14 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
* Telit does not support mode 1.
|
||||
* All indicator events shall be directed from TA to TE.
|
||||
*/
|
||||
mode = "2";
|
||||
ind = "2";
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Only those indicator events, which are not caused by +CIND
|
||||
* shall be indicated by the TA to the TE.
|
||||
*/
|
||||
mode = "1";
|
||||
ind = "1";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1623,7 +1634,7 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
|
||||
* <ind> indicates the indicator order number (as specified for +CIND)
|
||||
* and <value> is the new value of indicator.
|
||||
*/
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[3], mode, TRUE))
|
||||
if (!append_cmer_element(buf, &len, cmer_opts[3], ind, TRUE))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -1120,6 +1120,7 @@ static void at_pin_retries_query(struct ofono_sim *sim,
|
||||
return;
|
||||
break;
|
||||
case OFONO_VENDOR_UBLOX:
|
||||
case OFONO_VENDOR_UBLOX_TOBY_L2:
|
||||
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
|
||||
upincnt_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
@@ -1516,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;
|
||||
|
||||
@@ -1541,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);
|
||||
@@ -1626,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 = {
|
||||
@@ -1640,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)
|
||||
|
||||
@@ -45,5 +45,6 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_ALCATEL,
|
||||
OFONO_VENDOR_QUECTEL,
|
||||
OFONO_VENDOR_UBLOX,
|
||||
OFONO_VENDOR_UBLOX_TOBY_L2,
|
||||
OFONO_VENDOR_CINTERION,
|
||||
};
|
||||
|
||||
@@ -253,8 +253,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
|
||||
@@ -1147,8 +1146,7 @@ static void at_voicecall_remove(struct ofono_voicecall *vc)
|
||||
if (vd->vts_source)
|
||||
g_source_remove(vd->vts_source);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
|
||||
|
||||
@@ -286,8 +286,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
|
||||
@@ -709,6 +708,15 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
|
||||
int num_type, validity;
|
||||
struct ofono_call *call;
|
||||
|
||||
/* Waiting call notification makes no sense, when there are
|
||||
* no calls at all. This can happen when a phone already has
|
||||
* waiting and active calls and is being connected over HFP
|
||||
* but it first sends +CCWA before we manage to synchronize
|
||||
* calls with AT+CLCC.
|
||||
*/
|
||||
if (!vd->calls)
|
||||
return;
|
||||
|
||||
/* CCWA can repeat, ignore if we already have an waiting call */
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_WAITING),
|
||||
@@ -1110,6 +1118,17 @@ static void ciev_callheld_notify(struct ofono_voicecall *vc,
|
||||
*/
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
||||
poll_clcc, vc);
|
||||
} else {
|
||||
if (vd->clcc_source)
|
||||
g_source_remove(vd->clcc_source);
|
||||
|
||||
/*
|
||||
* We got a notification that there is a held call
|
||||
* and no active call but we already are in such state.
|
||||
* Let's schedule a poll to see what happened.
|
||||
*/
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_DELAY,
|
||||
poll_clcc, vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,8 +1255,7 @@ static void hfp_voicecall_remove(struct ofono_voicecall *vc)
|
||||
if (vd->expect_release_source)
|
||||
g_source_remove(vd->expect_release_source);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ static gboolean get_next_addr(GAtResultIter *iter, char **addr)
|
||||
if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
|
||||
return FALSE;
|
||||
|
||||
val = strtol(str, NULL, 16);
|
||||
val = strtoul(str, NULL, 16);
|
||||
|
||||
if (addr)
|
||||
*addr = g_strdup_printf("%u.%u.%u.%u",
|
||||
|
||||
@@ -1009,8 +1009,7 @@ static void ifx_voicecall_remove(struct ofono_voicecall *vc)
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
g_strfreev(vd->en_list);
|
||||
|
||||
|
||||
77
ofono/drivers/infineonmodem/infineon_constants.h
Normal file
77
ofono/drivers/infineonmodem/infineon_constants.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
*
|
||||
* RIL constants for infineon modem
|
||||
*
|
||||
* Copyright (C) 2014 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INFINEON_CONSTANTS_H
|
||||
#define INFINEON_CONSTANTS_H
|
||||
|
||||
/* Messages encapsulated in RIL_REQUEST_OEM_HOOK_RAW requests */
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_SELECT_BAND 1
|
||||
#define INF_RIL_REQUEST_OEM_SET_SELECT_BAND 2
|
||||
#define INF_RIL_REQUEST_OEM_SET_CIRCUIT_SWITCHING_PAGING 3
|
||||
#define INF_RIL_REQUEST_OEM_GET_LAST_FAILURE_REPORT_FOR_CS_REGISTRATION 4
|
||||
#define INF_RIL_REQUEST_OEM_GET_SELECT_BEARER_SERVICE_TYPE 5
|
||||
#define INF_RIL_REQUEST_OEM_GET_XPROGRESS_STATUS 6
|
||||
#define INF_RIL_REQUEST_OEM_SET_SS_NOTIFY 7
|
||||
#define INF_RIL_REQUEST_OEM_GET_SS_NOTIFY 8
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTHENTICATION_TYPE 9
|
||||
#define INF_RIL_REQUEST_OEM_SWITCH_OFF_MS 10
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_TIMEZONE_UPDATE 11
|
||||
#define INF_RIL_REQUEST_OEM_SET_TIMEZONE_RESPORTING 12
|
||||
#define INF_RIL_REQUEST_OEM_SET_DISPLAY_SIM_AND_PB_STATUS 13
|
||||
#define INF_RIL_REQUEST_OEM_GET_REMAIN_SIM_PIN_ATTEMPTS 14
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_REDIAL 15
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_CALL_STATUS_REPORTING 16
|
||||
#define INF_RIL_REQUEST_OEM_SET_AUTO_ANSWER 17
|
||||
#define INF_RIL_REQUEST_OEM_SET_LINE 18
|
||||
#define INF_RIL_REQUEST_OEM_PDP_ACTIVATE_OR_DEACTIVATE 19
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_GPRS_MS_CLASS 20
|
||||
#define INF_RIL_REQUEST_OEM_SET_TRACE_AND_AT_INTERFACES 21
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_TRACE_AND_AT_INTERFACES_CONFIGURE 22
|
||||
#define INF_RIL_REQUEST_OEM_SWITCH_TRACE_ON_OR_OFF 23
|
||||
#define INF_RIL_REQUEST_OEM_READ_EXCEPTION_LOG 24
|
||||
#define INF_RIL_REQUEST_OEM_GET_PHONE_ACTIVITY_STATUS 25
|
||||
#define INF_RIL_REQUEST_OEM_INITIATE_RESEND_SMS_IF_GPRS_FAILS 26
|
||||
#define INF_RIL_REQUEST_OEM_GET_DEVICE_NUMBER 27
|
||||
#define INF_RIL_REQUEST_OEM_ENABLE_STK 28
|
||||
#define INF_RIL_REQUEST_OEM_GET_SUBSCRIBER_NUMBER 29
|
||||
#define INF_RIL_REQUEST_OEM_SELECT_PHONE_BOOK 30
|
||||
#define INF_RIL_REQUEST_OEM_READ_PHONE_BOOK 31
|
||||
#define INF_RIL_REQUEST_OEM_INSERT_RECORD_TO_PHONE_BOOK 32
|
||||
#define INF_RIL_REQUEST_OEM_DELECT_RECORD_IN_PHONE_BOOK 33
|
||||
#define INF_RIL_REQUEST_OEM_GET_RECORD_FIELDS_MAX_LEN 34
|
||||
#define INF_RIL_REQUEST_OEM_SET_SERIAL_PORT 35
|
||||
#define INF_RIL_REQUEST_OEM_SET_DATA_PREFERED 36
|
||||
#define INF_RIL_REQUEST_OEM_SET_MODEM_ROUTING 37
|
||||
#define INF_RIL_REQUEST_OEM_CLEAR_MISS_NUMBER 38
|
||||
#define INF_RIL_REQUEST_OEM_ATH 39
|
||||
#define INF_RIL_REQUEST_OEM_NOSIG_MODE_TEST 40
|
||||
#define INF_RIL_REQUEST_OEM_SELECT_3G_BAND 41
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_3G_BAND 42
|
||||
#define INF_RIL_REQUEST_OEM_HW_RESET_MODEM 43
|
||||
#define INF_RIL_REQUEST_OEM_QUERY_DIRECT 44
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_QUERY 45
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_SET 46
|
||||
#define INF_RIL_REQUEST_OEM_USER_PLMN_DELTE 47
|
||||
#define INF_RIL_REQUEST_OEM_SET_USB_LOG 48
|
||||
#define INF_RIL_REQUEST_OEM_UPDATE_CSQ 49
|
||||
#define INF_RIL_REQUEST_OEM_DUMP_CELL_ENV 50
|
||||
|
||||
#endif /* INFINEON_CONSTANTS_H */
|
||||
@@ -652,7 +652,7 @@ static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
|
||||
|
||||
static void isi_query_locked(struct ofono_sim *sim,
|
||||
enum ofono_sim_password_type passwd_type,
|
||||
ofono_sim_locked_cb_t cb, void *data)
|
||||
ofono_query_facility_lock_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_data *sd = ofono_sim_get_data(sim);
|
||||
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
|
||||
@@ -963,7 +963,7 @@ static struct ofono_sim_driver driver = {
|
||||
.reset_passwd = isi_reset_passwd,
|
||||
.lock = isi_lock,
|
||||
.change_passwd = isi_change_passwd,
|
||||
.query_locked = isi_query_locked,
|
||||
.query_facility_lock = isi_query_locked,
|
||||
};
|
||||
|
||||
void isi_sim_init(void)
|
||||
|
||||
@@ -1032,14 +1032,6 @@ static void uicc_lock(struct ofono_sim *sim, enum ofono_sim_password_type type,
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void uicc_query_locked(struct ofono_sim *sim,
|
||||
enum ofono_sim_password_type type,
|
||||
ofono_sim_locked_cb_t cb, void *data)
|
||||
{
|
||||
DBG("Not implemented");
|
||||
CALLBACK_WITH_FAILURE(cb, -1, data);
|
||||
}
|
||||
|
||||
static gboolean decode_fcp_pin_status(const GIsiSubBlockIter *iter, uint8_t read,
|
||||
uint8_t *pin1, uint8_t *pin2)
|
||||
{
|
||||
@@ -1677,7 +1669,6 @@ static struct ofono_sim_driver driver = {
|
||||
.reset_passwd = uicc_reset_passwd,
|
||||
.change_passwd = uicc_change_passwd,
|
||||
.lock = uicc_lock,
|
||||
.query_locked = uicc_query_locked,
|
||||
};
|
||||
|
||||
void isi_uicc_init(void)
|
||||
|
||||
@@ -1715,7 +1715,7 @@ static void isi_release_specific(struct ofono_voicecall *ovc, int id,
|
||||
|
||||
if ((status->mode_info & CALL_MODE_ORIGINATOR))
|
||||
cause = CALL_CAUSE_BUSY_USER_REQUEST;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
isi_call_release_req(ovc, id, CALL_CAUSE_TYPE_CLIENT, cause, cb, data);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* 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
|
||||
@@ -25,14 +25,16 @@ struct ril_call_forward {
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
enum ril_call_forward_cmd {
|
||||
enum ril_call_forward_action {
|
||||
CF_ACTION_DISABLE,
|
||||
CF_ACTION_ENABLE,
|
||||
CF_ACTION_UNUSED,
|
||||
CF_ACTION_INTERROGATE,
|
||||
CF_ACTION_REGISTRATION,
|
||||
CF_ACTION_ERASURE
|
||||
};
|
||||
|
||||
#define CF_TIME_DEFAULT (0)
|
||||
|
||||
struct ril_call_forward_cbd {
|
||||
struct ril_call_forward *fd;
|
||||
union _ofono_call_forward_cb {
|
||||
@@ -43,35 +45,57 @@ struct ril_call_forward_cbd {
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_forward_cbd_free g_free
|
||||
|
||||
static inline struct ril_call_forward *ril_call_forward_get_data(
|
||||
struct ofono_call_forwarding *cf)
|
||||
{
|
||||
return ofono_call_forwarding_get_data(cf);
|
||||
}
|
||||
|
||||
static void ril_call_forward_cbd_free(gpointer cbd)
|
||||
{
|
||||
g_slice_free(struct ril_call_forward_cbd, cbd);
|
||||
}
|
||||
|
||||
static struct ril_call_forward_cbd *ril_call_forward_cbd_new(void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_forward_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_call_forward_cbd, 1);
|
||||
cbd = g_slice_new0(struct ril_call_forward_cbd);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_forward_submit_request(struct ril_call_forward *fd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
|
||||
int type, int cls, const struct ofono_phone_number *number, int time)
|
||||
{
|
||||
grilio_queue_send_request_full(fd->q, req, code, response,
|
||||
ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
/*
|
||||
* Modem seems to respond with error to all requests
|
||||
* made with bearer class BEARER_CLASS_DEFAULT.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, action);
|
||||
grilio_request_append_int32(req, type);
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
if (number) {
|
||||
grilio_request_append_int32(req, number->type);
|
||||
grilio_request_append_utf8(req, number->number);
|
||||
} else {
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, NULL); /* No number */
|
||||
}
|
||||
grilio_request_append_int32(req, time);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_forward_set_cb(GRilIoChannel *io, int status,
|
||||
static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
@@ -86,93 +110,51 @@ static void ril_forward_set_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_forward_set(struct ofono_call_forwarding *cf,
|
||||
enum ril_call_forward_action cmd, int type, int cls,
|
||||
const struct ofono_phone_number *number, int time,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = ril_call_forward_req(cmd, type, cls, number, time);
|
||||
|
||||
grilio_queue_send_request_full(fd->q, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_call_forward_set_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, const struct ofono_phone_number *number,
|
||||
int time, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("cf registration");
|
||||
grilio_request_append_int32(req, CF_ACTION_REGISTRATION);
|
||||
grilio_request_append_int32(req, type);
|
||||
|
||||
/*
|
||||
* Modem seems to respond with error to all queries
|
||||
* or settings made with bearer class
|
||||
* BEARER_CLASS_DEFAULT. Design decision: If given
|
||||
* class is BEARER_CLASS_DEFAULT let's map it to
|
||||
* BEARER_CLASS_VOICE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls);
|
||||
grilio_request_append_int32(req, number->type);
|
||||
grilio_request_append_utf8(req, number->number);
|
||||
grilio_request_append_int32(req, time);
|
||||
|
||||
ril_call_forward_submit_request(fd, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_forward_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_forward_send_cmd(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb,
|
||||
void *data, int action)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, action);
|
||||
grilio_request_append_int32(req, type);
|
||||
|
||||
/*
|
||||
* Modem seems to respond with error to all queries
|
||||
* or settings made with bearer class
|
||||
* BEARER_CLASS_DEFAULT. Design decision: If given
|
||||
* class is BEARER_CLASS_DEFAULT let's map it to
|
||||
* BEARER_CLASS_VOICE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
|
||||
/* Following 3 values have no real meaning in erasure
|
||||
* but apparently RIL expects them so fields need to
|
||||
* be filled. Otherwise there is no response
|
||||
*/
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, "1234567890");
|
||||
grilio_request_append_int32(req, 60);
|
||||
|
||||
ril_call_forward_submit_request(fd, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_forward_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
ril_call_forward_set(cf, CF_ACTION_REGISTRATION, type, cls,
|
||||
number, time, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_erasure(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("CF_ACTION_ERASURE");
|
||||
ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_ERASURE);
|
||||
ofono_info("cf erasure");
|
||||
ril_call_forward_set(cf, CF_ACTION_ERASURE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_deactivate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("CF_ACTION_DISABLE");
|
||||
ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_DISABLE);
|
||||
ofono_info("cf disable");
|
||||
ril_call_forward_set(cf, CF_ACTION_DISABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_activate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("CF_ACTION_ENABLE");
|
||||
ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_ENABLE);
|
||||
ofono_info("cf enable");
|
||||
ril_call_forward_set(cf, CF_ACTION_ENABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_query_cb(GRilIoChannel *io, int status,
|
||||
@@ -223,36 +205,14 @@ static void ril_call_forward_query(struct ofono_call_forwarding *cf, int type,
|
||||
int cls, ofono_call_forwarding_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
GRilIoRequest *req = ril_call_forward_req(CF_ACTION_INTERROGATE,
|
||||
type, cls, NULL, CF_TIME_DEFAULT);
|
||||
|
||||
ofono_info("cf query");
|
||||
grilio_request_append_int32(req, 2);
|
||||
grilio_request_append_int32(req, type);
|
||||
|
||||
/*
|
||||
* Modem seems to respond with error to all queries
|
||||
* or settings made with bearer class
|
||||
* BEARER_CLASS_DEFAULT. Design decision: If given
|
||||
* class is BEARER_CLASS_DEFAULT let's map it to
|
||||
* SERVICE_CLASS_NONE as per RIL design.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls);
|
||||
|
||||
/* Following 3 values have no real meaning in query
|
||||
* but apparently RIL expects them so fields need to
|
||||
* be filled. Otherwise there is no response
|
||||
*/
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, "1234567890");
|
||||
grilio_request_append_int32(req, 0);
|
||||
|
||||
ril_call_forward_submit_request(fd, req,
|
||||
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
ril_call_forward_query_cb, cb, data);
|
||||
grilio_queue_send_request_full(fd->q, req,
|
||||
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
ril_call_forward_query_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -286,7 +246,7 @@ static void ril_call_forward_remove(struct ofono_call_forwarding *cf)
|
||||
DBG("");
|
||||
ofono_call_forwarding_set_data(cf, NULL);
|
||||
|
||||
if (fd->timer_id > 0) {
|
||||
if (fd->timer_id) {
|
||||
g_source_remove(fd->timer_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,60 +16,155 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct ril_cbs {
|
||||
struct ofono_cbs *cbs;
|
||||
GRilIoChannel *io;
|
||||
guint timer_id;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
struct ril_cbs_cbd {
|
||||
struct ril_cbs *cd;
|
||||
ofono_cbs_set_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define RIL_CBS_CHECK_RETRY_MS 1000
|
||||
#define RIL_CBS_CHECK_RETRY_COUNT 30
|
||||
|
||||
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
|
||||
|
||||
#define ril_cbs_cbd_free g_free
|
||||
|
||||
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
|
||||
|
||||
cbd->cd = cd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_clear_topics(struct ofono_cbs *cbs,
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
GRilIoRequest* req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, activate ? 0 :1);
|
||||
|
||||
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||
GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
|
||||
int i, n = gutil_strv_length(list);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *entry = list[i];
|
||||
const char *delim = strchr(entry, '-');
|
||||
int from, to;
|
||||
if (delim) {
|
||||
char **range = g_strsplit(topics, "-", 0);
|
||||
from = atoi(range[0]);
|
||||
to = atoi(range[1]);
|
||||
g_strfreev(range);
|
||||
} else {
|
||||
from = to = atoi(entry);
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, from);
|
||||
grilio_request_append_int32(req, to);
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_append_int32(req, 0xff);
|
||||
grilio_request_append_int32(req, 1);
|
||||
}
|
||||
|
||||
DBG_(cd, "configuring CB");
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
g_strfreev(list);
|
||||
}
|
||||
|
||||
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = user_data;
|
||||
|
||||
if (cbd->cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "%s", topics);
|
||||
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char* pdu;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
pdu = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", pdu);
|
||||
if (pdu) {
|
||||
ofono_cbs_notify(cd->cbs, (const guchar *)pdu, strlen(pdu));
|
||||
g_free(pdu);
|
||||
}
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
DBG_(cd, "%u bytes", len);
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_register(gpointer user_data)
|
||||
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(cd->timer_id);
|
||||
cd->timer_id = 0;
|
||||
ofono_cbs_register(cd->cbs);
|
||||
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||
cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
} else {
|
||||
DBG_(cd, "failed to query CB config");
|
||||
ofono_cbs_remove(cd->cbs);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
@@ -77,12 +172,27 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
DBG("");
|
||||
cd->cbs = cbs;
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->timer_id = g_idle_add(ril_cbs_register, cd);
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
cd->cbs = cbs;
|
||||
|
||||
DBG_(cd, "");
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
|
||||
/*
|
||||
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup.
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -90,15 +200,13 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG("");
|
||||
DBG_(cd, "");
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
|
||||
if (cd->timer_id > 0) {
|
||||
g_source_remove(cd->timer_id);
|
||||
}
|
||||
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
grilio_queue_cancel_all(cd->q, FALSE);
|
||||
grilio_queue_unref(cd->q);
|
||||
g_free(cd->log_prefix);
|
||||
g_free(cd);
|
||||
}
|
||||
|
||||
@@ -106,8 +214,8 @@ const struct ofono_cbs_driver ril_cbs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_set_topics,
|
||||
.clear_topics = ril_clear_topics
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
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:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* 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
|
||||
@@ -13,15 +13,24 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_MCE_H
|
||||
#define RIL_MCE_H
|
||||
#ifndef RIL_CONFIG_H
|
||||
#define RIL_CONFIG_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_mce *ril_mce_new(GRilIoChannel *io);
|
||||
void ril_mce_free(struct ril_mce *mce);
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
#endif /* RIL_MCE_H */
|
||||
#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:
|
||||
@@ -277,6 +277,49 @@ enum ril_app_type {
|
||||
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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
@@ -50,8 +50,38 @@ struct ril_data {
|
||||
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(void);
|
||||
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);
|
||||
|
||||
@@ -62,12 +92,12 @@ typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
|
||||
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,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io);
|
||||
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);
|
||||
void ril_data_set_name(struct ril_data *data, const char *name);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||
@@ -76,16 +106,16 @@ 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, gboolean allow);
|
||||
void ril_data_allow(struct ril_data *data, enum ril_data_role role);
|
||||
|
||||
struct ril_data_call_request;
|
||||
struct ril_data_call_request *ril_data_call_setup(struct ril_data *data,
|
||||
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_call_request *ril_data_call_deactivate(struct ril_data *data,
|
||||
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_call_request_detach(struct ril_data_call_request *req);
|
||||
void ril_data_call_request_cancel(struct ril_data_call_request *req);
|
||||
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);
|
||||
|
||||
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:
|
||||
*/
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#define MAX_MTU 1280
|
||||
|
||||
struct ril_gprs_context_call {
|
||||
struct ril_data_call_request *req;
|
||||
struct ril_data_request *req;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
@@ -42,7 +42,7 @@ struct ril_gprs_context {
|
||||
struct ril_network *network;
|
||||
struct ril_data *data;
|
||||
guint active_ctx_cid;
|
||||
gulong calls_changed_event_id;
|
||||
gulong calls_changed_id;
|
||||
struct ril_mtu_watch *mtu_watch;
|
||||
struct ril_data_call *active_call;
|
||||
struct ril_gprs_context_call activate;
|
||||
@@ -55,71 +55,32 @@ static inline struct ril_gprs_context *ril_gprs_context_get_data(
|
||||
return ofono_gprs_context_get_data(gprs);
|
||||
}
|
||||
|
||||
static char *ril_gprs_context_netmask(const char *address)
|
||||
static char *ril_gprs_context_netmask(const char *bits)
|
||||
{
|
||||
if (address) {
|
||||
const char *suffix = strchr(address, '/');
|
||||
if (suffix) {
|
||||
int nbits = atoi(suffix + 1);
|
||||
if (nbits > 0 && nbits < 33) {
|
||||
const char* str;
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||
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);
|
||||
}
|
||||
str = inet_ntoa(in);
|
||||
if (str) {
|
||||
return g_strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return g_strdup("255.255.255.0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_ipv4(struct ofono_gprs_context *gc,
|
||||
char * const *ip_addr)
|
||||
static int ril_gprs_context_address_family(const char *addr)
|
||||
{
|
||||
const guint n = gutil_strv_length(ip_addr);
|
||||
|
||||
if (n > 0) {
|
||||
ofono_gprs_context_set_ipv4_address(gc, ip_addr[0], TRUE);
|
||||
if (n > 1) {
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, ip_addr[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_ipv6(struct ofono_gprs_context *gc,
|
||||
char * const *ipv6_addr)
|
||||
{
|
||||
const guint n = gutil_strv_length(ipv6_addr);
|
||||
|
||||
if (n > 0) {
|
||||
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr[0]);
|
||||
if (n > 1) {
|
||||
const int p = atoi(ipv6_addr[1]);
|
||||
if (p > 0 && p <= 128) {
|
||||
ofono_gprs_context_set_ipv6_prefix_length(gc, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_call_done(struct ril_gprs_context_call *call,
|
||||
gboolean ok)
|
||||
{
|
||||
ofono_gprs_context_cb_t cb = call->cb;
|
||||
gpointer data = call->data;
|
||||
|
||||
ril_data_call_request_cancel(call->req);
|
||||
|
||||
call->req = NULL;
|
||||
call->cb = NULL;
|
||||
call->data = NULL;
|
||||
|
||||
if (cb) {
|
||||
struct ofono_error error;
|
||||
cb(ok ? ril_error_ok(&error) : ril_error_failure(&error), data);
|
||||
if (strchr(addr, ':')) {
|
||||
return AF_INET6;
|
||||
} else if (strchr(addr, '.')) {
|
||||
return AF_INET;
|
||||
} else {
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +90,9 @@ static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = NULL;
|
||||
}
|
||||
if (gcd->calls_changed_event_id) {
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
|
||||
gcd->calls_changed_event_id = 0;
|
||||
if (gcd->calls_changed_id) {
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id = 0;
|
||||
}
|
||||
if (gcd->mtu_watch) {
|
||||
ril_mtu_watch_free(gcd->mtu_watch);
|
||||
@@ -159,7 +120,29 @@ 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) {
|
||||
ril_gprs_context_call_done(&gcd->deactivate, TRUE);
|
||||
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) {
|
||||
@@ -170,97 +153,161 @@ static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_split_ip_by_protocol(char **ip_array,
|
||||
char ***split_ip_addr,
|
||||
char ***split_ipv6_addr)
|
||||
static void ril_gprs_context_set_address(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const int n = gutil_strv_length(ip_array);
|
||||
const char *ip_addr = NULL;
|
||||
char *ip_mask = NULL;
|
||||
const char *ipv6_addr = NULL;
|
||||
unsigned char ipv6_prefix_length = 0;
|
||||
char *tmp_ip_addr = NULL;
|
||||
char *tmp_ipv6_addr = NULL;
|
||||
char * const *list = call->addresses;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
*split_ipv6_addr = *split_ip_addr = NULL;
|
||||
for (i = 0; i < n && (!*split_ipv6_addr || !*split_ip_addr); i++) {
|
||||
const char *addr = ip_array[i];
|
||||
switch (ril_address_family(addr)) {
|
||||
for (i = 0; i < n && (!ipv6_addr || !ip_addr); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!*split_ip_addr) {
|
||||
char *mask = ril_gprs_context_netmask(addr);
|
||||
*split_ip_addr = g_strsplit(addr, "/", 2);
|
||||
if (gutil_strv_length(*split_ip_addr) == 2) {
|
||||
g_free((*split_ip_addr)[1]);
|
||||
(*split_ip_addr)[1] = mask;
|
||||
if (!ip_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
tmp_ip_addr = g_strndup(addr, len);
|
||||
ip_addr = tmp_ip_addr;
|
||||
ip_mask = ril_gprs_context_netmask(s+1);
|
||||
} else {
|
||||
/* This is rather unlikely to happen */
|
||||
*split_ip_addr =
|
||||
gutil_strv_add(*split_ip_addr,
|
||||
mask);
|
||||
g_free(mask);
|
||||
ip_addr = addr;
|
||||
}
|
||||
if (!ip_mask) {
|
||||
ip_mask = g_strdup("255.255.255.0");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!*split_ipv6_addr) {
|
||||
*split_ipv6_addr = g_strsplit(addr, "/", 2);
|
||||
if (!ipv6_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
const int prefix = atoi(s + 1);
|
||||
tmp_ipv6_addr = g_strndup(addr, len);
|
||||
ipv6_addr = tmp_ipv6_addr;
|
||||
if (prefix >= 0 && prefix <= 128) {
|
||||
ipv6_prefix_length = prefix;
|
||||
}
|
||||
} else {
|
||||
ipv6_addr = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_address(gc, ip_addr, TRUE);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, ip_mask);
|
||||
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr);
|
||||
ofono_gprs_context_set_ipv6_prefix_length(gc, ipv6_prefix_length);
|
||||
|
||||
if (!ip_addr && !ipv6_addr) {
|
||||
ofono_error("GPRS context: No IP address");
|
||||
}
|
||||
|
||||
/* Allocate temporary strings */
|
||||
g_free(ip_mask);
|
||||
g_free(tmp_ip_addr);
|
||||
g_free(tmp_ipv6_addr);
|
||||
}
|
||||
|
||||
static void ril_gprs_split_gw_by_protocol(char **gw_array, char **ip_gw,
|
||||
char **ipv6_gw)
|
||||
static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const int n = gutil_strv_length(gw_array);
|
||||
const char *ip_gw = NULL;
|
||||
const char *ipv6_gw = NULL;
|
||||
char * const *list = call->gateways;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
*ip_gw = *ipv6_gw = NULL;
|
||||
for (i = 0; i < n && (!*ipv6_gw || !*ip_gw); i++) {
|
||||
const char *gw_addr = gw_array[i];
|
||||
switch (ril_address_family(gw_addr)) {
|
||||
/* Pick 1 gw for each protocol*/
|
||||
for (i = 0; i < n && (!ipv6_gw || !ip_gw); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!*ip_gw) *ip_gw = g_strdup(gw_addr);
|
||||
if (!ip_gw) ip_gw = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!*ipv6_gw) *ipv6_gw = g_strdup(gw_addr);
|
||||
if (!ipv6_gw) ipv6_gw = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
static void ril_gprs_split_dns_by_protocol(char **dns_array, char ***dns_addr,
|
||||
char ***dns_ipv6_addr)
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const int n = gutil_strv_length(dns_array);
|
||||
int i;
|
||||
char * const *list = call->dnses;
|
||||
const int n = gutil_strv_length(list);
|
||||
const char **ip_dns = g_new0(const char *, n+1);
|
||||
const char **ipv6_dns = g_new0(const char *, n+1);
|
||||
const char **ip_ptr = ip_dns;
|
||||
const char **ipv6_ptr = ipv6_dns;
|
||||
|
||||
*dns_ipv6_addr = *dns_addr = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *addr = dns_array[i];
|
||||
switch (ril_address_family(addr)) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
*dns_addr = gutil_strv_add(*dns_addr, addr);
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
*dns_ipv6_addr = gutil_strv_add(*dns_ipv6_addr, addr);
|
||||
*ipv6_ptr++ = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
|
||||
|
||||
g_free(ip_dns);
|
||||
g_free(ipv6_dns);
|
||||
}
|
||||
|
||||
/* Only compares the stuff that's important to us */
|
||||
static gboolean ril_gprs_context_data_call_equal(
|
||||
#define DATA_CALL_IFNAME_CHANGED (0x01)
|
||||
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||
#define DATA_CALL_ALL_CHANGED (0x0f)
|
||||
static int ril_gprs_context_data_call_change(
|
||||
const struct ril_data_call *c1,
|
||||
const struct ril_data_call *c2)
|
||||
{
|
||||
if (!c1 && !c2) {
|
||||
return TRUE;
|
||||
return 0;
|
||||
} else if (c1 && c2) {
|
||||
return c1->cid == c2->cid &&
|
||||
c1->active == c2->active && c1->prot == c2->prot &&
|
||||
!g_strcmp0(c1->ifname, c2->ifname) &&
|
||||
gutil_strv_equal(c1->dnses, c2->dnses) &&
|
||||
gutil_strv_equal(c1->gateways, c2->gateways) &&
|
||||
gutil_strv_equal(c1->addresses, c2->addresses);
|
||||
int changes = 0;
|
||||
|
||||
if (g_strcmp0(c1->ifname, c2->ifname)) {
|
||||
changes |= DATA_CALL_IFNAME_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->addresses, c2->addresses)) {
|
||||
changes |= DATA_CALL_ADDRESS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->gateways, c2->gateways)) {
|
||||
changes |= DATA_CALL_GATEWAY_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->dnses, c2->dnses)) {
|
||||
changes |= DATA_CALL_DNS_CHANGED;
|
||||
}
|
||||
|
||||
return changes;
|
||||
} else {
|
||||
return FALSE;
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,30 +324,25 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
struct ril_data_call *prev_call = gcd->active_call;
|
||||
const struct ril_data_call *call =
|
||||
ril_data_call_find(data->data_calls, prev_call->cid);
|
||||
int change = 0;
|
||||
|
||||
if (call) {
|
||||
/* Check if the call has been disconnected */
|
||||
if (call->active == RIL_DATA_CALL_INACTIVE) {
|
||||
ofono_error("Clearing active context");
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
call = NULL;
|
||||
|
||||
if (call && call->active != RIL_DATA_CALL_INACTIVE) {
|
||||
/* Compare it against the last known state */
|
||||
} else if (ril_gprs_context_data_call_equal(call, prev_call)) {
|
||||
DBG("call %u didn't change", call->cid);
|
||||
call = NULL;
|
||||
|
||||
} else {
|
||||
DBG("call %u changed", call->cid);
|
||||
}
|
||||
change = ril_gprs_context_data_call_change(call, prev_call);
|
||||
} else {
|
||||
ofono_error("Clearing active context");
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
call = NULL;
|
||||
}
|
||||
|
||||
if (!call) {
|
||||
/* We are not interested */
|
||||
return;
|
||||
} else if (!change) {
|
||||
DBG("call %u didn't change", call->cid);
|
||||
return;
|
||||
} else {
|
||||
DBG("call %u changed", call->cid);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -315,102 +357,27 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
ofono_info("data call status: %d", call->status);
|
||||
}
|
||||
|
||||
if (call->active == RIL_DATA_CALL_ACTIVE) {
|
||||
gboolean signal = FALSE;
|
||||
|
||||
if (call->ifname && g_strcmp0(call->ifname, prev_call->ifname)) {
|
||||
DBG("interface changed");
|
||||
signal = TRUE;
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(call->addresses, prev_call->addresses)) {
|
||||
char **split_ip_addr = NULL;
|
||||
char **split_ipv6_addr = NULL;
|
||||
|
||||
DBG("address changed");
|
||||
signal = TRUE;
|
||||
|
||||
/* Pick 1 address of each protocol */
|
||||
ril_gprs_split_ip_by_protocol(call->addresses,
|
||||
&split_ip_addr, &split_ipv6_addr);
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
|
||||
split_ipv6_addr) {
|
||||
ril_gprs_context_set_ipv6(gc, split_ipv6_addr);
|
||||
}
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IP) &&
|
||||
split_ip_addr) {
|
||||
ril_gprs_context_set_ipv4(gc, split_ip_addr);
|
||||
}
|
||||
|
||||
g_strfreev(split_ip_addr);
|
||||
g_strfreev(split_ipv6_addr);
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(call->gateways, prev_call->gateways)){
|
||||
char *ip_gw = NULL;
|
||||
char *ipv6_gw = NULL;
|
||||
|
||||
DBG("gateway changed");
|
||||
signal = TRUE;
|
||||
|
||||
/* Pick 1 gw for each protocol*/
|
||||
ril_gprs_split_gw_by_protocol(call->gateways,
|
||||
&ip_gw, &ipv6_gw);
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
|
||||
ipv6_gw) {
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IP) &&
|
||||
ip_gw) {
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
}
|
||||
|
||||
g_free(ip_gw);
|
||||
g_free(ipv6_gw);
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(call->dnses, prev_call->dnses)){
|
||||
char **dns_ip = NULL;
|
||||
char **dns_ipv6 = NULL;
|
||||
|
||||
DBG("name server(s) changed");
|
||||
signal = TRUE;
|
||||
|
||||
/* split based on protocol*/
|
||||
ril_gprs_split_dns_by_protocol(call->dnses,
|
||||
&dns_ip, &dns_ipv6);
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
|
||||
dns_ipv6) {
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc,
|
||||
(const char **) dns_ipv6);
|
||||
}
|
||||
|
||||
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IP) && dns_ip) {
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc,
|
||||
(const char**)dns_ip);
|
||||
}
|
||||
|
||||
g_strfreev(dns_ip);
|
||||
g_strfreev(dns_ipv6);
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
}
|
||||
if (change & DATA_CALL_IFNAME_CHANGED) {
|
||||
DBG("interface changed");
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_ADDRESS_CHANGED) {
|
||||
DBG("address changed");
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_GATEWAY_CHANGED) {
|
||||
DBG("gateway changed");
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_DNS_CHANGED) {
|
||||
DBG("name server(s) changed");
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, call->cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
|
||||
@@ -421,93 +388,47 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
struct ofono_error error;
|
||||
char **split_ip_addr = NULL;
|
||||
char **split_ipv6_addr = NULL;
|
||||
char* ip_gw = NULL;
|
||||
char* ipv6_gw = NULL;
|
||||
char** dns_addr = NULL;
|
||||
char** dns_ipv6_addr = NULL;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer cb_data;
|
||||
|
||||
ofono_info("setting up data call");
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("GPRS context: Reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (call->status != PDP_FAIL_NONE) {
|
||||
} else if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_error("Unexpected data call status %d", call->status);
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
error.error = call->status;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Must have interface */
|
||||
if (!call->ifname) {
|
||||
} else if (!call->ifname) {
|
||||
/* Must have interface */
|
||||
ofono_error("GPRS context: No interface");
|
||||
goto done;
|
||||
} else {
|
||||
ofono_info("setting up data call");
|
||||
|
||||
GASSERT(!gcd->calls_changed_id);
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id =
|
||||
ril_data_add_calls_changed_handler(gcd->data,
|
||||
ril_gprs_context_call_list_changed, gcd);
|
||||
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
ril_error_init_ok(&error);
|
||||
}
|
||||
|
||||
/* Check the ip address */
|
||||
ril_gprs_split_ip_by_protocol(call->addresses, &split_ip_addr,
|
||||
&split_ipv6_addr);
|
||||
if (!split_ip_addr && !split_ipv6_addr) {
|
||||
ofono_error("GPRS context: No IP address");
|
||||
goto done;
|
||||
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
}
|
||||
|
||||
ril_error_init_ok(&error);
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
|
||||
GASSERT(!gcd->calls_changed_event_id);
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
|
||||
gcd->calls_changed_event_id =
|
||||
ril_data_add_calls_changed_handler(gcd->data,
|
||||
ril_gprs_context_call_list_changed, gcd);
|
||||
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
ril_gprs_split_gw_by_protocol(call->gateways, &ip_gw, &ipv6_gw);
|
||||
ril_gprs_split_dns_by_protocol(call->dnses, &dns_addr, &dns_ipv6_addr);
|
||||
|
||||
if (split_ipv6_addr &&
|
||||
(call->prot == OFONO_GPRS_PROTO_IPV6 ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV4V6)) {
|
||||
ril_gprs_context_set_ipv6(gc, split_ipv6_addr);
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc,
|
||||
(const char **) dns_ipv6_addr);
|
||||
}
|
||||
|
||||
if (split_ip_addr &&
|
||||
(call->prot == OFONO_GPRS_PROTO_IP ||
|
||||
call->prot == OFONO_GPRS_PROTO_IPV4V6)) {
|
||||
ril_gprs_context_set_ipv4(gc, split_ip_addr);
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc,
|
||||
(const char **) dns_addr);
|
||||
}
|
||||
|
||||
done:
|
||||
g_strfreev(split_ip_addr);
|
||||
g_strfreev(split_ipv6_addr);
|
||||
g_strfreev(dns_addr);
|
||||
g_strfreev(dns_ipv6_addr);
|
||||
g_free(ip_gw);
|
||||
g_free(ipv6_gw);
|
||||
|
||||
cb = gcd->activate.cb;
|
||||
cb_data = gcd->activate.data;
|
||||
GASSERT(gcd->activate.req);
|
||||
memset(&gcd->activate, 0, sizeof(gcd->activate));
|
||||
|
||||
if (cb) {
|
||||
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
}
|
||||
cb(&error, cb_data);
|
||||
}
|
||||
}
|
||||
@@ -527,14 +448,14 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||
NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Can't activate context %d (roaming)",
|
||||
ofono_info("Can't activate context %u (roaming)",
|
||||
ctx->cid);
|
||||
cb(ril_error_failure(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Activating context: %d", ctx->cid);
|
||||
ofono_info("Activating context: %u", ctx->cid);
|
||||
GASSERT(!gcd->activate.req);
|
||||
GASSERT(ctx->cid != CTX_ID_NONE);
|
||||
|
||||
@@ -549,32 +470,37 @@ 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;
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer cb_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",
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
cb = gcd->deactivate.cb;
|
||||
cb_data = gcd->deactivate.data;
|
||||
GASSERT(gcd->deactivate.req);
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
|
||||
if (cb) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(&error, cb_data);
|
||||
} else {
|
||||
/* Have to tell ofono that the call has been disconnected */
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
}
|
||||
/* 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,
|
||||
@@ -583,7 +509,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivate primary");
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
gcd->deactivate.cb = cb;
|
||||
@@ -600,7 +526,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int id)
|
||||
{
|
||||
DBG("%d", id);
|
||||
DBG("%u", id);
|
||||
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -627,17 +553,25 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
DBG("");
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
ril_data_call_request_cancel(gcd->activate.req);
|
||||
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_call_request_detach(gcd->deactivate.req);
|
||||
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_event_id);
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
ril_data_unref(gcd->data);
|
||||
ril_network_unref(gcd->network);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* 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_mce.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
#define MCE_SERVICE "com.nokia.mce"
|
||||
#define MCE_SIGNAL_IF "com.nokia.mce.signal"
|
||||
#define MCE_DISPLAY_SIG "display_status_ind"
|
||||
#define MCE_DISPLAY_OFF_STRING "off"
|
||||
|
||||
struct ril_mce {
|
||||
GRilIoChannel *io;
|
||||
DBusConnection *conn;
|
||||
int screen_state;
|
||||
guint daemon_watch;
|
||||
guint signal_watch;
|
||||
};
|
||||
|
||||
static void ril_mce_send_screen_state(struct ril_mce *mce, gboolean on)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, on); /* screen on/off */
|
||||
|
||||
grilio_channel_send_request(mce->io, req, RIL_REQUEST_SCREEN_STATE);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_mce_display_changed(DBusConnection *conn,
|
||||
DBusMessage *message, void *user_data)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
|
||||
if (dbus_message_iter_init(message, &iter) &&
|
||||
dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
|
||||
struct ril_mce *mce = user_data;
|
||||
const char *value = NULL;
|
||||
int state;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &value);
|
||||
DBG(" %s", value);
|
||||
|
||||
/* It is on if it's not off */
|
||||
state = (g_strcmp0(value, MCE_DISPLAY_OFF_STRING) != 0);
|
||||
if (mce->screen_state != state) {
|
||||
mce->screen_state = state;
|
||||
ril_mce_send_screen_state(mce, state);
|
||||
}
|
||||
} else {
|
||||
DBG("");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ril_mce_connect(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
struct ril_mce *mce = user_data;
|
||||
|
||||
DBG("");
|
||||
if (!mce->signal_watch) {
|
||||
mce->signal_watch = g_dbus_add_signal_watch(conn,
|
||||
MCE_SERVICE, NULL, MCE_SIGNAL_IF, MCE_DISPLAY_SIG,
|
||||
ril_mce_display_changed, mce, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mce_disconnect(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
struct ril_mce *mce = user_data;
|
||||
|
||||
DBG("");
|
||||
if (mce->signal_watch) {
|
||||
g_dbus_remove_watch(conn, mce->signal_watch);
|
||||
mce->signal_watch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_mce *ril_mce_new(GRilIoChannel *io)
|
||||
{
|
||||
struct ril_mce *mce = g_new0(struct ril_mce, 1);
|
||||
|
||||
mce->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
mce->io = grilio_channel_ref(io);
|
||||
mce->screen_state = -1;
|
||||
mce->daemon_watch = g_dbus_add_service_watch(mce->conn, MCE_SERVICE,
|
||||
ril_mce_connect, ril_mce_disconnect, mce, NULL);
|
||||
|
||||
return mce;
|
||||
}
|
||||
|
||||
void ril_mce_free(struct ril_mce *mce)
|
||||
{
|
||||
if (mce) {
|
||||
if (mce->signal_watch) {
|
||||
g_dbus_remove_watch(mce->conn, mce->signal_watch);
|
||||
}
|
||||
if (mce->daemon_watch) {
|
||||
g_dbus_remove_watch(mce->conn, mce->daemon_watch);
|
||||
}
|
||||
dbus_connection_unref(mce->conn);
|
||||
grilio_channel_unref(mce->io);
|
||||
g_free(mce);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#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"
|
||||
@@ -49,12 +51,12 @@ struct ril_modem_online_request {
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_radio_settings *radio_settings;
|
||||
char *default_name;
|
||||
char *log_prefix;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gboolean pre_sim_done;
|
||||
gboolean devinfo_created;
|
||||
gboolean allow_data;
|
||||
gulong sim_imsi_event_id;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
@@ -72,6 +74,8 @@ struct ril_modem_data {
|
||||
|
||||
#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);
|
||||
@@ -114,6 +118,12 @@ struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
|
||||
}
|
||||
|
||||
static inline struct ofono_radio_settings *ril_modem_radio_settings(
|
||||
struct ril_modem *modem)
|
||||
{
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
|
||||
}
|
||||
|
||||
void ril_modem_delete(struct ril_modem *md)
|
||||
{
|
||||
if (md && md->ofono) {
|
||||
@@ -139,27 +149,6 @@ void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
md->online_cb_data = data;
|
||||
}
|
||||
|
||||
static void ril_modem_check_devinfo(struct ril_modem_data *md)
|
||||
{
|
||||
/* devinfo driver assumes that IMEI is known */
|
||||
if (md->imei && md->pre_sim_done && !md->devinfo_created &&
|
||||
md->modem.ofono) {
|
||||
md->devinfo_created = TRUE;
|
||||
ofono_devinfo_create(md->modem.ofono, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_modem_set_imei(struct ril_modem *modem, const char *imei)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
|
||||
|
||||
if (md) {
|
||||
g_free(md->imei);
|
||||
modem->imei = md->imei = g_strdup(imei);
|
||||
ril_modem_check_devinfo(md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
@@ -243,17 +232,23 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
if (md->modem.radio->state == RADIO_STATE_ON) {
|
||||
if (!md->radio_settings) {
|
||||
DBG("Initializing radio settings interface");
|
||||
md->radio_settings =
|
||||
ofono_radio_settings_create(md->modem.ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
struct ril_modem *m = &md->modem;
|
||||
if (m->radio->state == RADIO_STATE_ON && 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");
|
||||
}
|
||||
} else if (md->radio_settings) {
|
||||
DBG("Removing radio settings interface");
|
||||
ofono_radio_settings_remove(md->radio_settings);
|
||||
md->radio_settings = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +259,15 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *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)
|
||||
{
|
||||
@@ -272,10 +275,9 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->pre_sim_done = TRUE;
|
||||
ril_modem_check_devinfo(md);
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ril_modem_update_radio_settings(md);
|
||||
if (!md->radio_state_event_id) {
|
||||
md->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||
@@ -309,6 +311,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||
}
|
||||
|
||||
@@ -321,7 +324,7 @@ static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_settings_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_oem_raw_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,
|
||||
@@ -405,6 +408,10 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
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);
|
||||
}
|
||||
@@ -419,19 +426,22 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
|
||||
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->default_name);
|
||||
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,
|
||||
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_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,
|
||||
@@ -441,32 +451,46 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io,
|
||||
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);
|
||||
if (slot->config->default_name &&
|
||||
slot->config->default_name[0]) {
|
||||
md->default_name = g_strdup(slot->config->default_name);
|
||||
} else {
|
||||
md->default_name = g_strdup_printf("SIM%u",
|
||||
slot->config->slot + 1);
|
||||
}
|
||||
modem->config.default_name = md->default_name;
|
||||
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);
|
||||
ril_radio_power_on(modem->radio, RADIO_POWER_TAG(md));
|
||||
GASSERT(io->connected);
|
||||
|
||||
/*
|
||||
@@ -476,6 +500,17 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io,
|
||||
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",
|
||||
|
||||
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:
|
||||
*/
|
||||
@@ -164,7 +164,13 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
GASSERT(!nd->current_operator_id);
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -397,10 +403,13 @@ 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_queue_send_request_full(nd->q, NULL,
|
||||
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,
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
*
|
||||
* 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
|
||||
* 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"
|
||||
|
||||
@@ -22,22 +24,47 @@
|
||||
#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;
|
||||
gulong event_id;
|
||||
guint operator_poll_id;
|
||||
guint voice_poll_id;
|
||||
guint data_poll_id;
|
||||
gulong radio_event_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;
|
||||
};
|
||||
|
||||
@@ -45,12 +72,14 @@ 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 };
|
||||
|
||||
@@ -59,6 +88,40 @@ G_DEFINE_TYPE(RilNetwork, ril_network, G_TYPE_OBJECT)
|
||||
#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));
|
||||
@@ -72,7 +135,6 @@ static void ril_network_reset_state(struct ril_registration_state *reg)
|
||||
static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
const void *data, guint len, struct ril_registration_state *reg)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
int nparams, ril_status;
|
||||
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
|
||||
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
|
||||
@@ -83,13 +145,13 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
/* 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("%sbroken response", priv->log_prefix);
|
||||
DBG_(self, "broken response");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sstatus = grilio_parser_get_utf8(&rilp); /* response[0] */
|
||||
if (!sstatus) {
|
||||
DBG("%sNo sstatus value returned!", priv->log_prefix);
|
||||
DBG_(self, "No sstatus value returned!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -134,7 +196,7 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
* supply some reasonable default. We don't need more than 2
|
||||
* simultaneous data calls anyway.
|
||||
*/
|
||||
if (nparams <= 5) {
|
||||
if (reg->max_calls < 1) {
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
@@ -142,7 +204,7 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG("%s%s,%s,%s,%d,%s,%s,%s", priv->log_prefix,
|
||||
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),
|
||||
@@ -237,16 +299,15 @@ static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
|
||||
|
||||
if (changed) {
|
||||
if (self->operator) {
|
||||
DBG("%slalpha=%s, salpha=%s, numeric=%s, %s, "
|
||||
"mcc=%s, mnc=%s, %s", priv->log_prefix,
|
||||
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("%sno operator", priv->log_prefix);
|
||||
DBG_(self, "no operator");
|
||||
}
|
||||
g_signal_emit(self, ril_network_signals[
|
||||
SIGNAL_OPERATOR_CHANGED], 0);
|
||||
ril_network_emit(self, SIGNAL_OPERATOR_CHANGED);
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
@@ -269,10 +330,9 @@ static void ril_network_poll_voice_state_cb(GRilIoChannel *io, int req_status,
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->voice, sizeof(state))) {
|
||||
DBG("%svoice registration changed", priv->log_prefix);
|
||||
DBG_(self, "voice registration changed");
|
||||
self->voice = state;
|
||||
g_signal_emit(self, ril_network_signals[
|
||||
SIGNAL_VOICE_STATE_CHANGED], 0);
|
||||
ril_network_emit(self, SIGNAL_VOICE_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,10 +351,9 @@ static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->data, sizeof(state))) {
|
||||
DBG("%sdata registration changed", priv->log_prefix);
|
||||
DBG_(self, "data registration changed");
|
||||
self->data = state;
|
||||
g_signal_emit(self, ril_network_signals[
|
||||
SIGNAL_DATA_STATE_CHANGED], 0);
|
||||
ril_network_emit(self, SIGNAL_DATA_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,7 +382,7 @@ static void ril_network_poll_state(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
DBG_(self, "");
|
||||
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
||||
ril_network_poll_operator_cb);
|
||||
@@ -335,6 +394,267 @@ static void ril_network_poll_state(struct ril_network *self)
|
||||
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)
|
||||
{
|
||||
@@ -356,6 +676,13 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *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)) {
|
||||
@@ -363,48 +690,121 @@ void ril_network_remove_handler(struct ril_network *self, gulong 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);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
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 *user_data)
|
||||
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_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);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_new(GRilIoChannel *io, struct ril_radio *radio)
|
||||
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->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->event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
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 = ril_radio_add_state_changed_handler(priv->radio,
|
||||
ril_network_radio_state_cb, 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);
|
||||
}
|
||||
@@ -437,24 +837,31 @@ static void ril_network_init(struct ril_network *self)
|
||||
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;
|
||||
|
||||
if (priv->event_id) {
|
||||
grilio_channel_remove_handler(priv->io, priv->event_id);
|
||||
priv->event_id = 0;
|
||||
}
|
||||
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);
|
||||
|
||||
if (priv->radio_event_id) {
|
||||
ril_radio_remove_handler(priv->radio, priv->radio_event_id);
|
||||
priv->radio_event_id = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -463,11 +870,13 @@ static void ril_network_finalize(GObject *object)
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -478,18 +887,10 @@ static void ril_network_class_init(RilNetworkClass *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_signals[SIGNAL_OPERATOR_CHANGED] =
|
||||
g_signal_new(SIGNAL_OPERATOR_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_network_signals[SIGNAL_VOICE_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_VOICE_STATE_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_network_signals[SIGNAL_DATA_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_DATA_STATE_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
RIL_NETWORK_SIGNAL(klass, OPERATOR);
|
||||
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
@@ -35,21 +37,32 @@ struct ril_network {
|
||||
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, struct ril_radio *radio);
|
||||
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 */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* 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
|
||||
@@ -16,118 +16,147 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.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;
|
||||
guint timer_id;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
char *log_prefix;
|
||||
};
|
||||
|
||||
struct ril_oem_raw_cbd {
|
||||
ofono_oem_raw_query_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
|
||||
|
||||
#define ril_oem_raw_cbd_free g_free
|
||||
|
||||
static inline struct ril_oem_raw *ril_oem_raw_get_data(
|
||||
struct ofono_oem_raw *raw)
|
||||
{
|
||||
return ofono_oem_raw_get_data(raw);
|
||||
}
|
||||
|
||||
static struct ril_oem_raw_cbd *ril_oem_raw_cbd_new(ofono_oem_raw_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_oem_raw_cbd *cbd = g_new0(struct ril_oem_raw_cbd, 1);
|
||||
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_oem_raw_request_cb(GRilIoChannel *io, int status,
|
||||
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_oem_raw_cbd *cbd = user_data;
|
||||
DBusMessage *msg = user_data;
|
||||
DBusMessage *reply;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ofono_oem_raw_results result;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBusMessageIter it, array;
|
||||
const guchar* bytes = data;
|
||||
guint i;
|
||||
|
||||
result.data = (void *)data;
|
||||
result.length = len;
|
||||
cbd->cb(ril_error_ok(&error), &result, cbd->data);
|
||||
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:%d len:%d ", status, len);
|
||||
cbd->cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
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 void ril_oem_raw_request(struct ofono_oem_raw *raw,
|
||||
const struct ofono_oem_raw_request *request,
|
||||
ofono_oem_raw_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_oem_raw *od = ril_oem_raw_get_data(raw);
|
||||
GRilIoRequest *req = grilio_request_sized_new(request->length);
|
||||
|
||||
grilio_request_append_bytes(req, request->data, request->length);
|
||||
grilio_queue_send_request_full(od->q, req, RIL_REQUEST_OEM_HOOK_RAW,
|
||||
ril_oem_raw_request_cb, ril_oem_raw_cbd_free,
|
||||
ril_oem_raw_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_oem_raw_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_oem_raw *raw = user_data;
|
||||
struct ril_oem_raw *od = ril_oem_raw_get_data(raw);
|
||||
|
||||
DBG("");
|
||||
GASSERT(od->timer_id);
|
||||
od->timer_id = 0;
|
||||
ofono_oem_raw_dbus_register(raw);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_oem_raw_probe(struct ofono_oem_raw *raw, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_oem_raw *od = g_new0(struct ril_oem_raw, 1);
|
||||
|
||||
DBG("");
|
||||
od->q = grilio_queue_new(ril_modem_io(modem));
|
||||
od->timer_id = g_idle_add(ril_oem_raw_register, raw);
|
||||
ofono_oem_raw_set_data(raw, od);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_oem_raw_remove(struct ofono_oem_raw *raw)
|
||||
{
|
||||
struct ril_oem_raw *od = ril_oem_raw_get_data(raw);
|
||||
|
||||
DBG("");
|
||||
grilio_queue_cancel_all(od->q, TRUE);
|
||||
ofono_oem_raw_set_data(raw, NULL);
|
||||
|
||||
if (od->timer_id) {
|
||||
g_source_remove(od->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_unref(od->q);
|
||||
g_free(od);
|
||||
}
|
||||
|
||||
/* const */ struct ofono_oem_raw_driver ril_oem_raw_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_oem_raw_probe,
|
||||
.remove = ril_oem_raw_remove,
|
||||
.request = ril_oem_raw_request,
|
||||
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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,6 @@
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/oemraw.h>
|
||||
#include <ofono/phonebook.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/sim.h>
|
||||
@@ -36,6 +35,7 @@
|
||||
#include <ofono/stk.h>
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/voicecall.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
@@ -45,15 +45,10 @@
|
||||
|
||||
typedef struct ril_slot_info const *ril_slot_info_ptr;
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
gboolean enable_4g;
|
||||
const char *default_name;
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -67,16 +62,21 @@ struct ril_plugin {
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -87,6 +87,7 @@ struct ril_modem {
|
||||
#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,
|
||||
@@ -99,15 +100,22 @@ void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
|
||||
void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
|
||||
const char *imsi);
|
||||
|
||||
struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *modem);
|
||||
const char *ril_sim_dbus_imsi(struct ril_sim_dbus *dbus);
|
||||
void ril_sim_dbus_free(struct ril_sim_dbus *dbus);
|
||||
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,
|
||||
@@ -116,12 +124,12 @@ 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,
|
||||
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_data *data, struct ril_sim_settings *settings,
|
||||
struct ril_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
void ril_modem_set_imei(struct ril_modem *modem, const char *imei);
|
||||
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);
|
||||
@@ -135,19 +143,6 @@ void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
#define ril_modem_slot(modem) ((modem)->config.slot)
|
||||
#define ril_modem_io(modem) ((modem)->io)
|
||||
|
||||
void ril_sim_read_file_linear(struct ofono_sim *sim, int fileid,
|
||||
int record, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
|
||||
void ril_sim_read_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
int record, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
|
||||
void ril_sim_read_file_transparent(struct ofono_sim *sim, int fileid,
|
||||
int start, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
|
||||
void ril_sim_read_file_info(struct ofono_sim *sim, int fileid,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_file_info_cb_t cb, void *data);
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
|
||||
|
||||
@@ -161,7 +156,6 @@ 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_oem_raw_driver ril_oem_raw_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;
|
||||
@@ -169,6 +163,7 @@ extern const struct ofono_sms_driver ril_sms_driver;
|
||||
extern const struct ofono_stk_driver ril_stk_driver;
|
||||
extern const struct ofono_ussd_driver ril_ussd_driver;
|
||||
extern const struct ofono_voicecall_driver ril_voicecall_driver;
|
||||
extern const struct ofono_netmon_driver ril_netmon_driver;
|
||||
|
||||
#endif /* RIL_PLUGIN_H */
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ struct ril_plugin_dbus {
|
||||
|
||||
#define RIL_DBUS_PATH "/"
|
||||
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
|
||||
#define RIL_DBUS_INTERFACE_VERSION (4)
|
||||
#define RIL_DBUS_INTERFACE_VERSION (5)
|
||||
|
||||
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
|
||||
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
|
||||
@@ -56,6 +56,7 @@ struct ril_plugin_dbus {
|
||||
#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)
|
||||
@@ -133,6 +134,11 @@ static void ril_plugin_dbus_append_boolean_array(DBusMessageIter *it,
|
||||
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 = "";
|
||||
@@ -187,6 +193,13 @@ static inline void ril_plugin_dbus_signal_string(struct ril_plugin_dbus *dbus,
|
||||
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) {
|
||||
@@ -225,6 +238,11 @@ void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,6 +368,13 @@ static void ril_plugin_dbus_append_all4(DBusMessageIter *it,
|
||||
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)
|
||||
{
|
||||
@@ -378,6 +403,13 @@ static DBusMessage *ril_plugin_dbus_get_all4(DBusConnection *conn,
|
||||
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)
|
||||
{
|
||||
@@ -510,6 +542,18 @@ static DBusMessage *ril_plugin_dbus_get_mms_modem(DBusConnection *conn,
|
||||
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)
|
||||
{
|
||||
@@ -671,6 +715,9 @@ static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
|
||||
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",
|
||||
@@ -685,6 +732,9 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
|
||||
{ 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) },
|
||||
@@ -718,6 +768,9 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
|
||||
{ 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) },
|
||||
@@ -751,6 +804,8 @@ static const GDBusSignalTable ril_plugin_dbus_signals[] = {
|
||||
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" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
typedef GObjectClass RilRadioClass;
|
||||
typedef struct ril_radio RilRadio;
|
||||
|
||||
@@ -48,38 +50,53 @@ struct ril_radio_priv {
|
||||
|
||||
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);
|
||||
|
||||
G_INLINE_FUNC gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
return g_hash_table_size(priv->req_table) && !priv->power_cycle;
|
||||
return self->online && !priv->power_cycle &&
|
||||
g_hash_table_size(priv->req_table) > 0;
|
||||
}
|
||||
|
||||
G_INLINE_FUNC gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
{
|
||||
return radio_state == RADIO_STATE_OFF;
|
||||
}
|
||||
|
||||
G_INLINE_FUNC gboolean ril_radio_state_on(enum ril_radio_state radio_state)
|
||||
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;
|
||||
@@ -133,7 +150,7 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
ril_radio_state_to_string(self->state),
|
||||
ril_radio_state_to_string(priv->last_known_state));
|
||||
self->state = priv->last_known_state;
|
||||
g_signal_emit(self, ril_radio_signals[SIGNAL_STATE_CHANGED], 0);
|
||||
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +252,7 @@ void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
g_hash_table_insert(priv->req_table, tag, tag);
|
||||
if (!was_on) {
|
||||
if (!was_on && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, FALSE);
|
||||
}
|
||||
}
|
||||
@@ -257,6 +274,19 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -264,6 +294,13 @@ gulong ril_radio_add_state_changed_handler(struct ril_radio *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)) {
|
||||
@@ -271,6 +308,11 @@ void ril_radio_remove_handler(struct ril_radio *self, gulong 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;
|
||||
@@ -395,10 +437,8 @@ static void ril_radio_class_init(RilRadioClass *klass)
|
||||
object_class->dispose = ril_radio_dispose;
|
||||
object_class->finalize = ril_radio_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
|
||||
ril_radio_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);
|
||||
NEW_SIGNAL(klass, STATE);
|
||||
NEW_SIGNAL(klass, ONLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ 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);
|
||||
@@ -32,11 +33,15 @@ 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_confirm_power_on(struct ril_radio *radio);
|
||||
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 */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* 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
|
||||
@@ -14,17 +14,17 @@
|
||||
*/
|
||||
|
||||
#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 {
|
||||
GRilIoQueue *q;
|
||||
struct ofono_radio_settings *rs;
|
||||
enum ofono_radio_access_mode access_mode;
|
||||
gboolean enable_4g;
|
||||
int ratmode;
|
||||
guint query_rats_id;
|
||||
struct ril_sim_settings *settings;
|
||||
const char *log_prefix;
|
||||
char *allocated_log_prefix;
|
||||
guint source_id;
|
||||
};
|
||||
|
||||
struct ril_radio_settings_cbd {
|
||||
@@ -38,7 +38,7 @@ struct ril_radio_settings_cbd {
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_radio_settings_cbd_free g_free
|
||||
#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)
|
||||
@@ -46,8 +46,8 @@ static inline struct ril_radio_settings *ril_radio_settings_get_data(
|
||||
return ofono_radio_settings_get_data(rs);
|
||||
}
|
||||
|
||||
static struct ril_radio_settings_cbd *ril_radio_settings_cbd_new(
|
||||
struct ril_radio_settings *rsd, void *cb, void *data)
|
||||
static void ril_radio_settings_later(struct ril_radio_settings *rsd,
|
||||
GSourceFunc fn, void *cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd;
|
||||
|
||||
@@ -55,89 +55,22 @@ static struct ril_radio_settings_cbd *ril_radio_settings_cbd_new(
|
||||
cbd->rsd = rsd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
|
||||
GASSERT(!rsd->source_id);
|
||||
rsd->source_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
fn, cbd, g_free);
|
||||
}
|
||||
|
||||
static enum ofono_radio_access_mode ril_radio_settings_pref_to_mode(int pref)
|
||||
{
|
||||
switch (pref) {
|
||||
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_ONLY:
|
||||
return OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
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:
|
||||
return OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_radio_settings_mode_to_pref(struct ril_radio_settings *rsd,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (rsd->enable_4g) {
|
||||
return PREF_NET_TYPE_LTE_WCDMA;
|
||||
}
|
||||
/* no break */
|
||||
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;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_settings_submit_request(struct ril_radio_settings *rsd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
{
|
||||
grilio_queue_send_request_full(rsd->q, req, code, response,
|
||||
ril_radio_settings_cbd_free,
|
||||
ril_radio_settings_cbd_new(rsd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_radio_settings_set_rat_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static gboolean ril_radio_settings_set_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb.rat_mode_set;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("failed to set rat mode");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_radio_settings_set_pref_req(int pref)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, pref);
|
||||
return req;
|
||||
}
|
||||
|
||||
static int ril_radio_settings_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;
|
||||
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,
|
||||
@@ -145,45 +78,24 @@ static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
int pref = ril_radio_settings_mode_to_pref(rsd, mode);
|
||||
GRilIoRequest *req;
|
||||
|
||||
if (pref < 0) pref = rsd->ratmode;
|
||||
DBG("rat mode set %d (ril %d)", mode, pref);
|
||||
req = ril_radio_settings_set_pref_req(pref);
|
||||
ril_radio_settings_submit_request(rsd, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
|
||||
ril_radio_settings_set_rat_mode_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
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 void ril_radio_settings_query_rat_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static gboolean ril_radio_settings_query_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;
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb.rat_mode_query;
|
||||
enum ofono_radio_access_mode mode = rsd->settings->pref_mode;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
rsd->ratmode = ril_radio_settings_parse_pref_resp(data, len);
|
||||
DBG("rat mode %d (ril %d)",
|
||||
ril_radio_settings_pref_to_mode(rsd->ratmode),
|
||||
rsd->ratmode);
|
||||
} else {
|
||||
/*
|
||||
* With certain versions of RIL, preferred network type
|
||||
* queries don't work even though setting preferred network
|
||||
* type does actually work. In this case, assume that our
|
||||
* cached network type is the right one.
|
||||
*/
|
||||
ofono_error("rat mode query failed, assuming %d (ril %d)",
|
||||
ril_radio_settings_pref_to_mode(rsd->ratmode),
|
||||
rsd->ratmode);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), ril_radio_settings_pref_to_mode(rsd->ratmode),
|
||||
cbd->data);
|
||||
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,
|
||||
@@ -191,26 +103,26 @@ static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG("rat mode query");
|
||||
ril_radio_settings_submit_request(rsd, NULL,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_radio_settings_query_rat_mode_cb, cb, data);
|
||||
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->enable_4g) {
|
||||
if (cbd->rsd->settings->enable_4g) {
|
||||
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
}
|
||||
|
||||
GASSERT(cbd->rsd->query_rats_id);
|
||||
cbd->rsd->query_rats_id = 0;
|
||||
GASSERT(cbd->rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
|
||||
return FALSE;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_available_rats(
|
||||
@@ -219,50 +131,18 @@ static void ril_radio_settings_query_available_rats(
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG("");
|
||||
GASSERT(!rsd->query_rats_id);
|
||||
rsd->query_rats_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_radio_settings_query_available_rats_cb,
|
||||
ril_radio_settings_cbd_new(rsd, cb, data),
|
||||
ril_radio_settings_cbd_free);
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_query_available_rats_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static void ril_radio_settings_init_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
{
|
||||
int pref;
|
||||
struct ril_radio_settings *rsd = user_data;
|
||||
enum ofono_radio_access_mode mode;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
pref = ril_radio_settings_parse_pref_resp(data, len);
|
||||
DBG("rat mode %d", pref);
|
||||
} else {
|
||||
ofono_error("initial rat mode query failed");
|
||||
pref = ril_radio_settings_mode_to_pref(rsd,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY);
|
||||
}
|
||||
|
||||
mode = ril_radio_settings_pref_to_mode(pref);
|
||||
|
||||
if (!rsd->enable_4g && mode == OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
rsd->ratmode = ril_radio_settings_mode_to_pref(rsd,
|
||||
OFONO_RADIO_ACCESS_MODE_UMTS);
|
||||
} else {
|
||||
rsd->ratmode = pref;
|
||||
}
|
||||
|
||||
if (rsd->ratmode != pref || status != RIL_E_SUCCESS) {
|
||||
GRilIoRequest *req;
|
||||
|
||||
DBG("forcing rat mode %d", rsd->ratmode);
|
||||
req = ril_radio_settings_set_pref_req(rsd->ratmode);
|
||||
grilio_queue_send_request(rsd->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -271,13 +151,17 @@ static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
|
||||
|
||||
DBG("");
|
||||
DBG("%s", modem->log_prefix);
|
||||
rsd->rs = rs;
|
||||
rsd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
rsd->enable_4g = ril_modem_4g_enabled(modem);
|
||||
grilio_queue_send_request_full(rsd->q, NULL,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_radio_settings_init_query_cb, NULL, rsd);
|
||||
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;
|
||||
@@ -287,14 +171,13 @@ static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG("");
|
||||
DBG_(rsd, "");
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
if (rsd->query_rats_id > 0) {
|
||||
g_source_remove(rsd->query_rats_id);
|
||||
if (rsd->source_id) {
|
||||
g_source_remove(rsd->source_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(rsd->q, FALSE);
|
||||
grilio_queue_unref(rsd->q);
|
||||
ril_sim_settings_unref(rsd->settings);
|
||||
g_free(rsd->allocated_log_prefix);
|
||||
g_free(rsd);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,8 @@
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
typedef GObjectClass RilSimCardClass;
|
||||
typedef struct ril_sim_card RilSimCard;
|
||||
|
||||
@@ -436,6 +438,14 @@ void ril_sim_card_unref(struct ril_sim_card *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)
|
||||
{
|
||||
@@ -471,6 +481,11 @@ void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong 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,
|
||||
|
||||
@@ -55,6 +55,7 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_unref(struct ril_sim_card *sc);
|
||||
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,
|
||||
@@ -64,9 +65,10 @@ gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *sc,
|
||||
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 */
|
||||
G_INLINE_FUNC enum ril_app_type
|
||||
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; }
|
||||
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
|
||||
struct ril_sim_dbus {
|
||||
char *path;
|
||||
char *imsi;
|
||||
char *name;
|
||||
char *default_name;
|
||||
gboolean enable_4g;
|
||||
GKeyFile *storage;
|
||||
DBusConnection *conn;
|
||||
struct ril_modem *md;
|
||||
};
|
||||
|
||||
#define RIL_SIM_STORE "ril"
|
||||
#define RIL_SIM_STORE_GROUP "Settings"
|
||||
#define RIL_SIM_STORE_ENABLE_4G "Enable4G"
|
||||
#define RIL_SIM_STORE_DISPLAY_NAME "DisplayName"
|
||||
|
||||
#define RIL_SIM_DBUS_INTERFACE "org.nemomobile.ofono.SimSettings"
|
||||
#define RIL_SIM_DBUS_INTERFACE_VERSION (1)
|
||||
|
||||
#define RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL "DisplayNameChanged"
|
||||
|
||||
static DBusMessage *ril_sim_dbus_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
dbus_int32_t version = RIL_SIM_DBUS_INTERFACE_VERSION;
|
||||
dbus_bool_t enable_4g = dbus->enable_4g;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &enable_4g);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dbus->name);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_dbus_get_interface_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
dbus_int32_t version = RIL_SIM_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_dbus_get_enable_4g(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
dbus_bool_t enable_4g = dbus->enable_4g;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &enable_4g);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_dbus_get_display_name(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dbus->name);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_sim_dbus_update_display_name(struct ril_sim_dbus *dbus,
|
||||
const char *name)
|
||||
{
|
||||
if (g_strcmp0(dbus->name, name)) {
|
||||
g_free(dbus->name);
|
||||
dbus->name = g_strdup(name);
|
||||
g_key_file_set_string(dbus->storage, RIL_SIM_STORE_GROUP,
|
||||
RIL_SIM_STORE_DISPLAY_NAME, name);
|
||||
storage_sync(dbus->imsi, RIL_SIM_STORE, dbus->storage);
|
||||
g_dbus_emit_signal(dbus->conn, dbus->path,
|
||||
RIL_SIM_DBUS_INTERFACE,
|
||||
RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_dbus_set_display_name(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
|
||||
struct ril_sim_dbus *dbus = data;
|
||||
DBusBasicValue value;
|
||||
const char *name;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &value);
|
||||
name = value.str;
|
||||
if (!name || !name[0]) name = dbus->default_name;
|
||||
ril_sim_dbus_update_display_name(dbus, name);
|
||||
return dbus_message_new_method_return(msg);
|
||||
} else {
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_sim_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll",
|
||||
NULL, GDBUS_ARGS({ "settings", "ibs" }),
|
||||
ril_sim_dbus_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion",
|
||||
NULL, GDBUS_ARGS({ "version", "i" }),
|
||||
ril_sim_dbus_get_interface_version) },
|
||||
{ GDBUS_METHOD("GetEnable4G",
|
||||
NULL, GDBUS_ARGS({ "enable", "b" }),
|
||||
ril_sim_dbus_get_enable_4g) },
|
||||
{ GDBUS_METHOD("GetDisplayName",
|
||||
NULL, GDBUS_ARGS({ "name", "s" }),
|
||||
ril_sim_dbus_get_display_name) },
|
||||
{ GDBUS_METHOD("SetDisplayName",
|
||||
GDBUS_ARGS({ "name", "s" }), NULL,
|
||||
ril_sim_dbus_set_display_name) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_sim_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
const char *ril_sim_dbus_imsi(struct ril_sim_dbus *dbus)
|
||||
{
|
||||
return dbus ? dbus->imsi : NULL;
|
||||
}
|
||||
|
||||
struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *md)
|
||||
{
|
||||
const char *imsi = ofono_sim_get_imsi(ril_modem_ofono_sim(md));
|
||||
|
||||
if (imsi) {
|
||||
GError *error = NULL;
|
||||
const struct ril_slot_config *config = &md->config;
|
||||
struct ril_sim_dbus *dbus = g_new0(struct ril_sim_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->md = md;
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->imsi = g_strdup(imsi);
|
||||
dbus->default_name = g_strdup(config->default_name);
|
||||
|
||||
/* Load settings */
|
||||
dbus->storage = storage_open(imsi, RIL_SIM_STORE);
|
||||
dbus->enable_4g = g_key_file_get_boolean(dbus->storage,
|
||||
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_ENABLE_4G, &error);
|
||||
if (error) {
|
||||
dbus->enable_4g = config->enable_4g;
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
dbus->name = g_key_file_get_string(dbus->storage,
|
||||
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_DISPLAY_NAME, NULL);
|
||||
if (!dbus->name) {
|
||||
dbus->name = g_strdup(config->default_name);
|
||||
GASSERT(dbus->name);
|
||||
}
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_SIM_DBUS_INTERFACE, ril_sim_dbus_methods,
|
||||
ril_sim_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_SIM_DBUS_INTERFACE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_sim_dbus_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ril_sim_dbus_free(struct ril_sim_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_SIM_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_SIM_DBUS_INTERFACE);
|
||||
dbus_connection_unref(dbus->conn);
|
||||
g_key_file_free(dbus->storage);
|
||||
g_free(dbus->path);
|
||||
g_free(dbus->imsi);
|
||||
g_free(dbus->name);
|
||||
g_free(dbus->default_name);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ril_sim_info.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/sim.h>
|
||||
@@ -29,24 +30,41 @@
|
||||
#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 {
|
||||
void (*set_value)(struct ril_sim_info *self, const char *value);
|
||||
void (*remove)(struct ofono_sim *sim, unsigned int id);
|
||||
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 *spn;
|
||||
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;
|
||||
};
|
||||
@@ -58,9 +76,9 @@ enum ril_sim_info_signal {
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_ICCID_CHANGED_NAME "ril-siminfo-state-changed"
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "ril-siminfo-status-changed"
|
||||
#define SIGNAL_SPN_CHANGED_NAME "ril-siminfo-spn-changed"
|
||||
#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 };
|
||||
|
||||
@@ -75,31 +93,35 @@ G_DEFINE_TYPE(RilSimInfo, ril_sim_info, G_TYPE_OBJECT)
|
||||
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 *self,
|
||||
struct ril_sim_info_watch *watch)
|
||||
static void ril_sim_info_watch_remove(struct ril_sim_info_watch *watch)
|
||||
{
|
||||
if (watch->id) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
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(self, NULL);
|
||||
watch->set_value(watch->info, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim, unsigned int id)
|
||||
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim,
|
||||
unsigned int id)
|
||||
{
|
||||
ofono_sim_remove_spn_watch(sim, &id);
|
||||
}
|
||||
@@ -109,14 +131,34 @@ 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->spn && priv->spn[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);
|
||||
|
||||
DBG("Updating " STORAGEDIR "/%s/%s", priv->imsi, store);
|
||||
g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, priv->spn);
|
||||
storage_close(priv->imsi, store, cache, TRUE);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -129,11 +171,24 @@ static void ril_sim_info_update_iccid_map(struct ril_sim_info *self)
|
||||
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);
|
||||
|
||||
DBG("Updating " STORAGEDIR "/%s", store);
|
||||
g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
/*
|
||||
* 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);
|
||||
storage_close(NULL, store, map, TRUE);
|
||||
} else {
|
||||
g_key_file_free(map);
|
||||
}
|
||||
|
||||
g_free(imsi);
|
||||
priv->update_iccid_map = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -152,19 +207,120 @@ static void ril_sim_info_set_imsi(struct ril_sim_info *self, const char *imsi)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_spn(struct ril_sim_info *self, const char *spn)
|
||||
static void ril_sim_info_update_public_spn(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->spn, spn)) {
|
||||
g_free(priv->spn);
|
||||
self->spn = priv->spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
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;
|
||||
@@ -178,18 +334,19 @@ static void ril_sim_info_load_cache(struct ril_sim_info *self)
|
||||
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
/* Need to update ICCID -> IMSI map */
|
||||
DBG("IMSI changed %s -> %s", priv->imsi, imsi);
|
||||
DBG_(self, "IMSI changed %s -> %s",
|
||||
priv->imsi, imsi);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = imsi;
|
||||
DBG("imsi[%s] = %s", priv->iccid, 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("No imsi for iccid %s", priv->iccid);
|
||||
DBG_(self, "no imsi for iccid %s", priv->iccid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,21 +357,22 @@ static void ril_sim_info_load_cache(struct ril_sim_info *self)
|
||||
RIL_SIM_INFO_STORE_SPN, NULL);
|
||||
g_key_file_free(cache);
|
||||
|
||||
if (spn && spn[0] && g_strcmp0(priv->spn, spn)) {
|
||||
if (priv->spn && priv->spn[0]) {
|
||||
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("spn changing %s -> %s", priv->spn, spn);
|
||||
DBG_(self, "spn changing %s -> %s",
|
||||
priv->cached_spn, spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->spn);
|
||||
self->spn = priv->spn = spn;
|
||||
DBG("spn[%s] = \"%s\"", priv->imsi, spn);
|
||||
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_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
} else if (spn) {
|
||||
g_free(spn);
|
||||
} else {
|
||||
DBG("No spn for imsi %s", priv->imsi);
|
||||
DBG_(self, "no spn for imsi %s", priv->imsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,86 +391,102 @@ static void ril_sim_info_set_iccid(struct ril_sim_info *self, const char *iccid)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_imsi_event_cb(const char *imsi, void *data)
|
||||
static void ril_sim_info_imsi_watch_cb(const char *imsi, void *data)
|
||||
{
|
||||
DBG("%s", imsi);
|
||||
ril_sim_info_set_imsi(RIL_SIMINFO(data), imsi);
|
||||
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_cb(const char *spn, const char *dc, void *data)
|
||||
static void ril_sim_info_spn_watch_cb(const char *spn, const char *dc,
|
||||
void *data)
|
||||
{
|
||||
DBG("%s", spn);
|
||||
ril_sim_info_set_spn(RIL_SIMINFO(data), spn);
|
||||
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_event_cb(const char *iccid, void *data)
|
||||
static void ril_sim_info_iccid_watch_cb(const char *iccid, void *data)
|
||||
{
|
||||
DBG("%s", iccid);
|
||||
ril_sim_info_set_iccid(RIL_SIMINFO(data), iccid);
|
||||
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("%d", state);
|
||||
|
||||
if (state != OFONO_SIM_STATE_READY) {
|
||||
/*
|
||||
* These are only valid in the READY state. When SIM card
|
||||
* leaves the READY state, these watch ids are silently
|
||||
* invalidated.
|
||||
*/
|
||||
priv->imsi_watch.id = 0;
|
||||
priv->spn_watch.id = 0;
|
||||
}
|
||||
DBG_(self, "%d", state);
|
||||
|
||||
switch (state) {
|
||||
case OFONO_SIM_STATE_READY:
|
||||
if (!priv->spn_watch.id) {
|
||||
ofono_sim_add_spn_watch(priv->sim, &priv->spn_watch.id,
|
||||
ril_sim_info_spn_cb, self, NULL);
|
||||
/* 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);
|
||||
}
|
||||
if (!priv->imsi_watch.id) {
|
||||
priv->imsi_watch.id =
|
||||
ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_info_imsi_event_cb,
|
||||
self, NULL);
|
||||
GASSERT(priv->imsi_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:
|
||||
if (!priv->iccid_watch.id) {
|
||||
priv->iccid_watch.id =
|
||||
ofono_sim_add_iccid_watch(priv->sim,
|
||||
ril_sim_info_iccid_event_cb,
|
||||
self, NULL);
|
||||
GASSERT(priv->iccid_watch.id);
|
||||
/* 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(self, &priv->spn_watch);
|
||||
ril_sim_info_watch_remove(self, &priv->imsi_watch);
|
||||
ril_sim_info_watch_remove(self, &priv->iccid_watch);
|
||||
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_event_cb(enum ofono_sim_state new_state,
|
||||
static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
|
||||
void *data)
|
||||
{
|
||||
ril_sim_info_handle_sim_state(RIL_SIMINFO(data), new_state);
|
||||
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(struct ofono_sim *sim)
|
||||
struct ril_sim_info *ril_sim_info_new(const char *log_prefix)
|
||||
{
|
||||
struct ril_sim_info *self = g_object_new(RIL_SIMINFO_TYPE, NULL);
|
||||
|
||||
ril_sim_info_set_ofono_sim(self, sim);
|
||||
self->priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -333,16 +507,18 @@ void ril_sim_info_unref(struct ril_sim_info *self)
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self, struct ofono_sim *sim)
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim != sim) {
|
||||
ril_sim_info_watch_remove(self, &priv->state_watch);
|
||||
ril_sim_info_watch_remove(self, &priv->iccid_watch);
|
||||
ril_sim_info_watch_remove(self, &priv->imsi_watch);
|
||||
ril_sim_info_watch_remove(self, &priv->spn_watch);
|
||||
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;
|
||||
@@ -351,13 +527,45 @@ void ril_sim_info_set_ofono_sim(struct ril_sim_info *self, struct ofono_sim *sim
|
||||
if (sim) {
|
||||
priv->state_watch.id =
|
||||
ofono_sim_add_state_watch(sim,
|
||||
ril_sim_info_state_event_cb,
|
||||
self, NULL);
|
||||
ril_sim_info_state_watch_cb,
|
||||
&priv->state_watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(priv->state_watch.id);
|
||||
DBG("Attached to sim");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,19 +598,30 @@ void ril_sim_info_remove_handler(struct ril_sim_info *self, gulong 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;
|
||||
priv->state_watch.remove = ofono_sim_remove_state_watch;
|
||||
priv->iccid_watch.remove = ofono_sim_remove_iccid_watch;
|
||||
priv->iccid_watch.set_value = ril_sim_info_set_iccid;
|
||||
priv->imsi_watch.remove = ofono_sim_remove_imsi_watch;
|
||||
priv->imsi_watch.set_value = ril_sim_info_set_imsi;
|
||||
priv->spn_watch.remove = ril_sim_info_remove_spn_watch;
|
||||
priv->spn_watch.set_value = ril_sim_info_set_spn;
|
||||
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)
|
||||
@@ -410,14 +629,30 @@ 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);
|
||||
|
||||
@@ -29,10 +29,11 @@ struct ril_sim_info {
|
||||
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(struct ofono_sim *sim);
|
||||
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,
|
||||
|
||||
@@ -205,7 +205,7 @@ struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
|
||||
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
ril_sim_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* 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
|
||||
@@ -22,13 +22,16 @@
|
||||
#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 path[4] = {0x3F, 0x00, 0x7F, 0x10};
|
||||
static unsigned char sim_path[4] = {0x3F, 0x00, 0x7F, 0x10};
|
||||
|
||||
enum ril_sms_events {
|
||||
SMS_EVENT_NEW_SMS,
|
||||
@@ -42,6 +45,7 @@ struct ril_sms {
|
||||
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;
|
||||
};
|
||||
@@ -277,6 +281,8 @@ static void ril_ack_delivery(struct ril_sms *sd, gboolean error)
|
||||
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);
|
||||
@@ -366,11 +372,10 @@ static void ril_request_delete_sms_om_sim(struct ril_sms *sd, int record)
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_on_sim_cb(const struct ofono_error *error,
|
||||
const unsigned char *sdata,
|
||||
int length, void *data)
|
||||
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 = data;
|
||||
struct ril_sms_on_sim_req *cbd = userdata;
|
||||
struct ril_sms *sd = cbd->sd;
|
||||
|
||||
/*
|
||||
@@ -383,7 +388,7 @@ static void ril_sms_on_sim_cb(const struct ofono_error *error,
|
||||
* the read length to take into account this read octet in order
|
||||
* to calculate the proper tpdu length.
|
||||
*/
|
||||
if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
if (ok) {
|
||||
unsigned int smsc_len = sdata[1] + 1;
|
||||
ofono_sms_deliver_notify(sd->sms, sdata + 1, length - 1,
|
||||
length - smsc_len - 1);
|
||||
@@ -409,10 +414,15 @@ static void ril_sms_on_sim(GRilIoChannel *io, guint ril_event,
|
||||
grilio_parser_get_int32(&rilp, &data_len) && data_len > 0 &&
|
||||
grilio_parser_get_int32(&rilp, &rec)) {
|
||||
DBG("rec %d", rec);
|
||||
ril_sim_read_file_linear(sim, SIM_EFSMS_FILEID, rec,
|
||||
EFSMS_LENGTH, path, sizeof(path),
|
||||
ril_sms_on_sim_cb,
|
||||
ril_sms_on_sim_req_new(sd,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,14 +454,18 @@ 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;
|
||||
}
|
||||
|
||||
@@ -463,6 +477,10 @@ static void ril_sms_remove(struct ofono_sms *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]);
|
||||
|
||||
|
||||
@@ -1,11 +1,39 @@
|
||||
# This is a sample configuration file for the ril driver
|
||||
# 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.
|
||||
# Only the sections that start with the "ril_" prefix define the modems,
|
||||
# other sections are currently ignored.
|
||||
# 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]
|
||||
|
||||
@@ -53,3 +81,64 @@ socket=/dev/socket/rild
|
||||
# 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
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
@@ -38,13 +39,21 @@ struct ofono_modem;
|
||||
#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_plugin_dbus;
|
||||
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 */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* 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
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
@@ -50,17 +50,15 @@ static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data)
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_ussd_cb(GRilIoChannel *io, int status,
|
||||
static void ril_ussd_cancel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
/* Always report sucessful completion, otherwise ofono may get
|
||||
* stuck in the USSD_STATE_ACTIVE state */
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
@@ -101,11 +99,10 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
}
|
||||
grilio_request_append_utf8_chars(req, (char*)
|
||||
unpacked_buf, length);
|
||||
grilio_queue_send_request_full(ud->q, req,
|
||||
RIL_REQUEST_SEND_USSD, ril_ussd_cb,
|
||||
ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(cb, data));
|
||||
grilio_queue_send_request(ud->q, req,
|
||||
RIL_REQUEST_SEND_USSD);
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +118,8 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
|
||||
ril_ussd_cb, ril_ussd_cbd_free, ril_ussd_cbd_new(cb, data));
|
||||
ril_ussd_cancel_cb, ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(cb, data));
|
||||
}
|
||||
|
||||
static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
@@ -129,32 +127,32 @@ static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
{
|
||||
struct ril_ussd *ud = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *ussd_from_network = NULL;
|
||||
char *type = NULL;
|
||||
int ussdtype = 0;
|
||||
char *type;
|
||||
guint32 n = 0;
|
||||
|
||||
ofono_info("ussd_received");
|
||||
ofono_info("ussd received");
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_uint32(&rilp, NULL);
|
||||
grilio_parser_get_uint32(&rilp, &n);
|
||||
type = grilio_parser_get_utf8(&rilp);
|
||||
ussd_from_network = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
ussdtype = g_ascii_xdigit_value(*type);
|
||||
if (type) {
|
||||
int ussdtype = g_ascii_xdigit_value(*type);
|
||||
char *msg = (n > 1) ? grilio_parser_get_utf8(&rilp) : NULL;
|
||||
|
||||
if (ussd_from_network) {
|
||||
const int data_len = strlen(ussd_from_network);
|
||||
DBG("ussd_received, length %d", data_len);
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0xFF,
|
||||
(const unsigned char *) ussd_from_network, data_len);
|
||||
} else {
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0, NULL, 0);
|
||||
if (msg) {
|
||||
const int msglen = strlen(msg);
|
||||
DBG("ussd length %d", msglen);
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0xFF,
|
||||
(const unsigned char *)msg, msglen);
|
||||
/* msg is freed by core if dcs is 0xFF */
|
||||
} else {
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0, NULL, 0);
|
||||
}
|
||||
|
||||
g_free(type);
|
||||
}
|
||||
|
||||
/* ussd_from_network not freed because core does that if dcs is 0xFF */
|
||||
g_free(type);
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean ril_ussd_register(gpointer user_data)
|
||||
@@ -171,7 +169,7 @@ static gboolean ril_ussd_register(gpointer user_data)
|
||||
ril_ussd_notify, RIL_UNSOL_ON_USSD, ud);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
|
||||
|
||||
@@ -288,17 +288,6 @@ const char *ril_radio_state_to_string(int radio_state)
|
||||
}
|
||||
}
|
||||
|
||||
int ril_address_family(const char *addr)
|
||||
{
|
||||
if (strchr(addr, ':')) {
|
||||
return AF_INET6;
|
||||
} else if (strchr(addr, '.')) {
|
||||
return AF_INET;
|
||||
} else {
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns enum access_technology or -1 on failure. */
|
||||
int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
|
||||
@@ -25,16 +25,18 @@ const char *ril_request_to_string(guint request);
|
||||
const char *ril_unsol_event_to_string(guint event);
|
||||
const char *ril_radio_state_to_string(int radio_state);
|
||||
int ril_parse_tech(const char *stech, int *ril_tech);
|
||||
int ril_address_family(const char *addr);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
|
||||
#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 */
|
||||
|
||||
|
||||
@@ -15,14 +15,15 @@
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* Amount of ms we wait between CLCC calls */
|
||||
#include <gutil_ring.h>
|
||||
|
||||
#define FLAG_NEED_CLIP 1
|
||||
#define MAX_DTMF_BUFFER 32
|
||||
|
||||
enum ril_voicecall_events {
|
||||
VOICECALL_EVENT_CALL_STATE_CHANGED,
|
||||
@@ -36,24 +37,19 @@ struct ril_voicecall {
|
||||
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;
|
||||
gchar *tone_queue;
|
||||
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;
|
||||
};
|
||||
|
||||
struct release_id_req {
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
gpointer data;
|
||||
int id;
|
||||
gulong ecclist_change_id;
|
||||
};
|
||||
|
||||
struct ril_voicecall_change_state_req {
|
||||
@@ -68,12 +64,6 @@ struct lastcause_req {
|
||||
int id;
|
||||
};
|
||||
|
||||
struct ril_voicecall_req {
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
|
||||
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
|
||||
|
||||
@@ -322,9 +312,10 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
ofono_voicecall_notify(vd->vc, nc);
|
||||
if (vd->cb) {
|
||||
ofono_voicecall_cb_t cb = vd->cb;
|
||||
cb(ril_error_ok(&error), vd->data);
|
||||
void *cbdata = vd->data;
|
||||
vd->cb = NULL;
|
||||
vd->data = NULL;
|
||||
cb(ril_error_ok(&error), cbdata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,9 +374,12 @@ 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,
|
||||
NULL, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||
req, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||
ril_voicecall_clcc_poll_cb, NULL, vd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,9 +437,7 @@ static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
|
||||
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall_req *cbd = user_data;
|
||||
struct ofono_voicecall *vc = cbd->vc;
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall *vd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
if (vd->cb) {
|
||||
@@ -454,11 +446,21 @@ static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
|
||||
ril_voicecall_clcc_poll(vd);
|
||||
}
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
ofono_error("call failed.");
|
||||
vd->cb = cbd->cb;
|
||||
vd->data = cbd->data;
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,27 +470,22 @@ static void ril_voicecall_dial(struct ofono_voicecall *vc,
|
||||
void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall_req *cbd = g_new(struct ril_voicecall_req, 1);
|
||||
const char *phstr = phone_number_to_string(ph);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("dialing \"%s\"", phstr);
|
||||
|
||||
DBG("%s,%d,0", phstr, clir);
|
||||
cbd->vc = vc;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
|
||||
GASSERT(!vd->cb);
|
||||
vd->cb = cbd->cb;
|
||||
vd->data = cbd->data;
|
||||
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, g_free, cbd);
|
||||
ril_voicecall_dial_cb, NULL, vd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -599,11 +596,6 @@ static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
|
||||
vd->send_dtmf_id = 0;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
/* Remove sent DTMF character from queue */
|
||||
gchar *tmp = g_strdup(vd->tone_queue + 1);
|
||||
g_free(vd->tone_queue);
|
||||
vd->tone_queue = tmp;
|
||||
|
||||
/* Send the next one */
|
||||
ril_voicecall_send_one_dtmf(vd);
|
||||
} else {
|
||||
@@ -614,12 +606,15 @@ static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
|
||||
|
||||
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd)
|
||||
{
|
||||
if (!vd->send_dtmf_id && vd->tone_queue && vd->tone_queue[0]) {
|
||||
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 */
|
||||
DBG("%c", vd->tone_queue[0]);
|
||||
grilio_request_append_utf8_chars(req, vd->tone_queue, 1);
|
||||
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);
|
||||
@@ -632,43 +627,34 @@ static void ril_voicecall_send_dtmf(struct ofono_voicecall *vc,
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("Queue '%s'",dtmf);
|
||||
|
||||
/*
|
||||
* Queue any incoming DTMF (up to MAX_DTMF_BUFFER characters),
|
||||
* send them to RIL one-by-one, immediately call back
|
||||
* core with no error
|
||||
* Queue any incoming DTMF, send them to RIL one-by-one,
|
||||
* immediately call back core with no error
|
||||
*/
|
||||
g_strlcat(vd->tone_queue, dtmf, MAX_DTMF_BUFFER);
|
||||
ril_voicecall_send_one_dtmf(vd);
|
||||
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)
|
||||
{
|
||||
g_free(vd->tone_queue);
|
||||
vd->tone_queue = g_strnfill(MAX_DTMF_BUFFER + 1, '\0');
|
||||
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_clcc_poll_on_success(GRilIoChannel *io,
|
||||
int status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ril_voicecall_clcc_poll((struct ril_voicecall *)user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
grilio_queue_send_request_full(vd->q, NULL, RIL_REQUEST_CONFERENCE,
|
||||
ril_voicecall_clcc_poll_on_success, NULL, vd);
|
||||
ril_voicecall_request(RIL_REQUEST_CONFERENCE,
|
||||
vc, 0, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_transfer(struct ofono_voicecall *vc,
|
||||
@@ -681,14 +667,17 @@ static void ril_voicecall_transfer(struct ofono_voicecall *vc,
|
||||
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("Private chat with id %d", id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, id);
|
||||
grilio_queue_send_request_full(vd->q, req,
|
||||
RIL_REQUEST_SEPARATE_CONNECTION,
|
||||
ril_voicecall_clcc_poll_on_success, NULL, vd);
|
||||
|
||||
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,
|
||||
@@ -759,6 +748,13 @@ static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
|
||||
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;
|
||||
@@ -767,6 +763,14 @@ static gboolean ril_delayed_register(gpointer user_data)
|
||||
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);
|
||||
|
||||
@@ -805,8 +809,12 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
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;
|
||||
@@ -814,26 +822,25 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
|
||||
static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
{
|
||||
int i;
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
|
||||
DBG("");
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(vd->event_id); i++) {
|
||||
grilio_channel_remove_handler(vd->io, vd->event_id[i]);
|
||||
}
|
||||
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);
|
||||
g_free(vd->tone_queue);
|
||||
gutil_ring_unref(vd->dtmf_queue);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -29,6 +28,7 @@
|
||||
#include <gril.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/log.h>
|
||||
@@ -40,19 +40,6 @@
|
||||
#include "util.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ril_util_sim_state_query {
|
||||
GRil *ril;
|
||||
guint cpin_poll_source;
|
||||
guint cpin_poll_count;
|
||||
guint interval;
|
||||
guint num_times;
|
||||
ril_util_sim_inserted_cb_t cb;
|
||||
void *userdata;
|
||||
GDestroyNotify destroy;
|
||||
};
|
||||
|
||||
static gboolean cpin_check(gpointer userdata);
|
||||
|
||||
void decode_ril_error(struct ofono_error *error, const char *final)
|
||||
{
|
||||
if (!strcmp(final, "OK")) {
|
||||
@@ -64,642 +51,111 @@ void decode_ril_error(struct ofono_error *error, const char *final)
|
||||
}
|
||||
}
|
||||
|
||||
gint ril_util_call_compare_by_status(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ofono_call *call = a;
|
||||
int status = GPOINTER_TO_INT(b);
|
||||
|
||||
if (status != call->status)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint ril_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ofono_call *call = a;
|
||||
const struct ofono_phone_number *pb = b;
|
||||
|
||||
return memcmp(&call->phone_number, pb,
|
||||
sizeof(struct ofono_phone_number));
|
||||
}
|
||||
|
||||
gint ril_util_call_compare_by_id(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ofono_call *call = a;
|
||||
unsigned int id = GPOINTER_TO_UINT(b);
|
||||
|
||||
if (id < call->id)
|
||||
return -1;
|
||||
|
||||
if (id > call->id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint ril_util_call_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 gboolean cpin_check(gpointer userdata)
|
||||
{
|
||||
struct ril_util_sim_state_query *req = userdata;
|
||||
|
||||
req->cpin_poll_source = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gchar *ril_util_get_netmask(const gchar *address)
|
||||
{
|
||||
char *result;
|
||||
if (g_str_has_suffix(address, "/30"))
|
||||
return PREFIX_30_NETMASK;
|
||||
|
||||
if (g_str_has_suffix(address, "/30")) {
|
||||
result = PREFIX_30_NETMASK;
|
||||
} else if (g_str_has_suffix(address, "/29")) {
|
||||
result = PREFIX_29_NETMASK;
|
||||
} else if (g_str_has_suffix(address, "/28")) {
|
||||
result = PREFIX_28_NETMASK;
|
||||
} else if (g_str_has_suffix(address, "/27")) {
|
||||
result = PREFIX_27_NETMASK;
|
||||
} else if (g_str_has_suffix(address, "/26")) {
|
||||
result = PREFIX_26_NETMASK;
|
||||
} else if (g_str_has_suffix(address, "/25")) {
|
||||
result = PREFIX_25_NETMASK;
|
||||
} else if (g_str_has_suffix(address, "/24")) {
|
||||
result = PREFIX_24_NETMASK;
|
||||
} else {
|
||||
/*
|
||||
* This handles the case where the
|
||||
* Samsung RILD returns an address without
|
||||
* a prefix, however it explicitly sets a
|
||||
* /24 netmask ( which isn't returned as
|
||||
* an attribute of the DATA_CALL.
|
||||
*
|
||||
* TODO/OEM: this might need to be quirked
|
||||
* for specific devices.
|
||||
*/
|
||||
result = PREFIX_24_NETMASK;
|
||||
if (g_str_has_suffix(address, "/29"))
|
||||
return PREFIX_29_NETMASK;
|
||||
|
||||
if (g_str_has_suffix(address, "/28"))
|
||||
return PREFIX_28_NETMASK;
|
||||
|
||||
if (g_str_has_suffix(address, "/27"))
|
||||
return PREFIX_27_NETMASK;
|
||||
|
||||
if (g_str_has_suffix(address, "/26"))
|
||||
return PREFIX_26_NETMASK;
|
||||
|
||||
if (g_str_has_suffix(address, "/25"))
|
||||
return PREFIX_25_NETMASK;
|
||||
|
||||
if (g_str_has_suffix(address, "/24"))
|
||||
return PREFIX_24_NETMASK;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ril_util_build_deactivate_data_call(GRil *gril, struct parcel *rilp,
|
||||
int cid, unsigned int reason)
|
||||
{
|
||||
char *cid_str = NULL;
|
||||
char *reason_str = NULL;
|
||||
|
||||
cid_str = g_strdup_printf("%d", cid);
|
||||
reason_str = g_strdup_printf("%d", reason);
|
||||
|
||||
parcel_init(rilp);
|
||||
parcel_w_int32(rilp, 2);
|
||||
parcel_w_string(rilp, cid_str);
|
||||
parcel_w_string(rilp, reason_str);
|
||||
|
||||
g_ril_append_print_buf(gril, "(%s,%s)", cid_str, reason_str);
|
||||
|
||||
g_free(cid_str);
|
||||
g_free(reason_str);
|
||||
}
|
||||
|
||||
const char *ril_util_gprs_proto_to_ril_string(enum ofono_gprs_proto proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case OFONO_GPRS_PROTO_IPV6:
|
||||
return "IPV6";
|
||||
case OFONO_GPRS_PROTO_IPV4V6:
|
||||
return "IPV4V6";
|
||||
case OFONO_GPRS_PROTO_IP:
|
||||
default:
|
||||
return "IP";
|
||||
}
|
||||
}
|
||||
|
||||
int ril_util_registration_state_to_status(int reg_state)
|
||||
{
|
||||
switch (reg_state) {
|
||||
case RIL_REG_STATE_NOT_REGISTERED:
|
||||
case RIL_REG_STATE_REGISTERED:
|
||||
case RIL_REG_STATE_SEARCHING:
|
||||
case RIL_REG_STATE_DENIED:
|
||||
case RIL_REG_STATE_UNKNOWN:
|
||||
case RIL_REG_STATE_ROAMING:
|
||||
break;
|
||||
|
||||
case RIL_REG_STATE_EMERGENCY_NOT_REGISTERED:
|
||||
case RIL_REG_STATE_EMERGENCY_SEARCHING:
|
||||
case RIL_REG_STATE_EMERGENCY_DENIED:
|
||||
case RIL_REG_STATE_EMERGENCY_UNKNOWN:
|
||||
reg_state -= RIL_REG_STATE_EMERGENCY_NOT_REGISTERED;
|
||||
break;
|
||||
default:
|
||||
reg_state = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
DBG("address: %s netmask: %s", address, result);
|
||||
|
||||
return result;
|
||||
return reg_state;
|
||||
}
|
||||
|
||||
/* TODO: this function can go away, once all the code has been
|
||||
* re-factored to use grilreply.c */
|
||||
void ril_util_init_parcel(struct ril_msg *message, struct parcel *rilp)
|
||||
int ril_util_address_to_gprs_proto(const char *addr)
|
||||
{
|
||||
/* Set up Parcel struct for proper parsing */
|
||||
rilp->data = message->buf;
|
||||
rilp->size = message->buf_len;
|
||||
rilp->capacity = message->buf_len;
|
||||
rilp->offset = 0;
|
||||
}
|
||||
int ret = -1;
|
||||
struct in_addr ipv4;
|
||||
struct in6_addr ipv6;
|
||||
char **addr_split = g_strsplit(addr, "/", 2);
|
||||
|
||||
struct ril_util_sim_state_query *ril_util_sim_state_query_new(GRil *ril,
|
||||
guint interval, guint num_times,
|
||||
ril_util_sim_inserted_cb_t cb,
|
||||
void *userdata,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
struct ril_util_sim_state_query *req;
|
||||
|
||||
req = g_new0(struct ril_util_sim_state_query, 1);
|
||||
|
||||
req->ril = ril;
|
||||
req->interval = interval;
|
||||
req->num_times = num_times;
|
||||
req->cb = cb;
|
||||
req->userdata = userdata;
|
||||
req->destroy = destroy;
|
||||
|
||||
cpin_check(req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
void ril_util_sim_state_query_free(struct ril_util_sim_state_query *req)
|
||||
{
|
||||
if (req == NULL)
|
||||
return;
|
||||
|
||||
if (req->cpin_poll_source > 0)
|
||||
g_source_remove(req->cpin_poll_source);
|
||||
|
||||
if (req->destroy)
|
||||
req->destroy(req->userdata);
|
||||
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
GSList *ril_util_parse_clcc(GRil *gril, struct ril_msg *message)
|
||||
{
|
||||
struct ofono_call *call;
|
||||
struct parcel rilp;
|
||||
GSList *l = NULL;
|
||||
int num, i;
|
||||
gchar *number, *name;
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
g_ril_append_print_buf(gril, "{");
|
||||
|
||||
/* Number of RIL_Call structs */
|
||||
num = parcel_r_int32(&rilp);
|
||||
for (i = 0; i < num; i++) {
|
||||
call = g_try_new(struct ofono_call, 1);
|
||||
if (call == NULL)
|
||||
break;
|
||||
|
||||
ofono_call_init(call);
|
||||
call->status = parcel_r_int32(&rilp);
|
||||
call->id = parcel_r_int32(&rilp);
|
||||
call->phone_number.type = parcel_r_int32(&rilp);
|
||||
parcel_r_int32(&rilp); /* isMpty */
|
||||
call->direction = (parcel_r_int32(&rilp) ? /* isMT */
|
||||
CALL_DIRECTION_MOBILE_TERMINATED :
|
||||
CALL_DIRECTION_MOBILE_ORIGINATED);
|
||||
parcel_r_int32(&rilp); /* als */
|
||||
call->type = parcel_r_int32(&rilp); /* isVoice */
|
||||
parcel_r_int32(&rilp); /* isVoicePrivacy */
|
||||
number = parcel_r_string(&rilp);
|
||||
if (number) {
|
||||
strncpy(call->phone_number.number, number,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
g_free(number);
|
||||
}
|
||||
parcel_r_int32(&rilp); /* numberPresentation */
|
||||
name = parcel_r_string(&rilp);
|
||||
if (name) {
|
||||
strncpy(call->name, name,
|
||||
OFONO_MAX_CALLER_NAME_LENGTH);
|
||||
g_free(name);
|
||||
}
|
||||
parcel_r_int32(&rilp); /* namePresentation */
|
||||
parcel_r_int32(&rilp); /* uusInfo */
|
||||
|
||||
if (strlen(call->phone_number.number) > 0)
|
||||
call->clip_validity = 0;
|
||||
else
|
||||
call->clip_validity = 2;
|
||||
|
||||
/* TODO: figure out how to line-wrap properly
|
||||
* without introducing spaces in string.
|
||||
*/
|
||||
g_ril_append_print_buf(gril,
|
||||
"%s [id=%d,status=%d,type=%d,number=%s,name=%s]",
|
||||
print_buf,
|
||||
call->id, call->status, call->type,
|
||||
call->phone_number.number, call->name);
|
||||
|
||||
l = g_slist_insert_sorted(l, call, ril_util_call_compare);
|
||||
}
|
||||
|
||||
g_ril_append_print_buf(gril, "%s}", print_buf);
|
||||
g_ril_print_response(gril, message);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
char *ril_util_parse_sim_io_rsp(GRil *gril,
|
||||
struct ril_msg *message,
|
||||
int *sw1, int *sw2,
|
||||
int *hex_len)
|
||||
{
|
||||
struct parcel rilp;
|
||||
char *response = NULL;
|
||||
char *hex_response = NULL;
|
||||
|
||||
/* Minimum length of SIM_IO_Response is 12:
|
||||
* sw1 (int32)
|
||||
* sw2 (int32)
|
||||
* simResponse (string)
|
||||
*/
|
||||
if (message->buf_len < 12) {
|
||||
ofono_error("Invalid SIM IO reply: size too small (< 12): %d ",
|
||||
message->buf_len);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG("message->buf_len is: %d", message->buf_len);
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
*sw1 = parcel_r_int32(&rilp);
|
||||
*sw2 = parcel_r_int32(&rilp);
|
||||
|
||||
response = parcel_r_string(&rilp);
|
||||
if (response) {
|
||||
DBG("response is set; len is: %d", strlen(response));
|
||||
hex_response = (char *) decode_hex((const char *) response,
|
||||
strlen(response),
|
||||
(long *) hex_len, -1);
|
||||
}
|
||||
|
||||
g_ril_append_print_buf(gril,
|
||||
"(sw1=0x%.2X,sw2=0x%.2X,%s)",
|
||||
*sw1,
|
||||
*sw2,
|
||||
response);
|
||||
g_ril_print_response(gril, message);
|
||||
|
||||
g_free(response);
|
||||
return hex_response;
|
||||
}
|
||||
|
||||
gboolean ril_util_parse_sim_status(GRil *gril,
|
||||
struct ril_msg *message,
|
||||
struct sim_status *status,
|
||||
struct sim_app **apps)
|
||||
{
|
||||
struct parcel rilp;
|
||||
gboolean result = FALSE;
|
||||
int i;
|
||||
|
||||
g_ril_append_print_buf(gril, "[%04d]< %s",
|
||||
message->serial_no,
|
||||
ril_request_id_to_string(message->req));
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
/*
|
||||
* FIXME: Need to come up with a common scheme for verifying the
|
||||
* size of RIL message and properly reacting to bad messages.
|
||||
* This could be a runtime assertion, disconnect, drop/ignore
|
||||
* the message, ...
|
||||
*
|
||||
* 20 is the min length of RIL_CardStatus_v6 as the AppState
|
||||
* array can be 0-length.
|
||||
*/
|
||||
if (message->buf_len < 20) {
|
||||
ofono_error("Size of SIM_STATUS reply too small: %d bytes",
|
||||
message->buf_len);
|
||||
status->card_state = RIL_CARDSTATE_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status->card_state = parcel_r_int32(&rilp);
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
*
|
||||
* The global pin_status is used for multi-application
|
||||
* UICC cards. For example, there are SIM cards that
|
||||
* can be used in both GSM and CDMA phones. Instead
|
||||
* of managed PINs for both applications, a global PIN
|
||||
* is set instead. It's not clear at this point if
|
||||
* such SIM cards are supported by ofono or RILD.
|
||||
*/
|
||||
|
||||
status->pin_state = parcel_r_int32(&rilp);
|
||||
status->gsm_umts_index = parcel_r_int32(&rilp);
|
||||
status->cdma_index = parcel_r_int32(&rilp);
|
||||
status->ims_index = parcel_r_int32(&rilp);
|
||||
status->num_apps = parcel_r_int32(&rilp);
|
||||
|
||||
/* TODO:
|
||||
* How do we handle long (>80 chars) ril_append_print_buf strings?
|
||||
* Using line wrapping ( via '\' ) introduces spaces in the output.
|
||||
* Do we just make a style-guide exception for PrintBuf operations?
|
||||
*/
|
||||
g_ril_append_print_buf(gril,
|
||||
"card_state=%d,universal_pin_state=%d,gsm_umts_index=%d,cdma_index=%d,ims_index=%d, ",
|
||||
status->card_state,
|
||||
status->pin_state,
|
||||
status->gsm_umts_index,
|
||||
status->cdma_index,
|
||||
status->ims_index);
|
||||
|
||||
DBG("card_state=%d, universal_pin_state=%d, gsm_umts_index=%d, cdma_index=%d, ims_index=%d",
|
||||
status->card_state,
|
||||
status->pin_state,
|
||||
status->gsm_umts_index,
|
||||
status->cdma_index,
|
||||
status->ims_index);
|
||||
|
||||
if (status->card_state == RIL_CARDSTATE_PRESENT)
|
||||
result = TRUE;
|
||||
else
|
||||
if (addr_split == NULL || g_strv_length(addr_split) == 0)
|
||||
goto done;
|
||||
|
||||
DBG("sim num_apps: %d", status->num_apps);
|
||||
if (status->num_apps > MAX_UICC_APPS) {
|
||||
ofono_error("SIM error; too many apps: %d", status->num_apps);
|
||||
status->num_apps = MAX_UICC_APPS;
|
||||
if (inet_pton(AF_INET, addr_split[0], &ipv4) > 0) {
|
||||
ret = OFONO_GPRS_PROTO_IP;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < status->num_apps; i++) {
|
||||
apps[i] = g_try_new0(struct sim_app, 1);
|
||||
if (apps[i] == NULL) {
|
||||
ofono_error("Can't allocate app_data");
|
||||
goto error;
|
||||
}
|
||||
|
||||
apps[i]->app_type = parcel_r_int32(&rilp);
|
||||
apps[i]->app_state = parcel_r_int32(&rilp);
|
||||
|
||||
/*
|
||||
* 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 (apps[i]->app_state == RIL_APPSTATE_ILLEGAL) {
|
||||
DBG("RIL_APPSTATE_ILLEGAL => RIL_APPSTATE_READY");
|
||||
apps[i]->app_state = RIL_APPSTATE_READY;
|
||||
}
|
||||
|
||||
apps[i]->perso_substate = parcel_r_int32(&rilp);
|
||||
|
||||
/* TODO: we need a way to instruct parcel to skip
|
||||
* a string, without allocating memory...
|
||||
*/
|
||||
apps[i]->aid_str = parcel_r_string(&rilp); /* app ID (AID) */
|
||||
apps[i]->app_str = parcel_r_string(&rilp); /* app label */
|
||||
|
||||
apps[i]->pin_replaced = parcel_r_int32(&rilp);
|
||||
apps[i]->pin1_state = parcel_r_int32(&rilp);
|
||||
apps[i]->pin2_state = parcel_r_int32(&rilp);
|
||||
|
||||
g_ril_append_print_buf(gril,
|
||||
"%s[app_type=%d,app_state=%d,perso_substate=%d,aid_ptr=%s,app_label_ptr=%s,pin1_replaced=%d,pin1=%d,pin2=%d],",
|
||||
print_buf,
|
||||
apps[i]->app_type,
|
||||
apps[i]->app_state,
|
||||
apps[i]->perso_substate,
|
||||
apps[i]->aid_str,
|
||||
apps[i]->app_str,
|
||||
apps[i]->pin_replaced,
|
||||
apps[i]->pin1_state,
|
||||
apps[i]->pin2_state);
|
||||
|
||||
DBG("app[%d]: type=%d, state=%d, perso_substate=%d, aid_ptr=%s, app_label_ptr=%s, pin1_replaced=%d, pin1=%d, pin2=%d",
|
||||
i, apps[i]->app_type,
|
||||
apps[i]->app_state,
|
||||
apps[i]->perso_substate,
|
||||
apps[i]->aid_str,
|
||||
apps[i]->app_str,
|
||||
apps[i]->pin_replaced,
|
||||
apps[i]->pin1_state,
|
||||
apps[i]->pin2_state);
|
||||
if (inet_pton(AF_INET6, addr_split[0], &ipv6) > 0) {
|
||||
ret = OFONO_GPRS_PROTO_IPV6;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
g_ril_append_print_buf(gril, "%s}", print_buf);
|
||||
g_ril_print_response(gril, message);
|
||||
g_strfreev(addr_split);
|
||||
|
||||
return result;
|
||||
|
||||
error:
|
||||
if (apps)
|
||||
ril_util_free_sim_apps(apps, status->num_apps);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_util_parse_reg(GRil *gril,
|
||||
struct ril_msg *message, int *status,
|
||||
int *lac, int *ci, int *tech, int *max_calls)
|
||||
{
|
||||
struct parcel rilp;
|
||||
int tmp;
|
||||
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
|
||||
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
/* FIXME: need minimum message size check FIRST!!! */
|
||||
|
||||
/* Size of response string array
|
||||
*
|
||||
* Should be:
|
||||
* >= 4 for VOICE_REG reply
|
||||
* >= 5 for DATA_REG reply
|
||||
*/
|
||||
tmp = parcel_r_int32(&rilp);
|
||||
if (tmp < 4) {
|
||||
DBG("Size of response array is too small: %d", tmp);
|
||||
goto error;
|
||||
}
|
||||
|
||||
sstatus = parcel_r_string(&rilp);
|
||||
slac = parcel_r_string(&rilp);
|
||||
sci = parcel_r_string(&rilp);
|
||||
stech = parcel_r_string(&rilp);
|
||||
|
||||
tmp -= 4;
|
||||
|
||||
/* FIXME: need to review VOICE_REGISTRATION response
|
||||
* as it returns ~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 (tmp--) {
|
||||
/* TODO: different use for CDMA */
|
||||
sreason = parcel_r_string(&rilp);
|
||||
|
||||
if (tmp--) {
|
||||
/* TODO: different use for CDMA */
|
||||
smax = parcel_r_string(&rilp);
|
||||
|
||||
if (smax && max_calls)
|
||||
*max_calls = atoi(smax);
|
||||
}
|
||||
}
|
||||
|
||||
if (status) {
|
||||
if (!sstatus) {
|
||||
DBG("No sstatus value returned!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
*status = atoi(sstatus);
|
||||
}
|
||||
|
||||
if (lac) {
|
||||
if (slac)
|
||||
*lac = strtol(slac, NULL, 16);
|
||||
else
|
||||
*lac = -1;
|
||||
}
|
||||
|
||||
if (ci) {
|
||||
if (sci)
|
||||
*ci = strtol(sci, NULL, 16);
|
||||
else
|
||||
*ci = -1;
|
||||
}
|
||||
|
||||
|
||||
if (tech) {
|
||||
if (stech) {
|
||||
switch (atoi(stech)) {
|
||||
case RADIO_TECH_UNKNOWN:
|
||||
*tech = -1;
|
||||
break;
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
*tech = ACCESS_TECHNOLOGY_GSM;
|
||||
break;
|
||||
case RADIO_TECH_EDGE:
|
||||
*tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
|
||||
break;
|
||||
case RADIO_TECH_UMTS:
|
||||
*tech = ACCESS_TECHNOLOGY_UTRAN;
|
||||
break;
|
||||
case RADIO_TECH_HSDPA:
|
||||
*tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
|
||||
break;
|
||||
case RADIO_TECH_HSUPA:
|
||||
*tech = ACCESS_TECHNOLOGY_UTRAN_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_HSPA:
|
||||
case RADIO_TECH_HSPAP:
|
||||
case RADIO_TECH_DC_HSDPA:
|
||||
*tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_LTE:
|
||||
*tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
break;
|
||||
default:
|
||||
*tech = -1;
|
||||
}
|
||||
} else
|
||||
*tech = -1;
|
||||
}
|
||||
|
||||
g_ril_append_print_buf(gril,
|
||||
"{%s,%s,%s,%s,%s,%s}",
|
||||
registration_status_to_string(*status),
|
||||
slac,
|
||||
sci,
|
||||
registration_tech_to_string(*tech),
|
||||
sreason,
|
||||
smax);
|
||||
g_ril_print_response(gril, message);
|
||||
|
||||
/* Free our parcel handlers */
|
||||
g_free(sstatus);
|
||||
g_free(slac);
|
||||
g_free(sci);
|
||||
g_free(stech);
|
||||
g_free(sreason);
|
||||
g_free(smax);
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gint ril_util_parse_sms_response(GRil *gril, struct ril_msg *message)
|
||||
{
|
||||
struct parcel rilp;
|
||||
int error, mr;
|
||||
char *ack_pdu;
|
||||
|
||||
/* Set up Parcel struct for proper parsing */
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
/* TP-Message-Reference for GSM/
|
||||
* BearerData MessageId for CDMA
|
||||
*/
|
||||
mr = parcel_r_int32(&rilp);
|
||||
ack_pdu = parcel_r_string(&rilp);
|
||||
|
||||
/* error: 3GPP 27.005, 3.2.5, -1 if unknown or not applicable */
|
||||
error = parcel_r_int32(&rilp);
|
||||
DBG("sms msg ref: %d, error: %d, ack_pdu: %s", mr, error, ack_pdu);
|
||||
|
||||
g_ril_append_print_buf(gril, "{%d,%s,%d}",
|
||||
mr, ack_pdu, error);
|
||||
g_ril_print_response(gril, message);
|
||||
|
||||
return mr;
|
||||
}
|
||||
|
||||
gint ril_util_get_signal(GRil *gril, struct ril_msg *message)
|
||||
{
|
||||
struct parcel rilp;
|
||||
int gw_signal, cdma_dbm, evdo_dbm, lte_signal;
|
||||
|
||||
/* Set up Parcel struct for proper parsing */
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
/* RIL_SignalStrength_v6 */
|
||||
/* GW_SignalStrength */
|
||||
gw_signal = parcel_r_int32(&rilp);
|
||||
parcel_r_int32(&rilp); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
cdma_dbm = parcel_r_int32(&rilp);
|
||||
parcel_r_int32(&rilp); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
evdo_dbm = parcel_r_int32(&rilp);
|
||||
parcel_r_int32(&rilp); /* ecio */
|
||||
parcel_r_int32(&rilp); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
lte_signal = parcel_r_int32(&rilp);
|
||||
parcel_r_int32(&rilp); /* rsrp */
|
||||
parcel_r_int32(&rilp); /* rsrq */
|
||||
parcel_r_int32(&rilp); /* rssnr */
|
||||
parcel_r_int32(&rilp); /* cqi */
|
||||
|
||||
g_ril_append_print_buf(gril, "(gw: %d, cdma: %d, evdo: %d, lte: %d)",
|
||||
gw_signal, cdma_dbm, evdo_dbm, lte_signal);
|
||||
|
||||
if (message->unsolicited)
|
||||
g_ril_print_unsol(gril, message);
|
||||
else
|
||||
g_ril_print_response(gril, message);
|
||||
|
||||
/* 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) {
|
||||
if (cdma_dbm > 100)
|
||||
cdma_dbm = 100;
|
||||
return cdma_dbm;
|
||||
}
|
||||
if (evdo_dbm != -1) {
|
||||
if (evdo_dbm > 100)
|
||||
evdo_dbm = 100;
|
||||
return evdo_dbm;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ril_util_free_sim_apps(struct sim_app **apps, guint num_apps)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < num_apps; i++) {
|
||||
g_free(apps[i]->aid_str);
|
||||
g_free(apps[i]->app_str);
|
||||
g_free(apps[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -19,10 +19,13 @@
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#ifndef RILUTIL_H
|
||||
#define RILUTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "parcel.h"
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
/* TODO: create a table lookup*/
|
||||
#define PREFIX_30_NETMASK "255.255.255.252"
|
||||
@@ -33,6 +36,8 @@
|
||||
#define PREFIX_25_NETMASK "255.255.255.128"
|
||||
#define PREFIX_24_NETMASK "255.255.255.0"
|
||||
|
||||
#define MODEM_PROP_LTE_CAPABLE "lte-capable"
|
||||
|
||||
enum ril_util_sms_store {
|
||||
RIL_UTIL_SMS_STORE_SM = 0,
|
||||
RIL_UTIL_SMS_STORE_ME = 1,
|
||||
@@ -62,74 +67,13 @@ enum at_util_charset {
|
||||
RIL_UTIL_CHARSET_8859_H = 0x10000,
|
||||
};
|
||||
|
||||
#define MAX_UICC_APPS 16
|
||||
|
||||
struct sim_status {
|
||||
guint card_state;
|
||||
guint pin_state;
|
||||
guint gsm_umts_index;
|
||||
guint cdma_index;
|
||||
guint ims_index;
|
||||
guint num_apps;
|
||||
};
|
||||
|
||||
struct sim_app {
|
||||
guint app_type;
|
||||
guint app_state;
|
||||
guint perso_substate;
|
||||
char *aid_str;
|
||||
char *app_str;
|
||||
guint pin_replaced;
|
||||
guint pin1_state;
|
||||
guint pin2_state;
|
||||
};
|
||||
|
||||
typedef void (*ril_util_sim_inserted_cb_t)(gboolean present, void *userdata);
|
||||
|
||||
void decode_ril_error(struct ofono_error *error, const char *final);
|
||||
gint ril_util_call_compare_by_status(gconstpointer a, gconstpointer b);
|
||||
gint ril_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b);
|
||||
gint ril_util_call_compare_by_id(gconstpointer a, gconstpointer b);
|
||||
gint ril_util_call_compare(gconstpointer a, gconstpointer b);
|
||||
gchar *ril_util_get_netmask(const char *address);
|
||||
void ril_util_init_parcel(struct ril_msg *message, struct parcel *rilp);
|
||||
|
||||
struct ril_util_sim_state_query *ril_util_sim_state_query_new(GRil *ril,
|
||||
guint interval, guint num_times,
|
||||
ril_util_sim_inserted_cb_t cb,
|
||||
void *userdata,
|
||||
GDestroyNotify destroy);
|
||||
void ril_util_sim_state_query_free(struct ril_util_sim_state_query *req);
|
||||
|
||||
GSList *ril_util_parse_clcc(GRil *gril, struct ril_msg *message);
|
||||
char *ril_util_parse_sim_io_rsp(GRil *gril, struct ril_msg *message,
|
||||
int *sw1, int *sw2,
|
||||
int *hex_len);
|
||||
gboolean ril_util_parse_sim_status(GRil *gril, struct ril_msg *message,
|
||||
struct sim_status *status,
|
||||
struct sim_app **apps);
|
||||
gboolean ril_util_parse_reg(GRil *gril, struct ril_msg *message, int *status,
|
||||
int *lac, int *ci, int *tech, int *max_calls);
|
||||
|
||||
gint ril_util_parse_sms_response(GRil *gril, struct ril_msg *message);
|
||||
|
||||
gint ril_util_get_signal(GRil *gril, struct ril_msg *message);
|
||||
|
||||
gint ril_get_app_type();
|
||||
|
||||
struct ofono_sim_driver *get_sim_driver();
|
||||
|
||||
struct ofono_sim *get_sim();
|
||||
|
||||
gint check_if_really_roaming(gint status);
|
||||
|
||||
gboolean ril_roaming_allowed();
|
||||
|
||||
gboolean check_if_ok_to_attach();
|
||||
|
||||
gint get_current_network_status();
|
||||
|
||||
void ril_util_free_sim_apps(struct sim_app **apps, guint num_apps);
|
||||
void ril_util_build_deactivate_data_call(GRil *gril, struct parcel *rilp,
|
||||
int cid, unsigned int reason);
|
||||
|
||||
struct cb_data {
|
||||
void *cb;
|
||||
@@ -137,29 +81,14 @@ struct cb_data {
|
||||
void *user;
|
||||
};
|
||||
|
||||
static inline struct cb_data *cb_data_new(void *cb, void *data)
|
||||
static inline struct cb_data *cb_data_new(void *cb, void *data, void *user)
|
||||
{
|
||||
struct cb_data *ret;
|
||||
|
||||
ret = g_new0(struct cb_data, 1);
|
||||
ret->cb = cb;
|
||||
ret->data = data;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct cb_data *cb_data_new2(void *user, void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct cb_data *ret;
|
||||
|
||||
ret = g_new0(struct cb_data, 1);
|
||||
|
||||
if (ret) {
|
||||
ret->cb = cb;
|
||||
ret->data = data;
|
||||
ret->user = user;
|
||||
}
|
||||
ret->user = user;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -176,6 +105,12 @@ static inline int ril_util_convert_signal_strength(int strength)
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *ril_util_gprs_proto_to_ril_string(enum ofono_gprs_proto);
|
||||
|
||||
int ril_util_registration_state_to_status(int reg_state);
|
||||
|
||||
int ril_util_address_to_gprs_proto(const char *addr);
|
||||
|
||||
#define DECLARE_FAILURE(e) \
|
||||
struct ofono_error e; \
|
||||
e.type = OFONO_ERROR_TYPE_FAILURE; \
|
||||
@@ -197,3 +132,5 @@ static inline int ril_util_convert_signal_strength(int strength)
|
||||
e.error = 0; \
|
||||
f(&e, ##args); \
|
||||
} while (0)
|
||||
|
||||
#endif /* RILUTIL_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +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) 2012-2013 Canonical Ltd.
|
||||
* Copyright (C) 2013 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -38,35 +38,30 @@
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/sms.h>
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
#include "simutil.h"
|
||||
|
||||
#define SIM_EFSMS_FILEID 0x6F3C
|
||||
#define EFSMS_LENGTH 176
|
||||
|
||||
unsigned char path[4] = {0x3F, 0x00, 0x7F, 0x10};
|
||||
|
||||
struct sms_data {
|
||||
GRil *ril;
|
||||
unsigned int vendor;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
|
||||
static void ril_csca_set_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sms_sca_set_cb_t cb = cbd->cb;
|
||||
struct sms_data *sd = cbd->user;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
else {
|
||||
ofono_error("csca setting failed");
|
||||
} else {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(sd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
}
|
||||
@@ -75,121 +70,259 @@ static void ril_csca_set(struct ofono_sms *sms,
|
||||
const struct ofono_phone_number *sca,
|
||||
ofono_sms_sca_set_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, sd);
|
||||
struct parcel rilp;
|
||||
int ret = -1;
|
||||
char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 4];
|
||||
|
||||
if (sca->type == 129)
|
||||
snprintf(number, sizeof(number), "\"%s\"", sca->number);
|
||||
else
|
||||
snprintf(number, sizeof(number), "\"+%s\"", sca->number);
|
||||
|
||||
DBG("Setting sca: %s", number);
|
||||
snprintf(number, sizeof(number), "\"%s\"", phone_number_to_string(sca));
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_string(&rilp, number);
|
||||
|
||||
/* Send request to RIL */
|
||||
ret = g_ril_send(data->ril, RIL_REQUEST_SET_SMSC_ADDRESS, rilp.data,
|
||||
rilp.size, ril_csca_set_cb, cbd, g_free);
|
||||
parcel_free(&rilp);
|
||||
g_ril_append_print_buf(sd->ril, "(%s)", number);
|
||||
|
||||
/* In case of error free cbd and return the cb with failure */
|
||||
if (ret <= 0) {
|
||||
ofono_error("unable to set csca");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_SET_SMSC_ADDRESS, &rilp,
|
||||
ril_csca_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_csca_query_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sms_sca_query_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
struct sms_data *sd = cbd->user;
|
||||
struct ofono_phone_number sca;
|
||||
struct parcel rilp;
|
||||
gchar *number, *temp_buf;
|
||||
char *temp_buf;
|
||||
char *number;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
decode_ril_error(&error, "OK");
|
||||
} else {
|
||||
ofono_error("csca query failed");
|
||||
decode_ril_error(&error, "FAIL");
|
||||
cb(&error, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
temp_buf = parcel_r_string(&rilp);
|
||||
if (temp_buf == NULL)
|
||||
goto error;
|
||||
|
||||
if (temp_buf != NULL) {
|
||||
/* RIL gives address in quotes */
|
||||
number = strtok(temp_buf, "\"");
|
||||
|
||||
if (number[0] == '+') {
|
||||
number = number + 1;
|
||||
sca.type = 145;
|
||||
} else {
|
||||
sca.type = 129;
|
||||
}
|
||||
strncpy(sca.number, number, OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
|
||||
DBG("csca_query_cb: %s, %d", sca.number, sca.type);
|
||||
g_free(temp_buf); /*g_utf16_to_utf8 used by parcel_r_string*/
|
||||
cb(&error, &sca, cbd->data);
|
||||
} else {
|
||||
ofono_error("return value invalid");
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
/* RIL gives address in quotes */
|
||||
number = strtok(temp_buf, "\"");
|
||||
if (number == NULL || *number == '\0') {
|
||||
g_free(temp_buf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (number[0] == '+') {
|
||||
number = number + 1;
|
||||
sca.type = OFONO_NUMBER_TYPE_INTERNATIONAL;
|
||||
} else
|
||||
sca.type = OFONO_NUMBER_TYPE_UNKNOWN;
|
||||
|
||||
strncpy(sca.number, number, OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{type=%d,number=%s}",
|
||||
sca.type, sca.number);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
g_free(temp_buf);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, &sca, cbd->data);
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_csca_query(struct ofono_sms *sms, ofono_sms_sca_query_cb_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
int ret = -1;
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, sd);
|
||||
|
||||
DBG("Sending csca_query");
|
||||
|
||||
ret = g_ril_send(data->ril, RIL_REQUEST_GET_SMSC_ADDRESS, NULL, 0,
|
||||
ril_csca_query_cb, cbd, g_free);
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("unable to send sca query");
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_GET_SMSC_ADDRESS, NULL,
|
||||
ril_csca_query_cb, cbd, g_free) == 0) {
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void submit_sms_cb(struct ril_msg *message, gpointer user_data)
|
||||
static void ril_submit_sms_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_error error;
|
||||
ofono_sms_submit_cb_t cb = cbd->cb;
|
||||
struct sms_data *sd = cbd->user;
|
||||
struct parcel rilp;
|
||||
int mr;
|
||||
char *ack_pdu;
|
||||
int error;
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
ofono_info("sms sending successful");
|
||||
decode_ril_error(&error, "OK");
|
||||
} else if (message->error == 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");
|
||||
decode_ril_error(&error, "FAIL");
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
mr = ril_util_parse_sms_response(sd->ril, message);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
cb(&error, mr, cbd->data);
|
||||
/*
|
||||
* TP-Message-Reference for GSM/
|
||||
* BearerData MessageId for CDMA
|
||||
*/
|
||||
mr = parcel_r_int32(&rilp);
|
||||
ack_pdu = parcel_r_string(&rilp);
|
||||
error = parcel_r_int32(&rilp);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%d,%s,%d}", mr, ack_pdu, error);
|
||||
g_ril_print_response(sd->ril, message);
|
||||
g_free(ack_pdu);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, mr, cbd->data);
|
||||
}
|
||||
|
||||
static void imc_sms_bearer_query_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sms_bearer_query_cb_t cb = cbd->cb;
|
||||
struct parcel rilp;
|
||||
int bearer;
|
||||
char **strv = NULL;
|
||||
char *endptr;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("Reply failure: %s",
|
||||
ril_error_to_string(message->error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* OEM_HOOK_STRINGS response is a char**, representing
|
||||
* an array of null-terminated UTF-8 strings.
|
||||
*/
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
strv = parcel_r_strv(&rilp);
|
||||
|
||||
if (strv == NULL) {
|
||||
ofono_error("%s: malformed parcel", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
bearer = strtoul(strv[0], &endptr, 10); /* convert to int */
|
||||
|
||||
if (endptr == strv[0] || *endptr != '\0') {
|
||||
ofono_error("Convert to Int failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_strfreev(strv);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, bearer, cbd->data);
|
||||
return;
|
||||
error:
|
||||
|
||||
if(strv != NULL)
|
||||
g_strfreev(strv);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sms_bearer_query(struct ofono_sms *sms,
|
||||
ofono_sms_bearer_query_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, sd);
|
||||
struct parcel rilp;
|
||||
int cmd_id;
|
||||
char buf[4];
|
||||
|
||||
DBG("");
|
||||
|
||||
if (sd->vendor == OFONO_RIL_VENDOR_IMC_SOFIA3GR) {
|
||||
/*
|
||||
* OEM_HOOK_STRINGS request is a char **, representing an array
|
||||
* of null-terminated UTF-8 strings. Here just cmd_id as string.
|
||||
*/
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1); /* No. of strings */
|
||||
|
||||
/* RIL_OEM_HOOK_STRING_GET_SMS_TRANSPORT_MODE = 0x000000A9 */
|
||||
cmd_id = 0x000000A9;
|
||||
sprintf(buf, "%d", cmd_id);
|
||||
parcel_w_string(&rilp, buf);
|
||||
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
|
||||
imc_sms_bearer_query_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
}
|
||||
|
||||
static void imc_set_domain_pref_cb(struct ril_msg *message, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_sms_bearer_set_cb_t cb = cbd->cb;
|
||||
struct sms_data *sd = cbd->user;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (message->error != RIL_E_SUCCESS) {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(sd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sms_bearer_set(struct ofono_sms *sms, int bearer,
|
||||
ofono_sms_bearer_set_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, sd);
|
||||
struct parcel rilp;
|
||||
int cmd_id;
|
||||
char buf1[4];
|
||||
char buf2[4];
|
||||
|
||||
DBG("Bearer: %d", bearer);
|
||||
|
||||
if (sd->vendor == OFONO_RIL_VENDOR_IMC_SOFIA3GR) {
|
||||
/*
|
||||
* OEM_HOOK_STRINGS request is a char **, representing an array
|
||||
* of null-terminated UTF-8 strings. Here cmd_id and domain
|
||||
* to be sent as strings.
|
||||
*/
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 2); /* no. of strings */
|
||||
|
||||
/* RIL_OEM_HOOK_STRING_SET_SMS_TRANSPORT_MODE = 0x000000AA */
|
||||
cmd_id = 0x000000AA;
|
||||
sprintf(buf1, "%d", cmd_id);
|
||||
parcel_w_string(&rilp, buf1);
|
||||
sprintf(buf2, "%d", bearer);
|
||||
parcel_w_string(&rilp, buf2);
|
||||
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
|
||||
imc_set_domain_pref_cb,
|
||||
cbd, g_free) > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_cmgs(struct ofono_sms *sms, const unsigned char *pdu,
|
||||
@@ -197,267 +330,132 @@ static void ril_cmgs(struct ofono_sms *sms, const unsigned char *pdu,
|
||||
ofono_sms_submit_cb_t cb, void *user_data)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, sd);
|
||||
struct parcel rilp;
|
||||
char *tpdu;
|
||||
int request = RIL_REQUEST_SEND_SMS;
|
||||
int ret, smsc_len;
|
||||
|
||||
cbd->user = sd;
|
||||
int smsc_len;
|
||||
char hexbuf[tpdu_len * 2 + 1];
|
||||
|
||||
DBG("pdu_len: %d, tpdu_len: %d mms: %d", pdu_len, tpdu_len, mms);
|
||||
|
||||
/* TODO: if (mms) { ... } */
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 2); /* Number of strings */
|
||||
parcel_w_int32(&rilp, 2); /* Number of strings */
|
||||
|
||||
/* SMSC address:
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
/* TODO: encode SMSC & write to parcel */
|
||||
if (smsc_len > 1)
|
||||
ofono_error("SMSC address specified (smsc_len %d); "
|
||||
"NOT-IMPLEMENTED", smsc_len);
|
||||
|
||||
parcel_w_string(&rilp, NULL); /* SMSC address; NULL == default */
|
||||
|
||||
/* TPDU:
|
||||
/*
|
||||
* TPDU:
|
||||
*
|
||||
* 'pdu' is a raw hexadecimal string
|
||||
* encode_hex() turns it into an ASCII/hex UTF8 buffer
|
||||
* parcel_w_string() encodes utf8 -> utf16
|
||||
*/
|
||||
tpdu = encode_hex(pdu + smsc_len, tpdu_len, 0);
|
||||
parcel_w_string(&rilp, tpdu);
|
||||
encode_hex_own_buf(pdu + smsc_len, tpdu_len, 0, hexbuf);
|
||||
parcel_w_string(&rilp, hexbuf);
|
||||
|
||||
ret = g_ril_send(sd->ril,
|
||||
request,
|
||||
rilp.data,
|
||||
rilp.size,
|
||||
submit_sms_cb, cbd, g_free);
|
||||
g_ril_append_print_buf(sd->ril, "(%s)", hexbuf);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "(%s)", tpdu);
|
||||
g_free(tpdu);
|
||||
tpdu = NULL;
|
||||
g_ril_print_request(sd->ril, ret, request);
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_SEND_SMS, &rilp,
|
||||
ril_submit_sms_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
parcel_free(&rilp);
|
||||
|
||||
if (ret <= 0) {
|
||||
ofono_error("unable to send sms");
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
}
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, -1, user_data);
|
||||
}
|
||||
|
||||
static void ril_ack_delivery_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
if (message->error != RIL_E_SUCCESS)
|
||||
ofono_error(
|
||||
"SMS acknowledgement failed: Further SMS reception is not guaranteed");
|
||||
ofono_error("SMS acknowledgement failed: "
|
||||
"Further SMS reception is not guaranteed");
|
||||
}
|
||||
|
||||
static void ril_ack_delivery(struct ofono_sms *sms, int error)
|
||||
static void ril_ack_delivery(struct ofono_sms *sms)
|
||||
{
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct parcel rilp;
|
||||
int ret;
|
||||
int request = RIL_REQUEST_SMS_ACKNOWLEDGE;
|
||||
int code = 0;
|
||||
|
||||
if (!error)
|
||||
code = 0xFF;
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 2); /* Number of int32 values in array */
|
||||
parcel_w_int32(&rilp, error); /* Successful (1)/Failed (0) receipt */
|
||||
parcel_w_int32(&rilp, code); /* error code */
|
||||
|
||||
/* ACK the incoming NEW_SMS */
|
||||
ret = g_ril_send(sd->ril, request,
|
||||
rilp.data,
|
||||
rilp.size,
|
||||
ril_ack_delivery_cb, NULL, NULL);
|
||||
parcel_w_int32(&rilp, 1); /* Successful receipt */
|
||||
parcel_w_int32(&rilp, 0); /* error code */
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "(1,0)");
|
||||
g_ril_print_request(sd->ril, ret, request);
|
||||
|
||||
parcel_free(&rilp);
|
||||
/* TODO: should ACK be sent for either of the error cases? */
|
||||
|
||||
/* ACK the incoming NEW_SMS */
|
||||
g_ril_send(sd->ril, RIL_REQUEST_SMS_ACKNOWLEDGE, &rilp,
|
||||
ril_ack_delivery_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
static void ril_sms_notify(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_sms *sms = user_data;
|
||||
struct sms_data *sd = ofono_sms_get_data(sms);
|
||||
struct parcel rilp;
|
||||
char *ril_pdu;
|
||||
int ril_pdu_len;
|
||||
unsigned int smsc_len;
|
||||
long ril_buf_len;
|
||||
guchar *ril_data;
|
||||
struct parcel rilp;
|
||||
char *ril_pdu;
|
||||
size_t ril_pdu_len;
|
||||
unsigned char pdu[176];
|
||||
|
||||
ril_pdu = NULL;
|
||||
ril_data = NULL;
|
||||
DBG("req: %d; data_len: %d", message->req, (int) message->buf_len);
|
||||
|
||||
DBG("req: %d; data_len: %d", message->req, message->buf_len);
|
||||
|
||||
switch (message->req) {
|
||||
case RIL_UNSOL_RESPONSE_NEW_SMS:
|
||||
case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
ril_pdu = parcel_r_string(&rilp);
|
||||
if (ril_pdu == NULL)
|
||||
goto error;
|
||||
return;
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "{%s}", ril_pdu);
|
||||
g_ril_print_unsol(sd->ril, message);
|
||||
|
||||
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;
|
||||
if (ril_pdu_len > sizeof(pdu) * 2)
|
||||
goto fail;
|
||||
|
||||
/* 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);
|
||||
|
||||
g_ril_append_print_buf(sd->ril, "(%s)", ril_pdu);
|
||||
g_free(ril_pdu);
|
||||
ril_pdu = NULL;
|
||||
g_ril_print_unsol(sd->ril, message);
|
||||
|
||||
if (message->req == RIL_UNSOL_RESPONSE_NEW_SMS) {
|
||||
/* Last parameter is 'tpdu_len' ( substract SMSC length ) */
|
||||
ofono_sms_deliver_notify(sms, ril_data,
|
||||
ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
} else if (message->req == RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT) {
|
||||
ofono_sms_status_notify(sms, ril_data, ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
}
|
||||
|
||||
g_free(ril_data);
|
||||
ril_data = NULL;
|
||||
|
||||
ril_ack_delivery(sms, TRUE);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
g_free(ril_pdu);
|
||||
ril_pdu = NULL;
|
||||
|
||||
g_free(ril_data);
|
||||
ril_data = NULL;
|
||||
|
||||
ril_ack_delivery(sms, FALSE);
|
||||
|
||||
ofono_error("Unable to parse NEW_SMS notification");
|
||||
}
|
||||
|
||||
static void ril_new_sms_on_sim_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
DBG("");
|
||||
if (message->error == 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 ofono_sms *sms,int record)
|
||||
{
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
struct parcel rilp;
|
||||
int request = RIL_REQUEST_DELETE_SMS_ON_SIM;
|
||||
int ret;
|
||||
|
||||
DBG("Deleting record: %d", record);
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1); /* Number of int32 values in array */
|
||||
parcel_w_int32(&rilp, record);
|
||||
|
||||
ret = g_ril_send(data->ril, request, rilp.data,
|
||||
rilp.size, ril_new_sms_on_sim_cb, NULL, NULL);
|
||||
|
||||
parcel_free(&rilp);
|
||||
|
||||
if (ret <= 0)
|
||||
ofono_error("cannot delete sms from sim");
|
||||
}
|
||||
|
||||
static void ril_read_sms_on_sim_cb(const struct ofono_error *error,
|
||||
const unsigned char *sdata,
|
||||
int length, void *data)
|
||||
{
|
||||
struct cb_data *cbd = data;
|
||||
struct ofono_sms *sms = cbd->user;
|
||||
int record;
|
||||
unsigned int smsc_len;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
ofono_error("cannot read sms from sim");
|
||||
goto exit;
|
||||
}
|
||||
if (decode_hex_own_buf(ril_pdu, ril_pdu_len,
|
||||
&ril_buf_len, -1, pdu) == NULL)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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 = sdata[1] + 1;
|
||||
smsc_len = pdu[0] + 1;
|
||||
DBG("smsc_len is %d", smsc_len);
|
||||
|
||||
ofono_sms_deliver_notify(sms, sdata + 1, length - 1,
|
||||
length - smsc_len - 1);
|
||||
if (message->req == RIL_UNSOL_RESPONSE_NEW_SMS)
|
||||
/* Last parameter is 'tpdu_len' ( substract SMSC length ) */
|
||||
ofono_sms_deliver_notify(sms, pdu, ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
else if (message->req == RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT)
|
||||
ofono_sms_status_notify(sms, pdu, ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
|
||||
record = (int)cbd->data;
|
||||
ril_request_delete_sms_om_sim(sms,record);
|
||||
/* ACK the incoming NEW_SMS */
|
||||
ril_ack_delivery(sms);
|
||||
|
||||
exit:
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_new_sms_on_sim(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_sms *sms = user_data;
|
||||
struct parcel rilp;
|
||||
int record;
|
||||
|
||||
ofono_info("new sms on sim");
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
|
||||
/* data length of the response */
|
||||
record = parcel_r_int32(&rilp);
|
||||
|
||||
if (record > 0) {
|
||||
record = parcel_r_int32(&rilp);
|
||||
struct cb_data *cbd = cb_data_new2(sms, NULL, (void*)record);
|
||||
DBG(":%d", record);
|
||||
get_sim_driver()->read_file_linear(get_sim(), SIM_EFSMS_FILEID,
|
||||
record, EFSMS_LENGTH, path,
|
||||
sizeof(path),
|
||||
ril_read_sms_on_sim_cb, cbd);
|
||||
}
|
||||
fail:
|
||||
g_free(ril_pdu);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
@@ -466,19 +464,13 @@ static gboolean ril_delayed_register(gpointer user_data)
|
||||
struct sms_data *data = ofono_sms_get_data(sms);
|
||||
|
||||
DBG("");
|
||||
|
||||
data->timer_id = 0;
|
||||
|
||||
ofono_sms_register(sms);
|
||||
|
||||
g_ril_register(data->ril, RIL_UNSOL_RESPONSE_NEW_SMS,
|
||||
ril_sms_notify, sms);
|
||||
ril_sms_notify, sms);
|
||||
g_ril_register(data->ril, RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
|
||||
ril_sms_notify, sms);
|
||||
g_ril_register(data->ril, RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM,
|
||||
ril_new_sms_on_sim, sms);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -494,17 +486,7 @@ static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
|
||||
|
||||
ofono_sms_set_data(sms, data);
|
||||
|
||||
/*
|
||||
* TODO: analyze if capability check is needed
|
||||
* and/or timer should be adjusted.
|
||||
*
|
||||
* ofono_sms_register() needs to be called after
|
||||
* the driver has been set in ofono_sms_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.
|
||||
*/
|
||||
data->timer_id = g_timeout_add_seconds(2, ril_delayed_register, sms);
|
||||
g_idle_add(ril_delayed_register, sms);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -515,9 +497,6 @@ static void ril_sms_remove(struct ofono_sms *sms)
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->timer_id > 0)
|
||||
g_source_remove(data->timer_id);
|
||||
|
||||
g_ril_unref(data->ril);
|
||||
g_free(data);
|
||||
|
||||
@@ -525,25 +504,22 @@ static void ril_sms_remove(struct ofono_sms *sms)
|
||||
}
|
||||
|
||||
static struct ofono_sms_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.name = RILMODEM,
|
||||
.probe = ril_sms_probe,
|
||||
.remove = ril_sms_remove,
|
||||
.sca_query = ril_csca_query,
|
||||
.sca_set = ril_csca_set,
|
||||
.remove = ril_sms_remove,
|
||||
.submit = ril_cmgs,
|
||||
.bearer_query = NULL, /* FIXME: needs investigation. */
|
||||
.bearer_set = NULL,
|
||||
.bearer_query = ril_sms_bearer_query,
|
||||
.bearer_set = ril_sms_bearer_set
|
||||
};
|
||||
|
||||
void ril_sms_init(void)
|
||||
{
|
||||
DBG("");
|
||||
if (ofono_sms_driver_register(&driver))
|
||||
DBG("ofono_sms_driver_register failed!");
|
||||
ofono_sms_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ril_sms_exit(void)
|
||||
{
|
||||
DBG("");
|
||||
ofono_sms_driver_unregister(&driver);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2014 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
|
||||
@@ -26,178 +25,136 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/stk.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <gril.h>
|
||||
#include <parcel.h>
|
||||
|
||||
#include "rilmodem.h"
|
||||
#include "ril_constants.h"
|
||||
#include "vendor.h"
|
||||
|
||||
struct stk_data {
|
||||
GRil *ril;
|
||||
unsigned int vendor;
|
||||
};
|
||||
|
||||
gboolean subscribed;
|
||||
|
||||
static void ril_envelope_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_stk_envelope_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
decode_ril_error(&error, "OK");
|
||||
} else {
|
||||
DBG("Envelope reply failure: %s",
|
||||
ril_error_to_string(message->error));
|
||||
decode_ril_error(&error, "FAIL");
|
||||
}
|
||||
|
||||
cb(&error, NULL, 0, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_stk_envelope(struct ofono_stk *stk, int length,
|
||||
const unsigned char *command,
|
||||
ofono_stk_envelope_cb_t cb, void *data)
|
||||
{
|
||||
struct stk_data *sd = ofono_stk_get_data(stk);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct parcel rilp;
|
||||
char *hex_envelope = NULL;
|
||||
int request = RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND;
|
||||
guint ret;
|
||||
|
||||
DBG("");
|
||||
|
||||
hex_envelope = encode_hex(command, length, 0);
|
||||
DBG("rilmodem envelope: %s", hex_envelope);
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_string(&rilp, hex_envelope);
|
||||
g_free(hex_envelope);
|
||||
hex_envelope = NULL;
|
||||
|
||||
ret = g_ril_send(sd->ril, request,
|
||||
rilp.data, rilp.size, ril_envelope_cb,
|
||||
cbd, g_free);
|
||||
|
||||
parcel_free(&rilp);
|
||||
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, -1, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_tr_cb(struct ril_msg *message, gpointer user_data)
|
||||
static void ril_stk_terminal_response_cb(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_stk_generic_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
struct stk_data *sd = cbd->user;
|
||||
|
||||
DBG("");
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
decode_ril_error(&error, "OK");
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
} else {
|
||||
DBG("Error in sending terminal response");
|
||||
ofono_error("Error in sending terminal response");
|
||||
decode_ril_error(&error, "FAIL");
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(sd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
cb(&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)
|
||||
static void ril_stk_terminal_response(struct ofono_stk *stk, int len,
|
||||
const unsigned char *data,
|
||||
ofono_stk_generic_cb_t cb, void *user_data)
|
||||
{
|
||||
struct stk_data *sd = ofono_stk_get_data(stk);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, sd);
|
||||
struct parcel rilp;
|
||||
char *hex_tr = NULL;
|
||||
int request = RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE;
|
||||
guint ret;
|
||||
char *buf = alloca(len * 2 + 1);
|
||||
int size = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
hex_tr = encode_hex(resp, length, 0);
|
||||
DBG("rilmodem terminal response: %s", hex_tr);
|
||||
for (; len; len--)
|
||||
size += sprintf(buf + size, "%02hhX", *data++);
|
||||
|
||||
parcel_init(&rilp);
|
||||
parcel_w_string(&rilp, hex_tr);
|
||||
g_free(hex_tr);
|
||||
hex_tr = NULL;
|
||||
parcel_w_string(&rilp, buf);
|
||||
|
||||
ret = g_ril_send(sd->ril, request,
|
||||
rilp.data, rilp.size, ril_tr_cb,
|
||||
cbd, g_free);
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, &rilp,
|
||||
ril_stk_terminal_response_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
parcel_free(&rilp);
|
||||
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_stk_user_confirmation(struct ofono_stk *stk,
|
||||
ofono_bool_t confirm)
|
||||
static void ril_stk_envelope_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_stk_envelope_cb_t cb = cbd->cb;
|
||||
struct stk_data *sd = cbd->user;
|
||||
struct parcel rilp;
|
||||
unsigned char *response = NULL;
|
||||
long len = 0;
|
||||
char *pdu;
|
||||
|
||||
g_ril_print_response(sd->ril, message);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
pdu = parcel_r_string(&rilp);
|
||||
|
||||
if (pdu)
|
||||
response = decode_hex(pdu, -1, &len, -1);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, response, len, cbd->data);
|
||||
g_free(response);
|
||||
} else {
|
||||
ofono_error("%s RILD reply failure: %s",
|
||||
g_ril_request_id_to_string(sd->ril, message->req),
|
||||
ril_error_to_string(message->error));
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_stk_envelope(struct ofono_stk *stk, int len,
|
||||
const unsigned char *cmd,
|
||||
ofono_stk_envelope_cb_t cb, void *user_data)
|
||||
{
|
||||
struct stk_data *sd = ofono_stk_get_data(stk);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, sd);
|
||||
struct parcel rilp;
|
||||
int request = RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM;
|
||||
int ret;
|
||||
char *buf = alloca(len * 2 + 1);
|
||||
int size = 0;
|
||||
|
||||
DBG("");
|
||||
for (; len; len--)
|
||||
size += sprintf(buf + size, "%02hhX", *cmd++);
|
||||
|
||||
/* Only pcmd needing user confirmation is call set up
|
||||
* RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM
|
||||
*/
|
||||
parcel_init(&rilp);
|
||||
parcel_w_int32(&rilp, 1); /* size of array */
|
||||
parcel_w_int32(&rilp, confirm); /* yes/no */
|
||||
parcel_w_string(&rilp, buf);
|
||||
|
||||
/* fire and forget i.e. not waiting for the callback*/
|
||||
ret = g_ril_send(sd->ril, request, rilp.data,
|
||||
rilp.size, NULL, NULL, NULL);
|
||||
if (g_ril_send(sd->ril, RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, &rilp,
|
||||
ril_stk_envelope_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_ril_print_request_no_args(sd->ril, ret, request);
|
||||
|
||||
parcel_free(&rilp);
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, NULL, 0, user_data);
|
||||
}
|
||||
|
||||
static void ril_stk_pcmd_notify(struct ril_msg *message, gpointer user_data)
|
||||
static void ril_stk_proactive_cmd_notify(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_stk *stk = user_data;
|
||||
struct parcel rilp;
|
||||
char *pcmd = NULL;
|
||||
guchar *pdu = NULL;
|
||||
long len;
|
||||
long pdulen;
|
||||
unsigned char *pdu;
|
||||
|
||||
DBG("");
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
pcmd = parcel_r_string(&rilp);
|
||||
DBG("pcmd: %s", pcmd);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
pdu = decode_hex(parcel_r_string(&rilp), -1, &pdulen, -1);
|
||||
|
||||
pdu = decode_hex((const char *) pcmd,
|
||||
strlen(pcmd),
|
||||
&len, -1);
|
||||
|
||||
g_free(pcmd);
|
||||
ofono_stk_proactive_command_notify(stk, len, (const guchar *)pdu);
|
||||
ofono_stk_proactive_command_notify(stk, pdulen, pdu);
|
||||
g_free(pdu);
|
||||
}
|
||||
|
||||
@@ -205,130 +162,69 @@ static void ril_stk_event_notify(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_stk *stk = user_data;
|
||||
struct parcel rilp;
|
||||
char *pcmd = NULL;
|
||||
guchar *pdu = NULL;
|
||||
long len;
|
||||
long pdulen;
|
||||
unsigned char *pdu;
|
||||
|
||||
DBG("");
|
||||
|
||||
/* Proactive command has been handled by the modem. */
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
pcmd = parcel_r_string(&rilp);
|
||||
DBG("pcmd: %s", pcmd);
|
||||
pdu = decode_hex((const char *) pcmd,
|
||||
strlen(pcmd),
|
||||
&len, -1);
|
||||
g_free(pcmd);
|
||||
pcmd = NULL;
|
||||
ofono_stk_proactive_command_handled_notify(stk, len,
|
||||
(const guchar *)pdu);
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
pdu = decode_hex(parcel_r_string(&rilp), -1, &pdulen, -1);
|
||||
|
||||
ofono_stk_proactive_command_handled_notify(stk, pdulen, pdu);
|
||||
g_free(pdu);
|
||||
}
|
||||
|
||||
static void ril_stk_session_end_notify(struct ril_msg *message,
|
||||
gpointer user_data)
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ofono_stk *stk = user_data;
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_stk_proactive_session_end_notify(stk);
|
||||
}
|
||||
|
||||
static void ril_stk_agent_ready(struct ofono_stk *stk)
|
||||
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor,
|
||||
void *user)
|
||||
{
|
||||
struct stk_data *sd = ofono_stk_get_data(stk);
|
||||
int request = RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING;
|
||||
int ret;
|
||||
GRil *ril = user;
|
||||
struct stk_data *data;
|
||||
|
||||
DBG("");
|
||||
data = g_new0(struct stk_data, 1);
|
||||
data->ril = g_ril_clone(ril);
|
||||
data->vendor = vendor;
|
||||
|
||||
if (!subscribed) {
|
||||
DBG("Subscribing notifications");
|
||||
g_ril_register(sd->ril, RIL_UNSOL_STK_PROACTIVE_COMMAND,
|
||||
ril_stk_pcmd_notify, stk);
|
||||
ofono_stk_set_data(stk, data);
|
||||
|
||||
g_ril_register(sd->ril, RIL_UNSOL_STK_SESSION_END,
|
||||
ril_stk_session_end_notify, stk);
|
||||
g_ril_register(ril, RIL_UNSOL_STK_PROACTIVE_COMMAND,
|
||||
ril_stk_proactive_cmd_notify, stk);
|
||||
|
||||
g_ril_register(sd->ril, RIL_UNSOL_STK_EVENT_NOTIFY,
|
||||
ril_stk_event_notify, stk);
|
||||
subscribed = TRUE;
|
||||
}
|
||||
g_ril_register(ril, RIL_UNSOL_STK_SESSION_END,
|
||||
ril_stk_session_end_notify, stk);
|
||||
|
||||
/* fire and forget i.e. not waiting for the callback*/
|
||||
ret = g_ril_send(sd->ril, request, NULL, 0,
|
||||
NULL, NULL, NULL);
|
||||
g_ril_register(ril, RIL_UNSOL_STK_EVENT_NOTIFY,
|
||||
ril_stk_event_notify, stk);
|
||||
|
||||
g_ril_print_request_no_args(sd->ril, ret, request);
|
||||
}
|
||||
|
||||
void ril_stk_set_lang()
|
||||
{
|
||||
gchar *contents;
|
||||
GError *err = NULL;
|
||||
|
||||
if (!g_file_get_contents(UI_LANG, &contents, NULL, &err)) {
|
||||
if (err)
|
||||
ofono_error("cannot open %s error: %d: message: %s",
|
||||
UI_LANG, err->code, err->message);
|
||||
g_error_free(err);
|
||||
} else {
|
||||
gchar *pch = g_strrstr(contents, CFG_LANG);
|
||||
/* Set System UI lang to env LANG */
|
||||
if (pch) {
|
||||
setenv("LANG", pch + strlen(CFG_LANG), 1);
|
||||
DBG("LANG %s", getenv("LANG"));
|
||||
}
|
||||
g_free(contents);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
|
||||
{
|
||||
GRil *ril = data;
|
||||
struct stk_data *sd;
|
||||
|
||||
DBG("");
|
||||
|
||||
sd = g_try_new0(struct stk_data, 1);
|
||||
if (sd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
sd->ril = g_ril_clone(ril);
|
||||
ofono_stk_set_data(stk, sd);
|
||||
|
||||
/* Register interface in this phase for stk agent */
|
||||
ofono_stk_register(stk);
|
||||
|
||||
subscribed = FALSE;
|
||||
|
||||
/* UI language for local info */
|
||||
ril_stk_set_lang();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_stk_remove(struct ofono_stk *stk)
|
||||
{
|
||||
struct stk_data *sd = ofono_stk_get_data(stk);
|
||||
|
||||
DBG("");
|
||||
struct stk_data *data = ofono_stk_get_data(stk);
|
||||
|
||||
ofono_stk_set_data(stk, NULL);
|
||||
|
||||
g_ril_unref(sd->ril);
|
||||
g_free(sd);
|
||||
g_ril_unref(data->ril);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static struct ofono_stk_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.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
|
||||
.name = RILMODEM,
|
||||
.probe = ril_stk_probe,
|
||||
.remove = ril_stk_remove,
|
||||
.envelope = ril_stk_envelope,
|
||||
.terminal_response = ril_stk_terminal_response,
|
||||
};
|
||||
|
||||
void ril_stk_init(void)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013 Jolla Ltd
|
||||
* Copyright (C) 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
|
||||
@@ -38,25 +39,39 @@
|
||||
#include <util.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "grilutil.h"
|
||||
|
||||
#include "rilmodem.h"
|
||||
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ussd_data {
|
||||
GRil *ril;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
static gboolean request_success(gpointer data)
|
||||
{
|
||||
struct cb_data *cbd = data;
|
||||
ofono_ussd_cb_t cb = cbd->cb;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
g_free(cbd);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_ussd_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_ussd *ussd = user_data;
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
|
||||
/*
|
||||
* Calling oFono callback function at this point may lead to
|
||||
* segmentation fault. There is theoretical possibility that no
|
||||
* RIL_UNSOL_ON_USSD is received and therefore the original request
|
||||
* is not freed in oFono.
|
||||
* We fake an ON_USSD event if there was an error sending the request,
|
||||
* as core will be waiting for one to respond to the Initiate() call.
|
||||
* Note that we already made the callback (see ril_ussd_request()).
|
||||
*/
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
g_ril_print_response_no_args(ud->ril, message);
|
||||
else
|
||||
ofono_ussd_notify(ussd, OFONO_USSD_STATUS_NOT_SUPPORTED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
@@ -64,133 +79,129 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
enum sms_charset charset;
|
||||
int ret = -1;
|
||||
struct cb_data *cbd = cb_data_new(cb, data, ussd);
|
||||
char *text;
|
||||
struct parcel rilp;
|
||||
int ret;
|
||||
|
||||
ofono_info("send ussd, len:%d", len);
|
||||
text = ussd_decode(dcs, len, pdu);
|
||||
if (!text)
|
||||
goto error;
|
||||
|
||||
if (cbs_dcs_decode(dcs, NULL, NULL, &charset,
|
||||
NULL, NULL, NULL)) {
|
||||
if (charset == SMS_CHARSET_7BIT) {
|
||||
unsigned char unpacked_buf[182] = "";
|
||||
long written;
|
||||
int length;
|
||||
parcel_init(&rilp);
|
||||
parcel_w_string(&rilp, text);
|
||||
|
||||
unpack_7bit_own_buf(pdu, len, 0, TRUE,
|
||||
sizeof(unpacked_buf), &written, 0,
|
||||
unpacked_buf);
|
||||
g_ril_append_print_buf(ud->ril, "(%s)", text);
|
||||
|
||||
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. And in addition written doesn't
|
||||
contain correct length...
|
||||
|
||||
Over 2 characters long USSD string must
|
||||
end with # (checked in
|
||||
valid_ussd_string() ), so it should be
|
||||
safe to remove extra CR.
|
||||
*/
|
||||
length = strlen((char *)unpacked_buf);
|
||||
if (length > 2 &&
|
||||
unpacked_buf[length-1] == '\r')
|
||||
unpacked_buf[length-1] = 0;
|
||||
struct parcel rilp;
|
||||
parcel_init(&rilp);
|
||||
parcel_w_string(&rilp, (char *)unpacked_buf);
|
||||
ret = g_ril_send(ud->ril,
|
||||
RIL_REQUEST_SEND_USSD,
|
||||
rilp.data, rilp.size,
|
||||
ril_ussd_cb, cbd, g_free);
|
||||
parcel_free(&rilp);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = g_ril_send(ud->ril, RIL_REQUEST_SEND_USSD,
|
||||
&rilp, ril_ussd_cb, ussd, NULL);
|
||||
g_free(text);
|
||||
|
||||
/*
|
||||
* It cannot be guaranteed that response is received before notify or
|
||||
* user-activity request so we must complete the request now and later
|
||||
* ignore the actual response.
|
||||
* TODO: Is g_idle_add necessary?
|
||||
* We do not wait for the SEND_USSD reply to do the callback, as some
|
||||
* networks send it after sending one or more ON_USSD events. From the
|
||||
* ofono core perspective, Initiate() does not return until one ON_USSD
|
||||
* event is received: making here a successful callback just makes the
|
||||
* core wait for that event.
|
||||
*/
|
||||
if (ret <= 0) {
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
} else {
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
if (ret > 0) {
|
||||
g_idle_add(request_success, cbd);
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
g_free(cbd);
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void ril_ussd_cancel_cb(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
struct ofono_ussd *ussd = cbd->user;
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
ofono_ussd_cb_t cb = cbd->cb;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("%d", message->error);
|
||||
|
||||
if (message->error == RIL_E_SUCCESS)
|
||||
decode_ril_error(&error, "OK");
|
||||
else {
|
||||
ofono_error("ussd canceling failed");
|
||||
decode_ril_error(&error, "FAIL");
|
||||
if (message->error == RIL_E_SUCCESS) {
|
||||
g_ril_print_response_no_args(ud->ril, message);
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
} else {
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
ofono_ussd_cb_t cb, void *user_data)
|
||||
{
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data);
|
||||
struct cb_data *cbd = cb_data_new(cb, user_data, ussd);
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
|
||||
cbd->user = ud;
|
||||
|
||||
if (g_ril_send(ud->ril, RIL_REQUEST_CANCEL_USSD, NULL, 0,
|
||||
if (g_ril_send(ud->ril, RIL_REQUEST_CANCEL_USSD, NULL,
|
||||
ril_ussd_cancel_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
ofono_error("unable cancel ussd");
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, user_data);
|
||||
}
|
||||
|
||||
static void ril_ussd_notify(struct ril_msg *message, gpointer user_data)
|
||||
{
|
||||
struct ofono_ussd *ussd = user_data;
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
struct parcel rilp;
|
||||
gchar *ussd_from_network = NULL;
|
||||
gchar *type = NULL;
|
||||
gint ussdtype = 0;
|
||||
int numstr;
|
||||
char *typestr;
|
||||
int type;
|
||||
char *str = NULL;
|
||||
gsize written;
|
||||
char *ucs2;
|
||||
|
||||
ofono_info("ussd_received");
|
||||
g_ril_init_parcel(message, &rilp);
|
||||
|
||||
ril_util_init_parcel(message, &rilp);
|
||||
parcel_r_int32(&rilp);
|
||||
type = parcel_r_string(&rilp);
|
||||
ussdtype = g_ascii_xdigit_value(*type);
|
||||
g_free(type);
|
||||
type = NULL;
|
||||
ussd_from_network = parcel_r_string(&rilp);
|
||||
numstr = parcel_r_int32(&rilp);
|
||||
if (numstr < 1)
|
||||
return;
|
||||
|
||||
/* ussd_from_network not freed because core does that if dcs is 0xFF */
|
||||
if (ussd_from_network) {
|
||||
DBG("ussd_received, length %d", strlen(ussd_from_network));
|
||||
ofono_ussd_notify(ussd, ussdtype, 0xFF,
|
||||
(const unsigned char *)ussd_from_network,
|
||||
strlen(ussd_from_network));
|
||||
} else
|
||||
ofono_ussd_notify(ussd, ussdtype, 0, NULL, 0);
|
||||
typestr = parcel_r_string(&rilp);
|
||||
if (typestr == NULL || *typestr == '\0')
|
||||
return;
|
||||
|
||||
return;
|
||||
type = *typestr - '0';
|
||||
g_free(typestr);
|
||||
|
||||
if (numstr > 1)
|
||||
str = parcel_r_string(&rilp);
|
||||
|
||||
g_ril_append_print_buf(ud->ril, "{%d,%s}", type, str);
|
||||
|
||||
g_ril_print_unsol(ud->ril, message);
|
||||
|
||||
/* To fix bug in MTK: USSD-Notify arrive with type 2 instead of 0 */
|
||||
if (g_ril_vendor(ud->ril) == OFONO_RIL_VENDOR_MTK &&
|
||||
str != NULL && type == 2)
|
||||
type = 0;
|
||||
|
||||
if (str == NULL) {
|
||||
ofono_ussd_notify(ussd, type, 0, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* With data coding scheme 0x48, we are saying that the ussd string is a
|
||||
* UCS-2 string, uncompressed, and with unspecified message class. For
|
||||
* the DCS coding, see 3gpp 23.038, sect. 5.
|
||||
*/
|
||||
ucs2 = g_convert(str, -1, "UCS-2BE//TRANSLIT",
|
||||
"UTF-8", NULL, &written, NULL);
|
||||
g_free(str);
|
||||
|
||||
if (ucs2 == NULL) {
|
||||
ofono_error("%s: Error transcoding", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_ussd_notify(ussd, type, 0x48, (unsigned char *) ucs2, written);
|
||||
g_free(ucs2);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
@@ -200,13 +211,10 @@ static gboolean ril_delayed_register(gpointer user_data)
|
||||
|
||||
DBG("");
|
||||
|
||||
ud->timer_id = 0;
|
||||
|
||||
ofono_ussd_register(ussd);
|
||||
|
||||
/* Register for USSD responses */
|
||||
g_ril_register(ud->ril, RIL_UNSOL_ON_USSD,
|
||||
ril_ussd_notify, ussd);
|
||||
g_ril_register(ud->ril, RIL_UNSOL_ON_USSD, ril_ussd_notify, ussd);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -216,10 +224,11 @@ static int ril_ussd_probe(struct ofono_ussd *ussd,
|
||||
void *user)
|
||||
{
|
||||
GRil *ril = user;
|
||||
struct ussd_data *ud = g_try_new0(struct ussd_data, 1);
|
||||
struct ussd_data *ud = g_new0(struct ussd_data, 1);
|
||||
|
||||
ud->ril = g_ril_clone(ril);
|
||||
ofono_ussd_set_data(ussd, ud);
|
||||
ud->timer_id = g_timeout_add_seconds(2, ril_delayed_register, ussd);
|
||||
g_idle_add(ril_delayed_register, ussd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -229,19 +238,16 @@ static void ril_ussd_remove(struct ofono_ussd *ussd)
|
||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||
ofono_ussd_set_data(ussd, NULL);
|
||||
|
||||
if (ud->timer_id > 0)
|
||||
g_source_remove(ud->timer_id);
|
||||
|
||||
g_ril_unref(ud->ril);
|
||||
g_free(ud);
|
||||
}
|
||||
|
||||
static struct ofono_ussd_driver driver = {
|
||||
.name = "rilmodem",
|
||||
.probe = ril_ussd_probe,
|
||||
.remove = ril_ussd_remove,
|
||||
.request = ril_ussd_request,
|
||||
.cancel = ril_ussd_cancel
|
||||
.name = RILMODEM,
|
||||
.probe = ril_ussd_probe,
|
||||
.remove = ril_ussd_remove,
|
||||
.request = ril_ussd_request,
|
||||
.cancel = ril_ussd_cancel
|
||||
};
|
||||
|
||||
void ril_ussd_init(void)
|
||||
@@ -253,4 +259,3 @@ void ril_ussd_exit(void)
|
||||
{
|
||||
ofono_ussd_driver_unregister(&driver);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* RIL chat library with GLib integration
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012 Canonical Ltd.
|
||||
* Copyright (C) 2014 Canonical Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,27 +19,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GRIL_RESPONSE_H
|
||||
#define __GRIL_RESPONSE_H
|
||||
#ifndef RILMODEM_VENDOR_H
|
||||
#define RILMODEM_VENDOR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _GRilResponse {
|
||||
GSList *lines;
|
||||
char *final_or_pdu;
|
||||
enum ofono_ril_vendor {
|
||||
OFONO_RIL_VENDOR_AOSP = 0,
|
||||
OFONO_RIL_VENDOR_MTK,
|
||||
OFONO_RIL_VENDOR_INFINEON,
|
||||
OFONO_RIL_VENDOR_QCOM_MSIM,
|
||||
OFONO_RIL_VENDOR_IMC_SOFIA3GR
|
||||
};
|
||||
|
||||
typedef struct _GRilResponse GRilResponse;
|
||||
|
||||
#define G_RIL_RESPONSE_LINE_LENGTH_MAX 2048
|
||||
|
||||
const char *g_ril_final_response(GRilResponse *response);
|
||||
const char *g_ril_response_pdu(GRilResponse *response);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GRIL_RESPONSE_H */
|
||||
#endif /* RILMODEM_VENDOR_H */
|
||||
File diff suppressed because it is too large
Load Diff
66
ofono/drivers/rilmodem/voicecall.h
Normal file
66
ofono/drivers/rilmodem/voicecall.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
struct ril_voicecall_data {
|
||||
GSList *calls;
|
||||
/* Call local hangup indicator, one bit per call (1 << call_id) */
|
||||
unsigned int local_release;
|
||||
unsigned int clcc_source;
|
||||
GRil *ril;
|
||||
unsigned int vendor;
|
||||
unsigned char flags;
|
||||
ofono_voicecall_cb_t cb;
|
||||
void *data;
|
||||
gchar *tone_queue;
|
||||
gboolean tone_pending;
|
||||
};
|
||||
|
||||
int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
void *data);
|
||||
void ril_voicecall_remove(struct ofono_voicecall *vc);
|
||||
void ril_dial(struct ofono_voicecall *vc, const struct ofono_phone_number *ph,
|
||||
enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
|
||||
void *data);
|
||||
void ril_answer(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_hangup_all(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
|
||||
void *data);
|
||||
void ril_hangup_specific(struct ofono_voicecall *vc,
|
||||
int id, ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_create_multiparty(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_private_chat(struct ofono_voicecall *vc, int id,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_swap_without_accept(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_hold_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_release_all_held(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_set_udub(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
void ril_release_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data);
|
||||
|
||||
void ril_call_state_notify(struct ril_msg *message, gpointer user_data);
|
||||
gboolean ril_poll_clcc(gpointer user_data);
|
||||
@@ -574,8 +574,7 @@ static void ste_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);
|
||||
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
|
||||
|
||||
464
ofono/drivers/ubloxmodem/gprs-context.c
Normal file
464
ofono/drivers/ubloxmodem/gprs-context.c
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 EndoCode AG. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
||||
#include "ubloxmodem.h"
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
|
||||
|
||||
struct gprs_context_data {
|
||||
GAtChat *chat;
|
||||
unsigned int active_context;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* CGCONTRDP returns addr + netmask in the same string in the form
|
||||
* of "a.b.c.d.m.m.m.m" for IPv4. IPv6 is not supported so we ignore it.
|
||||
*/
|
||||
static int set_address_and_netmask(struct ofono_gprs_context *gc,
|
||||
const char *addrnetmask)
|
||||
{
|
||||
char *dup = strdup(addrnetmask);
|
||||
char *s = dup;
|
||||
|
||||
const char *addr = s;
|
||||
const char *netmask = NULL;
|
||||
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
/* Count 7 dots for ipv4, less or more means error. */
|
||||
for (i = 0; i < 8; i++, s++) {
|
||||
s = strchr(s, '.');
|
||||
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
if (i == 3) {
|
||||
/* set netmask ptr and break the string */
|
||||
netmask = s + 1;
|
||||
s[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 7) {
|
||||
ofono_gprs_context_set_ipv4_address(gc, addr, 1);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, netmask);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
free(dup);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void set_gprs_context_interface(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct ofono_modem *modem;
|
||||
const char *interface;
|
||||
|
||||
/* read interface name read at detection time */
|
||||
modem = ofono_gprs_context_get_modem(gc);
|
||||
interface = ofono_modem_get_string(modem, "NetworkInterface");
|
||||
ofono_gprs_context_set_interface(gc, interface);
|
||||
}
|
||||
|
||||
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
GAtResultIter iter;
|
||||
|
||||
const char *laddrnetmask = NULL;
|
||||
const char *gw = NULL;
|
||||
const char *dns[3] = { NULL, NULL, NULL };
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
gcd->cb(&error, gcd->cb_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
|
||||
/* skip cid, bearer_id, apn */
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
g_at_result_iter_skip_next(&iter);
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &laddrnetmask))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &gw))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[0]))
|
||||
break;
|
||||
|
||||
if (!g_at_result_iter_next_string(&iter, &dns[1]))
|
||||
break;
|
||||
}
|
||||
|
||||
set_gprs_context_interface(gc);
|
||||
|
||||
if (!laddrnetmask || set_address_and_netmask(gc, laddrnetmask) < 0) {
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw)
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, gw);
|
||||
|
||||
if (dns[0])
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static int ublox_send_cgcontrdp(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
/* read ip configuration info */
|
||||
snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%u", gcd->active_context);
|
||||
return g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
|
||||
cgcontrdp_cb, gc, NULL);
|
||||
}
|
||||
|
||||
static void ublox_read_settings(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
if (ublox_send_cgcontrdp(gc) < 0)
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void ublox_gprs_read_settings(struct ofono_gprs_context *gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("cid %u", cid);
|
||||
|
||||
gcd->active_context = cid;
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
ublox_read_settings(gc);
|
||||
}
|
||||
|
||||
static void cgact_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
gcd->active_context = 0;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
gcd->cb(&error, gcd->cb_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ublox_read_settings(gc);
|
||||
}
|
||||
|
||||
static void cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
struct ofono_error error;
|
||||
|
||||
gcd->active_context = 0;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
gcd->cb(&error, gcd->cb_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CGACT=1,%u", gcd->active_context);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
cgact_enable_cb, gc, NULL))
|
||||
return;
|
||||
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
#define UBLOX_MAX_USER_LEN 50
|
||||
#define UBLOX_MAX_PASS_LEN 50
|
||||
|
||||
static void ublox_send_uauthreq(struct ofono_gprs_context *gc,
|
||||
const char *username, const char *password,
|
||||
enum ofono_gprs_auth_method auth_method)
|
||||
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[UBLOX_MAX_USER_LEN + UBLOX_MAX_PASS_LEN + 32];
|
||||
unsigned auth;
|
||||
|
||||
switch (auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = 1;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = 2;
|
||||
break;
|
||||
default:
|
||||
ofono_error("Unsupported auth type %u", auth_method);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+UAUTHREQ=%u,%u,\"%s\",\"%s\"",
|
||||
gcd->active_context, auth, username, password);
|
||||
|
||||
/* If this failed, we will see it during context activation. */
|
||||
g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void ublox_send_cgdcont(struct ofono_gprs_context *gc, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ofono_gprs_auth_method auth_method)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[OFONO_GPRS_MAX_APN_LENGTH + 128];
|
||||
size_t u_len, p_len;
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"",
|
||||
gcd->active_context);
|
||||
|
||||
if (apn)
|
||||
snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"", apn);
|
||||
|
||||
if (g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
cgdcont_cb, gc, NULL) == 0)
|
||||
goto error;
|
||||
|
||||
u_len = strlen(username);
|
||||
p_len = strlen(password);
|
||||
|
||||
if (u_len && p_len) {
|
||||
if (u_len >= UBLOX_MAX_USER_LEN ||
|
||||
p_len >= UBLOX_MAX_PASS_LEN) {
|
||||
ofono_error("Toby L2: user or password length too big");
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
ublox_send_uauthreq(gc, username, password, auth_method);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void ublox_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
/* IPv6 support not implemented */
|
||||
if (ctx->proto != OFONO_GPRS_PROTO_IP) {
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("cid %u", ctx->cid);
|
||||
|
||||
gcd->active_context = ctx->cid;
|
||||
|
||||
if (!gcd->active_context) {
|
||||
ofono_error("can't activate more contexts");
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
return;
|
||||
}
|
||||
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
ublox_send_cgdcont(gc, ctx->apn, ctx->username, ctx->password,
|
||||
ctx->auth_method);
|
||||
}
|
||||
|
||||
static void cgact_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("ok %d", ok);
|
||||
|
||||
if (!ok) {
|
||||
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
|
||||
return;
|
||||
}
|
||||
|
||||
gcd->active_context = 0;
|
||||
|
||||
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
|
||||
}
|
||||
|
||||
static void ublox_gprs_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
unsigned int cid,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
char buf[64];
|
||||
|
||||
DBG("cid %u", cid);
|
||||
|
||||
gcd->cb = cb;
|
||||
gcd->cb_data = data;
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+CGACT=0,%u", gcd->active_context);
|
||||
g_at_chat_send(gcd->chat, buf, none_prefix,
|
||||
cgact_disable_cb, gc, NULL);
|
||||
}
|
||||
|
||||
static void cgev_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_gprs_context *gc = user_data;
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
GAtResultIter iter;
|
||||
const char *event;
|
||||
gint cid;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CGEV:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_unquoted_string(&iter, &event))
|
||||
return;
|
||||
|
||||
if (g_str_has_prefix(event, "NW PDN DEACT"))
|
||||
sscanf(event, "%*s %*s %*s %u", &cid);
|
||||
else if (g_str_has_prefix(event, "NW DEACT"))
|
||||
sscanf(event, "%*s %*s %u", &cid);
|
||||
else
|
||||
return;
|
||||
|
||||
DBG("cid %d", cid);
|
||||
|
||||
if ((unsigned int) cid != gcd->active_context)
|
||||
return;
|
||||
|
||||
ofono_gprs_context_deactivated(gc, gcd->active_context);
|
||||
gcd->active_context = 0;
|
||||
}
|
||||
|
||||
static int ublox_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
GAtChat *chat = data;
|
||||
struct gprs_context_data *gcd;
|
||||
|
||||
DBG("");
|
||||
|
||||
gcd = g_try_new0(struct gprs_context_data, 1);
|
||||
if (gcd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
gcd->chat = g_at_chat_clone(chat);
|
||||
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
|
||||
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ublox_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
g_at_chat_unref(gcd->chat);
|
||||
|
||||
memset(gcd, 0, sizeof(*gcd));
|
||||
}
|
||||
|
||||
static struct ofono_gprs_context_driver driver = {
|
||||
.name = "ubloxmodem",
|
||||
.probe = ublox_gprs_context_probe,
|
||||
.remove = ublox_gprs_context_remove,
|
||||
.activate_primary = ublox_gprs_activate_primary,
|
||||
.deactivate_primary = ublox_gprs_deactivate_primary,
|
||||
.read_settings = ublox_gprs_read_settings,
|
||||
};
|
||||
|
||||
void ublox_gprs_context_init(void)
|
||||
{
|
||||
ofono_gprs_context_driver_register(&driver);
|
||||
}
|
||||
|
||||
void ublox_gprs_context_exit(void)
|
||||
{
|
||||
ofono_gprs_context_driver_unregister(&driver);
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* RIL library with GLib integration
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2012-2013 Canonical Ltd.
|
||||
* Copyright (C) 2016 Endocode AG. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,38 +19,31 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GRILREPLY_H
|
||||
#define __GRILREPLY_H
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <gatchat.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/types.h>
|
||||
|
||||
#include "gril.h"
|
||||
#include "ubloxmodem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
static int ubloxmodem_init(void)
|
||||
{
|
||||
ublox_gprs_context_init();
|
||||
|
||||
struct reply_setup_data_call {
|
||||
guint version;
|
||||
guint status;
|
||||
gint cid;
|
||||
guint retry_time;
|
||||
guint active;
|
||||
guint protocol;
|
||||
gchar *ifname;
|
||||
gchar **dns_addresses;
|
||||
gchar **gateways;
|
||||
gchar **ip_addrs;
|
||||
};
|
||||
|
||||
void g_ril_reply_free_setup_data_call(struct reply_setup_data_call *reply);
|
||||
|
||||
struct reply_setup_data_call *g_ril_reply_parse_data_call(GRil *gril,
|
||||
struct ril_msg *message,
|
||||
struct ofono_error *error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GRILREPLY_H */
|
||||
static void ubloxmodem_exit(void)
|
||||
{
|
||||
ublox_gprs_context_exit();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(ubloxmodem, "U-Blox Toby L2 high speed modem driver",
|
||||
VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
ubloxmodem_init, ubloxmodem_exit)
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2016 Endocode AG. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -19,14 +19,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RILDEV_H
|
||||
#define __RILDEV_H
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
|
||||
#define RILD_CMD_SOCKET "/dev/socket/rild"
|
||||
#define RILD_SOCKET_DIR "/dev/socket"
|
||||
#define RILD_SOCKET_FILE "rild"
|
||||
|
||||
|
||||
void ril_modem_remove(struct ofono_modem *modem);
|
||||
|
||||
#endif /* __RILDEV_H */
|
||||
extern void ublox_gprs_context_init(void);
|
||||
extern void ublox_gprs_context_exit(void);
|
||||
@@ -305,8 +305,9 @@ static void at_command_destroy(struct at_command *cmd)
|
||||
g_free(cmd);
|
||||
}
|
||||
|
||||
static void free_terminator(struct terminator_info *info)
|
||||
static void free_terminator(gpointer pointer)
|
||||
{
|
||||
struct terminator_info *info = pointer;
|
||||
g_free(info->terminator);
|
||||
info->terminator = NULL;
|
||||
g_free(info);
|
||||
@@ -325,8 +326,7 @@ static void chat_cleanup(struct at_chat *chat)
|
||||
chat->command_queue = NULL;
|
||||
|
||||
/* Cleanup any response lines we have pending */
|
||||
g_slist_foreach(chat->response_lines, (GFunc)g_free, NULL);
|
||||
g_slist_free(chat->response_lines);
|
||||
g_slist_free_full(chat->response_lines, g_free);
|
||||
chat->response_lines = NULL;
|
||||
|
||||
/* Cleanup registered notifications */
|
||||
@@ -357,9 +357,7 @@ static void chat_cleanup(struct at_chat *chat)
|
||||
chat->syntax = NULL;
|
||||
|
||||
if (chat->terminator_list) {
|
||||
g_slist_foreach(chat->terminator_list,
|
||||
(GFunc)free_terminator, NULL);
|
||||
g_slist_free(chat->terminator_list);
|
||||
g_slist_free_full(chat->terminator_list, free_terminator);
|
||||
chat->terminator_list = NULL;
|
||||
}
|
||||
}
|
||||
@@ -461,8 +459,7 @@ static void at_chat_finish_command(struct at_chat *p, gboolean ok, char *final)
|
||||
cmd->callback(ok, &result, cmd->user_data);
|
||||
}
|
||||
|
||||
g_slist_foreach(response_lines, (GFunc)g_free, NULL);
|
||||
g_slist_free(response_lines);
|
||||
g_slist_free_full(response_lines, g_free);
|
||||
|
||||
g_free(final);
|
||||
at_command_destroy(cmd);
|
||||
|
||||
@@ -598,6 +598,13 @@ void g_at_mux_unref(GAtMux *mux)
|
||||
}
|
||||
}
|
||||
|
||||
static void read_watcher_destroy_notify(gpointer user_data)
|
||||
{
|
||||
GAtMux *mux = user_data;
|
||||
|
||||
mux->read_watch = 0;
|
||||
}
|
||||
|
||||
gboolean g_at_mux_start(GAtMux *mux)
|
||||
{
|
||||
if (mux->channel == NULL)
|
||||
@@ -611,7 +618,8 @@ gboolean g_at_mux_start(GAtMux *mux)
|
||||
|
||||
mux->read_watch = g_io_add_watch_full(mux->channel, G_PRIORITY_DEFAULT,
|
||||
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
|
||||
received_data, mux, NULL);
|
||||
received_data, mux,
|
||||
read_watcher_destroy_notify);
|
||||
|
||||
mux->shutdown = FALSE;
|
||||
|
||||
|
||||
@@ -1073,6 +1073,9 @@ static gboolean signal_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
|
||||
case SIGTERM:
|
||||
server_cleanup();
|
||||
break;
|
||||
case SIGUSR1:
|
||||
g_at_ppp_shutdown(ppp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1089,6 +1092,7 @@ static int create_signal_io(void)
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigaddset(&mask, SIGUSR1);
|
||||
|
||||
if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
|
||||
g_error("Can't set signal mask");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user