mirror of
https://github.com/sailfishos/ofono
synced 2025-11-29 06:01:05 +08:00
Compare commits
148 Commits
mer/1.16+g
...
mer/1.17+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12ffd8acf9 | ||
|
|
df9b35b440 | ||
|
|
76e991d3da | ||
|
|
90803904be | ||
|
|
84e547c2ed | ||
|
|
652798d592 | ||
|
|
979a3bcef3 | ||
|
|
69178c8ecb | ||
|
|
1ac1c9268d | ||
|
|
5483a8ecc0 | ||
|
|
95dacebb0c | ||
|
|
b92b1ce13f | ||
|
|
70ab2175a0 | ||
|
|
9810a258a1 | ||
|
|
760c17052f | ||
|
|
e77b62a91e | ||
|
|
7103c81a77 | ||
|
|
2bc610353d | ||
|
|
dd04ac248d | ||
|
|
c5b3357000 | ||
|
|
ddbdf9f649 | ||
|
|
7b5be51527 | ||
|
|
5aef6a8356 | ||
|
|
b99cd4f8ca | ||
|
|
47ee85e955 | ||
|
|
b500f4fa65 | ||
|
|
c2c048dc05 | ||
|
|
df923b481f | ||
|
|
ed0c1f94f6 | ||
|
|
6d2852cdaf | ||
|
|
72a1ecf5d0 | ||
|
|
2fa10fb265 | ||
|
|
f907c3a85d | ||
|
|
4a7b325191 | ||
|
|
a8103a39fa | ||
|
|
4076502017 | ||
|
|
7ed41beadd | ||
|
|
e45389cf84 | ||
|
|
4bae61c83e | ||
|
|
11d6e76f0a | ||
|
|
4cfa5cdf36 | ||
|
|
135923532c | ||
|
|
d112c042e3 | ||
|
|
b9407ff65f | ||
|
|
5a92625c9f | ||
|
|
c684033671 | ||
|
|
59cb9c39b9 | ||
|
|
0831fd803a | ||
|
|
1b6c20759c | ||
|
|
3681eb63b1 | ||
|
|
5303f766a9 | ||
|
|
2f68eeea6c | ||
|
|
7a7744781a | ||
|
|
fc1491c634 | ||
|
|
c631a48c41 | ||
|
|
21e90e5abd | ||
|
|
bfcf8b726b | ||
|
|
3b69c9843b | ||
|
|
f24252e2c6 | ||
|
|
4be4cb4f57 | ||
|
|
9d4f682b14 | ||
|
|
bd736f7aa6 | ||
|
|
ff328c2a73 | ||
|
|
10e908fa96 | ||
|
|
4aa59c7274 | ||
|
|
d61be44bb4 | ||
|
|
0ed1ef1e4c | ||
|
|
2fa193ad5b | ||
|
|
e686240eeb | ||
|
|
18bc7a3ad8 | ||
|
|
6624066917 | ||
|
|
6015490d41 | ||
|
|
a135d0ea52 | ||
|
|
f86159c180 | ||
|
|
de2b622f3b | ||
|
|
077f3f2e1e | ||
|
|
acbd40f9ad | ||
|
|
8929d131a3 | ||
|
|
51fc828c5e | ||
|
|
ac14de37ca | ||
|
|
665c053803 | ||
|
|
4e9cbcdb89 | ||
|
|
9ec8d03c7c | ||
|
|
3e6bbc676f | ||
|
|
8be0245664 | ||
|
|
ca105f7040 | ||
|
|
dbb3ec13e5 | ||
|
|
1b3302322a | ||
|
|
cd76f913f0 | ||
|
|
8dc220bc11 | ||
|
|
b04fabcda3 | ||
|
|
71df8bb15e | ||
|
|
35ebbf4c97 | ||
|
|
a2acb227fd | ||
|
|
def77f7653 | ||
|
|
c3af639874 | ||
|
|
b2b67fa74e | ||
|
|
96754c0dfc | ||
|
|
f2c474c55a | ||
|
|
58076d9a00 | ||
|
|
4a937b96aa | ||
|
|
fceb5a41c2 | ||
|
|
48da783732 | ||
|
|
eebe2f3ac2 | ||
|
|
4677729502 | ||
|
|
93ccb84761 | ||
|
|
e70afdd9dc | ||
|
|
1edb6eec9b | ||
|
|
946b568f43 | ||
|
|
f3f3dabfac | ||
|
|
4c0f783f5c | ||
|
|
444611c086 | ||
|
|
f8d9485dc2 | ||
|
|
23c45abd57 | ||
|
|
a371f46735 | ||
|
|
ce0529fcf6 | ||
|
|
fc3f937a67 | ||
|
|
7d4a19b114 | ||
|
|
4242f6ee72 | ||
|
|
b31a3c2390 | ||
|
|
8d47f97106 | ||
|
|
fdba39b8ed | ||
|
|
288364295c | ||
|
|
bce5d9579c | ||
|
|
1c2987670d | ||
|
|
a5b040b781 | ||
|
|
97abe1751d | ||
|
|
2f75b13ecd | ||
|
|
73e517bcca | ||
|
|
dae225a0d6 | ||
|
|
97ac3f7c76 | ||
|
|
26a00f2f31 | ||
|
|
cede3700f7 | ||
|
|
318d313fc9 | ||
|
|
8e6ebab83b | ||
|
|
d8edd49535 | ||
|
|
8660527b11 | ||
|
|
d6bc91ebfc | ||
|
|
3d592d7d46 | ||
|
|
e2398b4dfa | ||
|
|
42deee76a1 | ||
|
|
2af3c733b7 | ||
|
|
604fa223f4 | ||
|
|
04218d3a86 | ||
|
|
41fadd3787 | ||
|
|
d539ed19f3 | ||
|
|
25f926c733 | ||
|
|
151b837428 |
@@ -99,3 +99,8 @@ Jussi Pakkanen <jussi.pakkanen@canonical.com>
|
||||
Sergio Checa Blanco <sergio.checa@bmw-carit.de>
|
||||
Philip Paeps <philip@paeps.cx>
|
||||
Kuba Pawlak <kubax.t.pawlak@intel.com>
|
||||
Tommi Kenakkala <tommi.kenakkala@tieto.com>
|
||||
Alex J Lennon <ajlennon@dynamicdevices.co.uk>
|
||||
Sergey Alirzaev <zl29ah@gmail.com>
|
||||
Marko Sulejic <marko.sulejic@hale.at>
|
||||
Johannes 'josch' Schauer <josch@mister-muffin.de>
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
ver 1.17:
|
||||
Fix issue with alphanumeric TP-OA handling.
|
||||
Fix issue with push notification origin port.
|
||||
Fix issue with reading of EF_MWIS records.
|
||||
Fix issue with handling AT+CPINR results.
|
||||
Fix issue with SIM state polling for Sierra modems.
|
||||
Fix issue with HFP handling and AT command prefixes.
|
||||
Fix issue with HFP and extra CCWA event handling.
|
||||
Fix issue with HFP call state and +CHUP errors.
|
||||
|
||||
ver 1.16:
|
||||
Fix issue with PIN retry handling.
|
||||
Fix issue with HFP and multiple calls.
|
||||
|
||||
@@ -126,24 +126,33 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
drivers/ril/ril_devinfo.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_netreg.c \
|
||||
drivers/ril/ril_network.c \
|
||||
drivers/ril/ril_oem_raw.c \
|
||||
drivers/ril/ril_phonebook.c \
|
||||
drivers/ril/ril_plugin.c \
|
||||
drivers/ril/ril_plugin_dbus.c \
|
||||
drivers/ril/ril_radio.c \
|
||||
drivers/ril/ril_radio_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_dbus.c \
|
||||
drivers/ril/ril_sms.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
drivers/ril/ril_ussd.c \
|
||||
drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
else
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
@@ -175,6 +184,11 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/rilmodem/oemraw-messages.c \
|
||||
drivers/rilmodem/call-barring.c \
|
||||
drivers/rilmodem/stk.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += gril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -407,9 +421,6 @@ builtin_sources += plugins/phonesim.c
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += plugins/phonesim.conf
|
||||
if RILMODEM
|
||||
dist_conf_DATA += gril/ril_subscription.conf
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -465,8 +476,8 @@ builtin_sources += plugins/stemgr.c
|
||||
builtin_modules += caif
|
||||
builtin_sources += plugins/caif.c
|
||||
|
||||
builtin_modules += tc65
|
||||
builtin_sources += plugins/tc65.c
|
||||
builtin_modules += cinterion
|
||||
builtin_sources += plugins/cinterion.c
|
||||
|
||||
builtin_modules += nokia
|
||||
builtin_sources += plugins/nokia.c
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.16)
|
||||
AC_INIT(ofono, 1.17)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -173,8 +173,8 @@ AC_ARG_ENABLE(jolla-rilmodem,
|
||||
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
|
||||
|
||||
if (test "${enable_jolla_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio is required))
|
||||
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"
|
||||
@@ -216,7 +216,7 @@ AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE],
|
||||
[location of provision database]), [path_provisiondb=${withval}])
|
||||
|
||||
AC_ARG_ENABLE(provision, AC_HELP_STRING([--disable-provision],
|
||||
[disable provisioning suport]),
|
||||
[disable provisioning support]),
|
||||
[enable_provision=${enableval}])
|
||||
if (test "${enable_provision}" != "no"); then
|
||||
if (test -n "${path_provisiondb}"); then
|
||||
|
||||
@@ -306,6 +306,13 @@ Example:
|
||||
2)
|
||||
0x1 << y // Wrong
|
||||
|
||||
M17: Avoid forward-declaration of static functions
|
||||
==================================================
|
||||
|
||||
Functions that are static should not be forward-declared. The only exception
|
||||
to this rule is if a circular dependency condition exists, and the forward
|
||||
declaration cannot be avoided.
|
||||
|
||||
O1: Shorten the name
|
||||
====================
|
||||
Better to use abbreviation, rather than full name, to name a variable,
|
||||
|
||||
@@ -60,6 +60,16 @@ Methods dict GetProperties()
|
||||
[service].Error.NotFound
|
||||
[service].Error.Failed
|
||||
|
||||
void ResetContexts()
|
||||
|
||||
Removes all contexts and re-provisions from the APN
|
||||
database. Contexts must all be deactivated for this
|
||||
method to work, and the atom must not be powered.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.NotAllowed
|
||||
|
||||
Signals PropertyChanged(string property, variant value)
|
||||
|
||||
This signal indicates a changed value of the given
|
||||
|
||||
@@ -838,6 +838,39 @@ static void telit_ciev_notify(GAtResult *result, gpointer user_data)
|
||||
ofono_netreg_strength_notify(netreg, strength);
|
||||
}
|
||||
|
||||
static void cinterion_ciev_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
struct netreg_data *nd = ofono_netreg_get_data(netreg);
|
||||
const char *signal_identifier = "rssi";
|
||||
const char *ind_str;
|
||||
int strength;
|
||||
GAtResultIter iter;
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CIEV:"))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_unquoted_string(&iter, &ind_str))
|
||||
return;
|
||||
|
||||
if (!g_str_equal(signal_identifier, ind_str))
|
||||
return;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &strength))
|
||||
return;
|
||||
|
||||
DBG("rssi %d", strength);
|
||||
|
||||
if (strength == nd->signal_invalid)
|
||||
strength = -1;
|
||||
else
|
||||
strength = (strength * 100) / (nd->signal_max - nd->signal_min);
|
||||
|
||||
ofono_netreg_strength_notify(netreg, strength);
|
||||
}
|
||||
|
||||
static void ctzv_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_netreg *netreg = user_data;
|
||||
@@ -1915,6 +1948,27 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
g_at_chat_send(nd->chat, "AT*TLTS=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_CINTERION:
|
||||
/*
|
||||
* We can't set rssi bounds from Cinterion responses
|
||||
* so set them up to specified values here
|
||||
*
|
||||
* Cinterion rssi signal strength specified as:
|
||||
* 0 <= -112dBm
|
||||
* 1 - 4 signal strengh in 15 dB steps
|
||||
* 5 >= -51 dBm
|
||||
* 99 not known or undetectable
|
||||
*/
|
||||
nd->signal_min = 0;
|
||||
nd->signal_max = 5;
|
||||
nd->signal_invalid = 99;
|
||||
|
||||
/* Register for specific signal strength reports */
|
||||
g_at_chat_send(nd->chat, "AT^SIND=\"rssi\",1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
g_at_chat_register(nd->chat, "+CIEV:",
|
||||
cinterion_ciev_notify, FALSE, netreg, NULL);
|
||||
break;
|
||||
case OFONO_VENDOR_NOKIA:
|
||||
case OFONO_VENDOR_SAMSUNG:
|
||||
/* Signal strength reporting via CIND is not supported */
|
||||
|
||||
@@ -827,7 +827,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if (!strcmp(name, at_sim_name[i].name)) {
|
||||
retries[i] = val;
|
||||
retries[at_sim_name[i].type] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1350,6 +1350,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
||||
case OFONO_VENDOR_ALCATEL:
|
||||
case OFONO_VENDOR_HUAWEI:
|
||||
case OFONO_VENDOR_SIMCOM:
|
||||
case OFONO_VENDOR_SIERRA:
|
||||
/*
|
||||
* On ZTE modems, after pin is entered, SIM state is checked
|
||||
* by polling CPIN as their modem doesn't provide unsolicited
|
||||
|
||||
@@ -45,4 +45,5 @@ enum ofono_vendor {
|
||||
OFONO_VENDOR_ALCATEL,
|
||||
OFONO_VENDOR_QUECTEL,
|
||||
OFONO_VENDOR_UBLOX,
|
||||
OFONO_VENDOR_CINTERION,
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
static const char *binp_prefix[] = { "+BINP:", NULL };
|
||||
static const char *bvra_prefix[] = { "+BVRA:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct hf_data {
|
||||
GAtChat *chat;
|
||||
@@ -197,7 +198,7 @@ static void hfp_cnum_query(struct ofono_handsfree *hf,
|
||||
struct hf_data *hd = ofono_handsfree_get_data(hf);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
if (g_at_chat_send(hd->chat, "AT+CNUM", NULL,
|
||||
if (g_at_chat_send(hd->chat, "AT+CNUM", none_prefix,
|
||||
cnum_query_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
@@ -382,8 +383,8 @@ static void hfp_disable_nrec(struct ofono_handsfree *hf,
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
const char *buf = "AT+NREC=0";
|
||||
|
||||
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
|
||||
cbd, g_free) > 0)
|
||||
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||
hf_generic_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
@@ -401,8 +402,8 @@ static void hfp_hf_indicator(struct ofono_handsfree *hf,
|
||||
|
||||
snprintf(buf, sizeof(buf), "AT+BIEV=%u,%u", indicator, value);
|
||||
|
||||
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
|
||||
cbd, g_free) > 0)
|
||||
if (g_at_chat_send(hd->chat, buf, none_prefix,
|
||||
hf_generic_set_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
static const char *cops_prefix[] = { "+COPS:", NULL };
|
||||
static const char *cind_prefix[] = { "+CIND:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct netreg_data {
|
||||
GAtChat *chat;
|
||||
@@ -263,7 +264,7 @@ static void hfp_current_operator(struct ofono_netreg *netreg,
|
||||
|
||||
cbd->user = netreg;
|
||||
|
||||
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", NULL,
|
||||
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
|
||||
NULL, cbd, NULL);
|
||||
|
||||
if (ok)
|
||||
|
||||
@@ -113,7 +113,8 @@ static void slc_established(struct slc_establish_data *sed)
|
||||
{
|
||||
struct hfp_slc_info *info = sed->info;
|
||||
|
||||
g_at_chat_send(info->chat, "AT+CMEE=1", NULL, NULL, NULL, NULL);
|
||||
g_at_chat_send(info->chat, "AT+CMEE=1", none_prefix,
|
||||
NULL, NULL, NULL);
|
||||
sed->connect_cb(sed->userdata);
|
||||
}
|
||||
|
||||
@@ -434,8 +435,8 @@ static void brsf_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
sprintf(str, "AT+BAC=%d", HFP_CODEC_CVSD);
|
||||
|
||||
slc_establish_data_ref(sed);
|
||||
g_at_chat_send(info->chat, str, NULL, bac_cb, sed,
|
||||
slc_establish_data_unref);
|
||||
g_at_chat_send(info->chat, str, none_prefix, bac_cb,
|
||||
sed, slc_establish_data_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -333,6 +333,10 @@ static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok && vd->calls)
|
||||
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
|
||||
clcc_poll_cb, req->vc, NULL);
|
||||
|
||||
req->cb(&error, req->data);
|
||||
}
|
||||
|
||||
@@ -711,6 +715,16 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
|
||||
at_util_call_compare_by_status))
|
||||
return;
|
||||
|
||||
/* some phones may send extra CCWA after active call is ended
|
||||
* this would trigger creation of second call in state 'WAITING'
|
||||
* as our previous WAITING call has been promoted to INCOMING
|
||||
*/
|
||||
if (g_slist_find_custom(vd->calls,
|
||||
GINT_TO_POINTER(CALL_STATUS_INCOMING),
|
||||
at_util_call_compare_by_status))
|
||||
return;
|
||||
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CCWA:"))
|
||||
@@ -1134,6 +1148,10 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
struct ofono_voicecall *vc = user_data;
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
unsigned int mpty_ids;
|
||||
GSList *n;
|
||||
struct ofono_call *nc;
|
||||
unsigned int num_active = 0;
|
||||
unsigned int num_held = 0;
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
@@ -1142,6 +1160,22 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
|
||||
g_slist_foreach(vd->calls, voicecall_notify, vc);
|
||||
ofono_voicecall_mpty_hint(vc, mpty_ids);
|
||||
|
||||
n = vd->calls;
|
||||
|
||||
while (n) {
|
||||
nc = n->data;
|
||||
|
||||
if (nc->status == CALL_STATUS_ACTIVE)
|
||||
num_active++;
|
||||
else if (nc->status == CALL_STATUS_HELD)
|
||||
num_held++;
|
||||
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
|
||||
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc, vc);
|
||||
}
|
||||
|
||||
static void hfp_voicecall_initialized(gboolean ok, GAtResult *result,
|
||||
@@ -1183,8 +1217,8 @@ static int hfp_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
|
||||
ofono_voicecall_set_data(vc, vd);
|
||||
|
||||
g_at_chat_send(vd->chat, "AT+CLIP=1", NULL, NULL, NULL, NULL);
|
||||
g_at_chat_send(vd->chat, "AT+CCWA=1", NULL,
|
||||
g_at_chat_send(vd->chat, "AT+CLIP=1", none_prefix, NULL, NULL, NULL);
|
||||
g_at_chat_send(vd->chat, "AT+CCWA=1", none_prefix,
|
||||
hfp_voicecall_initialized, vc, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2015 Jolla Ltd.
|
||||
* Copyright (C) 2013-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -54,67 +54,67 @@
|
||||
|
||||
/* call states */
|
||||
enum ril_call_state {
|
||||
RIL_CALL_ACTIVE,
|
||||
RIL_CALL_HOLDING,
|
||||
RIL_CALL_DIALING,
|
||||
RIL_CALL_ALERTING,
|
||||
RIL_CALL_INCOMING,
|
||||
RIL_CALL_WAITING
|
||||
RIL_CALL_ACTIVE = 0,
|
||||
RIL_CALL_HOLDING = 1,
|
||||
RIL_CALL_DIALING = 2,
|
||||
RIL_CALL_ALERTING = 3,
|
||||
RIL_CALL_INCOMING = 4,
|
||||
RIL_CALL_WAITING = 5
|
||||
};
|
||||
|
||||
/* Radio state */
|
||||
enum ril_radio_state {
|
||||
RADIO_STATE_OFF,
|
||||
RADIO_STATE_UNAVAILABLE,
|
||||
RADIO_STATE_SIM_NOT_READY,
|
||||
RADIO_STATE_SIM_LOCKED_OR_ABSENT,
|
||||
RADIO_STATE_SIM_READY,
|
||||
RADIO_STATE_RUIM_NOT_READY,
|
||||
RADIO_STATE_RUIM_READY,
|
||||
RADIO_STATE_RUIM_LOCKED_OR_ABSENT,
|
||||
RADIO_STATE_NV_NOT_READY,
|
||||
RADIO_STATE_NV_READY,
|
||||
RADIO_STATE_ON
|
||||
RADIO_STATE_OFF = 0,
|
||||
RADIO_STATE_UNAVAILABLE = 1,
|
||||
RADIO_STATE_SIM_NOT_READY = 2,
|
||||
RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3,
|
||||
RADIO_STATE_SIM_READY = 4,
|
||||
RADIO_STATE_RUIM_NOT_READY = 5,
|
||||
RADIO_STATE_RUIM_READY = 6,
|
||||
RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7,
|
||||
RADIO_STATE_NV_NOT_READY = 8,
|
||||
RADIO_STATE_NV_READY = 9,
|
||||
RADIO_STATE_ON = 10
|
||||
};
|
||||
|
||||
/* Preferred network types */
|
||||
enum ril_pref_net_type {
|
||||
PREF_NET_TYPE_GSM_WCDMA,
|
||||
PREF_NET_TYPE_GSM_ONLY,
|
||||
PREF_NET_TYPE_WCDMA,
|
||||
PREF_NET_TYPE_GSM_WCDMA_AUTO,
|
||||
PREF_NET_TYPE_CDMA_EVDO_AUTO,
|
||||
PREF_NET_TYPE_CDMA_ONLY,
|
||||
PREF_NET_TYPE_EVDO_ONLY,
|
||||
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO,
|
||||
PREF_NET_TYPE_LTE_CDMA_EVDO,
|
||||
PREF_NET_TYPE_LTE_GSM_WCDMA,
|
||||
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA,
|
||||
PREF_NET_TYPE_LTE_ONLY,
|
||||
PREF_NET_TYPE_LTE_WCDMA
|
||||
PREF_NET_TYPE_GSM_WCDMA = 0,
|
||||
PREF_NET_TYPE_GSM_ONLY = 1,
|
||||
PREF_NET_TYPE_WCDMA = 2,
|
||||
PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,
|
||||
PREF_NET_TYPE_CDMA_EVDO_AUTO = 4,
|
||||
PREF_NET_TYPE_CDMA_ONLY = 5,
|
||||
PREF_NET_TYPE_EVDO_ONLY = 6,
|
||||
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7,
|
||||
PREF_NET_TYPE_LTE_CDMA_EVDO = 8,
|
||||
PREF_NET_TYPE_LTE_GSM_WCDMA = 9,
|
||||
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10,
|
||||
PREF_NET_TYPE_LTE_ONLY = 11,
|
||||
PREF_NET_TYPE_LTE_WCDMA = 12
|
||||
};
|
||||
|
||||
/* Radio technologies */
|
||||
enum ril_radio_tech {
|
||||
RADIO_TECH_UNKNOWN,
|
||||
RADIO_TECH_GPRS,
|
||||
RADIO_TECH_EDGE,
|
||||
RADIO_TECH_UMTS,
|
||||
RADIO_TECH_IS95A,
|
||||
RADIO_TECH_IS95B,
|
||||
RADIO_TECH_1xRTT ,
|
||||
RADIO_TECH_EVDO_0,
|
||||
RADIO_TECH_EVDO_A,
|
||||
RADIO_TECH_HSDPA,
|
||||
RADIO_TECH_HSUPA ,
|
||||
RADIO_TECH_HSPA,
|
||||
RADIO_TECH_EVDO_B,
|
||||
RADIO_TECH_EHRPD,
|
||||
RADIO_TECH_LTE,
|
||||
RADIO_TECH_HSPAP,
|
||||
RADIO_TECH_GSM,
|
||||
RADIO_TECH_TD_SCDMA,
|
||||
RADIO_TECH_DC_HSDPA
|
||||
RADIO_TECH_UNKNOWN = 0,
|
||||
RADIO_TECH_GPRS = 1,
|
||||
RADIO_TECH_EDGE = 2,
|
||||
RADIO_TECH_UMTS = 3,
|
||||
RADIO_TECH_IS95A = 4,
|
||||
RADIO_TECH_IS95B = 5,
|
||||
RADIO_TECH_1xRTT = 6,
|
||||
RADIO_TECH_EVDO_0 = 7,
|
||||
RADIO_TECH_EVDO_A = 8,
|
||||
RADIO_TECH_HSDPA = 9,
|
||||
RADIO_TECH_HSUPA = 10,
|
||||
RADIO_TECH_HSPA = 11,
|
||||
RADIO_TECH_EVDO_B = 12,
|
||||
RADIO_TECH_EHRPD = 13,
|
||||
RADIO_TECH_LTE = 14,
|
||||
RADIO_TECH_HSPAP = 15,
|
||||
RADIO_TECH_GSM = 16,
|
||||
RADIO_TECH_TD_SCDMA = 17,
|
||||
RADIO_TECH_IWLAN = 18
|
||||
};
|
||||
|
||||
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
|
||||
@@ -142,7 +142,23 @@ enum ril_radio_tech {
|
||||
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
|
||||
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
|
||||
|
||||
/* see RIL_REQUEST_DEACTIVATE_DATA_CALL parameter*/
|
||||
/* Not defined in ril.h but valid 3GPP specific cause values
|
||||
* for call control. See 3GPP TS 24.008 Annex H. */
|
||||
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
|
||||
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
|
||||
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
|
||||
#define CALL_FAIL_NO_USER_RESPONDING 18
|
||||
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
|
||||
#define CALL_FAIL_CALL_REJECTED 21
|
||||
#define CALL_FAIL_NUMBER_CHANGED 22
|
||||
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
|
||||
#define CALL_FAIL_PRE_EMPTION 25
|
||||
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
|
||||
#define CALL_FAIL_INCOMPLETE_NUMBER 28
|
||||
#define CALL_FAIL_FACILITY_REJECTED 29
|
||||
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
|
||||
|
||||
/* see RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
|
||||
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
|
||||
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
|
||||
|
||||
@@ -160,62 +176,75 @@ enum ril_radio_tech {
|
||||
#define RIL_AUTH_CHAP 2
|
||||
#define RIL_AUTH_BOTH 3
|
||||
|
||||
#define RIL_CARD_MAX_APPS 8
|
||||
|
||||
/* SIM card states */
|
||||
#define RIL_CARDSTATE_ABSENT 0
|
||||
#define RIL_CARDSTATE_PRESENT 1
|
||||
#define RIL_CARDSTATE_ERROR 2
|
||||
enum ril_card_state {
|
||||
RIL_CARDSTATE_UNKNOWN = -1,
|
||||
RIL_CARDSTATE_ABSENT = 0,
|
||||
RIL_CARDSTATE_PRESENT = 1,
|
||||
RIL_CARDSTATE_ERROR = 2
|
||||
};
|
||||
|
||||
/* SIM personalization substates */
|
||||
#define RIL_PERSOSUBSTATE_UNKNOWN 0
|
||||
#define RIL_PERSOSUBSTATE_IN_PROGRESS 1
|
||||
#define RIL_PERSOSUBSTATE_READY 2
|
||||
#define RIL_PERSOSUBSTATE_SIM_NETWORK 3
|
||||
#define RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET 4
|
||||
#define RIL_PERSOSUBSTATE_SIM_CORPORATE 5
|
||||
#define RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER 6
|
||||
#define RIL_PERSOSUBSTATE_SIM_SIM 7
|
||||
#define RIL_PERSOSUBSTATE_SIM_NETWORK_PUK 8
|
||||
#define RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK 9
|
||||
#define RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK 10
|
||||
#define RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK 11
|
||||
#define RIL_PERSOSUBSTATE_SIM_SIM_PUK 12
|
||||
#define RIL_PERSOSUBSTATE_RUIM_NETWORK1 13
|
||||
#define RIL_PERSOSUBSTATE_RUIM_NETWORK2 14
|
||||
#define RIL_PERSOSUBSTATE_RUIM_HRPD 15
|
||||
#define RIL_PERSOSUBSTATE_RUIM_CORPORATE 16
|
||||
#define RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER 17
|
||||
#define RIL_PERSOSUBSTATE_RUIM_RUIM 18
|
||||
#define RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK 19
|
||||
#define RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK 20
|
||||
#define RIL_PERSOSUBSTATE_RUIM_HRPD_PUK 21
|
||||
#define RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK 22
|
||||
#define RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK 23
|
||||
#define RIL_PERSOSUBSTATE_RUIM_RUIM_PUK 24
|
||||
enum ril_perso_substate {
|
||||
RIL_PERSOSUBSTATE_UNKNOWN = 0,
|
||||
RIL_PERSOSUBSTATE_IN_PROGRESS = 1,
|
||||
RIL_PERSOSUBSTATE_READY = 2,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK = 3,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE = 5,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM = 7,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_PUK = 8,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM_PUK = 12,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1 = 13,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2 = 14,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD = 15,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE = 16,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM = 18,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD_PUK = 21,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM_PUK = 24
|
||||
};
|
||||
|
||||
/* SIM - App states */
|
||||
#define RIL_APPSTATE_ILLEGAL -1
|
||||
#define RIL_APPSTATE_UNKNOWN 0
|
||||
#define RIL_APPSTATE_DETECTED 1
|
||||
#define RIL_APPSTATE_PIN 2
|
||||
#define RIL_APPSTATE_PUK 3
|
||||
#define RIL_APPSTATE_SUBSCRIPTION_PERSO 4
|
||||
#define RIL_APPSTATE_READY 5
|
||||
enum ril_app_state {
|
||||
RIL_APPSTATE_ILLEGAL = -1,
|
||||
RIL_APPSTATE_UNKNOWN = 0,
|
||||
RIL_APPSTATE_DETECTED = 1,
|
||||
RIL_APPSTATE_PIN = 2,
|
||||
RIL_APPSTATE_PUK = 3,
|
||||
RIL_APPSTATE_SUBSCRIPTION_PERSO = 4,
|
||||
RIL_APPSTATE_READY = 5
|
||||
};
|
||||
|
||||
/* SIM - PIN states */
|
||||
#define RIL_PINSTATE_UNKNOWN 0
|
||||
#define RIL_PINSTATE_ENABLED_NOT_VERIFIED 1
|
||||
#define RIL_PINSTATE_ENABLED_VERIFIED 2
|
||||
#define RIL_PINSTATE_DISABLED 3
|
||||
#define RIL_PINSTATE_ENABLED_BLOCKED 4
|
||||
#define RIL_PINSTATE_ENABLED_PERM_BLOCKED 5
|
||||
enum ril_pin_state {
|
||||
RIL_PINSTATE_UNKNOWN = 0,
|
||||
RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
|
||||
RIL_PINSTATE_ENABLED_VERIFIED = 2,
|
||||
RIL_PINSTATE_DISABLED = 3,
|
||||
RIL_PINSTATE_ENABLED_BLOCKED = 4,
|
||||
RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
|
||||
};
|
||||
|
||||
/* SIM - App types */
|
||||
#define RIL_APPTYPE_UNKNOWN 0
|
||||
#define RIL_APPTYPE_SIM 1
|
||||
#define RIL_APPTYPE_USIM 2
|
||||
#define RIL_APPTYPE_RUIM 3
|
||||
#define RIL_APPTYPE_CSIM 4
|
||||
#define RIL_APPTYPE_ISIM 5
|
||||
enum ril_app_type {
|
||||
RIL_APPTYPE_UNKNOWN = 0,
|
||||
RIL_APPTYPE_SIM = 1,
|
||||
RIL_APPTYPE_USIM = 2,
|
||||
RIL_APPTYPE_RUIM = 3,
|
||||
RIL_APPTYPE_CSIM = 4,
|
||||
RIL_APPTYPE_ISIM = 5
|
||||
};
|
||||
|
||||
/* RIL Request Messages */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
@@ -339,6 +368,8 @@ enum ril_radio_tech {
|
||||
#define RIL_REQUEST_NV_WRITE_ITEM 119
|
||||
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
|
||||
#define RIL_REQUEST_NV_RESET_CONFIG 121
|
||||
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
|
||||
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
|
||||
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
|
||||
#define RIL_REQUEST_ALLOW_DATA 123
|
||||
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
|
||||
@@ -406,3 +437,11 @@ enum ril_radio_tech {
|
||||
#define RIL_FACILITY_LOCK "1"
|
||||
|
||||
#endif /*__RIL_CONSTANTS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
|
||||
313
ofono/drivers/ril/ril_data.c
Normal file
313
ofono/drivers/ril/ril_data.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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_data.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
typedef GObjectClass RilDataClass;
|
||||
typedef struct ril_data RilData;
|
||||
|
||||
struct ril_data_manager {
|
||||
gint ref_count;
|
||||
struct ril_data *selected;
|
||||
guint pending_id;
|
||||
GSList *data_list;
|
||||
};
|
||||
|
||||
struct ril_data {
|
||||
GObject object;
|
||||
GRilIoQueue *q;
|
||||
const char *log_prefix;
|
||||
char *custom_log_prefix;
|
||||
struct ril_data_manager *dm;
|
||||
gboolean allowed;
|
||||
};
|
||||
|
||||
enum ril_data_signal {
|
||||
SIGNAL_ALLOW_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_ALLOW_CHANGED_NAME "ril-data-allow-changed"
|
||||
|
||||
static guint ril_data_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilData, ril_data, G_TYPE_OBJECT)
|
||||
#define RIL_DATA_TYPE (ril_data_get_type())
|
||||
#define RIL_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, RIL_DATA_TYPE,RilData))
|
||||
|
||||
static void ril_data_manager_check(struct ril_data_manager *self);
|
||||
|
||||
/*==========================================================================*
|
||||
* ril_data
|
||||
*==========================================================================*/
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
|
||||
ril_data_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_ALLOW_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_data_remove_handler(struct ril_data *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, GRilIoChannel *io)
|
||||
{
|
||||
GASSERT(dm);
|
||||
if (G_LIKELY(dm)) {
|
||||
struct ril_data *self = g_object_new(RIL_DATA_TYPE, NULL);
|
||||
self->q = grilio_queue_new(io);
|
||||
self->dm = ril_data_manager_ref(dm);
|
||||
dm->data_list = g_slist_append(dm->data_list, self);
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ril_data *ril_data_ref(struct ril_data *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_DATA(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_data_unref(struct ril_data *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_DATA(self));
|
||||
}
|
||||
}
|
||||
|
||||
G_INLINE_FUNC void ril_data_signal(struct ril_data *self)
|
||||
{
|
||||
g_signal_emit(self, ril_data_signals[SIGNAL_ALLOW_CHANGED], 0);
|
||||
}
|
||||
|
||||
void ril_data_allow(struct ril_data *self, gboolean allow)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_data_manager *dm = self->dm;
|
||||
DBG("%s%s", self->log_prefix, allow ? "yes" : "no");
|
||||
if (allow) {
|
||||
if (!self->allowed) {
|
||||
self->allowed = TRUE;
|
||||
ril_data_manager_check(dm);
|
||||
}
|
||||
} else {
|
||||
if (self->allowed) {
|
||||
self->allowed = FALSE;
|
||||
if (dm->selected == self) {
|
||||
ril_data_manager_check(dm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_data_allowed(struct ril_data *self)
|
||||
{
|
||||
return G_LIKELY(self) && self->allowed && self->dm->selected == self;
|
||||
}
|
||||
|
||||
void ril_data_set_name(struct ril_data *self, const char *name)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_free(self->custom_log_prefix);
|
||||
if (name) {
|
||||
self->custom_log_prefix = g_strconcat(name, " ", NULL);
|
||||
self->log_prefix = self->custom_log_prefix;
|
||||
} else {
|
||||
self->custom_log_prefix = NULL;
|
||||
self->log_prefix = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_init(struct ril_data *self)
|
||||
{
|
||||
self->log_prefix = "";
|
||||
}
|
||||
|
||||
static void ril_data_dispose(GObject *object)
|
||||
{
|
||||
struct ril_data *self = RIL_DATA(object);
|
||||
struct ril_data_manager *dm = self->dm;
|
||||
|
||||
dm->data_list = g_slist_remove(dm->data_list, self);
|
||||
grilio_queue_cancel_all(self->q, FALSE);
|
||||
ril_data_manager_check(dm);
|
||||
G_OBJECT_CLASS(ril_data_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_data_finalize(GObject *object)
|
||||
{
|
||||
struct ril_data *self = RIL_DATA(object);
|
||||
|
||||
g_free(self->custom_log_prefix);
|
||||
grilio_queue_unref(self->q);
|
||||
ril_data_manager_unref(self->dm);
|
||||
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_data_class_init(RilDataClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_data_dispose;
|
||||
object_class->finalize = ril_data_finalize;
|
||||
ril_data_signals[SIGNAL_ALLOW_CHANGED] =
|
||||
g_signal_new(SIGNAL_ALLOW_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ril_data_manager
|
||||
*==========================================================================*/
|
||||
|
||||
struct ril_data_manager *ril_data_manager_new()
|
||||
{
|
||||
struct ril_data_manager *self = g_new0(struct ril_data_manager, 1);
|
||||
self->ref_count = 1;
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *self)
|
||||
{
|
||||
if (self) {
|
||||
GASSERT(self->ref_count > 0);
|
||||
g_atomic_int_inc(&self->ref_count);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void ril_data_manager_unref(struct ril_data_manager *self)
|
||||
{
|
||||
if (self) {
|
||||
GASSERT(self->ref_count > 0);
|
||||
if (g_atomic_int_dec_and_test(&self->ref_count)) {
|
||||
GASSERT(!self->selected);
|
||||
g_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_manager_allow_data_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_data_manager *self = user_data;
|
||||
|
||||
GASSERT(self->selected);
|
||||
GASSERT(self->pending_id);
|
||||
self->pending_id = 0;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBG("%sselected", self->selected->log_prefix);
|
||||
} else {
|
||||
DBG("%srequest failed", self->selected->log_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_data *ril_data_manager_pick(struct ril_data_manager *self)
|
||||
{
|
||||
GSList *list = self->data_list;
|
||||
while (list) {
|
||||
struct ril_data *data = list->data;
|
||||
if (data->allowed) {
|
||||
return data;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_data_allow_req(gboolean allow)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, allow != FALSE);
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_data_manager_check(struct ril_data_manager *self)
|
||||
{
|
||||
struct ril_data *data = ril_data_manager_pick(self);
|
||||
|
||||
if (data) {
|
||||
if (self->selected != data) {
|
||||
GRilIoRequest *req = ril_data_allow_req(TRUE);
|
||||
struct ril_data *prev = self->selected;
|
||||
|
||||
/* Cancel pending request, if any */
|
||||
GASSERT(prev || !self->pending_id);
|
||||
if (prev) {
|
||||
grilio_queue_cancel_request(prev->q,
|
||||
self->pending_id, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Submit the RIL request. Note that with
|
||||
* some older RILs this request will never
|
||||
* get completed (no reply from rild will
|
||||
* ever come).
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
self->pending_id =
|
||||
grilio_queue_send_request_full(data->q, req,
|
||||
RIL_REQUEST_ALLOW_DATA,
|
||||
ril_data_manager_allow_data_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
DBG("%srequested", data->log_prefix);
|
||||
self->selected = data;
|
||||
if (prev) {
|
||||
ril_data_signal(prev);
|
||||
}
|
||||
ril_data_signal(data);
|
||||
}
|
||||
} else {
|
||||
if (self->selected) {
|
||||
struct ril_data *prev = self->selected;
|
||||
if (self->pending_id) {
|
||||
grilio_queue_cancel_request(prev->q,
|
||||
self->pending_id, FALSE);
|
||||
self->pending_id = 0;
|
||||
}
|
||||
self->selected = NULL;
|
||||
ril_data_signal(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
46
ofono/drivers/ril/ril_data.h
Normal file
46
ofono/drivers/ril/ril_data.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_DATA_H
|
||||
#define RIL_DATA_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(void);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, GRilIoChannel *io);
|
||||
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);
|
||||
void ril_data_allow(struct ril_data *data, gboolean allow);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
void ril_data_remove_handler(struct ril_data *data, gulong id);
|
||||
|
||||
#endif /* RIL_DATA_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
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -26,15 +25,18 @@
|
||||
struct ril_devinfo {
|
||||
struct ofono_devinfo *info;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
guint register_id;
|
||||
guint imei_id;
|
||||
char *imei;
|
||||
};
|
||||
|
||||
struct ril_devinfo_req {
|
||||
struct ril_devinfo_cbd {
|
||||
struct ril_devinfo *di;
|
||||
ofono_devinfo_query_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_devinfo_req_free g_free
|
||||
#define ril_devinfo_cbd_free g_free
|
||||
|
||||
static inline struct ril_devinfo *ril_devinfo_get_data(
|
||||
struct ofono_devinfo *info)
|
||||
@@ -42,11 +44,12 @@ static inline struct ril_devinfo *ril_devinfo_get_data(
|
||||
return ofono_devinfo_get_data(info);
|
||||
}
|
||||
|
||||
struct ril_devinfo_req *ril_devinfo_req_new(ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
struct ril_devinfo_cbd *ril_devinfo_cbd_new(struct ril_devinfo *di,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo_req *cbd = g_new0(struct ril_devinfo_req, 1);
|
||||
struct ril_devinfo_cbd *cbd = g_new0(struct ril_devinfo_cbd, 1);
|
||||
|
||||
cbd->di = di;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
@@ -63,10 +66,10 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_devinfo_req *cbd = user_data;
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
gchar *res;
|
||||
char *res;
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
res = grilio_parser_get_utf8(&rilp);
|
||||
@@ -78,37 +81,47 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devinfo_query(struct ofono_devinfo *info, guint cmd,
|
||||
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
/* See comment in ril_devinfo_remove */
|
||||
if (di->q) {
|
||||
grilio_queue_send_request_full(di->q, NULL, cmd,
|
||||
ril_devinfo_query_cb, ril_devinfo_req_free,
|
||||
ril_devinfo_req_new(cb, data));
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_failure(&error), NULL, data);
|
||||
}
|
||||
DBG("");
|
||||
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
|
||||
ril_devinfo_query_cb, ril_devinfo_cbd_free,
|
||||
ril_devinfo_cbd_new(di, cb, data));
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
static gboolean ril_devinfo_query_serial_cb(void *user_data)
|
||||
{
|
||||
DBG("");
|
||||
ril_devinfo_query(info, RIL_REQUEST_BASEBAND_VERSION, cb, data);
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
struct ril_devinfo *di = cbd->di;
|
||||
struct ofono_error error;
|
||||
|
||||
GASSERT(di->imei_id);
|
||||
di->imei_id = 0;
|
||||
|
||||
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
/* TODO: make it support both RIL_REQUEST_GET_IMEI (deprecated) and
|
||||
* RIL_REQUEST_DEVICE_IDENTITY depending on the rild version used */
|
||||
DBG("");
|
||||
ril_devinfo_query(info, RIL_REQUEST_GET_IMEI, cb, data);
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
GASSERT(!di->imei_id);
|
||||
if (di->imei_id) {
|
||||
g_source_remove(di->imei_id);
|
||||
di->imei_id = 0;
|
||||
}
|
||||
|
||||
DBG("%s", di->imei);
|
||||
di->imei_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_devinfo_query_serial_cb,
|
||||
ril_devinfo_cbd_new(di, cb, data),
|
||||
ril_devinfo_cbd_free);
|
||||
}
|
||||
|
||||
static gboolean ril_devinfo_register(gpointer user_data)
|
||||
@@ -116,7 +129,7 @@ static gboolean ril_devinfo_register(gpointer user_data)
|
||||
struct ril_devinfo *di = user_data;
|
||||
|
||||
DBG("");
|
||||
di->timer_id = 0;
|
||||
di->register_id = 0;
|
||||
ofono_devinfo_register(di->info);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
@@ -129,11 +142,13 @@ static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
|
||||
|
||||
DBG("");
|
||||
DBG("%s %s %p", ril_modem_get_path(modem), modem->imei, di);
|
||||
GASSERT(modem->imei);
|
||||
di->q = grilio_queue_new(ril_modem_io(modem));
|
||||
di->info = info;
|
||||
di->imei = g_strdup(modem->imei);
|
||||
|
||||
di->timer_id = g_idle_add(ril_devinfo_register, di);
|
||||
di->register_id = g_idle_add(ril_devinfo_register, di);
|
||||
ofono_devinfo_set_data(info, di);
|
||||
return 0;
|
||||
}
|
||||
@@ -142,15 +157,20 @@ static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG("");
|
||||
DBG("%p", di);
|
||||
ofono_devinfo_set_data(info, NULL);
|
||||
|
||||
if (di->timer_id > 0) {
|
||||
g_source_remove(di->timer_id);
|
||||
if (di->register_id > 0) {
|
||||
g_source_remove(di->register_id);
|
||||
}
|
||||
|
||||
if (di->imei_id > 0) {
|
||||
g_source_remove(di->imei_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(di->q, FALSE);
|
||||
grilio_queue_unref(di->q);
|
||||
g_free(di->imei);
|
||||
g_free(di);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +14,8 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -40,85 +41,96 @@
|
||||
struct ril_gprs {
|
||||
struct ofono_gprs *gprs;
|
||||
struct ril_modem *md;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean ofono_attached;
|
||||
gboolean ofono_registered;
|
||||
gboolean attached;
|
||||
int max_cids;
|
||||
int last_status;
|
||||
int ril_data_tech;
|
||||
gulong event_id;
|
||||
guint poll_id;
|
||||
guint timer_id;
|
||||
enum network_registration_status registration_status;
|
||||
guint register_id;
|
||||
gulong network_event_id;
|
||||
gulong data_event_id;
|
||||
guint set_attached_id;
|
||||
};
|
||||
|
||||
struct ril_gprs_cbd {
|
||||
struct ril_gprs *gd;
|
||||
union _ofono_gprs_cb {
|
||||
ofono_gprs_status_cb_t status;
|
||||
ofono_gprs_cb_t cb;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
ofono_gprs_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_gprs_cbd_free g_free
|
||||
|
||||
static void ril_gprs_poll_data_reg_state_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data);
|
||||
|
||||
static inline struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *b)
|
||||
static struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *ofono)
|
||||
{
|
||||
return ofono_gprs_get_data(b);
|
||||
return ofono ? ofono_gprs_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd, void *cb,
|
||||
void *data)
|
||||
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_cbd *cbd = g_new0(struct ril_gprs_cbd, 1);
|
||||
|
||||
cbd->gd = gd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
int ril_gprs_ril_data_tech(struct ofono_gprs *gprs)
|
||||
static enum network_registration_status ril_gprs_fix_registration_status(
|
||||
struct ril_gprs *gd, enum network_registration_status status)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
return gd ? gd->ril_data_tech : -1;
|
||||
}
|
||||
|
||||
static void ril_gprs_poll_data_reg_state(struct ril_gprs *gd)
|
||||
{
|
||||
if (!gd->poll_id) {
|
||||
DBG("");
|
||||
gd->poll_id = grilio_queue_send_request_full(gd->q, NULL,
|
||||
RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_gprs_poll_data_reg_state_cb, NULL, gd);
|
||||
if (!ril_data_allowed(gd->data)) {
|
||||
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
} else {
|
||||
/* TODO: need a way to make sure that SPDI information has
|
||||
* already been read from the SIM (i.e. sim_spdi_read_cb in
|
||||
* network.c has been called) */
|
||||
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gd->md);
|
||||
return ril_netreg_check_if_really_roaming(netreg, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
const enum network_registration_status status =
|
||||
ril_gprs_fix_registration_status(gd, gd->network->data.status);
|
||||
|
||||
DBG("%s", ril_modem_get_path(gd->md));
|
||||
ril_gprs_poll_data_reg_state(gd);
|
||||
if (gd->registration_status != status) {
|
||||
ofono_info("data reg changed %d -> %d (%s), attached %d",
|
||||
gd->registration_status, status,
|
||||
registration_status_to_string(status),
|
||||
gd->attached);
|
||||
gd->registration_status = status;
|
||||
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_set_attached_callback(gpointer user_data)
|
||||
static void ril_gprs_check_data_allowed(struct ril_gprs *gd)
|
||||
{
|
||||
DBG("%s %d %d", ril_modem_get_path(gd->md), ril_data_allowed(gd->data),
|
||||
gd->attached);
|
||||
if (!ril_data_allowed(gd->data) && gd->attached) {
|
||||
gd->attached = FALSE;
|
||||
if (gd->gprs) {
|
||||
ofono_gprs_detached_notify(gd->gprs);
|
||||
}
|
||||
}
|
||||
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_set_attached_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_gprs_cbd *cbd = user_data;
|
||||
struct ril_gprs *gd = cbd->gd;
|
||||
|
||||
DBG("%s", ril_modem_get_path(cbd->gd->md));
|
||||
cbd->gd->timer_id = 0;
|
||||
cbd->cb.cb(ril_error_ok(&error), cbd->data);
|
||||
ril_gprs_cbd_free(cbd);
|
||||
|
||||
/* Single shot */
|
||||
GASSERT(gd->set_attached_id);
|
||||
gd->set_attached_id = 0;
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -127,209 +139,84 @@ static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
|
||||
DBG("%s attached: %d", ril_modem_get_path(gd->md), 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.
|
||||
*/
|
||||
|
||||
gd->ofono_attached = attached;
|
||||
|
||||
/*
|
||||
* 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_idle_add(ril_gprs_set_attached_callback,
|
||||
ril_gprs_cbd_new(gd, cb, data));
|
||||
}
|
||||
|
||||
static int ril_gprs_parse_data_reg_state(struct ril_gprs *gd,
|
||||
const void *data, guint len)
|
||||
{
|
||||
struct ofono_gprs *gprs = gd->gprs;
|
||||
struct ril_reg_data reg;
|
||||
|
||||
if (!ril_util_parse_reg(data, len, ®)) {
|
||||
ofono_error("Failure parsing data registration response.");
|
||||
gd->ril_data_tech = -1;
|
||||
return NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
if (ril_data_allowed(gd->data) || !attached) {
|
||||
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
gd->attached = attached;
|
||||
gd->set_attached_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_gprs_set_attached_cb,
|
||||
ril_gprs_cbd_new(gd, cb, data),
|
||||
ril_gprs_cbd_free);
|
||||
} else {
|
||||
const int rawstatus = reg.status;
|
||||
|
||||
if (gd->ril_data_tech != reg.ril_tech) {
|
||||
gd->ril_data_tech = reg.ril_tech;
|
||||
DBG("ril data tech %d", reg.ril_tech);
|
||||
}
|
||||
|
||||
if (!gd->ofono_registered) {
|
||||
ofono_gprs_register(gprs);
|
||||
gd->ofono_registered = TRUE;
|
||||
}
|
||||
|
||||
if (reg.max_calls > gd->max_cids) {
|
||||
DBG("Setting max cids to %d", reg.max_calls);
|
||||
gd->max_cids = reg.max_calls;
|
||||
ofono_gprs_set_cid_range(gprs, 1, reg.max_calls);
|
||||
}
|
||||
|
||||
if (reg.status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
reg.status = ril_netreg_check_if_really_roaming(
|
||||
ril_modem_ofono_netreg(gd->md), reg.status);
|
||||
}
|
||||
|
||||
if (rawstatus != reg.status) {
|
||||
ofono_info("data registration modified %d => %d",
|
||||
rawstatus, reg.status);
|
||||
}
|
||||
|
||||
return reg.status;
|
||||
struct ofono_error error;
|
||||
DBG("%s not allowed to attach", ril_modem_get_path(gd->md));
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_registration_status_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_gprs_cbd *cbd = user_data;
|
||||
ofono_gprs_status_cb_t cb = cbd->cb.status;
|
||||
struct ril_gprs *gd = cbd->gd;
|
||||
struct ofono_gprs *gprs = gd->gprs;
|
||||
struct ofono_error error;
|
||||
int status = -1;
|
||||
|
||||
DBG("%s", ril_modem_get_path(gd->md));
|
||||
if (gd && ril_status == RIL_E_SUCCESS) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ofono_error("ril_gprs_data_reg_cb: reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
ril_error_init_failure(&error);
|
||||
goto cb_out;
|
||||
}
|
||||
|
||||
status = ril_gprs_parse_data_reg_state(gd, data, len);
|
||||
if (status == NETWORK_REGISTRATION_STATUS_UNKNOWN) {
|
||||
ril_error_init_failure(&error);
|
||||
goto cb_out;
|
||||
}
|
||||
|
||||
/* Let's minimize logging */
|
||||
if (status != gd->last_status) {
|
||||
ofono_info("data reg changes %d (%d), attached %d",
|
||||
status, gd->last_status, gd->ofono_attached);
|
||||
}
|
||||
|
||||
/* Must be attached if registered or roaming */
|
||||
if (gd->last_status != NETWORK_REGISTRATION_STATUS_REGISTERED &&
|
||||
gd->last_status != NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED) {
|
||||
gd->ofono_attached = TRUE;
|
||||
} else if ((status == NETWORK_REGISTRATION_STATUS_ROAMING) &&
|
||||
ofono_gprs_get_roaming_allowed(gd->gprs)) {
|
||||
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->last_status) && gd->ofono_attached) {
|
||||
goto cb_out;
|
||||
}
|
||||
|
||||
if (!gd->ofono_attached) {
|
||||
if (!cb) {
|
||||
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
if (!ofono_gprs_get_roaming_allowed(gd->gprs)) {
|
||||
ofono_gprs_detached_notify(gprs);
|
||||
}
|
||||
|
||||
/*
|
||||
* This prevents core ending
|
||||
* into eternal loop with driver
|
||||
*/
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This prevents core ending
|
||||
* into eternal loop with driver
|
||||
*/
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
gd->last_status = status;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cb) {
|
||||
ofono_gprs_status_notify(gprs, status);
|
||||
}
|
||||
|
||||
gd->last_status = status;
|
||||
|
||||
exit:
|
||||
DBG("data reg status %d, last status %d, attached %d",
|
||||
status, gd->last_status, gd->ofono_attached);
|
||||
cb_out:
|
||||
if (cb) {
|
||||
cb(&error, status, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_poll_data_reg_state_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static void ril_gprs_allow_data_changed(struct ril_data *data, void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
int status;
|
||||
|
||||
DBG("%s", ril_modem_get_path(gd->md));
|
||||
GASSERT(gd->poll_id);
|
||||
gd->poll_id = 0;
|
||||
GASSERT(gd->data == data);
|
||||
DBG("%s %d", ril_modem_get_path(gd->md), ril_data_allowed(data));
|
||||
if (!gd->set_attached_id) {
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
}
|
||||
}
|
||||
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("ril_gprs_data_probe_reg_cb: reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
} else {
|
||||
status = ril_gprs_parse_data_reg_state(gd, data, len);
|
||||
ofono_info("data reg status probed %d", status);
|
||||
static void ril_gprs_data_registration_state_changed(struct ril_network *net,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
const struct ril_registration_state *data = &net->data;
|
||||
|
||||
GASSERT(gd->network == net);
|
||||
if (data->max_calls > gd->max_cids) {
|
||||
DBG("Setting max cids to %d", data->max_calls);
|
||||
gd->max_cids = data->max_calls;
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
if (status != gd->last_status) {
|
||||
ofono_info("data reg changes %d (%d), attached %d",
|
||||
status, gd->last_status, gd->ofono_attached);
|
||||
gd->last_status = status;
|
||||
if (gd->ofono_attached) {
|
||||
ofono_gprs_status_notify(gd->gprs, status);
|
||||
}
|
||||
}
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
ofono_gprs_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
struct ofono_error error;
|
||||
const enum network_registration_status status = gd->attached ?
|
||||
gd->registration_status :
|
||||
NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
|
||||
DBG("");
|
||||
if (gd) {
|
||||
grilio_queue_send_request_full(gd->q, NULL,
|
||||
RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_gprs_registration_status_cb, ril_gprs_cbd_free,
|
||||
ril_gprs_cbd_new(gd, cb, data));
|
||||
|
||||
DBG("%d (%s)", status, registration_status_to_string(status));
|
||||
cb(ril_error_ok(&error), status, data);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_register(gpointer user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
|
||||
gd->register_id = 0;
|
||||
gd->network_event_id = ril_network_add_data_state_changed_handler(
|
||||
gd->network, ril_gprs_data_registration_state_changed, gd);
|
||||
gd->data_event_id = ril_data_add_allow_changed_handler(gd->data,
|
||||
ril_gprs_allow_data_changed, gd);
|
||||
gd->registration_status = ril_gprs_fix_registration_status(gd,
|
||||
gd->network->data.status);
|
||||
|
||||
gd->max_cids = gd->network->data.max_calls;
|
||||
if (gd->max_cids > 0) {
|
||||
DBG("Setting max cids to %d", gd->max_cids);
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
ofono_gprs_register(gd->gprs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||
@@ -342,15 +229,13 @@ static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||
gd->md = modem;
|
||||
gd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
gd->q = grilio_queue_new(gd->io);
|
||||
gd->last_status = -1;
|
||||
gd->ril_data_tech = -1;
|
||||
gd->data = ril_data_ref(modem->data);
|
||||
gd->network = ril_network_ref(modem->network);
|
||||
gd->gprs = gprs;
|
||||
|
||||
ofono_gprs_set_data(gprs, gd);
|
||||
ril_gprs_poll_data_reg_state(gd);
|
||||
gd->event_id = grilio_channel_add_unsol_event_handler(gd->io,
|
||||
ril_gprs_state_changed,
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, gd);
|
||||
|
||||
/* ofono crashes if we register right away */
|
||||
gd->register_id = g_idle_add(ril_gprs_register, gd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -361,11 +246,20 @@ static void ril_gprs_remove(struct ofono_gprs *gprs)
|
||||
DBG("%s", ril_modem_get_path(gd->md));
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
if (gd->timer_id > 0) {
|
||||
g_source_remove(gd->timer_id);
|
||||
}
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
|
||||
if (gd->register_id) {
|
||||
g_source_remove(gd->register_id);
|
||||
}
|
||||
|
||||
ril_network_remove_handler(gd->network, gd->network_event_id);
|
||||
ril_network_unref(gd->network);
|
||||
|
||||
ril_data_remove_handler(gd->data, gd->data_event_id);
|
||||
ril_data_unref(gd->data);
|
||||
|
||||
grilio_channel_remove_handler(gd->io, gd->event_id);
|
||||
grilio_channel_unref(gd->io);
|
||||
grilio_queue_cancel_all(gd->q, FALSE);
|
||||
grilio_queue_unref(gd->q);
|
||||
|
||||
@@ -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,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -55,6 +55,7 @@ enum ril_gprs_context_state {
|
||||
struct ril_gprs_context {
|
||||
struct ofono_gprs_context *gc;
|
||||
struct ril_modem *modem;
|
||||
struct ril_network *network;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
guint active_ctx_cid;
|
||||
@@ -760,7 +761,7 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
*
|
||||
* Makes little sense but it is what it is.
|
||||
*/
|
||||
tech = ril_gprs_ril_data_tech(gprs);
|
||||
tech = gcd->network->data.ril_tech;
|
||||
if (tech > 2) {
|
||||
tech += 2;
|
||||
} else {
|
||||
@@ -918,6 +919,7 @@ static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
DBG("");
|
||||
gcd->gc = gc;
|
||||
gcd->modem = modem;
|
||||
gcd->network = ril_network_ref(modem->network);
|
||||
gcd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
gcd->q = grilio_queue_new(gcd->io);
|
||||
gcd->regid = grilio_channel_add_unsol_event_handler(gcd->io,
|
||||
@@ -943,6 +945,7 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
gcd->deactivate_req->cbd.gcd = NULL;
|
||||
}
|
||||
|
||||
ril_network_unref(gcd->network);
|
||||
grilio_channel_remove_handler(gcd->io, gcd->regid);
|
||||
grilio_channel_unref(gcd->io);
|
||||
grilio_queue_cancel_all(gcd->q, FALSE);
|
||||
|
||||
@@ -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,13 +14,17 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define MAX_PDP_CONTEXTS (2)
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
enum ril_modem_power_state {
|
||||
POWERED_OFF,
|
||||
@@ -37,19 +41,22 @@ enum ril_modem_online_state {
|
||||
|
||||
struct ril_modem_online_request {
|
||||
ofono_modem_online_cb_t cb;
|
||||
struct ril_modem_data *md;
|
||||
void *data;
|
||||
guint id;
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
struct ril_modem {
|
||||
GRilIoChannel *io;
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_modem *modem;
|
||||
struct ofono_radio_settings *radio_settings;
|
||||
struct ril_modem_config config;
|
||||
char *default_name;
|
||||
char *imei;
|
||||
gboolean pre_sim_done;
|
||||
gboolean devinfo_created;
|
||||
gboolean allow_data;
|
||||
|
||||
enum ril_radio_state radio_state;
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
gulong radio_state_event_id;
|
||||
|
||||
@@ -60,83 +67,92 @@ struct ril_modem {
|
||||
struct ril_modem_online_request set_offline;
|
||||
};
|
||||
|
||||
static guint ril_modem_request_power(struct ril_modem *md, gboolean on,
|
||||
GRilIoChannelResponseFunc cb);
|
||||
#define RADIO_POWER_TAG(md) (md)
|
||||
|
||||
static inline struct ril_modem *ril_modem_from_ofono(struct ofono_modem *modem)
|
||||
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||
{
|
||||
return ofono_modem_get_data(modem);
|
||||
struct ril_modem_data *md = ofono_modem_get_data(o);
|
||||
GASSERT(md->modem.ofono == o);
|
||||
return md;
|
||||
}
|
||||
|
||||
GRilIoChannel *ril_modem_io(struct ril_modem *md)
|
||||
static struct ril_modem_data *ril_modem_data_from_modem(struct ril_modem *m)
|
||||
{
|
||||
return md ? md->io : NULL;
|
||||
return m ? G_CAST(m, struct ril_modem_data, modem) : NULL;
|
||||
}
|
||||
|
||||
const struct ril_modem_config *ril_modem_config(struct ril_modem *md)
|
||||
static void *ril_modem_get_atom_data(struct ril_modem *modem,
|
||||
enum ofono_atom_type type)
|
||||
{
|
||||
return md ? &md->config : NULL;
|
||||
if (modem && modem->ofono) {
|
||||
struct ofono_atom *atom =
|
||||
__ofono_modem_find_atom(modem->ofono, type);
|
||||
|
||||
if (atom) {
|
||||
return __ofono_atom_get_data(atom);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ofono_modem *ril_modem_ofono_modem(struct ril_modem *md)
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
|
||||
{
|
||||
return md ? md->modem : NULL;
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
|
||||
}
|
||||
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *md)
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
|
||||
{
|
||||
return (md && md->modem) ?
|
||||
__ofono_atom_find(OFONO_ATOM_TYPE_SIM, md->modem) :
|
||||
NULL;
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
|
||||
}
|
||||
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *md)
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
|
||||
{
|
||||
return (md && md->modem) ?
|
||||
__ofono_atom_find(OFONO_ATOM_TYPE_GPRS, md->modem) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *md)
|
||||
{
|
||||
return (md && md->modem) ?
|
||||
__ofono_atom_find(OFONO_ATOM_TYPE_NETREG, md->modem) :
|
||||
NULL;
|
||||
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
|
||||
}
|
||||
|
||||
void ril_modem_delete(struct ril_modem *md)
|
||||
{
|
||||
if (md && md->modem) {
|
||||
ofono_modem_remove(md->modem);
|
||||
if (md && md->ofono) {
|
||||
ofono_modem_remove(md->ofono);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_modem_set_removed_cb(struct ril_modem *md, ril_modem_cb_t cb,
|
||||
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
|
||||
|
||||
md->removed_cb = cb;
|
||||
md->removed_cb_data = data;
|
||||
}
|
||||
|
||||
void ril_modem_allow_data(struct ril_modem *md)
|
||||
static void ril_modem_check_devinfo(struct ril_modem_data *md)
|
||||
{
|
||||
if (md && md->modem) {
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(md->modem));
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, TRUE);
|
||||
grilio_queue_send_request(md->q, req, RIL_REQUEST_ALLOW_DATA);
|
||||
grilio_request_unref(req);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(GRilIoChannel* io,
|
||||
struct ril_modem_online_request *req)
|
||||
void ril_modem_set_imei(struct ril_modem *modem, const char *imei)
|
||||
{
|
||||
if (req->id) {
|
||||
grilio_channel_cancel_request(io, req->id, FALSE);
|
||||
req->id = 0;
|
||||
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) {
|
||||
g_source_remove(req->timeout_id);
|
||||
req->timeout_id = 0;
|
||||
}
|
||||
|
||||
if (req->cb) {
|
||||
@@ -150,121 +166,124 @@ static void ril_modem_online_request_ok(GRilIoChannel* io,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_update_online_state(struct ril_modem *md)
|
||||
static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||
{
|
||||
switch (md->radio_state) {
|
||||
switch (md->modem.radio->state) {
|
||||
case RADIO_STATE_ON:
|
||||
ril_modem_online_request_ok(md->io, &md->set_online);
|
||||
DBG("online");
|
||||
ril_modem_online_request_ok(&md->set_online);
|
||||
break;
|
||||
|
||||
case RADIO_STATE_OFF:
|
||||
case RADIO_STATE_UNAVAILABLE:
|
||||
ril_modem_online_request_ok(md->io, &md->set_offline);
|
||||
DBG("offline");
|
||||
ril_modem_online_request_ok(&md->set_offline);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!md->set_offline.id && !md->set_online.id &&
|
||||
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
|
||||
md->power_state == POWERING_OFF) {
|
||||
md->power_state = POWERED_OFF;
|
||||
ofono_modem_set_powered(md->modem, FALSE);
|
||||
if (md->modem.ofono) {
|
||||
ofono_modem_set_powered(md->modem.ofono, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_done(struct ril_modem *md,
|
||||
struct ril_modem_online_request *req, int ril_status)
|
||||
static gboolean ril_modem_online_request_timeout(gpointer data)
|
||||
{
|
||||
GASSERT(req->id);
|
||||
GASSERT(req->cb);
|
||||
GASSERT(req->data);
|
||||
req->id = 0;
|
||||
struct ril_modem_online_request *req = data;
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *cb_data = req->data;
|
||||
|
||||
/* If this request has completed successfully, we will
|
||||
* invoke the callback and notify ofono core when we get
|
||||
* RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, i.e. the power
|
||||
* state has actually changed */
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *data = req->data;
|
||||
GASSERT(req->timeout_id);
|
||||
GASSERT(cb);
|
||||
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
req->timeout_id = 0;
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
cb(ril_error_failure(&error), cb_data);
|
||||
ril_modem_update_online_state(req->md);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_check(gpointer data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->online_check_id);
|
||||
md->online_check_id = 0;
|
||||
ril_modem_update_online_state(md);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_modem_set_online_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
{
|
||||
struct ril_modem *md = user_data;
|
||||
|
||||
DBG("Power on status %s", ril_error_to_string(status));
|
||||
ril_modem_online_request_done(md, &md->set_online, status);
|
||||
}
|
||||
|
||||
static void ril_modem_set_offline_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_modem *md = user_data;
|
||||
|
||||
DBG("Power on status %s", ril_error_to_string(status));
|
||||
ril_modem_online_request_done(md, &md->set_offline, status);
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_modem_request_radio_power(gboolean on)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
|
||||
return req;
|
||||
}
|
||||
|
||||
static guint ril_modem_request_power(struct ril_modem *md, gboolean on,
|
||||
GRilIoChannelResponseFunc cb)
|
||||
{
|
||||
guint id = 0;
|
||||
|
||||
if (md->q) {
|
||||
GRilIoRequest *req = ril_modem_request_radio_power(on);
|
||||
|
||||
DBG("[%u] %s", md->config.slot, on ? "ON" : "OFF");
|
||||
id = grilio_queue_send_request_full(md->q, req,
|
||||
RIL_REQUEST_RADIO_POWER, cb, NULL, md);
|
||||
grilio_request_unref(req);
|
||||
if (!md->online_check_id) {
|
||||
md->online_check_id = g_idle_add(ril_modem_online_check, md);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} else if (md->radio_settings) {
|
||||
DBG("Removing radio settings interface");
|
||||
ofono_radio_settings_remove(md->radio_settings);
|
||||
md->radio_settings = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.radio == radio);
|
||||
ril_modem_update_radio_settings(md);
|
||||
ril_modem_update_online_state(md);
|
||||
};
|
||||
|
||||
static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem *md = ril_modem_from_ofono(modem);
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("");
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->pre_sim_done = TRUE;
|
||||
ril_modem_check_devinfo(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,
|
||||
ril_modem_radio_state_cb, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem *md = ril_modem_from_ofono(modem);
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
struct ofono_gprs_context *gc;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (gprs) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
|
||||
gc = ofono_gprs_context_create(modem, 0,
|
||||
struct ofono_gprs_context *gc =
|
||||
ofono_gprs_context_create(modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
if (gc == NULL)
|
||||
break;
|
||||
@@ -282,9 +301,9 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem *md = ril_modem_from_ofono(modem);
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("");
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_call_volume_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
@@ -295,36 +314,33 @@ static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_modem *md = ril_modem_from_ofono(modem);
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ril_modem_online_request *req;
|
||||
|
||||
DBG("%s going %sline", ofono_modem_get_path(modem),
|
||||
online ? "on" : "off");
|
||||
|
||||
if (online) {
|
||||
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_online;
|
||||
GASSERT(!req->id);
|
||||
req->id = ril_modem_request_power(md, TRUE,
|
||||
ril_modem_set_online_cb);
|
||||
} else {
|
||||
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_offline;
|
||||
GASSERT(!req->id);
|
||||
req->id = ril_modem_request_power(md, FALSE,
|
||||
ril_modem_set_offline_cb);
|
||||
}
|
||||
|
||||
if (req->id) {
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_failure(&error), data);
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
}
|
||||
req->timeout_id = g_timeout_add_seconds(ONLINE_TIMEOUT_SECS,
|
||||
ril_modem_online_request_timeout, req);
|
||||
ril_modem_schedule_online_check(md);
|
||||
}
|
||||
|
||||
static int ril_modem_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem *md = ril_modem_from_ofono(modem);
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->power_state = POWERED_ON;
|
||||
@@ -333,10 +349,10 @@ static int ril_modem_enable(struct ofono_modem *modem)
|
||||
|
||||
static int ril_modem_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem *md = ril_modem_from_ofono(modem);
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
if (md->set_online.id || md->set_offline.id) {
|
||||
if (md->set_online.timeout_id || md->set_offline.timeout_id) {
|
||||
md->power_state = POWERING_OFF;
|
||||
return -EINPROGRESS;
|
||||
} else {
|
||||
@@ -351,108 +367,99 @@ static int ril_modem_probe(struct ofono_modem *modem)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_modem_remove(struct ofono_modem *modem)
|
||||
static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
{
|
||||
struct ril_modem *md = ril_modem_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
GASSERT(md->modem);
|
||||
|
||||
if (md->radio_state > RADIO_STATE_UNAVAILABLE) {
|
||||
GRilIoRequest *req = ril_modem_request_radio_power(FALSE);
|
||||
grilio_channel_send_request(md->io, req,
|
||||
RIL_REQUEST_RADIO_POWER);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(ofono);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
if (md->removed_cb) {
|
||||
ril_modem_cb_t cb = md->removed_cb;
|
||||
void *data = md->removed_cb_data;
|
||||
|
||||
md->removed_cb = NULL;
|
||||
md->removed_cb_data = NULL;
|
||||
cb(md, data);
|
||||
cb(modem, data);
|
||||
}
|
||||
|
||||
ofono_modem_set_data(modem, NULL);
|
||||
ofono_modem_set_data(ofono, NULL);
|
||||
|
||||
grilio_channel_remove_handler(md->io, md->radio_state_event_id);
|
||||
grilio_channel_unref(md->io);
|
||||
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_unref(modem->radio);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
}
|
||||
|
||||
if (md->set_online.timeout_id) {
|
||||
g_source_remove(md->set_online.timeout_id);
|
||||
}
|
||||
|
||||
if (md->set_offline.timeout_id) {
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_data_unref(modem->data);
|
||||
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->imei);
|
||||
g_free(md);
|
||||
}
|
||||
|
||||
static void ril_modem_radio_state_changed(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io,
|
||||
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_modem *md = user_data;
|
||||
GRilIoParser rilp;
|
||||
int radio_state;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &radio_state) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
DBG("%s %s", ofono_modem_get_path(md->modem),
|
||||
ril_radio_state_to_string(radio_state));
|
||||
md->radio_state = radio_state;
|
||||
if (radio_state == RADIO_STATE_ON && !md->radio_settings) {
|
||||
DBG("Initializing radio settings interface");
|
||||
md->radio_settings =
|
||||
ofono_radio_settings_create(md->modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
|
||||
ril_modem_update_online_state(md);
|
||||
} else {
|
||||
ofono_error("Error parsing RADIO_STATE_CHANGED");
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *dev,
|
||||
const struct ril_modem_config *config)
|
||||
{
|
||||
struct ofono_modem *modem = ofono_modem_create(dev, RILMODEM_DRIVER);
|
||||
|
||||
if (modem) {
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
struct ofono_modem *ofono = ofono_modem_create(slot->path + 1,
|
||||
RILMODEM_DRIVER);
|
||||
if (ofono) {
|
||||
int err;
|
||||
struct ril_modem *md = g_new0(struct ril_modem, 1);
|
||||
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
/* Copy config */
|
||||
md->config = *config;
|
||||
if (config->default_name && config->default_name[0]) {
|
||||
md->default_name = g_strdup(config->default_name);
|
||||
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",
|
||||
config->slot + 1);
|
||||
slot->config->slot + 1);
|
||||
}
|
||||
md->config.default_name = md->default_name;
|
||||
modem->config.default_name = md->default_name;
|
||||
|
||||
md->modem = modem;
|
||||
md->io = grilio_channel_ref(io);
|
||||
modem->ofono = ofono;
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
ofono_modem_set_data(modem, md);
|
||||
err = ofono_modem_register(modem);
|
||||
md->set_online.md = md;
|
||||
md->set_offline.md = md;
|
||||
ofono_modem_set_data(ofono, md);
|
||||
err = ofono_modem_register(ofono);
|
||||
if (!err) {
|
||||
md->radio_state_event_id =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_modem_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
|
||||
md);
|
||||
|
||||
ril_radio_power_cycle(modem->radio);
|
||||
ril_radio_power_on(modem->radio, RADIO_POWER_TAG(md));
|
||||
GASSERT(io->connected);
|
||||
ril_modem_request_power(md, FALSE, NULL);
|
||||
|
||||
/*
|
||||
* ofono_modem_reset sets Powered to TRUE without
|
||||
* issuing PropertyChange signal.
|
||||
*/
|
||||
ofono_modem_set_powered(md->modem, FALSE);
|
||||
ofono_modem_set_powered(md->modem, TRUE);
|
||||
ofono_modem_set_powered(modem->ofono, FALSE);
|
||||
ofono_modem_set_powered(modem->ofono, TRUE);
|
||||
md->power_state = POWERED_ON;
|
||||
return md;
|
||||
return modem;
|
||||
} else {
|
||||
ofono_error("Error %d registering %s",
|
||||
err, RILMODEM_DRIVER);
|
||||
@@ -462,10 +469,10 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *dev,
|
||||
* ofono_modem_remove() won't invoke
|
||||
* ril_modem_remove() callback.
|
||||
*/
|
||||
ril_modem_remove(modem);
|
||||
ril_modem_remove(ofono);
|
||||
}
|
||||
|
||||
ofono_modem_remove(modem);
|
||||
ofono_modem_remove(ofono);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -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,41 +14,36 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "simutil.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
enum ril_netreg_events {
|
||||
NETREG_EVENT_VOICE_NETWORK_STATE_CHANGED,
|
||||
NETREG_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_EVENT_SIGNAL_STRENGTH,
|
||||
NETREG_EVENT_COUNT
|
||||
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||
NETREG_RIL_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_netreg_network_events {
|
||||
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
|
||||
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
|
||||
NETREG_NETWORK_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_netreg *netreg;
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
int tech;
|
||||
struct ofono_network_time time;
|
||||
struct ril_network *network;
|
||||
char *log_prefix;
|
||||
guint timer_id;
|
||||
int corestatus; /* Registration status previously reported to core */
|
||||
gulong event_id[NETREG_EVENT_COUNT];
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.3 <stat> */
|
||||
enum operator_status {
|
||||
OPERATOR_STATUS_UNKNOWN = 0,
|
||||
OPERATOR_STATUS_AVAILABLE = 1,
|
||||
OPERATOR_STATUS_CURRENT = 2,
|
||||
OPERATOR_STATUS_FORBIDDEN = 3,
|
||||
guint notify_id;
|
||||
guint current_operator_id;
|
||||
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
|
||||
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
|
||||
};
|
||||
|
||||
struct ril_netreg_cbd {
|
||||
@@ -66,9 +61,9 @@ struct ril_netreg_cbd {
|
||||
|
||||
#define ril_netreg_cbd_free g_free
|
||||
|
||||
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *nr)
|
||||
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
|
||||
{
|
||||
return ofono_netreg_get_data(nr);
|
||||
return ofono ? ofono_netreg_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
|
||||
@@ -82,190 +77,86 @@ static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_extract_mcc_mnc(const char *str,
|
||||
struct ofono_network_operator *op)
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
|
||||
gint status)
|
||||
{
|
||||
if (str) {
|
||||
int i;
|
||||
const char *ptr = str;
|
||||
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
/* These functions tolerate NULL argument */
|
||||
const char *net_mcc = ofono_netreg_get_mcc(netreg);
|
||||
const char *net_mnc = ofono_netreg_get_mnc(netreg);
|
||||
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
|
||||
|
||||
/* Three digit country code */
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MCC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mcc[i] = *ptr++;
|
||||
}
|
||||
op->mcc[i] = 0;
|
||||
|
||||
if (i == OFONO_MAX_MCC_LENGTH) {
|
||||
/* Usually a 2 but sometimes 3 digit network code */
|
||||
for (i=0;
|
||||
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mnc[i] = *ptr++;
|
||||
}
|
||||
op->mnc[i] = 0;
|
||||
|
||||
if (i > 0) {
|
||||
|
||||
/*
|
||||
* Sometimes MCC/MNC are followed by + and
|
||||
* what looks like the technology code. This
|
||||
* is of course completely undocumented.
|
||||
*/
|
||||
if (*ptr == '+') {
|
||||
int tech = ril_parse_tech(ptr+1, NULL);
|
||||
if (tech >= 0) {
|
||||
op->tech = tech;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
if (spdi && net_mcc && net_mnc) {
|
||||
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
|
||||
ofono_info("not roaming based on spdi");
|
||||
return NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ril_netreg_check_status(struct ril_netreg *nd, int status)
|
||||
{
|
||||
return (nd && nd->netreg) ?
|
||||
ril_netreg_check_if_really_roaming(nd->netreg, status) :
|
||||
status;
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_status_notify_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
|
||||
DBG("%s", nd->log_prefix);
|
||||
GASSERT(nd->notify_id);
|
||||
nd->notify_id = 0;
|
||||
ofono_netreg_status_notify(nd->netreg,
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_state_cb(GRilIoChannel *io, int call_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_status_cb_t cb = cbd->cb.status;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
struct ril_reg_data reg;
|
||||
int rawstatus;
|
||||
|
||||
DBG("");
|
||||
if (call_status != RIL_E_SUCCESS || !nd->netreg) {
|
||||
ofono_error("voice registration status query fail");
|
||||
nd->corestatus = -1;
|
||||
cb(ril_error_failure(&error), -1, -1, -1, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ril_util_parse_reg(data, len, ®)) {
|
||||
DBG("voice registration status parsing fail");
|
||||
nd->corestatus = -1;
|
||||
cb(ril_error_failure(&error), -1, -1, -1, -1, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
rawstatus = reg.status;
|
||||
if (reg.status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
reg.status = ril_netreg_check_if_really_roaming(nd->netreg,
|
||||
reg.status);
|
||||
}
|
||||
|
||||
if (rawstatus != reg.status) {
|
||||
ofono_info("voice registration modified %d => %d",
|
||||
rawstatus, reg.status);
|
||||
}
|
||||
|
||||
DBG("status:%d corestatus:%d", reg.status, nd->corestatus);
|
||||
|
||||
if (nd->corestatus != reg.status) {
|
||||
ofono_info("voice registration changes %d (%d)",
|
||||
reg.status, nd->corestatus);
|
||||
}
|
||||
|
||||
nd->corestatus = reg.status;
|
||||
nd->tech = reg.access_tech;
|
||||
cb(ril_error_ok(&error), reg.status, reg.lac, reg.ci, reg.access_tech,
|
||||
cbd->data);
|
||||
}
|
||||
|
||||
static void ril_netreg_status_notify(struct ofono_error *error, int status,
|
||||
int lac, int ci, int tech, gpointer user_data)
|
||||
static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
DBG("Error during status notification");
|
||||
} else if (nd->netreg) {
|
||||
ofono_netreg_status_notify(nd->netreg, status, lac, ci, tech);
|
||||
/* Coalesce multiple notifications into one */
|
||||
if (nd->notify_id) {
|
||||
DBG("%snotification aready queued", nd->log_prefix);
|
||||
} else {
|
||||
DBG("%squeuing notification", nd->log_prefix);
|
||||
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_network_state_change(GRilIoChannel *io,
|
||||
guint ril_event, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||
ril_netreg_state_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, ril_netreg_status_notify, nd));
|
||||
}
|
||||
|
||||
static void ril_netreg_registration_status(struct ofono_netreg *netreg,
|
||||
ofono_netreg_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
struct ofono_error error;
|
||||
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_VOICE_REGISTRATION_STATE, ril_netreg_state_cb,
|
||||
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
|
||||
DBG("%s", nd->log_prefix);
|
||||
cb(ril_error_ok(&error),
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech, data);
|
||||
}
|
||||
|
||||
static void ril_netreg_current_operator_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static gboolean ril_netreg_current_operator_cb(void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
|
||||
struct ofono_error error;
|
||||
struct ofono_network_operator op;
|
||||
struct ofono_network_operator *result = NULL;
|
||||
gchar *lalpha = NULL, *salpha = NULL, *numeric = NULL;
|
||||
int tmp;
|
||||
GRilIoParser rilp;
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("Failed to retrive the current operator: %s",
|
||||
ril_error_to_string(status));
|
||||
goto done;
|
||||
}
|
||||
DBG("%s", nd->log_prefix);
|
||||
GASSERT(nd->current_operator_id);
|
||||
nd->current_operator_id = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (!grilio_parser_get_int32(&rilp, &tmp) || !tmp) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
lalpha = grilio_parser_get_utf8(&rilp);
|
||||
salpha = grilio_parser_get_utf8(&rilp);
|
||||
numeric = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
/* Try to use long by default */
|
||||
if (lalpha) {
|
||||
strncpy(op.name, lalpha, OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else if (salpha) {
|
||||
strncpy(op.name, salpha, OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!ril_netreg_extract_mcc_mnc(numeric, &op)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Set to current */
|
||||
op.status = OPERATOR_STATUS_CURRENT;
|
||||
op.tech = nd->tech;
|
||||
result = &op;
|
||||
ril_error_init_ok(&error);
|
||||
|
||||
DBG("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));
|
||||
|
||||
done:
|
||||
cbd->cb.operator(&error, result, cbd->data);
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
cb(ril_error_ok(&error), nd->network->operator, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
@@ -273,9 +164,15 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
grilio_queue_send_request_full(nd->q, NULL, RIL_REQUEST_OPERATOR,
|
||||
ril_netreg_current_operator_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
GASSERT(!nd->current_operator_id);
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
nd->current_operator_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_netreg_current_operator_cb,
|
||||
ril_netreg_cbd_new(nd, cb, data),
|
||||
ril_netreg_cbd_free);
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
@@ -334,11 +231,16 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
list[i].status = OPERATOR_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
op->tech = ACCESS_TECHNOLOGY_GSM;
|
||||
ok = ril_netreg_extract_mcc_mnc(numeric, op);
|
||||
op->tech = -1;
|
||||
ok = ril_parse_mcc_mnc(numeric, op);
|
||||
if (ok) {
|
||||
if (op->tech < 0) {
|
||||
op->tech = cbd->nd->network->voice.access_tech;
|
||||
}
|
||||
DBG("[operator=%s, %s, %s, status: %s]", op->name,
|
||||
op->mcc, op->mnc, status);
|
||||
} else {
|
||||
DBG("failed to parse operator list");
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
@@ -506,6 +408,7 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
GRilIoParser rilp;
|
||||
struct ofono_network_time time;
|
||||
int year, mon, mday, hour, min, sec, dst, tzi;
|
||||
char tzs, tz[4];
|
||||
gchar *nitz;
|
||||
@@ -520,37 +423,19 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
&hour, &min, &sec, &tzs, &tzi, &dst);
|
||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||
|
||||
nd->time.utcoff = atoi(tz) * 15 * 60;
|
||||
nd->time.dst = dst;
|
||||
nd->time.sec = sec;
|
||||
nd->time.min = min;
|
||||
nd->time.hour = hour;
|
||||
nd->time.mday = mday;
|
||||
nd->time.mon = mon;
|
||||
nd->time.year = 2000 + year;
|
||||
time.utcoff = atoi(tz) * 15 * 60;
|
||||
time.dst = dst;
|
||||
time.sec = sec;
|
||||
time.min = min;
|
||||
time.hour = hour;
|
||||
time.mday = mday;
|
||||
time.mon = mon;
|
||||
time.year = 2000 + year;
|
||||
|
||||
ofono_netreg_time_notify(nd->netreg, &nd->time);
|
||||
ofono_netreg_time_notify(nd->netreg, &time);
|
||||
g_free(nitz);
|
||||
}
|
||||
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
|
||||
gint status)
|
||||
{
|
||||
/* These functions tolerate NULL argument */
|
||||
const char *net_mcc = ofono_netreg_get_mcc(netreg);
|
||||
const char *net_mnc = ofono_netreg_get_mnc(netreg);
|
||||
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
|
||||
|
||||
if (spdi && net_mcc && net_mnc) {
|
||||
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
|
||||
ofono_info("voice reg: not roaming based on spdi");
|
||||
return NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_register(gpointer user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
@@ -560,19 +445,21 @@ static gboolean ril_netreg_register(gpointer user_data)
|
||||
ofono_netreg_register(nd->netreg);
|
||||
|
||||
/* Register for network state changes */
|
||||
nd->event_id[NETREG_EVENT_VOICE_NETWORK_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_network_state_change,
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, nd);
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_OPERATOR_CHANGED] =
|
||||
ril_network_add_operator_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED] =
|
||||
ril_network_add_voice_state_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
|
||||
/* Register for network time update reports */
|
||||
nd->event_id[NETREG_EVENT_NITZ_TIME_RECEIVED] =
|
||||
/* Register for network time updates */
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_NITZ_TIME_RECEIVED] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_nitz_notify,
|
||||
RIL_UNSOL_NITZ_TIME_RECEIVED, nd);
|
||||
|
||||
/* Register for signal strength changes */
|
||||
nd->event_id[NETREG_EVENT_SIGNAL_STRENGTH] =
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_SIGNAL_STRENGTH] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_strength_notify,
|
||||
RIL_UNSOL_SIGNAL_STRENGTH, nd);
|
||||
@@ -586,21 +473,14 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
|
||||
guint slot = ril_modem_slot(modem);
|
||||
|
||||
DBG("[%u] %p", ril_modem_slot(modem), netreg);
|
||||
DBG("[%u] %p", slot, netreg);
|
||||
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
nd->tech = -1;
|
||||
nd->time.sec = -1;
|
||||
nd->time.min = -1;
|
||||
nd->time.hour = -1;
|
||||
nd->time.mday = -1;
|
||||
nd->time.mon = -1;
|
||||
nd->time.year = -1;
|
||||
nd->time.dst = 0;
|
||||
nd->time.utcoff = 0;
|
||||
nd->corestatus = -1;
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||
@@ -609,23 +489,36 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
|
||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
int i;
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
int i;
|
||||
|
||||
DBG("%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
ofono_netreg_set_data(netreg, NULL);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(nd->event_id); i++) {
|
||||
grilio_channel_remove_handler(nd->io, nd->event_id[i]);
|
||||
}
|
||||
|
||||
if (nd->timer_id > 0) {
|
||||
g_source_remove(nd->timer_id);
|
||||
}
|
||||
|
||||
if (nd->notify_id) {
|
||||
g_source_remove(nd->notify_id);
|
||||
}
|
||||
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
|
||||
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
|
||||
}
|
||||
ril_network_unref(nd->network);
|
||||
|
||||
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
|
||||
G_N_ELEMENTS(nd->ril_event_id));
|
||||
|
||||
grilio_channel_unref(nd->io);
|
||||
grilio_queue_unref(nd->q);
|
||||
g_free(nd->log_prefix);
|
||||
g_free(nd);
|
||||
}
|
||||
|
||||
|
||||
501
ofono/drivers/ril/ril_network.c
Normal file
501
ofono/drivers/ril/ril_network.c
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
#include "common.h"
|
||||
|
||||
typedef GObjectClass RilNetworkClass;
|
||||
typedef struct ril_network RilNetwork;
|
||||
|
||||
struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
guint operator_poll_id;
|
||||
guint voice_poll_id;
|
||||
guint data_poll_id;
|
||||
gulong radio_event_id;
|
||||
struct ofono_network_operator operator;
|
||||
};
|
||||
|
||||
enum ril_network_signal {
|
||||
SIGNAL_OPERATOR_CHANGED,
|
||||
SIGNAL_VOICE_STATE_CHANGED,
|
||||
SIGNAL_DATA_STATE_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"
|
||||
|
||||
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilNetwork, ril_network, G_TYPE_OBJECT)
|
||||
#define RIL_NETWORK_TYPE (ril_network_get_type())
|
||||
#define RIL_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,\
|
||||
RIL_NETWORK_TYPE,RilNetwork))
|
||||
|
||||
static void ril_network_reset_state(struct ril_registration_state *reg)
|
||||
{
|
||||
memset(reg, 0, sizeof(*reg));
|
||||
reg->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
|
||||
reg->access_tech = -1;
|
||||
reg->ril_tech = -1;
|
||||
reg->lac = -1;
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
const void *data, guint len, struct ril_registration_state *reg)
|
||||
{
|
||||
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;
|
||||
GRilIoParser rilp;
|
||||
|
||||
ril_network_reset_state(reg);
|
||||
|
||||
/* Size of response string array. The minimum seen in the wild is 3 */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (!grilio_parser_get_int32(&rilp, &nparams) || nparams < 3) {
|
||||
DBG("%sbroken response", priv->log_prefix);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sstatus = grilio_parser_get_utf8(&rilp); /* response[0] */
|
||||
if (!sstatus) {
|
||||
DBG("%sNo sstatus value returned!", priv->log_prefix);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
slac = grilio_parser_get_utf8(&rilp); /* response[1] */
|
||||
sci = grilio_parser_get_utf8(&rilp); /* response[2] */
|
||||
|
||||
if (nparams > 3) {
|
||||
stech = grilio_parser_get_utf8(&rilp); /* response[3] */
|
||||
}
|
||||
|
||||
ril_status = atoi(sstatus);
|
||||
if (ril_status > 10) {
|
||||
reg->status = ril_status - 10;
|
||||
} else {
|
||||
reg->status = ril_status;
|
||||
}
|
||||
|
||||
/* FIXME: need to review VOICE_REGISTRATION response
|
||||
* as it returns up to 15 parameters ( vs. 6 for DATA ).
|
||||
*
|
||||
* The first four parameters are the same for both
|
||||
* responses ( although status includes values for
|
||||
* emergency calls for VOICE response ).
|
||||
*
|
||||
* Parameters 5 & 6 have different meanings for
|
||||
* voice & data response.
|
||||
*/
|
||||
if (nparams > 4) {
|
||||
/* TODO: different use for CDMA */
|
||||
sreason = grilio_parser_get_utf8(&rilp); /* response[4] */
|
||||
if (nparams > 5) {
|
||||
/* TODO: different use for CDMA */
|
||||
smax = grilio_parser_get_utf8(&rilp); /* response[5] */
|
||||
if (smax) {
|
||||
reg->max_calls = atoi(smax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some older RILs don't provide max calls, in that case let's
|
||||
* supply some reasonable default. We don't need more than 2
|
||||
* simultaneous data calls anyway.
|
||||
*/
|
||||
if (nparams <= 5) {
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
|
||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG("%s%s,%s,%s,%d,%s,%s,%s", priv->log_prefix,
|
||||
registration_status_to_string(reg->status),
|
||||
slac, sci, reg->ril_tech,
|
||||
registration_tech_to_string(reg->access_tech),
|
||||
sreason, smax);
|
||||
|
||||
g_free(sstatus);
|
||||
g_free(slac);
|
||||
g_free(sci);
|
||||
g_free(stech);
|
||||
g_free(sreason);
|
||||
g_free(smax);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ril_network_op_copy(struct ofono_network_operator *dest,
|
||||
const struct ofono_network_operator *src)
|
||||
{
|
||||
strncpy(dest->mcc, src->mcc, sizeof(dest->mcc));
|
||||
strncpy(dest->mnc, src->mnc, sizeof(dest->mnc));
|
||||
strncpy(dest->name, src->name, sizeof(dest->name));
|
||||
dest->mcc[sizeof(dest->mcc)-1] = 0;
|
||||
dest->mnc[sizeof(dest->mnc)-1] = 0;
|
||||
dest->name[sizeof(dest->name)-1] = 0;
|
||||
dest->status = src->status;
|
||||
dest->tech = src->tech;
|
||||
}
|
||||
|
||||
static gboolean ril_network_op_equal(const struct ofono_network_operator *op1,
|
||||
const struct ofono_network_operator *op2)
|
||||
{
|
||||
if (op1 == op2) {
|
||||
return TRUE;
|
||||
} else if (!op1 || !op2) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return op1->status == op2->status &&
|
||||
op1->tech == op2->tech &&
|
||||
!strncmp(op1->mcc, op2->mcc, sizeof(op2->mcc)) &&
|
||||
!strncmp(op1->mnc, op2->mnc, sizeof(op2->mnc)) &&
|
||||
!strncmp(op1->name, op2->name, sizeof(op2->name));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->operator_poll_id);
|
||||
priv->operator_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ofono_network_operator op;
|
||||
gboolean changed = FALSE;
|
||||
gchar *lalpha;
|
||||
char *salpha;
|
||||
char *numeric;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
lalpha = grilio_parser_get_utf8(&rilp);
|
||||
salpha = grilio_parser_get_utf8(&rilp);
|
||||
numeric = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
op.tech = -1;
|
||||
if (ril_parse_mcc_mnc(numeric, &op)) {
|
||||
if (op.tech < 0) op.tech = self->voice.access_tech;
|
||||
op.status = OPERATOR_STATUS_CURRENT;
|
||||
op.name[0] = 0;
|
||||
if (lalpha) {
|
||||
strncpy(op.name, lalpha, sizeof(op.name));
|
||||
} else if (salpha) {
|
||||
strncpy(op.name, salpha, sizeof(op.name));
|
||||
} else {
|
||||
strncpy(op.name, numeric, sizeof(op.name));
|
||||
}
|
||||
op.name[sizeof(op.name)-1] = 0;
|
||||
if (!self->operator) {
|
||||
self->operator = &priv->operator;
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
} else if (!ril_network_op_equal(&op, &priv->operator)) {
|
||||
ril_network_op_copy(&priv->operator, &op);
|
||||
changed = TRUE;
|
||||
}
|
||||
} else if (self->operator) {
|
||||
self->operator = NULL;
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (self->operator) {
|
||||
DBG("%slalpha=%s, salpha=%s, numeric=%s, %s, "
|
||||
"mcc=%s, mnc=%s, %s", priv->log_prefix,
|
||||
lalpha, salpha, numeric,
|
||||
op.name, op.mcc, op.mnc,
|
||||
registration_tech_to_string(op.tech));
|
||||
} else {
|
||||
DBG("%sno operator", priv->log_prefix);
|
||||
}
|
||||
g_signal_emit(self, ril_network_signals[
|
||||
SIGNAL_OPERATOR_CHANGED], 0);
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_voice_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->voice_poll_id);
|
||||
priv->voice_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->voice, sizeof(state))) {
|
||||
DBG("%svoice registration changed", priv->log_prefix);
|
||||
self->voice = state;
|
||||
g_signal_emit(self, ril_network_signals[
|
||||
SIGNAL_VOICE_STATE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->data_poll_id);
|
||||
priv->data_poll_id = 0;
|
||||
|
||||
if (req_status == RIL_E_SUCCESS) {
|
||||
struct ril_registration_state state;
|
||||
|
||||
ril_network_parse_response(self, data, len, &state);
|
||||
if (memcmp(&state, &self->data, sizeof(state))) {
|
||||
DBG("%sdata registration changed", priv->log_prefix);
|
||||
self->data = state;
|
||||
g_signal_emit(self, ril_network_signals[
|
||||
SIGNAL_DATA_STATE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
|
||||
int code, GRilIoChannelResponseFunc fn)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, id);
|
||||
} else {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
id = grilio_queue_send_request_full(priv->q, req, code, fn,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_network_poll_state(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
priv->operator_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
|
||||
ril_network_poll_operator_cb);
|
||||
priv->voice_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
|
||||
ril_network_poll_voice_state_cb);
|
||||
priv->data_poll_id = ril_network_poll_and_retry(self,
|
||||
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
|
||||
ril_network_poll_data_state_cb);
|
||||
}
|
||||
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_OPERATOR_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_VOICE_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_data_state_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_DATA_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_network_remove_handler(struct ril_network *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_new(GRilIoChannel *io, struct ril_radio *radio)
|
||||
{
|
||||
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
/*
|
||||
* Query the initial state. Querying network state before the radio
|
||||
* has been turned on makes RIL unhappy.
|
||||
*/
|
||||
if (radio->state == RADIO_STATE_ON) {
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_ref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_NETWORK(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_unref(struct ril_network *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_NETWORK(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_init(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_NETWORK_TYPE, struct ril_network_priv);
|
||||
|
||||
self->priv = priv;
|
||||
ril_network_reset_state(&self->voice);
|
||||
ril_network_reset_state(&self->data);
|
||||
}
|
||||
|
||||
static void ril_network_dispose(GObject *object)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->event_id) {
|
||||
grilio_channel_remove_handler(priv->io, priv->event_id);
|
||||
priv->event_id = 0;
|
||||
}
|
||||
|
||||
if (priv->radio_event_id) {
|
||||
ril_radio_remove_handler(priv->radio, priv->radio_event_id);
|
||||
priv->radio_event_id = 0;
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_network_finalize(GObject *object)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_radio_unref(priv->radio);
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_network_class_init(RilNetworkClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_network_dispose;
|
||||
object_class->finalize = ril_network_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_network_priv));
|
||||
ril_network_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
62
ofono/drivers/ril/ril_network.h
Normal file
62
ofono/drivers/ril/ril_network.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_NETWORK_H
|
||||
#define RIL_NETWORK_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
int status; /* enum network_registration_status */
|
||||
int access_tech; /* enum access_technology or -1 if none */
|
||||
int ril_tech;
|
||||
int max_calls;
|
||||
int lac;
|
||||
int ci;
|
||||
};
|
||||
|
||||
struct ril_network {
|
||||
GObject object;
|
||||
struct ril_network_priv *priv;
|
||||
struct ril_registration_state voice;
|
||||
struct ril_registration_state data;
|
||||
const struct ofono_network_operator *operator;
|
||||
};
|
||||
|
||||
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_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||
|
||||
#endif /* RIL_NETWORK */
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -14,8 +14,11 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_mce.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -42,6 +45,7 @@
|
||||
#define RILMODEM_DEFAULT_4G TRUE /* 4G is on by default */
|
||||
#define RILMODEM_DEFAULT_SLOT 0xffffffff
|
||||
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
|
||||
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
|
||||
|
||||
#define RILCONF_DEV_PREFIX "ril_"
|
||||
#define RILCONF_PATH_PREFIX "/" RILCONF_DEV_PREFIX
|
||||
@@ -51,6 +55,7 @@
|
||||
#define RILCONF_SUB "sub"
|
||||
#define RILCONF_TIMEOUT "timeout"
|
||||
#define RILCONF_4G "enable4G"
|
||||
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
|
||||
|
||||
#define RIL_STORE "ril"
|
||||
#define RIL_STORE_GROUP "Settings"
|
||||
@@ -63,19 +68,20 @@ enum ril_plugin_io_events {
|
||||
IO_EVENT_CONNECTED,
|
||||
IO_EVENT_ERROR,
|
||||
IO_EVENT_EOF,
|
||||
IO_EVENT_SIM_STATUS,
|
||||
IO_EVENT_RADIO_STATE_CHANGED,
|
||||
IO_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_plugin_priv {
|
||||
struct ril_plugin pub;
|
||||
struct ril_plugin_dbus *dbus;
|
||||
struct ril_data_manager *data_manager;
|
||||
GSList *slots;
|
||||
struct ril_modem *data_modem;
|
||||
ril_slot_info_ptr *slots_info;
|
||||
struct ril_slot *data_slot;
|
||||
struct ril_slot *voice_slot;
|
||||
char *default_voice_imsi;
|
||||
char *default_data_imsi;
|
||||
char *default_voice_path;
|
||||
char *default_data_path;
|
||||
GKeyFile *storage;
|
||||
};
|
||||
|
||||
@@ -86,18 +92,23 @@ struct ril_slot {
|
||||
char *name;
|
||||
char *sockpath;
|
||||
char *sub;
|
||||
gint timeout; /* RIL timeout, in seconds */
|
||||
gint timeout; /* RIL timeout, in milliseconds */
|
||||
int index;
|
||||
struct ril_modem_config config;
|
||||
int sim_flags;
|
||||
struct ril_slot_config config;
|
||||
struct ril_plugin_priv *plugin;
|
||||
struct ril_sim_dbus *sim_dbus;
|
||||
struct ril_modem *modem;
|
||||
struct ril_mce *mce;
|
||||
struct ofono_sim *sim;
|
||||
struct ril_radio *radio;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_data *data;
|
||||
GRilIoChannel *io;
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
gulong sim_status_req_id;
|
||||
gulong imei_req_id;
|
||||
gulong sim_card_state_event_id;
|
||||
guint trace_id;
|
||||
guint dump_id;
|
||||
guint retry_id;
|
||||
@@ -108,7 +119,9 @@ struct ril_slot {
|
||||
|
||||
static void ril_debug_trace_notify(struct ofono_debug_desc *desc);
|
||||
static void ril_debug_dump_notify(struct ofono_debug_desc *desc);
|
||||
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
|
||||
static void ril_plugin_retry_init_io(struct ril_slot *slot);
|
||||
static void ril_plugin_update_modem_paths_full(struct ril_plugin_priv *plugin);
|
||||
|
||||
GLOG_MODULE_DEFINE("rilmodem");
|
||||
|
||||
@@ -117,17 +130,29 @@ static struct ofono_debug_desc ril_debug_trace OFONO_DEBUG_ATTR = {
|
||||
.flags = OFONO_DEBUG_FLAG_DEFAULT,
|
||||
.notify = ril_debug_trace_notify
|
||||
};
|
||||
|
||||
static struct ofono_debug_desc ril_debug_dump OFONO_DEBUG_ATTR = {
|
||||
.name = "ril_dump",
|
||||
.flags = OFONO_DEBUG_FLAG_DEFAULT,
|
||||
.notify = ril_debug_dump_notify
|
||||
};
|
||||
|
||||
static inline struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
|
||||
static struct ofono_debug_desc grilio_debug OFONO_DEBUG_ATTR = {
|
||||
.name = "grilio",
|
||||
.flags = OFONO_DEBUG_FLAG_DEFAULT,
|
||||
.notify = ril_debug_grilio_notify
|
||||
};
|
||||
|
||||
static struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
|
||||
{
|
||||
return G_CAST(pub, struct ril_plugin_priv, pub);
|
||||
}
|
||||
|
||||
static gboolean ril_plugin_multisim(struct ril_plugin_priv *plugin)
|
||||
{
|
||||
return plugin->slots && plugin->slots->next;
|
||||
}
|
||||
|
||||
static void ril_plugin_foreach_slot_proc(gpointer data, gpointer user_data)
|
||||
{
|
||||
void (*fn)(struct ril_slot *) = user_data;
|
||||
@@ -160,7 +185,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
|
||||
}
|
||||
|
||||
if (slot->modem) {
|
||||
struct ofono_modem *m = ril_modem_ofono_modem(slot->modem);
|
||||
struct ofono_modem *m = slot->modem->ofono;
|
||||
|
||||
if (m && slot->sim_watch_id) {
|
||||
__ofono_modem_remove_atom_watch(m, slot->sim_watch_id);
|
||||
@@ -188,6 +213,30 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
|
||||
slot->retry_id = 0;
|
||||
}
|
||||
|
||||
if (slot->data) {
|
||||
ril_data_allow(slot->data, FALSE);
|
||||
ril_data_unref(slot->data);
|
||||
slot->data = NULL;
|
||||
}
|
||||
|
||||
if (slot->radio) {
|
||||
ril_radio_unref(slot->radio);
|
||||
slot->radio = NULL;
|
||||
}
|
||||
|
||||
if (slot->network) {
|
||||
ril_network_unref(slot->network);
|
||||
slot->network = NULL;
|
||||
}
|
||||
|
||||
if (slot->sim_card) {
|
||||
ril_sim_card_remove_handler(slot->sim_card,
|
||||
slot->sim_card_state_event_id);
|
||||
ril_sim_card_unref(slot->sim_card);
|
||||
slot->sim_card_state_event_id = 0;
|
||||
slot->sim_card = NULL;
|
||||
}
|
||||
|
||||
if (slot->io) {
|
||||
int i;
|
||||
|
||||
@@ -198,10 +247,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
|
||||
|
||||
grilio_channel_cancel_request(slot->io,
|
||||
slot->imei_req_id, FALSE);
|
||||
grilio_channel_cancel_request(slot->io,
|
||||
slot->sim_status_req_id, FALSE);
|
||||
slot->imei_req_id = 0;
|
||||
slot->sim_status_req_id = 0;
|
||||
|
||||
for (i=0; i<IO_EVENT_COUNT; i++) {
|
||||
ril_plugin_remove_slot_handler(slot, i);
|
||||
@@ -274,57 +320,86 @@ static struct ril_slot *ril_plugin_find_slot_number(GSList *slots, guint number)
|
||||
static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
|
||||
{
|
||||
int mask = 0;
|
||||
struct ril_slot *voice = ril_plugin_find_slot_imsi(plugin->slots,
|
||||
plugin->default_voice_imsi);
|
||||
struct ril_slot *data = ril_plugin_find_slot_imsi(plugin->slots,
|
||||
plugin->default_data_imsi);
|
||||
struct ril_slot *slot = NULL;
|
||||
|
||||
if (!voice) {
|
||||
/* If there's no default voice SIM, find any SIM instead.
|
||||
* One should always be able to make and receive a phone call
|
||||
* if there's a working SIM in the phone. However if the
|
||||
* previously selected voice SIM is inserted, we will switch
|
||||
* back to it. */
|
||||
voice = ril_plugin_find_slot_imsi(plugin->slots, NULL);
|
||||
/* Voice */
|
||||
if (plugin->default_voice_imsi) {
|
||||
slot = ril_plugin_find_slot_imsi(plugin->slots,
|
||||
plugin->default_voice_imsi);
|
||||
} else if (plugin->voice_slot) {
|
||||
/* Make sure that the slot is enabled and SIM is in */
|
||||
slot = ril_plugin_find_slot_imsi(plugin->slots,
|
||||
plugin->voice_slot->modem ?
|
||||
ofono_sim_get_imsi(plugin->voice_slot->sim) :
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (voice) {
|
||||
if (g_strcmp0(plugin->default_voice_path, voice->path)) {
|
||||
DBG("Default voice SIM at %s", voice->path);
|
||||
g_free(plugin->default_voice_path);
|
||||
plugin->default_voice_path = g_strdup(voice->path);
|
||||
mask |= RIL_PLUGIN_SIGNAL_VOICE_PATH;
|
||||
}
|
||||
} else if (plugin->default_voice_path) {
|
||||
DBG("No default voice SIM");
|
||||
g_free(plugin->default_voice_path);
|
||||
plugin->default_voice_path = NULL;
|
||||
/*
|
||||
* If there's no default voice SIM, we will find any SIM instead.
|
||||
* One should always be able to make and receive a phone call
|
||||
* if there's a working SIM in the phone. However if the
|
||||
* previously selected voice SIM is inserted, we will switch
|
||||
* back to it.
|
||||
*
|
||||
* There is no such fallback for the data.
|
||||
*/
|
||||
if (!slot) {
|
||||
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
|
||||
}
|
||||
|
||||
if (plugin->voice_slot != slot) {
|
||||
mask |= RIL_PLUGIN_SIGNAL_VOICE_PATH;
|
||||
plugin->voice_slot = slot;
|
||||
if (slot) {
|
||||
DBG("Default voice SIM at %s", slot->path);
|
||||
plugin->pub.default_voice_path = slot->path;
|
||||
} else {
|
||||
DBG("No default voice SIM");
|
||||
plugin->pub.default_voice_path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
if (g_strcmp0(plugin->default_data_path, data->path)) {
|
||||
DBG("Default data SIM at %s", data->path);
|
||||
g_free(plugin->default_data_path);
|
||||
plugin->default_data_path = g_strdup(data->path);
|
||||
mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
|
||||
}
|
||||
if (plugin->data_modem != data->modem) {
|
||||
plugin->data_modem = data->modem;
|
||||
ril_modem_allow_data(data->modem);
|
||||
}
|
||||
} else if (plugin->default_data_path) {
|
||||
DBG("No default data SIM");
|
||||
g_free(plugin->default_data_path);
|
||||
plugin->default_data_path = NULL;
|
||||
/* Data */
|
||||
if (plugin->default_data_imsi) {
|
||||
slot = ril_plugin_find_slot_imsi(plugin->slots,
|
||||
plugin->default_data_imsi);
|
||||
} else if (plugin->data_slot) {
|
||||
/* Make sure that the slot is enabled and SIM is in */
|
||||
slot = ril_plugin_find_slot_imsi(plugin->slots,
|
||||
plugin->data_slot->modem ?
|
||||
ofono_sim_get_imsi(plugin->data_slot->sim) :
|
||||
NULL);
|
||||
} else {
|
||||
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
|
||||
}
|
||||
|
||||
if (plugin->data_slot != slot) {
|
||||
mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
|
||||
if (plugin->data_slot) {
|
||||
/* Data no longer required for this slot */
|
||||
ril_data_allow(plugin->data_slot->data, FALSE);
|
||||
}
|
||||
plugin->data_slot = slot;
|
||||
if (slot) {
|
||||
DBG("Default data SIM at %s", slot->path);
|
||||
plugin->pub.default_data_path = slot->path;
|
||||
ril_data_allow(slot->data, TRUE);
|
||||
} else {
|
||||
DBG("No default data SIM");
|
||||
plugin->pub.default_data_path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
plugin->pub.default_voice_path = plugin->default_voice_path;
|
||||
plugin->pub.default_data_path = plugin->default_data_path;
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* Update modem paths and emit D-Bus signal if necessary */
|
||||
static void ril_plugin_update_modem_paths_full(struct ril_plugin_priv *plugin)
|
||||
{
|
||||
ril_plugin_dbus_signal(plugin->dbus,
|
||||
ril_plugin_update_modem_paths(plugin));
|
||||
}
|
||||
|
||||
static void ril_plugin_check_sim_state(struct ril_slot *slot)
|
||||
{
|
||||
const char *slot_imsi = ofono_sim_get_imsi(slot->sim);
|
||||
@@ -341,53 +416,25 @@ static void ril_plugin_check_sim_state(struct ril_slot *slot)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_request_sim_status_cb(GRilIoChannel *io, int err,
|
||||
const void *data, guint len, void *user_data)
|
||||
static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
|
||||
{
|
||||
struct ril_slot *slot = user_data;
|
||||
struct ril_slot *slot = data;
|
||||
gboolean present;
|
||||
|
||||
slot->sim_status_req_id = 0;
|
||||
if (err != RIL_E_SUCCESS) {
|
||||
ofono_error("SIM status error %s", ril_error_to_string(err));
|
||||
if (card && card->status &&
|
||||
card->status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
DBG("SIM found in slot %u", slot->config.slot);
|
||||
present = TRUE;
|
||||
} else {
|
||||
GRilIoParser rilp;
|
||||
guint32 cardstate;
|
||||
gboolean present;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &cardstate) &&
|
||||
(cardstate == RIL_CARDSTATE_PRESENT)) {
|
||||
DBG("SIM found in slot %u", slot->config.slot);
|
||||
present = TRUE;
|
||||
} else {
|
||||
DBG("No SIM in slot %u", slot->config.slot);
|
||||
present = FALSE;
|
||||
}
|
||||
|
||||
if (slot->pub.sim_present != present) {
|
||||
slot->pub.sim_present = present;
|
||||
ril_plugin_dbus_signal_sim(slot->plugin->dbus,
|
||||
slot->index, present);
|
||||
}
|
||||
DBG("No SIM in slot %u", slot->config.slot);
|
||||
present = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_request_sim_status(struct ril_slot *slot)
|
||||
{
|
||||
grilio_channel_cancel_request(slot->io, slot->sim_status_req_id, FALSE);
|
||||
slot->sim_status_req_id = grilio_channel_send_request_full(slot->io,
|
||||
NULL, RIL_REQUEST_GET_SIM_STATUS,
|
||||
ril_plugin_request_sim_status_cb, NULL, slot);
|
||||
}
|
||||
|
||||
static void ril_plugin_slot_status_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_slot *slot = user_data;
|
||||
|
||||
DBG("%s", slot->path);
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED);
|
||||
ril_plugin_request_sim_status(slot);
|
||||
if (slot->pub.sim_present != present) {
|
||||
slot->pub.sim_present = present;
|
||||
ril_plugin_dbus_signal_sim(slot->plugin->dbus,
|
||||
slot->index, present);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_sim_watch_done(void *data)
|
||||
@@ -412,8 +459,7 @@ static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
|
||||
DBG("%s sim state %d", slot->path + 1, new_state);
|
||||
slot->sim_state = new_state;
|
||||
ril_plugin_check_sim_state(slot);
|
||||
ril_plugin_dbus_signal(slot->plugin->dbus,
|
||||
ril_plugin_update_modem_paths(slot->plugin));
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
static void ril_plugin_register_sim(struct ril_slot *slot, struct ofono_sim *sim)
|
||||
@@ -443,13 +489,13 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
|
||||
}
|
||||
|
||||
ril_plugin_check_sim_state(slot);
|
||||
ril_plugin_dbus_signal(slot->plugin->dbus,
|
||||
ril_plugin_update_modem_paths(slot->plugin));
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
static void ril_plugin_handle_error(struct ril_slot *slot)
|
||||
{
|
||||
ril_plugin_shutdown_slot(slot, TRUE);
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
ril_plugin_retry_init_io(slot);
|
||||
}
|
||||
|
||||
@@ -478,9 +524,8 @@ static void ril_plugin_modem_removed(struct ril_modem *modem, void *data)
|
||||
}
|
||||
|
||||
slot->modem = NULL;
|
||||
if (slot->plugin->data_modem == modem) {
|
||||
slot->plugin->data_modem = NULL;
|
||||
}
|
||||
ril_data_allow(slot->data, FALSE);
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
||||
@@ -488,12 +533,20 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
|
||||
{
|
||||
/* Use log sub-module to turn prefix off */
|
||||
static GLOG_MODULE_DEFINE2_(log_module, NULL, GLOG_MODULE_NAME);
|
||||
const char *prefix = io->name ? io->name : "";
|
||||
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
|
||||
const char *prefix = io->name ? io->name : "";
|
||||
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
|
||||
const char *scode;
|
||||
|
||||
switch (type) {
|
||||
case GRILIO_PACKET_REQ:
|
||||
if (io->ril_version <= 9 &&
|
||||
code == RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION) {
|
||||
scode = "V9_SET_UICC_SUBSCRIPTION";
|
||||
} else {
|
||||
scode = ril_request_to_string(code);
|
||||
}
|
||||
gutil_log(&log_module, GLOG_LEVEL_INFO, "%s%c [%08x] %s",
|
||||
prefix, dir, id, ril_request_to_string(code));
|
||||
prefix, dir, id, scode);
|
||||
break;
|
||||
case GRILIO_PACKET_RESP:
|
||||
gutil_log(&log_module, GLOG_LEVEL_INFO, "%s%c [%08x] %s",
|
||||
@@ -562,14 +615,14 @@ static void ril_plugin_create_modem(struct ril_slot *slot)
|
||||
GASSERT(slot->io && slot->io->connected);
|
||||
GASSERT(!slot->modem);
|
||||
|
||||
modem = ril_modem_create(slot->io, slot->path + 1, &slot->config);
|
||||
modem = ril_modem_create(slot->io, &slot->pub, slot->radio,
|
||||
slot->network, slot->sim_card, slot->data);
|
||||
|
||||
if (modem) {
|
||||
struct ofono_sim *sim = ril_modem_ofono_sim(modem);
|
||||
|
||||
slot->modem = modem;
|
||||
slot->sim_watch_id = __ofono_modem_add_atom_watch(
|
||||
ril_modem_ofono_modem(modem),
|
||||
slot->sim_watch_id = __ofono_modem_add_atom_watch(modem->ofono,
|
||||
OFONO_ATOM_TYPE_SIM, ril_plugin_sim_watch,
|
||||
slot, ril_plugin_sim_watch_done);
|
||||
if (sim) {
|
||||
@@ -580,6 +633,8 @@ static void ril_plugin_create_modem(struct ril_slot *slot)
|
||||
} else {
|
||||
ril_plugin_shutdown_slot(slot, TRUE);
|
||||
}
|
||||
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
|
||||
@@ -599,6 +654,9 @@ static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
slot->pub.imei = slot->imei = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", slot->imei);
|
||||
if (slot->modem) {
|
||||
ril_modem_set_imei(slot->modem, slot->imei);
|
||||
}
|
||||
} else {
|
||||
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
|
||||
ril_error_to_string(status));
|
||||
@@ -616,9 +674,32 @@ static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It seems to be necessary to kick (with RIL_REQUEST_RADIO_POWER) the
|
||||
* modems with power on after one of the modems has been powered off.
|
||||
* Otherwise bad things may happen (like the modem never registering
|
||||
* on the network).
|
||||
*/
|
||||
static void ril_plugin_power_check(struct ril_slot *slot)
|
||||
{
|
||||
ril_radio_confirm_power_on(slot->radio);
|
||||
}
|
||||
|
||||
static void ril_plugin_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (ril_radio_state_parse(data, len) == RADIO_STATE_OFF) {
|
||||
struct ril_slot *slot = user_data;
|
||||
|
||||
DBG("power off for slot %u", slot->config.slot);
|
||||
ril_plugin_foreach_slot(slot->plugin, ril_plugin_power_check);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_slot_connected(struct ril_slot *slot)
|
||||
{
|
||||
ofono_debug("%s version %u", slot->name, slot->io->ril_version);
|
||||
ofono_debug("%s version %u", (slot->name && slot->name[0]) ?
|
||||
slot->name : "RIL", slot->io->ril_version);
|
||||
|
||||
GASSERT(slot->io->connected);
|
||||
GASSERT(!slot->io_event_id[IO_EVENT_CONNECTED]);
|
||||
@@ -630,7 +711,29 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
|
||||
slot->imei_req_id = grilio_channel_send_request_full(slot->io, NULL,
|
||||
RIL_REQUEST_GET_IMEI, ril_plugin_imei_cb, NULL, slot);
|
||||
|
||||
ril_plugin_request_sim_status(slot);
|
||||
GASSERT(!slot->radio);
|
||||
slot->radio = ril_radio_new(slot->io);
|
||||
slot->network = ril_network_new(slot->io, slot->radio);
|
||||
|
||||
GASSERT(!slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED]);
|
||||
slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(slot->io,
|
||||
ril_plugin_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, slot);
|
||||
|
||||
GASSERT(!slot->sim_card);
|
||||
slot->sim_card = ril_sim_card_new(slot->io, slot->config.slot,
|
||||
slot->sim_flags);
|
||||
slot->sim_card_state_event_id = ril_sim_card_add_state_changed_handler(
|
||||
slot->sim_card, ril_plugin_sim_state_changed, slot);
|
||||
|
||||
GASSERT(!slot->data);
|
||||
slot->data = ril_data_new(slot->plugin->data_manager, slot->io);
|
||||
|
||||
if (ril_plugin_multisim(slot->plugin)) {
|
||||
ril_data_set_name(slot->data, slot->path + 1);
|
||||
}
|
||||
|
||||
if (ril_plugin_can_create_modem(slot) && !slot->modem) {
|
||||
ril_plugin_create_modem(slot);
|
||||
}
|
||||
@@ -664,11 +767,6 @@ static void ril_plugin_init_io(struct ril_slot *slot)
|
||||
slot->io_event_id[IO_EVENT_EOF] =
|
||||
grilio_channel_add_disconnected_handler(slot->io,
|
||||
ril_plugin_slot_disconnected, slot);
|
||||
slot->io_event_id[IO_EVENT_SIM_STATUS] =
|
||||
grilio_channel_add_unsol_event_handler(slot->io,
|
||||
ril_plugin_slot_status_changed,
|
||||
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
|
||||
slot);
|
||||
|
||||
if (slot->io->connected) {
|
||||
ril_plugin_slot_connected(slot);
|
||||
@@ -724,6 +822,7 @@ static GSList *ril_plugin_create_default_config()
|
||||
slot->name = g_strdup("RIL1");
|
||||
slot->config.enable_4g = RILMODEM_DEFAULT_4G;
|
||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||
list = g_slist_append(list, slot);
|
||||
|
||||
slot = g_new0(struct ril_slot, 1);
|
||||
@@ -732,6 +831,7 @@ static GSList *ril_plugin_create_default_config()
|
||||
slot->name = g_strdup("RIL2");
|
||||
slot->config.enable_4g = RILMODEM_DEFAULT_4G;
|
||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||
slot->config.slot = 1;
|
||||
list = g_slist_append(list, slot);
|
||||
} else {
|
||||
@@ -744,6 +844,7 @@ static GSList *ril_plugin_create_default_config()
|
||||
slot->name = g_strdup("");
|
||||
slot->config.enable_4g = RILMODEM_DEFAULT_4G;
|
||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||
list = g_slist_append(list, slot);
|
||||
}
|
||||
} else {
|
||||
@@ -753,6 +854,20 @@ static GSList *ril_plugin_create_default_config()
|
||||
return list;
|
||||
}
|
||||
|
||||
static void ril_plugin_read_config_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags)
|
||||
{
|
||||
GError *err = NULL;
|
||||
|
||||
if (g_key_file_get_boolean(file, group, key, &err)) {
|
||||
*flags |= flag;
|
||||
} else if (!err) {
|
||||
*flags &= ~flag;
|
||||
} else {
|
||||
g_error_free(err);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
const char *group)
|
||||
{
|
||||
@@ -769,6 +884,7 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
slot->path = g_strconcat("/", group, NULL);
|
||||
slot->name = g_key_file_get_string(file, group, RILCONF_NAME,
|
||||
NULL);
|
||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||
|
||||
if (sub && strlen(sub) == RIL_SUB_SIZE) {
|
||||
DBG("%s: %s:%s", group, sock, sub);
|
||||
@@ -812,6 +928,14 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
err = NULL;
|
||||
}
|
||||
DBG("%s: 4G %s", group, slot->config.enable_4g ? "on" : "off");
|
||||
|
||||
ril_plugin_read_config_flag(file, group,
|
||||
RILCONF_UICC_WORKAROUND,
|
||||
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND,
|
||||
&slot->sim_flags);
|
||||
DBG("%s: UICC workaround %s", group, (slot->sim_flags &
|
||||
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND) ?
|
||||
"on" : "off");
|
||||
} else {
|
||||
DBG("no socket path in %s", group);
|
||||
}
|
||||
@@ -972,6 +1096,7 @@ static void ril_plugin_update_disabled_slot(struct ril_slot *slot)
|
||||
if (!slot->pub.enabled) {
|
||||
DBG("%s disabled", slot->path + 1);
|
||||
ril_plugin_shutdown_slot(slot, FALSE);
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,8 +1104,7 @@ static void ril_plugin_update_slots(struct ril_plugin_priv *plugin)
|
||||
{
|
||||
ril_plugin_foreach_slot(plugin, ril_plugin_update_disabled_slot);
|
||||
ril_plugin_foreach_slot(plugin, ril_plugin_update_enabled_slot);
|
||||
ril_plugin_dbus_signal(plugin->dbus,
|
||||
ril_plugin_update_modem_paths(plugin));
|
||||
ril_plugin_update_modem_paths_full(plugin);
|
||||
}
|
||||
|
||||
struct ril_plugin_set_enabled_slots_data {
|
||||
@@ -1101,21 +1225,21 @@ static void ril_plugin_init_slots(struct ril_plugin_priv *plugin)
|
||||
{
|
||||
int i;
|
||||
GSList *link;
|
||||
const struct ril_slot_info **pub =
|
||||
g_new0(const struct ril_slot_info*,
|
||||
ril_slot_info_ptr *info = g_new0(ril_slot_info_ptr,
|
||||
g_slist_length(plugin->slots) + 1);
|
||||
|
||||
plugin->pub.slots = pub;
|
||||
plugin->pub.slots = plugin->slots_info = info;
|
||||
for (i = 0, link = plugin->slots; link; link = link->next, i++) {
|
||||
struct ril_slot *slot = link->data;
|
||||
|
||||
*pub++ = &slot->pub;
|
||||
*info++ = &slot->pub;
|
||||
slot->index = i;
|
||||
slot->plugin = plugin;
|
||||
slot->pub.path = slot->path;
|
||||
slot->pub.config = &slot->config;
|
||||
}
|
||||
|
||||
*pub = NULL;
|
||||
*info = NULL;
|
||||
}
|
||||
|
||||
static void ril_plugin_enable_disable_slot(gpointer data, gpointer user_data)
|
||||
@@ -1145,6 +1269,15 @@ static void ril_debug_dump_notify(struct ofono_debug_desc *desc)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc)
|
||||
{
|
||||
if (desc->flags & OFONO_DEBUG_FLAG_PRINT) {
|
||||
grilio_log.level = GLOG_LEVEL_VERBOSE;
|
||||
} else {
|
||||
grilio_log.level = GLOG_LEVEL_INHERIT;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_plugin_init(void)
|
||||
{
|
||||
char *enabled_slots;
|
||||
@@ -1152,6 +1285,7 @@ static int ril_plugin_init(void)
|
||||
DBG("");
|
||||
GASSERT(!ril_plugin);
|
||||
|
||||
/* ofono core calls openlog() */
|
||||
gutil_log_func = gutil_log_syslog;
|
||||
|
||||
ril_plugin_switch_user();
|
||||
@@ -1160,6 +1294,7 @@ static int ril_plugin_init(void)
|
||||
ril_plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE);
|
||||
ril_plugin_init_slots(ril_plugin);
|
||||
ril_plugin->dbus = ril_plugin_dbus_new(&ril_plugin->pub);
|
||||
ril_plugin->data_manager = ril_data_manager_new();
|
||||
|
||||
if (ril_plugin->slots) {
|
||||
/*
|
||||
@@ -1257,12 +1392,11 @@ static void ril_plugin_exit(void)
|
||||
if (ril_plugin) {
|
||||
g_slist_free_full(ril_plugin->slots, ril_plugin_destroy_slot);
|
||||
ril_plugin_dbus_free(ril_plugin->dbus);
|
||||
ril_data_manager_unref(ril_plugin->data_manager);
|
||||
g_key_file_free(ril_plugin->storage);
|
||||
g_free(ril_plugin->pub.slots);
|
||||
g_free(ril_plugin->slots_info);
|
||||
g_free(ril_plugin->default_voice_imsi);
|
||||
g_free(ril_plugin->default_data_imsi);
|
||||
g_free(ril_plugin->default_voice_path);
|
||||
g_free(ril_plugin->default_data_path);
|
||||
g_free(ril_plugin);
|
||||
ril_plugin = NULL;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -42,14 +42,21 @@
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#define RILMODEM_DRIVER "ril"
|
||||
#define RIL_RETRY_SECS (2)
|
||||
#define MAX_SIM_STATUS_RETRIES (15)
|
||||
|
||||
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;
|
||||
gboolean enabled;
|
||||
gboolean sim_present;
|
||||
const struct ril_slot_config *config;
|
||||
};
|
||||
|
||||
struct ril_plugin {
|
||||
@@ -57,13 +64,18 @@ struct ril_plugin {
|
||||
const char *default_data_imsi;
|
||||
const char *default_voice_path;
|
||||
const char *default_data_path;
|
||||
const struct ril_slot_info **slots;
|
||||
const ril_slot_info_ptr *slots;
|
||||
};
|
||||
|
||||
struct ril_modem_config {
|
||||
guint slot;
|
||||
gboolean enable_4g;
|
||||
const char *default_name;
|
||||
struct ril_modem {
|
||||
GRilIoChannel *io;
|
||||
const char *imei;
|
||||
struct ofono_modem *ofono;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_slot_config config;
|
||||
};
|
||||
|
||||
#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
|
||||
@@ -72,8 +84,6 @@ struct ril_modem_config {
|
||||
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x10)
|
||||
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x20)
|
||||
|
||||
struct ril_modem;
|
||||
struct ril_plugin_dbus;
|
||||
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
|
||||
|
||||
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
|
||||
@@ -94,22 +104,22 @@ void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
|
||||
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
|
||||
gboolean present);
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *dev,
|
||||
const struct ril_modem_config *config);
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io,
|
||||
const struct ril_slot_info *slot, struct ril_radio *radio,
|
||||
struct ril_network *network, struct ril_sim_card *card,
|
||||
struct ril_data *data);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
void ril_modem_allow_data(struct ril_modem *modem);
|
||||
GRilIoChannel *ril_modem_io(struct ril_modem *modem);
|
||||
const struct ril_modem_config *ril_modem_config(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);
|
||||
struct ofono_modem *ril_modem_ofono_modem(struct ril_modem *modem);
|
||||
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
|
||||
void *data);
|
||||
|
||||
#define ril_modem_slot(md) (ril_modem_config(modem)->slot)
|
||||
#define ril_modem_4g_enabled(md) (ril_modem_config(modem)->enable_4g)
|
||||
#define ril_modem_get_path(md) ofono_modem_get_path(ril_modem_ofono_modem(md))
|
||||
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
|
||||
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
|
||||
#define ril_modem_slot(modem) ((modem)->config.slot)
|
||||
#define ril_modem_io(modem) ((modem)->io)
|
||||
|
||||
void ril_sim_read_file_linear(struct ofono_sim *sim, int fileid,
|
||||
int record, int length, const unsigned char *path,
|
||||
@@ -125,9 +135,7 @@ void ril_sim_read_file_info(struct ofono_sim *sim, int fileid,
|
||||
ofono_sim_file_info_cb_t cb, void *data);
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim);
|
||||
int ril_gprs_ril_data_tech(struct ofono_gprs *gprs);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
|
||||
gint status);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
|
||||
|
||||
extern const struct ofono_call_barring_driver ril_call_barring_driver;
|
||||
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
|
||||
|
||||
405
ofono/drivers/ril/ril_radio.c
Normal file
405
ofono/drivers/ril/ril_radio.c
Normal file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
typedef GObjectClass RilRadioClass;
|
||||
typedef struct ril_radio RilRadio;
|
||||
|
||||
/*
|
||||
* Object states:
|
||||
*
|
||||
* 1. Idle (!pending && !retry)
|
||||
* 2. Power on/off request pending (pending)
|
||||
* 3. Power on retry has been scheduled (retry)
|
||||
*/
|
||||
struct ril_radio_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gulong state_event_id;
|
||||
char *log_prefix;
|
||||
GHashTable *req_table;
|
||||
guint pending_id;
|
||||
guint retry_id;
|
||||
guint state_changed_while_request_pending;
|
||||
enum ril_radio_state last_known_state;
|
||||
gboolean power_cycle;
|
||||
gboolean next_state_valid;
|
||||
gboolean next_state;
|
||||
};
|
||||
|
||||
enum ril_radio_signal {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define POWER_RETRY_SECS (1)
|
||||
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
|
||||
|
||||
static guint ril_radio_signals[SIGNAL_COUNT] = { 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)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
return g_hash_table_size(priv->req_table) && !priv->power_cycle;
|
||||
}
|
||||
|
||||
G_INLINE_FUNC 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)
|
||||
{
|
||||
return !ril_radio_state_off(radio_state);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_radio_cancel_retry(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->retry_id) {
|
||||
DBG("%sretry cancelled", priv->log_prefix);
|
||||
g_source_remove(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_check_state(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (!priv->pending_id) {
|
||||
const gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
if (ril_radio_state_on(self->priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
/* All is good, cancel pending retry if there is one */
|
||||
ril_radio_cancel_retry(self);
|
||||
} else if (priv->state_changed_while_request_pending) {
|
||||
/* Hmm... RIL's reaction was inadequate, repeat */
|
||||
ril_radio_submit_power_request(self, should_be_on);
|
||||
} else if (!priv->retry_id) {
|
||||
/* There has been no reaction so far, wait a bit */
|
||||
DBG("%sretry scheduled", priv->log_prefix);
|
||||
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
|
||||
ril_radio_power_request_retry_cb, self);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't update public state while something is pending */
|
||||
if (!priv->pending_id && !priv->retry_id &&
|
||||
self->state != priv->last_known_state) {
|
||||
DBG("%s%s -> %s", priv->log_prefix,
|
||||
ril_radio_state_to_string(self->state),
|
||||
ril_radio_state_to_string(priv->last_known_state));
|
||||
self->state = priv->last_known_state;
|
||||
g_signal_emit(self, ril_radio_signals[SIGNAL_STATE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
priv->pending_id = 0;
|
||||
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("Power request failed: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
if (priv->next_state_valid) {
|
||||
ril_radio_submit_power_request(self, priv->next_state);
|
||||
} else {
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
|
||||
|
||||
priv->next_state_valid = FALSE;
|
||||
priv->next_state = on;
|
||||
priv->state_changed_while_request_pending = 0;
|
||||
ril_radio_cancel_retry(self);
|
||||
|
||||
GASSERT(!priv->pending_id);
|
||||
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||
gboolean allow_repeat)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
const char *on_off = on ? "on" : "off";
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (allow_repeat || priv->next_state != on) {
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = on;
|
||||
DBG("%s%s (queued)", priv->log_prefix, on_off);
|
||||
} else {
|
||||
DBG("%s%s (ignored)", priv->log_prefix, on_off);
|
||||
}
|
||||
} else {
|
||||
DBG("%s%s", priv->log_prefix, on_off);
|
||||
ril_radio_submit_power_request(self, on);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_confirm_power_on(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_cycle(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (ril_radio_state_off(priv->last_known_state)) {
|
||||
DBG("%spower is already off", priv->log_prefix);
|
||||
GASSERT(!priv->power_cycle);
|
||||
} else if (priv->power_cycle) {
|
||||
DBG("%salready in progress", priv->log_prefix);
|
||||
} else {
|
||||
DBG("%sinitiated", priv->log_prefix);
|
||||
priv->power_cycle = TRUE;
|
||||
if (!priv->pending_id) {
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
const gboolean was_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
g_hash_table_insert(priv->req_table, tag, tag);
|
||||
if (!was_on) {
|
||||
ril_radio_power_request(self, TRUE, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s%p", priv->log_prefix, tag);
|
||||
if (g_hash_table_remove(priv->req_table, tag) &&
|
||||
!ril_radio_power_should_be_on(self)) {
|
||||
/* The last one turns the lights off */
|
||||
ril_radio_power_request(self, FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int radio_state;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &radio_state)) {
|
||||
return radio_state;
|
||||
} else {
|
||||
ofono_error("Error parsing radio state");
|
||||
return RADIO_STATE_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
|
||||
if (radio_state != RADIO_STATE_UNAVAILABLE) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s%s", priv->log_prefix,
|
||||
ril_radio_state_to_string(radio_state));
|
||||
GASSERT(!priv->pending_id || !priv->retry_id);
|
||||
|
||||
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
|
||||
DBG("%sswitched off for power cycle", priv->log_prefix);
|
||||
priv->power_cycle = FALSE;
|
||||
}
|
||||
|
||||
if (priv->pending_id) {
|
||||
priv->state_changed_while_request_pending++;
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io)
|
||||
{
|
||||
struct ril_radio *self = g_object_new(RIL_RADIO_TYPE, NULL);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->log_prefix =
|
||||
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
|
||||
g_strconcat(io->name, " ", NULL) : g_strdup("");
|
||||
DBG("%s", priv->log_prefix);
|
||||
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_RADIO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_unref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_RADIO(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_init(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_RADIO_TYPE, struct ril_radio_priv);
|
||||
self->priv = priv;
|
||||
priv->req_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static void ril_radio_dispose(GObject *object)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->state_event_id) {
|
||||
grilio_channel_remove_handler(priv->io, priv->state_event_id);
|
||||
priv->state_event_id = 0;
|
||||
}
|
||||
if (priv->pending_id) {
|
||||
grilio_queue_cancel_request(priv->q, priv->pending_id, FALSE);
|
||||
priv->pending_id = 0;
|
||||
}
|
||||
priv->next_state_valid = FALSE;
|
||||
ril_radio_cancel_retry(self);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_radio_finalize(GObject *object)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
g_hash_table_unref(priv->req_table);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_radio_class_init(RilRadioClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_radio_dispose;
|
||||
object_class->finalize = ril_radio_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
50
ofono/drivers/ril/ril_radio.h
Normal file
50
ofono/drivers/ril/ril_radio.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_RADIO_H
|
||||
#define RIL_RADIO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_radio {
|
||||
GObject object;
|
||||
struct ril_radio_priv *priv;
|
||||
enum ril_radio_state state;
|
||||
};
|
||||
|
||||
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io);
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *radio);
|
||||
void ril_radio_unref(struct ril_radio *radio);
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_confirm_power_on(struct ril_radio *radio);
|
||||
void ril_radio_power_cycle(struct ril_radio *radio);
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
|
||||
|
||||
#endif /* RIL_RADIO */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -18,12 +18,13 @@
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "storage.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 timer_id;
|
||||
guint query_rats_id;
|
||||
};
|
||||
|
||||
struct ril_radio_settings_cbd {
|
||||
@@ -31,14 +32,12 @@ struct ril_radio_settings_cbd {
|
||||
union _ofono_radio_settings_cb {
|
||||
ofono_radio_settings_rat_mode_set_cb_t rat_mode_set;
|
||||
ofono_radio_settings_rat_mode_query_cb_t rat_mode_query;
|
||||
ofono_radio_settings_available_rats_query_cb_t available_rats;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define RIL_STORE "rilmodem"
|
||||
#define LTE_FLAG "4gOn"
|
||||
|
||||
#define ril_radio_settings_cbd_free g_free
|
||||
|
||||
static inline struct ril_radio_settings *ril_radio_settings_get_data(
|
||||
@@ -59,6 +58,45 @@ static struct ril_radio_settings_cbd *ril_radio_settings_cbd_new(
|
||||
return cbd;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -78,112 +116,74 @@ static void ril_radio_settings_set_rat_mode_cb(GRilIoChannel *io, int status,
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("rat mode setting failed");
|
||||
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;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
int pref = rsd->ratmode;
|
||||
int pref = ril_radio_settings_mode_to_pref(rsd, mode);
|
||||
GRilIoRequest *req;
|
||||
|
||||
ofono_info("rat mode set %d", mode);
|
||||
switch (mode) {
|
||||
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; /* per UI design */
|
||||
break;
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
pref = PREF_NET_TYPE_LTE_ONLY;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, pref);
|
||||
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);
|
||||
}
|
||||
|
||||
static void ril_radio_settings_force_rat(struct ril_radio_settings *rsd,
|
||||
int pref)
|
||||
{
|
||||
if (pref != rsd->ratmode) {
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
DBG("pref ril rat mode %d, ril current %d", pref, rsd->ratmode);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, rsd->ratmode);
|
||||
grilio_queue_send_request(rsd->q, req,
|
||||
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_rat_mode_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *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;
|
||||
|
||||
DBG("");
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
int pref = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &pref);
|
||||
|
||||
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;
|
||||
break;
|
||||
case PREF_NET_TYPE_GSM_WCDMA_AUTO:/* according to UI design */
|
||||
if (!cb) {
|
||||
ril_radio_settings_force_rat(cbd->rsd, 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_radio_settings_force_rat(cbd->rsd, 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:
|
||||
break;
|
||||
}
|
||||
|
||||
ofono_info("rat mode %d (ril %d)", mode, pref);
|
||||
if (cb) {
|
||||
cb(ril_error_ok(&error), mode, cbd->data);
|
||||
}
|
||||
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 {
|
||||
ofono_error("rat mode query failed");
|
||||
if (cb) {
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
@@ -191,61 +191,78 @@ static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
ofono_info("rat mode query");
|
||||
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);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_get_config(struct ril_radio_settings *rsd)
|
||||
static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
|
||||
{
|
||||
gboolean needsconfig = FALSE;
|
||||
gboolean value = FALSE;
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = data;
|
||||
guint rats = OFONO_RADIO_ACCESS_MODE_GSM | OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
|
||||
/* Hmm... One file shared by all modems... Why?? */
|
||||
|
||||
GKeyFile *keyfile = storage_open(NULL, RIL_STORE);
|
||||
char **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;
|
||||
if (cbd->rsd->enable_4g) {
|
||||
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
}
|
||||
|
||||
g_strfreev(alreadyset);
|
||||
storage_close(NULL, RIL_STORE, keyfile, TRUE);
|
||||
|
||||
DBG("needsconfig %d, rat mode %d", needsconfig, rsd->ratmode);
|
||||
return needsconfig;
|
||||
GASSERT(cbd->rsd->query_rats_id);
|
||||
cbd->rsd->query_rats_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
static void ril_radio_settings_query_available_rats(
|
||||
struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
rsd->timer_id = 0;
|
||||
ofono_radio_settings_register(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);
|
||||
}
|
||||
|
||||
if (ril_radio_settings_get_config(rsd)) {
|
||||
ril_radio_settings_submit_request(rsd, NULL,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
ril_radio_settings_query_rat_mode_cb, NULL, NULL);
|
||||
static void ril_radio_settings_init_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *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);
|
||||
}
|
||||
|
||||
/* Single shot */
|
||||
return FALSE;
|
||||
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);
|
||||
}
|
||||
|
||||
ofono_radio_settings_register(rsd->rs);
|
||||
}
|
||||
|
||||
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
@@ -255,37 +272,39 @@ static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
|
||||
|
||||
DBG("");
|
||||
rsd->rs = rs;
|
||||
rsd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
rsd->ratmode = ril_modem_4g_enabled(modem) ?
|
||||
PREF_NET_TYPE_LTE_GSM_WCDMA :
|
||||
PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
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->timer_id = g_idle_add(ril_radio_settings_register, rs);
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
{
|
||||
struct ril_radio_settings *rd = ril_radio_settings_get_data(rs);
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG("");
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
if (rd->timer_id > 0) {
|
||||
g_source_remove(rd->timer_id);
|
||||
if (rsd->query_rats_id > 0) {
|
||||
g_source_remove(rsd->query_rats_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(rd->q, FALSE);
|
||||
grilio_queue_unref(rd->q);
|
||||
g_free(rd);
|
||||
grilio_queue_cancel_all(rsd->q, FALSE);
|
||||
grilio_queue_unref(rsd->q);
|
||||
g_free(rsd);
|
||||
}
|
||||
|
||||
const struct ofono_radio_settings_driver ril_radio_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.query_rat_mode = ril_radio_settings_query_rat_mode,
|
||||
.set_rat_mode = ril_radio_settings_set_rat_mode,
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.query_rat_mode = ril_radio_settings_query_rat_mode,
|
||||
.set_rat_mode = ril_radio_settings_set_rat_mode,
|
||||
.query_available_rats = ril_radio_settings_query_available_rats
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
532
ofono/drivers/ril/ril_sim_card.c
Normal file
532
ofono/drivers/ril/ril_sim_card.c
Normal file
@@ -0,0 +1,532 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
typedef GObjectClass RilSimCardClass;
|
||||
typedef struct ril_sim_card RilSimCard;
|
||||
|
||||
enum ril_sim_card_event {
|
||||
EVENT_SIM_STATUS_CHANGED,
|
||||
EVENT_UICC_SUBSCRIPTION_STATUS_CHANGED,
|
||||
EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_card_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
int flags;
|
||||
guint status_req_id;
|
||||
gulong event_id[EVENT_COUNT];
|
||||
};
|
||||
|
||||
enum ril_sim_card_signal {
|
||||
SIGNAL_STATUS_RECEIVED,
|
||||
SIGNAL_STATUS_CHANGED,
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_APP_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
|
||||
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
|
||||
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
|
||||
|
||||
static guint ril_sim_card_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
|
||||
#define RIL_SIMCARD_TYPE (ril_sim_card_get_type())
|
||||
#define RIL_SIMCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_SIMCARD_TYPE, RilSimCard))
|
||||
|
||||
#define RIL_SIMCARD_STATE_CHANGED (0x01)
|
||||
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self);
|
||||
|
||||
static gboolean ril_sim_card_app_equal(const struct ril_sim_card_app *a1,
|
||||
const struct ril_sim_card_app *a2)
|
||||
{
|
||||
if (a1 == a2) {
|
||||
return TRUE;
|
||||
} else if (!a1 || !a2) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return a1->app_type == a2->app_type &&
|
||||
a1->app_state == a2->app_state &&
|
||||
a1->perso_substate == a2->perso_substate &&
|
||||
a1->pin_replaced == a2->pin_replaced &&
|
||||
a1->pin1_state == a2->pin1_state &&
|
||||
a1->pin2_state == a2->pin2_state &&
|
||||
!g_strcmp0(a1->aid, a2->aid) &&
|
||||
!g_strcmp0(a1->label, a2->label);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_sim_card_status_compare(const struct ril_sim_card_status *s1,
|
||||
const struct ril_sim_card_status *s2)
|
||||
{
|
||||
if (s1 == s2) {
|
||||
return 0;
|
||||
} else if (!s1 || !s2) {
|
||||
return RIL_SIMCARD_STATE_CHANGED | RIL_SIMCARD_STATUS_CHANGED;
|
||||
} else {
|
||||
int diff = 0;
|
||||
|
||||
if (s1->card_state != s2->card_state) {
|
||||
diff |= RIL_SIMCARD_STATE_CHANGED;
|
||||
}
|
||||
|
||||
if (s1->pin_state != s2->pin_state ||
|
||||
s1->gsm_umts_index != s2->gsm_umts_index ||
|
||||
s1->cdma_index != s2->cdma_index ||
|
||||
s1->ims_index != s2->ims_index ||
|
||||
s1->num_apps != s2->num_apps) {
|
||||
diff |= RIL_SIMCARD_STATUS_CHANGED;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s1->num_apps; i++) {
|
||||
if (!ril_sim_card_app_equal(s1->apps + i,
|
||||
s2->apps + i)) {
|
||||
diff |= RIL_SIMCARD_STATUS_CHANGED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_status_free(struct ril_sim_card_status *status)
|
||||
{
|
||||
if (status) {
|
||||
if (status->apps) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < status->num_apps; i++) {
|
||||
g_free(status->apps[i].aid);
|
||||
g_free(status->apps[i].label);
|
||||
}
|
||||
g_free(status->apps);
|
||||
}
|
||||
g_free(status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self,
|
||||
int app_index, int sub_status)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||
const guint sub_id = self->slot;
|
||||
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_status);
|
||||
grilio_request_append_int32(req, self->slot);
|
||||
grilio_request_append_int32(req, app_index);
|
||||
grilio_request_append_int32(req, sub_id);
|
||||
grilio_request_append_int32(req, sub_status);
|
||||
grilio_queue_send_request(priv->q, req, (priv->io->ril_version <= 9 &&
|
||||
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
|
||||
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
|
||||
RIL_REQUEST_SET_UICC_SUBSCRIPTION);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
|
||||
{
|
||||
int selected_app = -1;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < status->num_apps; i++) {
|
||||
const int type = status->apps[i].app_type;
|
||||
if (type == RIL_APPTYPE_USIM || type == RIL_APPTYPE_RUIM) {
|
||||
selected_app = i;
|
||||
break;
|
||||
} else if (type != RIL_APPTYPE_UNKNOWN && selected_app == -1) {
|
||||
selected_app = i;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("%d", selected_app);
|
||||
return selected_app;
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
{
|
||||
const struct ril_sim_card_app *old_app = self->app;
|
||||
const struct ril_sim_card_status *status = self->status;
|
||||
int app_index;
|
||||
|
||||
if (status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
if (status->gsm_umts_index >= 0 &&
|
||||
status->gsm_umts_index < status->num_apps) {
|
||||
app_index = status->gsm_umts_index;
|
||||
} else {
|
||||
app_index = ril_sim_card_select_app(status);
|
||||
if (app_index >= 0) {
|
||||
ril_sim_card_subscribe(self, app_index, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app_index = -1;
|
||||
}
|
||||
|
||||
if (app_index >= 0 &&
|
||||
status->apps[app_index].app_type != RIL_APPTYPE_UNKNOWN) {
|
||||
self->app = status->apps + app_index;
|
||||
} else {
|
||||
self->app = NULL;
|
||||
}
|
||||
|
||||
if (!ril_sim_card_app_equal(old_app, self->app)) {
|
||||
g_signal_emit(self,
|
||||
ril_sim_card_signals[SIGNAL_APP_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
struct ril_sim_card_status *status)
|
||||
{
|
||||
const int diff = ril_sim_card_status_compare(self->status, status);
|
||||
|
||||
if (diff) {
|
||||
struct ril_sim_card_status *old_status = self->status;
|
||||
|
||||
self->status = status;
|
||||
ril_sim_card_update_app(self);
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_RECEIVED], 0);
|
||||
if (diff & RIL_SIMCARD_STATUS_CHANGED) {
|
||||
DBG("status changed");
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_CHANGED], 0);
|
||||
}
|
||||
if (diff & RIL_SIMCARD_STATE_CHANGED) {
|
||||
DBG("state changed");
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATE_CHANGED], 0);
|
||||
}
|
||||
ril_sim_card_status_free(old_status);
|
||||
} else {
|
||||
ril_sim_card_status_free(status);
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_RECEIVED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_card_app_parse(GRilIoParser *rilp,
|
||||
struct ril_sim_card_app *app)
|
||||
{
|
||||
gint32 app_type, app_state, perso_substate;
|
||||
gint32 pin_replaced, pin1_state, pin2_state;
|
||||
|
||||
grilio_parser_get_int32(rilp, &app_type);
|
||||
grilio_parser_get_int32(rilp, &app_state);
|
||||
|
||||
/*
|
||||
* Consider RIL_APPSTATE_ILLEGAL also READY. Even if app state is
|
||||
* RIL_APPSTATE_ILLEGAL (-1), ICC operations must be permitted.
|
||||
* Network access requests will anyway be rejected and ME will be
|
||||
* in limited service.
|
||||
*/
|
||||
if (app_state == RIL_APPSTATE_ILLEGAL) {
|
||||
DBG("RIL_APPSTATE_ILLEGAL => RIL_APPSTATE_READY");
|
||||
app_state = RIL_APPSTATE_READY;
|
||||
}
|
||||
|
||||
grilio_parser_get_int32(rilp, &perso_substate);
|
||||
app->aid = grilio_parser_get_utf8(rilp);
|
||||
app->label = grilio_parser_get_utf8(rilp);
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &pin_replaced) &&
|
||||
grilio_parser_get_int32(rilp, &pin1_state) &&
|
||||
grilio_parser_get_int32(rilp, &pin2_state)) {
|
||||
|
||||
app->app_type = app_type;
|
||||
app->app_state = app_state;
|
||||
app->perso_substate = perso_substate;
|
||||
app->pin_replaced = pin_replaced;
|
||||
app->pin1_state = pin1_state;
|
||||
app->pin2_state = pin2_state;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
gint32 card_state, pin_state, gsm_umts_index, cdma_index;
|
||||
gint32 ims_index, num_apps;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
if (!grilio_parser_get_int32(&rilp, &card_state) ||
|
||||
!grilio_parser_get_int32(&rilp, &pin_state) ||
|
||||
!grilio_parser_get_int32(&rilp, &gsm_umts_index) ||
|
||||
!grilio_parser_get_int32(&rilp, &cdma_index) ||
|
||||
!grilio_parser_get_int32(&rilp, &ims_index) ||
|
||||
!grilio_parser_get_int32(&rilp, &num_apps)) {
|
||||
ofono_error("Failed to parse SIM card status request");
|
||||
return NULL;
|
||||
} else if (num_apps < 0 || num_apps > RIL_CARD_MAX_APPS) {
|
||||
ofono_error("Invalid SIM app count %d", num_apps);
|
||||
return NULL;
|
||||
} else {
|
||||
int i;
|
||||
struct ril_sim_card_status *status =
|
||||
g_new0(struct ril_sim_card_status, 1);
|
||||
|
||||
DBG("card_state=%d, universal_pin_state=%d, gsm_umts_index=%d, "
|
||||
"cdma_index=%d, ims_index=%d, num_apps=%d",
|
||||
card_state, pin_state, gsm_umts_index, cdma_index,
|
||||
ims_index, num_apps);
|
||||
|
||||
status->card_state = card_state;
|
||||
status->pin_state = pin_state;
|
||||
status->gsm_umts_index = gsm_umts_index;
|
||||
status->cdma_index = cdma_index;
|
||||
status->ims_index = ims_index;
|
||||
status->num_apps = num_apps;
|
||||
|
||||
if (num_apps > 0) {
|
||||
status->apps = g_new0(struct ril_sim_card_app, num_apps);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_apps; i++) {
|
||||
struct ril_sim_card_app *app = status->apps + i;
|
||||
|
||||
if (ril_sim_card_app_parse(&rilp, app)) {
|
||||
DBG("app[%d]: type=%d, state=%d, "
|
||||
"perso_substate=%d, aid_ptr=%s, "
|
||||
"label=%s, pin1_replaced=%d, pin1=%d, "
|
||||
"pin2=%d", i, app->app_type,
|
||||
app->app_state, app->perso_substate,
|
||||
app->aid, app->label,
|
||||
app->pin_replaced, app->pin1_state,
|
||||
app->pin2_state);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == num_apps) {
|
||||
return status;
|
||||
} else {
|
||||
ril_sim_card_status_free(status);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_card *self = user_data;
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->status_req_id);
|
||||
priv->status_req_id = 0;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
struct ril_sim_card_status *status =
|
||||
ril_sim_card_status_parse(data, len);
|
||||
|
||||
if (status) {
|
||||
ril_sim_card_update_status(self, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->status_req_id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, priv->status_req_id);
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->status_req_id = grilio_queue_send_request_full(priv->q,
|
||||
req, RIL_REQUEST_GET_SIM_STATUS,
|
||||
ril_sim_card_status_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_card *self = user_data;
|
||||
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags)
|
||||
{
|
||||
struct ril_sim_card *self = g_object_new(RIL_SIMCARD_TYPE, NULL);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* We need to know the RIL version (for UICC subscription hack),
|
||||
* so we must be connected. The caller is supposed to make sure
|
||||
* that we get connected first.
|
||||
*/
|
||||
DBG("%u", slot);
|
||||
GASSERT(io->connected);
|
||||
|
||||
self->slot = slot;
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(io);
|
||||
priv->flags = flags;
|
||||
|
||||
priv->event_id[EVENT_SIM_STATUS_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_sim_card_status_changed,
|
||||
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, self);
|
||||
priv->event_id[EVENT_UICC_SUBSCRIPTION_STATUS_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_sim_card_status_changed,
|
||||
RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, self);
|
||||
ril_sim_card_request_status(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIMCARD(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_unref(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIMCARD(self));
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATUS_RECEIVED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_status_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATUS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_APP_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_init(struct ril_sim_card *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIMCARD_TYPE,
|
||||
struct ril_sim_card_priv);
|
||||
}
|
||||
|
||||
static void ril_sim_card_dispose(GObject *object)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(object);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, priv->event_id, EVENT_COUNT);
|
||||
grilio_queue_cancel_all(priv->q, TRUE);
|
||||
G_OBJECT_CLASS(ril_sim_card_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_sim_card_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(object);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_sim_card_status_free(self->status);
|
||||
G_OBJECT_CLASS(ril_sim_card_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_card_class_init(RilSimCardClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_sim_card_dispose;
|
||||
object_class->finalize = ril_sim_card_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_card_priv));
|
||||
ril_sim_card_signals[SIGNAL_STATUS_RECEIVED] =
|
||||
g_signal_new(SIGNAL_STATUS_RECEIVED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_STATUS_CHANGED] =
|
||||
g_signal_new(SIGNAL_STATUS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_STATE_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_APP_CHANGED] =
|
||||
g_signal_new(SIGNAL_APP_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
81
ofono/drivers/ril/ril_sim_card.h
Normal file
81
ofono/drivers/ril/ril_sim_card.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_SIM_CARD_H
|
||||
#define RIL_SIM_CARD_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_sim_card_app {
|
||||
enum ril_app_type app_type;
|
||||
enum ril_app_state app_state;
|
||||
enum ril_perso_substate perso_substate;
|
||||
char *aid;
|
||||
char *label;
|
||||
guint pin_replaced;
|
||||
enum ril_pin_state pin1_state;
|
||||
enum ril_pin_state pin2_state;
|
||||
};
|
||||
|
||||
struct ril_sim_card_status {
|
||||
enum ril_card_state card_state;
|
||||
enum ril_pin_state pin_state;
|
||||
int gsm_umts_index;
|
||||
int cdma_index;
|
||||
int ims_index;
|
||||
int num_apps;
|
||||
struct ril_sim_card_app *apps;
|
||||
};
|
||||
|
||||
struct ril_sim_card {
|
||||
GObject object;
|
||||
struct ril_sim_card_priv *priv;
|
||||
struct ril_sim_card_status *status;
|
||||
const struct ril_sim_card_app *app;
|
||||
guint slot;
|
||||
};
|
||||
|
||||
typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
||||
|
||||
/* Flags for ril_sim_card_new */
|
||||
#define RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND (0x01)
|
||||
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_unref(struct ril_sim_card *sc);
|
||||
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
gulong ril_sim_card_add_status_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
|
||||
|
||||
/* Inline wrappers */
|
||||
G_INLINE_FUNC enum ril_app_type
|
||||
ril_sim_card_app_type(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
|
||||
|
||||
#endif /* RIL_SIM_CARD_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -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,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
@@ -174,7 +173,7 @@ struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *md)
|
||||
|
||||
if (imsi) {
|
||||
GError *error = NULL;
|
||||
const struct ril_modem_config *config= ril_modem_config(md);
|
||||
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));
|
||||
@@ -204,7 +203,7 @@ struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *md)
|
||||
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(ril_modem_ofono_modem(md),
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_SIM_DBUS_INTERFACE);
|
||||
return dbus;
|
||||
} else {
|
||||
@@ -222,7 +221,7 @@ void ril_sim_dbus_free(struct ril_sim_dbus *dbus)
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_SIM_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(ril_modem_ofono_modem(dbus->md),
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_SIM_DBUS_INTERFACE);
|
||||
dbus_connection_unref(dbus->conn);
|
||||
g_key_file_free(dbus->storage);
|
||||
|
||||
55
ofono/drivers/ril/ril_subscription.conf
Normal file
55
ofono/drivers/ril/ril_subscription.conf
Normal file
@@ -0,0 +1,55 @@
|
||||
# This is a sample configuration file for the 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.
|
||||
#
|
||||
|
||||
[ril_0]
|
||||
|
||||
# Required entry, defines the RIL socket path
|
||||
socket=/dev/socket/rild
|
||||
|
||||
# Subscription string. Some (mostly, older) RILs require that 4 bytes
|
||||
# (usually SUB1 or SUB2) are written to the socket before rild starts
|
||||
# talking to us.
|
||||
#
|
||||
# Not sent by default.
|
||||
#
|
||||
#sub=SUB1
|
||||
|
||||
# RIL logging prefix, to tell one socket from another in the log.
|
||||
# Makes sense if you have more than one modem configured.
|
||||
#
|
||||
# No prefix by default.
|
||||
#
|
||||
#name=RIL1
|
||||
|
||||
# Slot id for SET_UICC_SUBSCRIPTION request.
|
||||
#
|
||||
# By default the first modem becomes slot 0, the next one slot 1 and so on.
|
||||
#
|
||||
#slot=0
|
||||
|
||||
# RIL request timeout, in milliseconds.
|
||||
#
|
||||
# The default is zero (no timeout)
|
||||
#
|
||||
#timeout=0
|
||||
|
||||
# Setting this one to false would disable 4G technology selection.
|
||||
#
|
||||
# By default 4G is enabled
|
||||
#
|
||||
#enable4G=true
|
||||
|
||||
# RIL_REQUEST_SET_UICC_SUBSCRIPTION is 115 in RIL version 9 (or earlier)
|
||||
# and 122 in RIL version 10 and later. Since ofono doesn't know in advance
|
||||
# which RIL version it's dealing with, it makes the decision at runtime.
|
||||
# Settings it to false disables the workaround and always sends 122.
|
||||
#
|
||||
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
|
||||
#
|
||||
#uiccWorkaround=true
|
||||
@@ -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,14 +22,29 @@
|
||||
|
||||
#include <grilio_types.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ril_constants.h"
|
||||
|
||||
#define RIL_RETRY_SECS (2)
|
||||
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
|
||||
|
||||
struct ril_data;
|
||||
struct ril_modem;
|
||||
struct ril_radio;
|
||||
struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_plugin_dbus;
|
||||
|
||||
#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
|
||||
@@ -15,15 +15,14 @@
|
||||
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "netreg.h"
|
||||
|
||||
const char *ril_error_to_string(int error)
|
||||
{
|
||||
@@ -300,86 +299,6 @@ int ril_address_family(const char *addr)
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_util_parse_reg(const void *data, guint len,
|
||||
struct ril_reg_data *reg)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int nparams;
|
||||
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
|
||||
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
|
||||
|
||||
memset(reg, 0, sizeof(*reg));
|
||||
|
||||
/* Size of response string array
|
||||
*
|
||||
* Should be:
|
||||
* >= 4 for VOICE_REG reply
|
||||
* >= 5 for DATA_REG reply
|
||||
*/
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (!grilio_parser_get_int32(&rilp, &nparams) || nparams < 4) {
|
||||
DBG("broken response");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sstatus = grilio_parser_get_utf8(&rilp);
|
||||
if (!sstatus) {
|
||||
DBG("No sstatus value returned!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
slac = grilio_parser_get_utf8(&rilp);
|
||||
sci = grilio_parser_get_utf8(&rilp);
|
||||
stech = grilio_parser_get_utf8(&rilp);
|
||||
nparams -= 4;
|
||||
|
||||
reg->ril_status = atoi(sstatus);
|
||||
if (reg->ril_status > 10) {
|
||||
reg->status = reg->ril_status - 10;
|
||||
} else {
|
||||
reg->status = reg->ril_status;
|
||||
}
|
||||
|
||||
/* 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 (nparams--) {
|
||||
/* TODO: different use for CDMA */
|
||||
sreason = grilio_parser_get_utf8(&rilp);
|
||||
if (nparams--) {
|
||||
/* TODO: different use for CDMA */
|
||||
smax = grilio_parser_get_utf8(&rilp);
|
||||
if (smax) {
|
||||
reg->max_calls = atoi(smax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
|
||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG("%s,%s,%s,%d,%s,%s,%s", registration_status_to_string(reg->status),
|
||||
slac, sci, reg->ril_tech,
|
||||
registration_tech_to_string(reg->access_tech),
|
||||
sreason, smax);
|
||||
|
||||
g_free(sstatus);
|
||||
g_free(slac);
|
||||
g_free(sci);
|
||||
g_free(stech);
|
||||
g_free(sreason);
|
||||
g_free(smax);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Returns enum access_technology or -1 on failure. */
|
||||
int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
@@ -406,7 +325,6 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
break;
|
||||
case RADIO_TECH_HSPA:
|
||||
case RADIO_TECH_HSPAP:
|
||||
case RADIO_TECH_DC_HSDPA:
|
||||
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_LTE:
|
||||
@@ -415,6 +333,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
default:
|
||||
DBG("Unknown RIL tech %s", stech);
|
||||
/* no break */
|
||||
case RADIO_TECH_IWLAN:
|
||||
case RADIO_TECH_UNKNOWN:
|
||||
tech = -1;
|
||||
break;
|
||||
@@ -427,6 +346,50 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
return access_tech;
|
||||
}
|
||||
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
{
|
||||
if (str) {
|
||||
int i;
|
||||
const char *ptr = str;
|
||||
|
||||
/* Three digit country code */
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MCC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mcc[i] = *ptr++;
|
||||
}
|
||||
op->mcc[i] = 0;
|
||||
|
||||
if (i == OFONO_MAX_MCC_LENGTH) {
|
||||
/* Usually 2 but sometimes 3 digit network code */
|
||||
for (i=0;
|
||||
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mnc[i] = *ptr++;
|
||||
}
|
||||
op->mnc[i] = 0;
|
||||
|
||||
if (i > 0) {
|
||||
|
||||
/*
|
||||
* Sometimes MCC/MNC are followed by + and
|
||||
* what looks like the technology code. This
|
||||
* is of course completely undocumented.
|
||||
*/
|
||||
if (*ptr == '+') {
|
||||
int tech = ril_parse_tech(ptr+1, NULL);
|
||||
if (tech >= 0) {
|
||||
op->tech = tech;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -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
|
||||
@@ -18,17 +18,7 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
struct ril_reg_data {
|
||||
int ril_status;
|
||||
int ril_tech;
|
||||
int status; /* enum network_registration_status or -1 if none */
|
||||
int access_tech; /* enum access_technology or -1 if none */
|
||||
int lac;
|
||||
int ci;
|
||||
int max_calls;
|
||||
};
|
||||
struct ofono_network_operator;
|
||||
|
||||
const char *ril_error_to_string(int error);
|
||||
const char *ril_request_to_string(guint request);
|
||||
@@ -36,8 +26,7 @@ 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_util_parse_reg(const void *data, guint len,
|
||||
struct ril_reg_data *parsed);
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
@@ -175,6 +175,24 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Valid call statuses have value >= 0 */
|
||||
static int call_status_with_id(struct ofono_voicecall *vc, int id)
|
||||
{
|
||||
GSList *l;
|
||||
struct voicecall *v;
|
||||
|
||||
GASSERT(vc);
|
||||
|
||||
for (l = vc->call_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
if (v->call->id == id) {
|
||||
return v->call->status;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -182,6 +200,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_voicecall *vc = reqdata->vc;
|
||||
int tmp;
|
||||
int id = reqdata->id;
|
||||
int call_status;
|
||||
|
||||
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
|
||||
@@ -197,32 +216,54 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
* protocols", Annex H, are properly reflected in the RIL API.
|
||||
* For example, cause #21 "call rejected" is mapped to
|
||||
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
|
||||
* from a network failure. We signal disconnect reason "remote"
|
||||
* for cause values
|
||||
* - #16 "normal call clearing"
|
||||
* - #17 "user busy"
|
||||
* - UNSPECIFIED for MO calls that are not yet connected
|
||||
* , and disconnect reason "network" otherwise.
|
||||
* from a network failure.
|
||||
*/
|
||||
ofono_info("Call %d ended with RIL cause %d", id, last_cause);
|
||||
if (last_cause == CALL_FAIL_NORMAL || last_cause == CALL_FAIL_BUSY) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
switch (last_cause) {
|
||||
case CALL_FAIL_UNOBTAINABLE_NUMBER:
|
||||
case CALL_FAIL_NORMAL:
|
||||
case CALL_FAIL_BUSY:
|
||||
case CALL_FAIL_NO_ROUTE_TO_DESTINATION:
|
||||
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
|
||||
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
|
||||
case CALL_FAIL_NO_USER_RESPONDING:
|
||||
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
|
||||
case CALL_FAIL_CALL_REJECTED:
|
||||
case CALL_FAIL_NUMBER_CHANGED:
|
||||
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
|
||||
case CALL_FAIL_PRE_EMPTION:
|
||||
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
|
||||
case CALL_FAIL_INCOMPLETE_NUMBER:
|
||||
case CALL_FAIL_FACILITY_REJECTED:
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
break;
|
||||
|
||||
case CALL_FAIL_NORMAL_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_ACTIVE ||
|
||||
call_status == CALL_STATUS_HELD ||
|
||||
call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
} else if (call_status == CALL_STATUS_INCOMING) {
|
||||
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
|
||||
}
|
||||
break;
|
||||
|
||||
case CALL_FAIL_ERROR_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (last_cause == CALL_FAIL_ERROR_UNSPECIFIED) {
|
||||
GSList *l;
|
||||
struct voicecall *v;
|
||||
for (l = vc->call_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
if (v->call->id == id) {
|
||||
if (v->call->status == CALL_STATUS_DIALING ||
|
||||
v->call->status == CALL_STATUS_ALERTING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
|
||||
id, last_cause, reason);
|
||||
|
||||
ofono_voicecall_disconnected(vc, id, reason, NULL);
|
||||
}
|
||||
|
||||
@@ -128,9 +128,8 @@ static void bt_connect(struct dundee_device *device,
|
||||
if (status == 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
struct dundee_device_driver bluetooth_driver = {
|
||||
|
||||
@@ -583,7 +583,7 @@ static void have_line(struct at_chat *p, char *str)
|
||||
return;
|
||||
|
||||
/* Check for echo, this should not happen, but lets be paranoid */
|
||||
if (!strncmp(str, "AT", 2) == TRUE)
|
||||
if (!strncmp(str, "AT", 2))
|
||||
goto done;
|
||||
|
||||
cmd = g_queue_peek_head(p->command_queue);
|
||||
@@ -1135,6 +1135,29 @@ static gboolean at_chat_cancel_group(struct at_chat *chat, guint group)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gpointer at_chat_get_userdata(struct at_chat *chat,
|
||||
guint group, guint id)
|
||||
{
|
||||
GList *l;
|
||||
struct at_command *c;
|
||||
|
||||
if (chat->command_queue == NULL)
|
||||
return NULL;
|
||||
|
||||
l = g_queue_find_custom(chat->command_queue, GUINT_TO_POINTER(id),
|
||||
at_command_compare_by_id);
|
||||
|
||||
if (l == NULL)
|
||||
return NULL;
|
||||
|
||||
c = l->data;
|
||||
|
||||
if (c->gid != group)
|
||||
return NULL;
|
||||
|
||||
return c->user_data;
|
||||
}
|
||||
|
||||
static guint at_chat_register(struct at_chat *chat, guint group,
|
||||
const char *prefix, GAtNotifyFunc func,
|
||||
gboolean expect_pdu, gpointer user_data,
|
||||
@@ -1540,6 +1563,14 @@ gboolean g_at_chat_cancel_all(GAtChat *chat)
|
||||
return at_chat_cancel_group(chat->parent, chat->group);
|
||||
}
|
||||
|
||||
gpointer g_at_chat_get_userdata(GAtChat *chat, guint id)
|
||||
{
|
||||
if (chat == NULL)
|
||||
return NULL;
|
||||
|
||||
return at_chat_get_userdata(chat->parent, chat->group, id);
|
||||
}
|
||||
|
||||
guint g_at_chat_register(GAtChat *chat, const char *prefix,
|
||||
GAtNotifyFunc func, gboolean expect_pdu,
|
||||
gpointer user_data,
|
||||
|
||||
@@ -150,6 +150,8 @@ guint g_at_chat_send_and_expect_short_prompt(GAtChat *chat, const char *cmd,
|
||||
gboolean g_at_chat_cancel(GAtChat *chat, guint id);
|
||||
gboolean g_at_chat_cancel_all(GAtChat *chat);
|
||||
|
||||
gpointer g_at_chat_get_userdata(GAtChat *chat, guint id);
|
||||
|
||||
guint g_at_chat_register(GAtChat *chat, const char *prefix,
|
||||
GAtNotifyFunc func, gboolean expect_pdu,
|
||||
gpointer user_data, GDestroyNotify notify);
|
||||
|
||||
@@ -64,10 +64,10 @@ gboolean ppp_net_set_mtu(struct ppp_net *net, guint16 mtu)
|
||||
return FALSE;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, net->if_name, sizeof(ifr.ifr_name));
|
||||
strncpy(ifr.ifr_name, net->if_name, IFNAMSIZ - 1);
|
||||
ifr.ifr_mtu = mtu;
|
||||
|
||||
err = ioctl(sk, SIOCSIFMTU, (caddr_t) &ifr);
|
||||
err = ioctl(sk, SIOCSIFMTU, (void *) &ifr);
|
||||
|
||||
close(sk);
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ struct GDBusClient {
|
||||
DBusConnection *dbus_conn;
|
||||
char *service_name;
|
||||
char *base_path;
|
||||
char *root_path;
|
||||
guint watch;
|
||||
guint added_watch;
|
||||
guint removed_watch;
|
||||
@@ -1107,7 +1108,11 @@ static void get_managed_objects(GDBusClient *client)
|
||||
{
|
||||
DBusMessage *msg;
|
||||
|
||||
if (!client->proxy_added && !client->proxy_removed) {
|
||||
if (!client->connected)
|
||||
return;
|
||||
|
||||
if ((!client->proxy_added && !client->proxy_removed) ||
|
||||
!client->root_path) {
|
||||
refresh_properties(client);
|
||||
return;
|
||||
}
|
||||
@@ -1115,9 +1120,10 @@ static void get_managed_objects(GDBusClient *client)
|
||||
if (client->get_objects_call != NULL)
|
||||
return;
|
||||
|
||||
msg = dbus_message_new_method_call(client->service_name, "/",
|
||||
DBUS_INTERFACE_DBUS ".ObjectManager",
|
||||
"GetManagedObjects");
|
||||
msg = dbus_message_new_method_call(client->service_name,
|
||||
client->root_path,
|
||||
DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"GetManagedObjects");
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
@@ -1142,13 +1148,13 @@ static void service_connect(DBusConnection *conn, void *user_data)
|
||||
|
||||
g_dbus_client_ref(client);
|
||||
|
||||
client->connected = TRUE;
|
||||
|
||||
if (client->connect_func)
|
||||
client->connect_func(conn, client->connect_data);
|
||||
|
||||
get_managed_objects(client);
|
||||
|
||||
client->connected = TRUE;
|
||||
|
||||
g_dbus_client_unref(client);
|
||||
}
|
||||
|
||||
@@ -1156,13 +1162,13 @@ static void service_disconnect(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
GDBusClient *client = user_data;
|
||||
|
||||
client->connected = FALSE;
|
||||
|
||||
g_list_free_full(client->proxy_list, proxy_free);
|
||||
client->proxy_list = NULL;
|
||||
|
||||
if (client->disconn_func) {
|
||||
if (client->disconn_func)
|
||||
client->disconn_func(conn, client->disconn_data);
|
||||
client->connected = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static DBusHandlerResult message_filter(DBusConnection *connection,
|
||||
@@ -1195,11 +1201,19 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
|
||||
|
||||
GDBusClient *g_dbus_client_new(DBusConnection *connection,
|
||||
const char *service, const char *path)
|
||||
{
|
||||
return g_dbus_client_new_full(connection, service, path, "/");
|
||||
}
|
||||
|
||||
GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
|
||||
const char *service,
|
||||
const char *path,
|
||||
const char *root_path)
|
||||
{
|
||||
GDBusClient *client;
|
||||
unsigned int i;
|
||||
|
||||
if (connection == NULL)
|
||||
if (!connection || !service)
|
||||
return NULL;
|
||||
|
||||
client = g_try_new0(GDBusClient, 1);
|
||||
@@ -1215,6 +1229,7 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
|
||||
client->dbus_conn = dbus_connection_ref(connection);
|
||||
client->service_name = g_strdup(service);
|
||||
client->base_path = g_strdup(path);
|
||||
client->root_path = g_strdup(root_path);
|
||||
client->connected = FALSE;
|
||||
|
||||
client->match_rules = g_ptr_array_sized_new(1);
|
||||
@@ -1224,14 +1239,18 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
|
||||
service_connect,
|
||||
service_disconnect,
|
||||
client, NULL);
|
||||
|
||||
if (!root_path)
|
||||
return g_dbus_client_ref(client);
|
||||
|
||||
client->added_watch = g_dbus_add_signal_watch(connection, service,
|
||||
"/",
|
||||
client->root_path,
|
||||
DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesAdded",
|
||||
interfaces_added,
|
||||
client, NULL);
|
||||
client->removed_watch = g_dbus_add_signal_watch(connection, service,
|
||||
"/",
|
||||
client->root_path,
|
||||
DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesRemoved",
|
||||
interfaces_removed,
|
||||
@@ -1305,6 +1324,7 @@ void g_dbus_client_unref(GDBusClient *client)
|
||||
|
||||
g_free(client->service_name);
|
||||
g_free(client->base_path);
|
||||
g_free(client->root_path);
|
||||
|
||||
g_free(client);
|
||||
}
|
||||
@@ -1371,7 +1391,8 @@ gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
|
||||
client->property_changed = property_changed;
|
||||
client->user_data = user_data;
|
||||
|
||||
get_managed_objects(client);
|
||||
if (proxy_added || proxy_removed || property_changed)
|
||||
get_managed_objects(client);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -216,6 +216,7 @@ struct GDBusSecurityTable {
|
||||
.flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL
|
||||
|
||||
void g_dbus_set_flags(int flags);
|
||||
int g_dbus_get_flags(void);
|
||||
|
||||
gboolean g_dbus_register_interface(DBusConnection *connection,
|
||||
const char *path, const char *name,
|
||||
@@ -355,6 +356,10 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
|
||||
|
||||
GDBusClient *g_dbus_client_new(DBusConnection *connection,
|
||||
const char *service, const char *path);
|
||||
GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
|
||||
const char *service,
|
||||
const char *path,
|
||||
const char *root_path);
|
||||
|
||||
GDBusClient *g_dbus_client_ref(GDBusClient *client);
|
||||
void g_dbus_client_unref(GDBusClient *client);
|
||||
|
||||
@@ -322,6 +322,7 @@ DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
|
||||
return NULL;
|
||||
|
||||
if (setup_bus(conn, name, error) == FALSE) {
|
||||
dbus_connection_close(conn);
|
||||
dbus_connection_unref(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1412,7 +1412,10 @@ DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
|
||||
{
|
||||
char str[1024];
|
||||
|
||||
vsnprintf(str, sizeof(str), format, args);
|
||||
if (format)
|
||||
vsnprintf(str, sizeof(str), format, args);
|
||||
else
|
||||
str[0] = '\0';
|
||||
|
||||
return dbus_message_new_error(message, name, str);
|
||||
}
|
||||
@@ -1530,11 +1533,8 @@ gboolean g_dbus_send_error_valist(DBusConnection *connection,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
DBusMessage *error;
|
||||
char str[1024];
|
||||
|
||||
vsnprintf(str, sizeof(str), format, args);
|
||||
|
||||
error = dbus_message_new_error(message, name, str);
|
||||
error = g_dbus_create_error_valist(message, name, format, args);
|
||||
if (error == NULL)
|
||||
return FALSE;
|
||||
|
||||
@@ -1816,3 +1816,8 @@ void g_dbus_set_flags(int flags)
|
||||
{
|
||||
global_flags = flags;
|
||||
}
|
||||
|
||||
int g_dbus_get_flags(void)
|
||||
{
|
||||
return global_flags;
|
||||
}
|
||||
|
||||
@@ -523,7 +523,7 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
|
||||
member = dbus_message_get_member(message);
|
||||
dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
|
||||
|
||||
/* Sender is always the owner */
|
||||
/* If sender != NULL it is always the owner */
|
||||
|
||||
for (current = listeners; current != NULL; current = current->next) {
|
||||
data = current->data;
|
||||
@@ -531,19 +531,24 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
|
||||
if (connection != data->connection)
|
||||
continue;
|
||||
|
||||
if (data->owner && g_strcmp0(sender, data->owner) != 0)
|
||||
if (!sender && data->owner)
|
||||
continue;
|
||||
|
||||
if (data->path && g_strcmp0(path, data->path) != 0)
|
||||
if (data->owner && g_str_equal(sender, data->owner) == FALSE)
|
||||
continue;
|
||||
|
||||
if (data->interface && g_strcmp0(iface, data->interface) != 0)
|
||||
if (data->path && g_str_equal(path, data->path) == FALSE)
|
||||
continue;
|
||||
|
||||
if (data->member && g_strcmp0(member, data->member) != 0)
|
||||
if (data->interface && g_str_equal(iface,
|
||||
data->interface) == FALSE)
|
||||
continue;
|
||||
|
||||
if (data->argument && g_strcmp0(arg, data->argument) != 0)
|
||||
if (data->member && g_str_equal(member, data->member) == FALSE)
|
||||
continue;
|
||||
|
||||
if (data->argument && g_str_equal(arg,
|
||||
data->argument) == FALSE)
|
||||
continue;
|
||||
|
||||
if (data->handle_func) {
|
||||
|
||||
@@ -101,6 +101,8 @@ struct ofono_modem *ofono_gprs_context_get_modem(struct ofono_gprs_context *gc);
|
||||
|
||||
void ofono_gprs_context_set_type(struct ofono_gprs_context *gc,
|
||||
enum ofono_gprs_context_type type);
|
||||
enum ofono_gprs_context_type ofono_gprs_context_get_type(
|
||||
struct ofono_gprs_context *gc);
|
||||
|
||||
void ofono_gprs_context_set_interface(struct ofono_gprs_context *gc,
|
||||
const char *interface);
|
||||
|
||||
@@ -61,6 +61,8 @@ void ofono_gprs_suspend_notify(struct ofono_gprs *gprs, int cause);
|
||||
void ofono_gprs_resume_notify(struct ofono_gprs *gprs);
|
||||
void ofono_gprs_bearer_notify(struct ofono_gprs *gprs, int bearer);
|
||||
|
||||
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs);
|
||||
|
||||
int ofono_gprs_driver_register(const struct ofono_gprs_driver *d);
|
||||
void ofono_gprs_driver_unregister(const struct ofono_gprs_driver *d);
|
||||
|
||||
@@ -78,7 +80,6 @@ void ofono_gprs_set_cid_range(struct ofono_gprs *gprs,
|
||||
void ofono_gprs_add_context(struct ofono_gprs *gprs,
|
||||
struct ofono_gprs_context *gc);
|
||||
|
||||
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs);
|
||||
ofono_bool_t ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -41,6 +41,7 @@ struct ofono_handsfree_card_driver {
|
||||
void (*connect)(struct ofono_handsfree_card *card,
|
||||
ofono_handsfree_card_connect_cb_t cb,
|
||||
void *data);
|
||||
void (*sco_connected_hint)(struct ofono_handsfree_card *card);
|
||||
};
|
||||
|
||||
struct ofono_handsfree_card *ofono_handsfree_card_create(unsigned int vendor,
|
||||
|
||||
@@ -133,6 +133,9 @@ void ofono_radio_settings_remove(struct ofono_radio_settings *rs);
|
||||
void ofono_radio_settings_set_data(struct ofono_radio_settings *rs, void *data);
|
||||
void *ofono_radio_settings_get_data(struct ofono_radio_settings *rs);
|
||||
|
||||
struct ofono_modem *ofono_radio_settings_get_modem(
|
||||
struct ofono_radio_settings *rs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -83,6 +83,12 @@ struct ofono_error {
|
||||
#define OFONO_MAX_PHONE_NUMBER_LENGTH 80
|
||||
#define OFONO_MAX_CALLER_NAME_LENGTH 80
|
||||
|
||||
/* Number types, 3GPP TS 24.008 subclause 10.5.4.7, octect 3 */
|
||||
/* Unknown, ISDN numbering plan */
|
||||
#define OFONO_NUMBER_TYPE_UNKNOWN 129
|
||||
/* International, ISDN numbering plan */
|
||||
#define OFONO_NUMBER_TYPE_INTERNATIONAL 145
|
||||
|
||||
struct ofono_phone_number {
|
||||
char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 1];
|
||||
int type;
|
||||
|
||||
@@ -52,23 +52,25 @@
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
static int tc65_probe(struct ofono_modem *modem)
|
||||
#include <drivers/atmodem/vendor.h>
|
||||
|
||||
static int cinterion_probe(struct ofono_modem *modem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tc65_remove(struct ofono_modem *modem)
|
||||
static void cinterion_remove(struct ofono_modem *modem)
|
||||
{
|
||||
}
|
||||
|
||||
static void tc65_debug(const char *str, void *user_data)
|
||||
static void cinterion_debug(const char *str, void *user_data)
|
||||
{
|
||||
const char *prefix = user_data;
|
||||
|
||||
ofono_info("%s%s", prefix, str);
|
||||
}
|
||||
|
||||
static int tc65_enable(struct ofono_modem *modem)
|
||||
static int cinterion_enable(struct ofono_modem *modem)
|
||||
{
|
||||
GAtChat *chat;
|
||||
GIOChannel *channel;
|
||||
@@ -102,7 +104,10 @@ static int tc65_enable(struct ofono_modem *modem)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* TC65 works almost as the 27.007 says. But for example after
|
||||
* (Cinterion plugin is based on tc65 plugin. Comment left in but may
|
||||
* not be applicable in the general case)
|
||||
*
|
||||
* TC65 works almost as the 27.007 says. But for example after
|
||||
* AT+CRSM the modem replies with the data in the queried EF and
|
||||
* writes three pairs of <CR><LF> after the data and before OK.
|
||||
*/
|
||||
@@ -116,14 +121,14 @@ static int tc65_enable(struct ofono_modem *modem)
|
||||
return -ENOMEM;
|
||||
|
||||
if (getenv("OFONO_AT_DEBUG"))
|
||||
g_at_chat_set_debug(chat, tc65_debug, "");
|
||||
g_at_chat_set_debug(chat, cinterion_debug, "");
|
||||
|
||||
ofono_modem_set_data(modem, chat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc65_disable(struct ofono_modem *modem)
|
||||
static int cinterion_disable(struct ofono_modem *modem)
|
||||
{
|
||||
GAtChat *chat = ofono_modem_get_data(modem);
|
||||
|
||||
@@ -149,7 +154,7 @@ static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void tc65_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
static void cinterion_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *user_data)
|
||||
{
|
||||
GAtChat *chat = ofono_modem_get_data(modem);
|
||||
@@ -161,12 +166,12 @@ static void tc65_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
if (g_at_chat_send(chat, command, NULL, set_online_cb, cbd, g_free))
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void tc65_pre_sim(struct ofono_modem *modem)
|
||||
static void cinterion_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
GAtChat *chat = ofono_modem_get_data(modem);
|
||||
struct ofono_sim *sim;
|
||||
@@ -181,7 +186,7 @@ static void tc65_pre_sim(struct ofono_modem *modem)
|
||||
ofono_sim_inserted_notify(sim, TRUE);
|
||||
}
|
||||
|
||||
static void tc65_post_sim(struct ofono_modem *modem)
|
||||
static void cinterion_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
GAtChat *chat = ofono_modem_get_data(modem);
|
||||
|
||||
@@ -192,7 +197,7 @@ static void tc65_post_sim(struct ofono_modem *modem)
|
||||
ofono_sms_create(modem, 0, "atmodem", chat);
|
||||
}
|
||||
|
||||
static void tc65_post_online(struct ofono_modem *modem)
|
||||
static void cinterion_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
GAtChat *chat = ofono_modem_get_data(modem);
|
||||
struct ofono_message_waiting *mw;
|
||||
@@ -204,7 +209,7 @@ static void tc65_post_online(struct ofono_modem *modem)
|
||||
ofono_ussd_create(modem, 0, "atmodem", chat);
|
||||
ofono_call_forwarding_create(modem, 0, "atmodem", chat);
|
||||
ofono_call_settings_create(modem, 0, "atmodem", chat);
|
||||
ofono_netreg_create(modem, 0, "atmodem", chat);
|
||||
ofono_netreg_create(modem, OFONO_VENDOR_CINTERION, "atmodem", chat);
|
||||
ofono_call_meter_create(modem, 0, "atmodem", chat);
|
||||
ofono_call_barring_create(modem, 0, "atmodem", chat);
|
||||
|
||||
@@ -219,27 +224,27 @@ static void tc65_post_online(struct ofono_modem *modem)
|
||||
ofono_message_waiting_register(mw);
|
||||
}
|
||||
|
||||
static struct ofono_modem_driver tc65_driver = {
|
||||
.name = "tc65",
|
||||
.probe = tc65_probe,
|
||||
.remove = tc65_remove,
|
||||
.enable = tc65_enable,
|
||||
.disable = tc65_disable,
|
||||
.set_online = tc65_set_online,
|
||||
.pre_sim = tc65_pre_sim,
|
||||
.post_sim = tc65_post_sim,
|
||||
.post_online = tc65_post_online,
|
||||
static struct ofono_modem_driver cinterion_driver = {
|
||||
.name = "cinterion",
|
||||
.probe = cinterion_probe,
|
||||
.remove = cinterion_remove,
|
||||
.enable = cinterion_enable,
|
||||
.disable = cinterion_disable,
|
||||
.set_online = cinterion_set_online,
|
||||
.pre_sim = cinterion_pre_sim,
|
||||
.post_sim = cinterion_post_sim,
|
||||
.post_online = cinterion_post_online,
|
||||
};
|
||||
|
||||
static int tc65_init(void)
|
||||
static int cinterion_init(void)
|
||||
{
|
||||
return ofono_modem_driver_register(&tc65_driver);
|
||||
return ofono_modem_driver_register(&cinterion_driver);
|
||||
}
|
||||
|
||||
static void tc65_exit(void)
|
||||
static void cinterion_exit(void)
|
||||
{
|
||||
ofono_modem_driver_unregister(&tc65_driver);
|
||||
ofono_modem_driver_unregister(&cinterion_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(tc65, "Cinterion TC65 driver plugin", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, tc65_init, tc65_exit)
|
||||
OFONO_PLUGIN_DEFINE(cinterion, "Cinterion driver plugin", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, cinterion_init, cinterion_exit)
|
||||
@@ -70,6 +70,7 @@ struct hfp {
|
||||
struct hfp_slc_info info;
|
||||
DBusMessage *msg;
|
||||
struct ofono_handsfree_card *card;
|
||||
unsigned int bcc_id;
|
||||
};
|
||||
|
||||
static const char *none_prefix[] = { NULL };
|
||||
@@ -373,8 +374,12 @@ static void bcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_handsfree_card_connect_cb_t cb = cbd->cb;
|
||||
struct ofono_handsfree_card *card = cbd->user;
|
||||
struct hfp *hfp = ofono_handsfree_card_get_data(card);
|
||||
struct ofono_error error;
|
||||
|
||||
hfp->bcc_id = 0;
|
||||
|
||||
decode_at_error(&error, g_at_result_final_response(result));
|
||||
|
||||
cb(&error, cbd->data);
|
||||
@@ -391,7 +396,10 @@ static void hfp16_card_connect(struct ofono_handsfree_card *card,
|
||||
info->ag_features & HFP_AG_FEATURE_CODEC_NEGOTIATION) {
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
|
||||
g_at_chat_send(info->chat, "AT+BCC", NULL, bcc_cb, cbd, g_free);
|
||||
cbd->user = card;
|
||||
hfp->bcc_id = g_at_chat_send(info->chat, "AT+BCC",
|
||||
none_prefix, bcc_cb,
|
||||
cbd, g_free);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -404,11 +412,40 @@ static void hfp16_card_connect(struct ofono_handsfree_card *card,
|
||||
ofono_handsfree_card_connect_sco(card);
|
||||
}
|
||||
|
||||
static void hfp16_sco_connected_hint(struct ofono_handsfree_card *card)
|
||||
{
|
||||
struct hfp *hfp = ofono_handsfree_card_get_data(card);
|
||||
struct hfp_slc_info *info = &hfp->info;
|
||||
struct cb_data *cbd;
|
||||
ofono_handsfree_card_connect_cb_t cb;
|
||||
|
||||
/*
|
||||
* SCO has just been connected, probably initiated by the AG.
|
||||
* If we have any outstanding BCC requests, then lets cancel these
|
||||
* as they're no longer needed
|
||||
*/
|
||||
|
||||
if (hfp->bcc_id == 0)
|
||||
return;
|
||||
|
||||
cbd = g_at_chat_get_userdata(info->chat, hfp->bcc_id);
|
||||
if (cbd == NULL)
|
||||
return;
|
||||
|
||||
cb = cbd->cb;
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
|
||||
/* cbd will be freed once cancel is processed */
|
||||
g_at_chat_cancel(info->chat, hfp->bcc_id);
|
||||
hfp->bcc_id = 0;
|
||||
}
|
||||
|
||||
static struct ofono_handsfree_card_driver hfp16_hf_driver = {
|
||||
.name = HFP16_HF_DRIVER,
|
||||
.probe = hfp16_card_probe,
|
||||
.remove = hfp16_card_remove,
|
||||
.connect = hfp16_card_connect,
|
||||
.name = HFP16_HF_DRIVER,
|
||||
.probe = hfp16_card_probe,
|
||||
.remove = hfp16_card_remove,
|
||||
.connect = hfp16_card_connect,
|
||||
.sco_connected_hint = hfp16_sco_connected_hint,
|
||||
};
|
||||
|
||||
static ofono_bool_t device_path_compare(struct ofono_modem *modem,
|
||||
@@ -702,8 +739,17 @@ static void modem_register_from_proxy(GDBusProxy *proxy, const char *path)
|
||||
return;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &paired);
|
||||
if (paired == FALSE)
|
||||
|
||||
if (paired == FALSE) {
|
||||
modem = ofono_modem_find(device_path_compare, (void *) path);
|
||||
|
||||
if (modem != NULL) {
|
||||
ofono_modem_remove(modem);
|
||||
g_dbus_proxy_set_removed_watch(proxy, NULL, NULL);
|
||||
g_dbus_proxy_set_property_watch(proxy, NULL, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
|
||||
return;
|
||||
|
||||
@@ -204,7 +204,7 @@ static void reachable_cb(const GIsiMessage *msg, void *data)
|
||||
struct ofono_modem *om = data;
|
||||
struct isi_data *isi = ofono_modem_get_data(om);
|
||||
|
||||
if (!g_isi_msg_error(msg) < 0)
|
||||
if (g_isi_msg_error(msg) < 0)
|
||||
return;
|
||||
|
||||
ISI_RESOURCE_DBG(msg);
|
||||
|
||||
@@ -238,7 +238,7 @@ static void mtc_reachable_cb(const GIsiMessage *msg, void *data)
|
||||
struct ofono_modem *modem = data;
|
||||
struct isi_data *isi = ofono_modem_get_data(modem);
|
||||
|
||||
if (!g_isi_msg_error(msg) < 0)
|
||||
if (g_isi_msg_error(msg) < 0)
|
||||
return;
|
||||
|
||||
ISI_RESOURCE_DBG(msg);
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#define PUSH_NOTIFICATION_INTERFACE "org.ofono.PushNotification"
|
||||
#define AGENT_INTERFACE "org.ofono.PushNotificationAgent"
|
||||
|
||||
#define WAP_PUSH_SRC_PORT 9200
|
||||
#define WAP_PUSH_SRC_PORT -1
|
||||
#define WAP_PUSH_DST_PORT 2948
|
||||
|
||||
static unsigned int modemwatch_id;
|
||||
@@ -50,21 +50,16 @@ struct push_notification {
|
||||
struct ofono_modem *modem;
|
||||
struct ofono_sms *sms;
|
||||
struct sms_agent *agent;
|
||||
unsigned int push_watch[2];
|
||||
unsigned int push_watch;
|
||||
};
|
||||
|
||||
static void agent_exited(void *userdata)
|
||||
{
|
||||
struct push_notification *pn = userdata;
|
||||
|
||||
if (pn->push_watch[0] > 0) {
|
||||
__ofono_sms_datagram_watch_remove(pn->sms, pn->push_watch[0]);
|
||||
pn->push_watch[0] = 0;
|
||||
}
|
||||
|
||||
if (pn->push_watch[1] > 0) {
|
||||
__ofono_sms_datagram_watch_remove(pn->sms, pn->push_watch[1]);
|
||||
pn->push_watch[1] = 0;
|
||||
if (pn->push_watch > 0) {
|
||||
__ofono_sms_datagram_watch_remove(pn->sms, pn->push_watch);
|
||||
pn->push_watch = 0;
|
||||
}
|
||||
|
||||
pn->agent = NULL;
|
||||
@@ -113,17 +108,12 @@ static DBusMessage *push_notification_register_agent(DBusConnection *conn,
|
||||
|
||||
sms_agent_set_removed_notify(pn->agent, agent_exited, pn);
|
||||
|
||||
pn->push_watch[0] = __ofono_sms_datagram_watch_add(pn->sms,
|
||||
pn->push_watch = __ofono_sms_datagram_watch_add(pn->sms,
|
||||
push_received,
|
||||
WAP_PUSH_DST_PORT,
|
||||
WAP_PUSH_SRC_PORT,
|
||||
pn, NULL);
|
||||
|
||||
pn->push_watch[1] = __ofono_sms_datagram_watch_add(pn->sms,
|
||||
push_received,
|
||||
WAP_PUSH_DST_PORT,
|
||||
0, pn, NULL);
|
||||
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
|
||||
@@ -166,8 +156,7 @@ static void push_notification_cleanup(gpointer user)
|
||||
DBG("%p", pn);
|
||||
|
||||
/* The push watch was already cleaned up */
|
||||
pn->push_watch[0] = 0;
|
||||
pn->push_watch[1] = 0;
|
||||
pn->push_watch = 0;
|
||||
pn->sms = NULL;
|
||||
|
||||
sms_agent_free(pn->agent);
|
||||
|
||||
@@ -48,6 +48,8 @@ static const char *none_prefix[] = { NULL };
|
||||
|
||||
struct sierra_data {
|
||||
GAtChat *modem;
|
||||
gboolean have_sim;
|
||||
struct at_util_sim_state_query *sim_state_query;
|
||||
};
|
||||
|
||||
static void sierra_debug(const char *str, void *user_data)
|
||||
@@ -80,6 +82,9 @@ static void sierra_remove(struct ofono_modem *modem)
|
||||
|
||||
ofono_modem_set_data(modem, NULL);
|
||||
|
||||
/* Cleanup potential SIM state polling */
|
||||
at_util_sim_state_query_free(data->sim_state_query);
|
||||
|
||||
/* Cleanup after hot-unplug */
|
||||
g_at_chat_unref(data->modem);
|
||||
|
||||
@@ -119,6 +124,21 @@ static GAtChat *open_device(struct ofono_modem *modem,
|
||||
return chat;
|
||||
}
|
||||
|
||||
static void sim_state_cb(gboolean present, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct sierra_data *data = ofono_modem_get_data(modem);
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
at_util_sim_state_query_free(data->sim_state_query);
|
||||
data->sim_state_query = NULL;
|
||||
|
||||
data->have_sim = present;
|
||||
ofono_modem_set_powered(modem, TRUE);
|
||||
|
||||
}
|
||||
|
||||
static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
@@ -131,7 +151,9 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
data->modem = NULL;
|
||||
}
|
||||
|
||||
ofono_modem_set_powered(modem, ok);
|
||||
data->sim_state_query = at_util_sim_state_query_new(data->modem,
|
||||
2, 20, sim_state_cb, modem,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int sierra_enable(struct ofono_modem *modem)
|
||||
@@ -222,7 +244,7 @@ static void sierra_pre_sim(struct ofono_modem *modem)
|
||||
sim = ofono_sim_create(modem, OFONO_VENDOR_SIERRA,
|
||||
"atmodem", data->modem);
|
||||
|
||||
if (sim)
|
||||
if (sim && data->have_sim == TRUE)
|
||||
ofono_sim_inserted_notify(sim, TRUE);
|
||||
}
|
||||
|
||||
|
||||
@@ -423,9 +423,8 @@ static void ste_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
if (g_at_chat_send(chat, command, NULL, set_online_cb, cbd, g_free))
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void ste_pre_sim(struct ofono_modem *modem)
|
||||
|
||||
@@ -232,7 +232,7 @@ static void reachable_cb(const GIsiMessage *msg, void *data)
|
||||
struct ofono_modem *om = data;
|
||||
struct isi_data *isi = ofono_modem_get_data(om);
|
||||
|
||||
if (!g_isi_msg_error(msg) < 0)
|
||||
if (g_isi_msg_error(msg) < 0)
|
||||
return;
|
||||
|
||||
ISI_RESOURCE_DBG(msg);
|
||||
|
||||
@@ -192,7 +192,7 @@ static void add_wavecom(struct ofono_modem *modem,
|
||||
ofono_modem_register(modem);
|
||||
}
|
||||
|
||||
static void add_tc65(struct ofono_modem *modem,
|
||||
static void add_cinterion(struct ofono_modem *modem,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *devnode;
|
||||
@@ -243,6 +243,11 @@ static void add_modem(struct udev_device *udev_device)
|
||||
if (devpath == NULL)
|
||||
return;
|
||||
|
||||
if(g_strcmp0(driver, "tc65") == 0)
|
||||
driver = "cinterion";
|
||||
if(g_strcmp0(driver, "ehs6") == 0)
|
||||
driver = "cinterion";
|
||||
|
||||
modem = ofono_modem_create(NULL, driver);
|
||||
if (modem == NULL)
|
||||
return;
|
||||
@@ -305,8 +310,8 @@ done:
|
||||
add_isi(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "calypso") == 0)
|
||||
add_calypso(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "tc65") == 0)
|
||||
add_tc65(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "cinterion") == 0)
|
||||
add_cinterion(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "nokiacdma") == 0)
|
||||
add_nokiacdma(modem, udev_device);
|
||||
else if (g_strcmp0(driver, "sim900") == 0)
|
||||
|
||||
@@ -117,6 +117,8 @@ static gboolean setup_mbm(struct modem_info *modem)
|
||||
gps = info->devnode;
|
||||
} else if (g_str_has_suffix(info->sysattr,
|
||||
"Network Adapter") == TRUE ||
|
||||
g_str_has_suffix(info->sysattr,
|
||||
"gw") == TRUE ||
|
||||
g_str_has_suffix(info->sysattr,
|
||||
"NetworkAdapter") == TRUE) {
|
||||
network = info->devnode;
|
||||
@@ -1078,14 +1080,19 @@ static struct {
|
||||
{ "icera", "cdc_ether", "0421", "0633" },
|
||||
{ "mbm", "cdc_acm", "0bdb" },
|
||||
{ "mbm", "cdc_ether", "0bdb" },
|
||||
{ "mbm", "cdc_ncm", "0bdb" },
|
||||
{ "mbm", "cdc_acm", "0fce" },
|
||||
{ "mbm", "cdc_ether", "0fce" },
|
||||
{ "mbm", "cdc_ncm", "0fce" },
|
||||
{ "mbm", "cdc_acm", "413c" },
|
||||
{ "mbm", "cdc_ether", "413c" },
|
||||
{ "mbm", "cdc_ncm", "413c" },
|
||||
{ "mbm", "cdc_acm", "03f0" },
|
||||
{ "mbm", "cdc_ether", "03f0" },
|
||||
{ "mbm", "cdc_ncm", "03f0" },
|
||||
{ "mbm", "cdc_acm", "0930" },
|
||||
{ "mbm", "cdc_ether", "0930" },
|
||||
{ "mbm", "cdc_ncm", "0930" },
|
||||
{ "hso", "hso" },
|
||||
{ "gobi", "qmi_wwan" },
|
||||
{ "gobi", "qcserial" },
|
||||
|
||||
@@ -1029,11 +1029,14 @@ out:
|
||||
|
||||
/*
|
||||
* In order to minimize signal transmissions we wait about X seconds
|
||||
* before reseting the base station id. The hope is that we receive
|
||||
* before resetting the base station id. The hope is that we receive
|
||||
* another cell broadcast with the new base station name within
|
||||
* that time
|
||||
*/
|
||||
if (lac_changed || ci_changed) {
|
||||
if(cbs->reset_source)
|
||||
g_source_remove(cbs->reset_source);
|
||||
|
||||
cbs->reset_source =
|
||||
g_timeout_add_seconds(3, reset_base_station_name, cbs);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ static void cdma_connman_ifupdown(const char *interface, ofono_bool_t active)
|
||||
return;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
|
||||
strncpy(ifr.ifr_name, interface, IFNAMSIZ - 1);
|
||||
|
||||
if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0)
|
||||
goto done;
|
||||
|
||||
@@ -41,6 +41,14 @@ enum network_registration_status {
|
||||
NETWORK_REGISTRATION_STATUS_ROAMING = 5,
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.3 <stat> */
|
||||
enum operator_status {
|
||||
OPERATOR_STATUS_UNKNOWN = 0,
|
||||
OPERATOR_STATUS_AVAILABLE = 1,
|
||||
OPERATOR_STATUS_CURRENT = 2,
|
||||
OPERATOR_STATUS_FORBIDDEN = 3,
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.6 */
|
||||
enum clip_validity {
|
||||
CLIP_VALIDITY_VALID = 0,
|
||||
@@ -48,6 +56,18 @@ enum clip_validity {
|
||||
CLIP_VALIDITY_NOT_AVAILABLE = 2,
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.29 */
|
||||
enum packet_bearer {
|
||||
PACKET_BEARER_NONE = 0,
|
||||
PACKET_BEARER_GPRS = 1,
|
||||
PACKET_BEARER_EGPRS = 2,
|
||||
PACKET_BEARER_UMTS = 3,
|
||||
PACKET_BEARER_HSUPA = 4,
|
||||
PACKET_BEARER_HSDPA = 5,
|
||||
PACKET_BEARER_HSUPA_HSDPA = 6,
|
||||
PACKET_BEARER_EPS = 7,
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.30 */
|
||||
enum cnap_validity {
|
||||
CNAP_VALIDITY_VALID = 0,
|
||||
|
||||
386
ofono/src/gprs.c
386
ofono/src/gprs.c
@@ -60,18 +60,6 @@
|
||||
#define MAX_MMS_MTU 1280
|
||||
#define MAX_GPRS_MTU 1280
|
||||
|
||||
/* 27.007 Section 7.29 */
|
||||
enum packet_bearer {
|
||||
PACKET_BEARER_NONE = 0,
|
||||
PACKET_BEARER_GPRS = 1,
|
||||
PACKET_BEARER_EGPRS = 2,
|
||||
PACKET_BEARER_UMTS = 3,
|
||||
PACKET_BEARER_HSUPA = 4,
|
||||
PACKET_BEARER_HSDPA = 5,
|
||||
PACKET_BEARER_HSUPA_HSDPA = 6,
|
||||
PACKET_BEARER_EPS = 7,
|
||||
};
|
||||
|
||||
struct ofono_gprs {
|
||||
GSList *contexts;
|
||||
ofono_bool_t attached;
|
||||
@@ -1889,6 +1877,8 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
|
||||
|
||||
attach = attach && gprs->powered;
|
||||
|
||||
DBG("attach: %u, driver_attached: %u", attach, gprs->driver_attached);
|
||||
|
||||
if (gprs->driver_attached == attach)
|
||||
return;
|
||||
|
||||
@@ -1899,8 +1889,8 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
|
||||
|
||||
gprs->flags |= GPRS_FLAG_ATTACHING;
|
||||
|
||||
gprs->driver->set_attached(gprs, attach, gprs_attach_callback, gprs);
|
||||
gprs->driver_attached = attach;
|
||||
gprs->driver->set_attached(gprs, attach, gprs_attach_callback, gprs);
|
||||
}
|
||||
|
||||
static void netreg_status_changed(int status, int lac, int ci, int tech,
|
||||
@@ -1911,9 +1901,6 @@ static void netreg_status_changed(int status, int lac, int ci, int tech,
|
||||
|
||||
DBG("%d", status);
|
||||
|
||||
if (gprs->netreg_status == status)
|
||||
return;
|
||||
|
||||
gprs->netreg_status = status;
|
||||
|
||||
gprs_netreg_update(gprs);
|
||||
@@ -2123,6 +2110,36 @@ static struct pri_context *add_context(struct ofono_gprs *gprs,
|
||||
return context;
|
||||
}
|
||||
|
||||
static void send_context_added_signal(struct ofono_gprs *gprs,
|
||||
struct pri_context *context,
|
||||
DBusConnection *conn)
|
||||
{
|
||||
const char *path;
|
||||
DBusMessage *signal;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter dict;
|
||||
|
||||
path = __ofono_atom_get_path(gprs->atom);
|
||||
signal = dbus_message_new_signal(path,
|
||||
OFONO_CONNECTION_MANAGER_INTERFACE,
|
||||
"ContextAdded");
|
||||
if (!signal)
|
||||
return;
|
||||
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
|
||||
path = context->path;
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
|
||||
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
OFONO_PROPERTIES_ARRAY_SIGNATURE,
|
||||
&dict);
|
||||
append_context_properties(context, &dict);
|
||||
dbus_message_iter_close_container(&iter, &dict);
|
||||
|
||||
g_dbus_send_message(conn, signal);
|
||||
}
|
||||
|
||||
static DBusMessage *gprs_add_context(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -2132,7 +2149,6 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
|
||||
const char *name;
|
||||
const char *path;
|
||||
enum ofono_gprs_context_type type;
|
||||
DBusMessage *signal;
|
||||
|
||||
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
|
||||
DBUS_TYPE_INVALID))
|
||||
@@ -2154,29 +2170,7 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
|
||||
g_dbus_send_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &path,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
path = __ofono_atom_get_path(gprs->atom);
|
||||
signal = dbus_message_new_signal(path,
|
||||
OFONO_CONNECTION_MANAGER_INTERFACE,
|
||||
"ContextAdded");
|
||||
|
||||
if (signal) {
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter dict;
|
||||
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
|
||||
path = context->path;
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
OFONO_PROPERTIES_ARRAY_SIGNATURE,
|
||||
&dict);
|
||||
append_context_properties(context, &dict);
|
||||
dbus_message_iter_close_container(&iter, &dict);
|
||||
|
||||
g_dbus_send_message(conn, signal);
|
||||
}
|
||||
send_context_added_signal(gprs, context, conn);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -2411,6 +2405,196 @@ static DBusMessage *gprs_get_contexts(DBusConnection *conn,
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void provision_context(const struct ofono_gprs_provision_data *ap,
|
||||
struct ofono_gprs *gprs)
|
||||
{
|
||||
unsigned int id;
|
||||
struct pri_context *context = NULL;
|
||||
|
||||
/* Sanity check */
|
||||
if (ap == NULL)
|
||||
return;
|
||||
|
||||
if (ap->name && strlen(ap->name) > MAX_CONTEXT_NAME_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->apn == NULL || strlen(ap->apn) > OFONO_GPRS_MAX_APN_LENGTH)
|
||||
return;
|
||||
|
||||
if (is_valid_apn(ap->apn) == FALSE)
|
||||
return;
|
||||
|
||||
if (ap->username &&
|
||||
strlen(ap->username) > OFONO_GPRS_MAX_USERNAME_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->password &&
|
||||
strlen(ap->password) > OFONO_GPRS_MAX_PASSWORD_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->message_proxy &&
|
||||
strlen(ap->message_proxy) > MAX_MESSAGE_PROXY_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->message_center &&
|
||||
strlen(ap->message_center) > MAX_MESSAGE_CENTER_LENGTH)
|
||||
return;
|
||||
|
||||
if (gprs->last_context_id)
|
||||
id = idmap_alloc_next(gprs->pid_map, gprs->last_context_id);
|
||||
else
|
||||
id = idmap_alloc(gprs->pid_map);
|
||||
|
||||
if (id > idmap_get_max(gprs->pid_map))
|
||||
return;
|
||||
|
||||
context = pri_context_create(gprs, ap->name, ap->type);
|
||||
if (context == NULL) {
|
||||
idmap_put(gprs->pid_map, id);
|
||||
return;
|
||||
}
|
||||
|
||||
context->id = id;
|
||||
|
||||
if (ap->username != NULL)
|
||||
strcpy(context->context.username, ap->username);
|
||||
|
||||
if (ap->password != NULL)
|
||||
strcpy(context->context.password, ap->password);
|
||||
|
||||
context->context.auth_method = ap->auth_method;
|
||||
|
||||
strcpy(context->context.apn, ap->apn);
|
||||
context->context.proto = ap->proto;
|
||||
|
||||
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
if (ap->message_proxy != NULL)
|
||||
strcpy(context->message_proxy, ap->message_proxy);
|
||||
|
||||
if (ap->message_center != NULL)
|
||||
strcpy(context->message_center, ap->message_center);
|
||||
}
|
||||
|
||||
if (context_dbus_register(context) == FALSE)
|
||||
return;
|
||||
|
||||
gprs->last_context_id = id;
|
||||
|
||||
if (gprs->settings) {
|
||||
write_context_settings(gprs, context);
|
||||
storage_sync(gprs->imsi, SETTINGS_STORE, gprs->settings);
|
||||
}
|
||||
|
||||
gprs->contexts = g_slist_append(gprs->contexts, context);
|
||||
}
|
||||
|
||||
static void provision_contexts(struct ofono_gprs *gprs, const char *mcc,
|
||||
const char *mnc, const char *spn)
|
||||
{
|
||||
struct ofono_gprs_provision_data *settings;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
if (__ofono_gprs_provision_get_settings(mcc, mnc, spn,
|
||||
&settings, &count) == FALSE) {
|
||||
ofono_warn("Provisioning failed");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
provision_context(&settings[i], gprs);
|
||||
|
||||
__ofono_gprs_provision_free_settings(settings, count);
|
||||
}
|
||||
|
||||
static void remove_non_active_context(struct ofono_gprs *gprs,
|
||||
struct pri_context *ctx, DBusConnection *conn)
|
||||
{
|
||||
char *path;
|
||||
const char *atompath;
|
||||
|
||||
if (gprs->settings) {
|
||||
g_key_file_remove_group(gprs->settings, ctx->key, NULL);
|
||||
storage_sync(gprs->imsi, SETTINGS_STORE, gprs->settings);
|
||||
}
|
||||
|
||||
/* Make a backup copy of path for signal emission below */
|
||||
path = g_strdup(ctx->path);
|
||||
|
||||
context_dbus_unregister(ctx);
|
||||
gprs->contexts = g_slist_remove(gprs->contexts, ctx);
|
||||
|
||||
atompath = __ofono_atom_get_path(gprs->atom);
|
||||
g_dbus_emit_signal(conn, atompath, OFONO_CONNECTION_MANAGER_INTERFACE,
|
||||
"ContextRemoved", DBUS_TYPE_OBJECT_PATH, &path,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
static DBusMessage *gprs_reset_contexts(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
|
||||
struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
|
||||
DBusMessage *reply;
|
||||
GSList *l;
|
||||
|
||||
if (gprs->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
/*
|
||||
* We want __ofono_error_busy to take precedence over
|
||||
* __ofono_error_not_allowed errors, so we check it first.
|
||||
*/
|
||||
|
||||
for (l = gprs->contexts; l; l = l->next) {
|
||||
struct pri_context *ctx = l->data;
|
||||
|
||||
if (ctx->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
}
|
||||
|
||||
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID))
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
if (gprs->powered)
|
||||
return __ofono_error_not_allowed(msg);
|
||||
|
||||
for (l = gprs->contexts; l; l = l->next) {
|
||||
struct pri_context *ctx = l->data;
|
||||
|
||||
if (ctx->active)
|
||||
return __ofono_error_not_allowed(msg);
|
||||
}
|
||||
|
||||
reply = dbus_message_new_method_return(msg);
|
||||
if (reply == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Remove first the current contexts, re-provision after */
|
||||
|
||||
while (gprs->contexts != NULL) {
|
||||
struct pri_context *ctx = gprs->contexts->data;
|
||||
remove_non_active_context(gprs, ctx, conn);
|
||||
}
|
||||
|
||||
gprs->last_context_id = 0;
|
||||
|
||||
provision_contexts(gprs, ofono_sim_get_mcc(sim),
|
||||
ofono_sim_get_mnc(sim), ofono_sim_get_spn(sim));
|
||||
|
||||
if (gprs->contexts == NULL) /* Automatic provisioning failed */
|
||||
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
|
||||
for (l = gprs->contexts; l; l = l->next) {
|
||||
struct pri_context *ctx = l->data;
|
||||
send_context_added_signal(gprs, ctx, conn);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable manager_methods[] = {
|
||||
{ GDBUS_METHOD("GetProperties",
|
||||
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
@@ -2430,6 +2614,8 @@ static const GDBusMethodTable manager_methods[] = {
|
||||
{ GDBUS_METHOD("GetContexts", NULL,
|
||||
GDBUS_ARGS({ "contexts_with_properties", "a(oa{sv})" }),
|
||||
gprs_get_contexts) },
|
||||
{ GDBUS_ASYNC_METHOD("ResetContexts", NULL, NULL,
|
||||
gprs_reset_contexts) },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -2437,7 +2623,7 @@ static const GDBusSignalTable manager_signals[] = {
|
||||
{ GDBUS_SIGNAL("PropertyChanged",
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL("ContextAdded",
|
||||
GDBUS_ARGS({ "path", "o" }, { "properties", "v" })) },
|
||||
GDBUS_ARGS({ "path", "o" }, { "properties", "a{sv}" })) },
|
||||
{ GDBUS_SIGNAL("ContextRemoved", GDBUS_ARGS({ "path", "o" })) },
|
||||
{ }
|
||||
};
|
||||
@@ -2725,6 +2911,12 @@ void ofono_gprs_context_set_type(struct ofono_gprs_context *gc,
|
||||
gc->type = type;
|
||||
}
|
||||
|
||||
enum ofono_gprs_context_type ofono_gprs_context_get_type(
|
||||
struct ofono_gprs_context *gc)
|
||||
{
|
||||
return gc->type;
|
||||
}
|
||||
|
||||
void ofono_gprs_context_set_interface(struct ofono_gprs_context *gc,
|
||||
const char *interface)
|
||||
{
|
||||
@@ -3234,108 +3426,6 @@ remove:
|
||||
storage_sync(imsi, SETTINGS_STORE, gprs->settings);
|
||||
}
|
||||
|
||||
static void provision_context(const struct ofono_gprs_provision_data *ap,
|
||||
struct ofono_gprs *gprs)
|
||||
{
|
||||
unsigned int id;
|
||||
struct pri_context *context = NULL;
|
||||
|
||||
/* Sanity check */
|
||||
if (ap == NULL)
|
||||
return;
|
||||
|
||||
if (ap->name && strlen(ap->name) > MAX_CONTEXT_NAME_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->apn == NULL || strlen(ap->apn) > OFONO_GPRS_MAX_APN_LENGTH)
|
||||
return;
|
||||
|
||||
if (is_valid_apn(ap->apn) == FALSE)
|
||||
return;
|
||||
|
||||
if (ap->username &&
|
||||
strlen(ap->username) > OFONO_GPRS_MAX_USERNAME_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->password &&
|
||||
strlen(ap->password) > OFONO_GPRS_MAX_PASSWORD_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->message_proxy &&
|
||||
strlen(ap->message_proxy) > MAX_MESSAGE_PROXY_LENGTH)
|
||||
return;
|
||||
|
||||
if (ap->message_center &&
|
||||
strlen(ap->message_center) > MAX_MESSAGE_CENTER_LENGTH)
|
||||
return;
|
||||
|
||||
if (gprs->last_context_id)
|
||||
id = idmap_alloc_next(gprs->pid_map, gprs->last_context_id);
|
||||
else
|
||||
id = idmap_alloc(gprs->pid_map);
|
||||
|
||||
if (id > idmap_get_max(gprs->pid_map))
|
||||
return;
|
||||
|
||||
context = pri_context_create(gprs, ap->name, ap->type);
|
||||
if (context == NULL) {
|
||||
idmap_put(gprs->pid_map, id);
|
||||
return;
|
||||
}
|
||||
|
||||
context->id = id;
|
||||
|
||||
if (ap->username != NULL)
|
||||
strcpy(context->context.username, ap->username);
|
||||
|
||||
if (ap->password != NULL)
|
||||
strcpy(context->context.password, ap->password);
|
||||
|
||||
context->context.auth_method = ap->auth_method;
|
||||
|
||||
strcpy(context->context.apn, ap->apn);
|
||||
context->context.proto = ap->proto;
|
||||
|
||||
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
if (ap->message_proxy != NULL)
|
||||
strcpy(context->message_proxy, ap->message_proxy);
|
||||
|
||||
if (ap->message_center != NULL)
|
||||
strcpy(context->message_center, ap->message_center);
|
||||
}
|
||||
|
||||
if (context_dbus_register(context) == FALSE)
|
||||
return;
|
||||
|
||||
gprs->last_context_id = id;
|
||||
|
||||
if (gprs->settings) {
|
||||
write_context_settings(gprs, context);
|
||||
storage_sync(gprs->imsi, SETTINGS_STORE, gprs->settings);
|
||||
}
|
||||
|
||||
gprs->contexts = g_slist_append(gprs->contexts, context);
|
||||
}
|
||||
|
||||
static void provision_contexts(struct ofono_gprs *gprs, const char *mcc,
|
||||
const char *mnc, const char *spn)
|
||||
{
|
||||
struct ofono_gprs_provision_data *settings;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
if (__ofono_gprs_provision_get_settings(mcc, mnc, spn,
|
||||
&settings, &count) == FALSE) {
|
||||
ofono_warn("Provisioning failed");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
provision_context(&settings[i], gprs);
|
||||
|
||||
__ofono_gprs_provision_free_settings(settings, count);
|
||||
}
|
||||
|
||||
static void ofono_gprs_finish_register(struct ofono_gprs *gprs)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
@@ -3422,6 +3512,11 @@ static void spn_read_cb(const char *spn, const char *dc, void *data)
|
||||
ofono_gprs_finish_register(gprs);
|
||||
}
|
||||
|
||||
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs)
|
||||
{
|
||||
return __ofono_atom_get_modem(gprs->atom);
|
||||
}
|
||||
|
||||
void ofono_gprs_register(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
|
||||
@@ -3457,11 +3552,6 @@ void *ofono_gprs_get_data(struct ofono_gprs *gprs)
|
||||
return gprs->driver_data;
|
||||
}
|
||||
|
||||
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs)
|
||||
{
|
||||
return __ofono_atom_get_modem(gprs->atom);
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs)
|
||||
{
|
||||
return gprs->roaming_allowed;
|
||||
|
||||
@@ -101,6 +101,8 @@ static void send_new_connection(const char *card, int fd, uint8_t codec)
|
||||
DBusMessage *msg;
|
||||
DBusMessageIter iter;
|
||||
|
||||
DBG("%p, fd: %d, codec: %hu", card, fd, codec);
|
||||
|
||||
msg = dbus_message_new_method_call(agent->owner, agent->path,
|
||||
HFP_AUDIO_AGENT_INTERFACE, "NewConnection");
|
||||
if (msg == NULL)
|
||||
@@ -183,9 +185,15 @@ static gboolean sco_accept(GIOChannel *io, GIOCondition cond,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DBG("SCO connection setup between local: %s and remote: %s",
|
||||
local, remote);
|
||||
|
||||
send_new_connection(card->path, nsk, card->selected_codec);
|
||||
close(nsk);
|
||||
|
||||
if (card->driver->sco_connected_hint)
|
||||
card->driver->sco_connected_hint(card);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -845,6 +853,8 @@ void ofono_handsfree_audio_ref(void)
|
||||
if (ref_count != 1)
|
||||
return;
|
||||
|
||||
__ofono_handsfree_audio_manager_init();
|
||||
|
||||
if (!g_dbus_register_interface(ofono_dbus_get_connection(),
|
||||
OFONO_MANAGER_PATH,
|
||||
HFP_AUDIO_MANAGER_INTERFACE,
|
||||
@@ -873,6 +883,8 @@ void ofono_handsfree_audio_unref(void)
|
||||
agent_release(agent);
|
||||
agent_free(agent);
|
||||
}
|
||||
|
||||
__ofono_handsfree_audio_manager_cleanup();
|
||||
}
|
||||
|
||||
int __ofono_handsfree_audio_manager_init(void)
|
||||
@@ -882,15 +894,11 @@ int __ofono_handsfree_audio_manager_init(void)
|
||||
|
||||
void __ofono_handsfree_audio_manager_cleanup(void)
|
||||
{
|
||||
if (ref_count == 0)
|
||||
if (ref_count != 0)
|
||||
return;
|
||||
|
||||
ofono_error("Handsfree Audio manager not cleaned up properly,"
|
||||
"fixing...");
|
||||
|
||||
ref_count = 1;
|
||||
ofono_handsfree_audio_unref();
|
||||
|
||||
if (sco_watch > 0)
|
||||
if (sco_watch > 0) {
|
||||
g_source_remove(sco_watch);
|
||||
sco_watch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,11 @@ struct ofono_handsfree {
|
||||
static const char **ag_features_list(unsigned int features,
|
||||
unsigned int chld_features)
|
||||
{
|
||||
static const char *list[10];
|
||||
/*
|
||||
* BRSF response is a 32-bit unsigned int. Only 32 entries are posible,
|
||||
* and we do not ever report the presence of bit 8.
|
||||
*/
|
||||
static const char *list[32];
|
||||
unsigned int i = 0;
|
||||
|
||||
if (features & HFP_AG_FEATURE_3WAY)
|
||||
@@ -602,7 +606,7 @@ static DBusMessage *handsfree_request_phone_number(DBusConnection *conn,
|
||||
}
|
||||
|
||||
static const GDBusMethodTable handsfree_methods[] = {
|
||||
{ GDBUS_METHOD("GetProperties",
|
||||
{ GDBUS_ASYNC_METHOD("GetProperties",
|
||||
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
handsfree_get_properties) },
|
||||
{ GDBUS_ASYNC_METHOD("SetProperty",
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#ifdef __GLIBC__
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "ofono.h"
|
||||
@@ -113,6 +115,7 @@ void ofono_debug(const char *format, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef __GLIBC__
|
||||
static void print_backtrace(unsigned int offset)
|
||||
{
|
||||
void *frames[99];
|
||||
@@ -240,6 +243,7 @@ static void signal_setup(sighandler_t handler)
|
||||
sigaction(SIGABRT, &sa, NULL);
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern struct ofono_debug_desc __start___debug[];
|
||||
extern struct ofono_debug_desc __stop___debug[];
|
||||
@@ -311,8 +315,10 @@ int __ofono_log_init(const char *program, const char *debug,
|
||||
if (detach == FALSE)
|
||||
option |= LOG_PERROR;
|
||||
|
||||
#ifdef __GLIBC__
|
||||
if (backtrace == TRUE)
|
||||
signal_setup(signal_handler);
|
||||
#endif
|
||||
|
||||
openlog(basename(program), option, LOG_DAEMON);
|
||||
|
||||
@@ -327,8 +333,10 @@ void __ofono_log_cleanup(ofono_bool_t backtrace)
|
||||
|
||||
closelog();
|
||||
|
||||
#ifdef __GLIBC__
|
||||
if (backtrace == TRUE)
|
||||
signal_setup(SIG_DFL);
|
||||
#endif
|
||||
|
||||
g_strfreev(enabled);
|
||||
}
|
||||
|
||||
@@ -244,12 +244,6 @@ int main(int argc, char **argv)
|
||||
|
||||
__ofono_manager_init();
|
||||
|
||||
/*
|
||||
* BT HFP SCO socket creation moved to Bluez5 plugin.
|
||||
* Bluez4 handles the SCO socket, it will conflict with oFono.
|
||||
*/
|
||||
//__ofono_handsfree_audio_manager_init();
|
||||
|
||||
__ofono_plugin_init(option_plugin, option_noplugin);
|
||||
|
||||
g_free(option_plugin);
|
||||
@@ -259,8 +253,6 @@ int main(int argc, char **argv)
|
||||
|
||||
__ofono_plugin_cleanup();
|
||||
|
||||
//__ofono_handsfree_audio_manager_cleanup(); See comment above
|
||||
|
||||
__ofono_manager_cleanup();
|
||||
|
||||
__ofono_modemwatch_cleanup();
|
||||
|
||||
@@ -481,7 +481,7 @@ static void mw_mwis_read_cb(int ok, int total_length, int record,
|
||||
status = data[0];
|
||||
data++;
|
||||
|
||||
for (i = 0; i < 5 && i < record_length - 1; i++) {
|
||||
for (i = 0; i < 5 && i < record_length - 1; i++, data++) {
|
||||
info.indication = (status >> i) & 1;
|
||||
info.message_count = info.indication ? data[0] : 0;
|
||||
|
||||
@@ -732,6 +732,7 @@ static void mw_set_indicator(struct ofono_message_waiting *mw, int profile,
|
||||
efmwis[i + 1] = mw->messages[i].message_count;
|
||||
|
||||
/* Fill in indicator state bits in byte 0 */
|
||||
efmwis[0] = 0;
|
||||
for (i = 0; i < 5 && i < mw->efmwis_length - 1; i++)
|
||||
if (mw->messages[i].indication)
|
||||
efmwis[0] |= 1 << i;
|
||||
|
||||
@@ -2144,6 +2144,9 @@ void ofono_modem_reset(struct ofono_modem *modem)
|
||||
if (err == -EINPROGRESS)
|
||||
return;
|
||||
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
modem_change_state(modem, MODEM_STATE_PRE_SIM);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,14 +50,6 @@ enum network_registration_mode {
|
||||
NETWORK_REGISTRATION_MODE_AUTO_ONLY = 5, /* Out of range of 27.007 */
|
||||
};
|
||||
|
||||
/* 27.007 Section 7.3 <stat> */
|
||||
enum operator_status {
|
||||
OPERATOR_STATUS_UNKNOWN = 0,
|
||||
OPERATOR_STATUS_AVAILABLE = 1,
|
||||
OPERATOR_STATUS_CURRENT = 2,
|
||||
OPERATOR_STATUS_FORBIDDEN = 3,
|
||||
};
|
||||
|
||||
struct ofono_netreg {
|
||||
int status;
|
||||
int location;
|
||||
@@ -718,6 +710,7 @@ static gboolean update_operator_list(struct ofono_netreg *netreg, int total,
|
||||
GSList *o;
|
||||
GSList *compressed;
|
||||
GSList *c;
|
||||
struct network_operator_data *current_op = NULL;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
compressed = compress_operator_list(list, total);
|
||||
@@ -762,8 +755,19 @@ static gboolean update_operator_list(struct ofono_netreg *netreg, int total,
|
||||
if (netreg->operator_list)
|
||||
changed = TRUE;
|
||||
|
||||
for (o = netreg->operator_list; o; o = o->next)
|
||||
network_operator_dbus_unregister(netreg, o->data);
|
||||
for (o = netreg->operator_list; o; o = o->next) {
|
||||
struct network_operator_data *op = o->data;
|
||||
if (op != op->netreg->current_operator)
|
||||
network_operator_dbus_unregister(netreg, op);
|
||||
else
|
||||
current_op = op;
|
||||
}
|
||||
|
||||
if (current_op) {
|
||||
n = g_slist_prepend(n, current_op);
|
||||
netreg->operator_list =
|
||||
g_slist_remove(netreg->operator_list, current_op);
|
||||
}
|
||||
|
||||
g_slist_free(netreg->operator_list);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Type=dbus
|
||||
BusName=org.ofono
|
||||
User=root
|
||||
EnvironmentFile=-/var/lib/environment/ofono/*.conf
|
||||
ExecStart=@prefix@/sbin/ofonod -n --nobacktrace $OFONO_ARGS
|
||||
ExecStart=@prefix@/sbin/ofonod -n --nobacktrace $OFONO_ARGS $OFONO_DEBUG
|
||||
StandardError=null
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
|
||||
@@ -40,6 +40,7 @@ static GSList *g_drivers = NULL;
|
||||
|
||||
struct ofono_radio_settings {
|
||||
DBusMessage *pending;
|
||||
GSList *pending_get_prop;
|
||||
int flags;
|
||||
enum ofono_radio_access_mode mode;
|
||||
enum ofono_radio_band_gsm band_gsm;
|
||||
@@ -387,14 +388,35 @@ static void radio_mode_set_callback(const struct ofono_error *error, void *data)
|
||||
radio_set_rat_mode(rs, rs->pending_mode);
|
||||
}
|
||||
|
||||
static void radio_send_properties_reply(struct ofono_radio_settings *rs)
|
||||
static void radio_send_properties_ok(gpointer data, gpointer user_data)
|
||||
{
|
||||
DBusMessage *reply;
|
||||
DBusMessage *msg = data;
|
||||
struct ofono_radio_settings *rs = user_data;
|
||||
DBusMessage *reply = radio_get_properties_reply(msg, rs);
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, reply);
|
||||
}
|
||||
|
||||
static void radio_send_properties_error(gpointer data, gpointer user_data)
|
||||
{
|
||||
DBusMessage *msg = data;
|
||||
DBusMessage *reply = __ofono_error_failed(msg);
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, reply);
|
||||
}
|
||||
|
||||
static void radio_send_properties_reply(struct ofono_radio_settings *rs,
|
||||
GFunc func)
|
||||
{
|
||||
g_slist_foreach(rs->pending_get_prop, func, rs);
|
||||
g_slist_free(rs->pending_get_prop);
|
||||
rs->pending_get_prop = NULL;
|
||||
}
|
||||
|
||||
static void radio_send_properties_reply_ok(struct ofono_radio_settings *rs)
|
||||
{
|
||||
rs->flags |= RADIO_SETTINGS_FLAG_CACHED;
|
||||
|
||||
reply = radio_get_properties_reply(rs->pending, rs);
|
||||
__ofono_dbus_pending_reply(&rs->pending, reply);
|
||||
radio_send_properties_reply(rs, radio_send_properties_ok);
|
||||
}
|
||||
|
||||
static void radio_available_rats_query_callback(const struct ofono_error *error,
|
||||
@@ -408,14 +430,14 @@ static void radio_available_rats_query_callback(const struct ofono_error *error,
|
||||
else
|
||||
DBG("Error while querying available rats");
|
||||
|
||||
radio_send_properties_reply(rs);
|
||||
radio_send_properties_reply_ok(rs);
|
||||
}
|
||||
|
||||
static void radio_query_available_rats(struct ofono_radio_settings *rs)
|
||||
{
|
||||
/* Modem technology is not supposed to change, so one query is enough */
|
||||
if (rs->driver->query_available_rats == NULL || rs->available_rats) {
|
||||
radio_send_properties_reply(rs);
|
||||
radio_send_properties_reply_ok(rs);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -427,14 +449,11 @@ static void radio_fast_dormancy_query_callback(const struct ofono_error *error,
|
||||
ofono_bool_t enable, void *data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = data;
|
||||
DBusMessage *reply;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
DBG("Error during fast dormancy query");
|
||||
|
||||
reply = __ofono_error_failed(rs->pending);
|
||||
__ofono_dbus_pending_reply(&rs->pending, reply);
|
||||
|
||||
radio_send_properties_reply(rs, radio_send_properties_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -459,14 +478,11 @@ static void radio_band_query_callback(const struct ofono_error *error,
|
||||
void *data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = data;
|
||||
DBusMessage *reply;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
DBG("Error during radio frequency band query");
|
||||
|
||||
reply = __ofono_error_failed(rs->pending);
|
||||
__ofono_dbus_pending_reply(&rs->pending, reply);
|
||||
|
||||
radio_send_properties_reply(rs, radio_send_properties_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -492,14 +508,11 @@ static void radio_rat_mode_query_callback(const struct ofono_error *error,
|
||||
void *data)
|
||||
{
|
||||
struct ofono_radio_settings *rs = data;
|
||||
DBusMessage *reply;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
DBG("Error during radio access mode query");
|
||||
|
||||
reply = __ofono_error_failed(rs->pending);
|
||||
__ofono_dbus_pending_reply(&rs->pending, reply);
|
||||
|
||||
radio_send_properties_reply(rs, radio_send_properties_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -518,11 +531,15 @@ static DBusMessage *radio_get_properties(DBusConnection *conn,
|
||||
if (rs->driver->query_rat_mode == NULL)
|
||||
return __ofono_error_not_implemented(msg);
|
||||
|
||||
if (rs->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
rs->pending = dbus_message_ref(msg);
|
||||
rs->driver->query_rat_mode(rs, radio_rat_mode_query_callback, rs);
|
||||
if (rs->pending_get_prop) {
|
||||
rs->pending_get_prop = g_slist_append(rs->pending_get_prop,
|
||||
dbus_message_ref(msg));
|
||||
} else {
|
||||
rs->pending_get_prop = g_slist_append(NULL,
|
||||
dbus_message_ref(msg));
|
||||
rs->driver->query_rat_mode(rs, radio_rat_mode_query_callback,
|
||||
rs);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -688,6 +705,13 @@ void ofono_radio_settings_driver_unregister(const struct ofono_radio_settings_dr
|
||||
g_drivers = g_slist_remove(g_drivers, (void *) d);
|
||||
}
|
||||
|
||||
static void radio_settings_cancel_get_properties(gpointer data)
|
||||
{
|
||||
DBusMessage *msg = data;
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, __ofono_error_canceled(msg));
|
||||
}
|
||||
|
||||
static void radio_settings_unregister(struct ofono_atom *atom)
|
||||
{
|
||||
struct ofono_radio_settings *rs = __ofono_atom_get_data(atom);
|
||||
@@ -695,6 +719,12 @@ static void radio_settings_unregister(struct ofono_atom *atom)
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(rs->atom);
|
||||
|
||||
if (rs->pending_get_prop) {
|
||||
g_slist_free_full(rs->pending_get_prop,
|
||||
radio_settings_cancel_get_properties);
|
||||
rs->pending_get_prop = NULL;
|
||||
}
|
||||
|
||||
ofono_modem_remove_interface(modem, OFONO_RADIO_SETTINGS_INTERFACE);
|
||||
g_dbus_unregister_interface(conn, path, OFONO_RADIO_SETTINGS_INTERFACE);
|
||||
}
|
||||
@@ -785,3 +815,9 @@ void *ofono_radio_settings_get_data(struct ofono_radio_settings *rs)
|
||||
{
|
||||
return rs->driver_data;
|
||||
}
|
||||
|
||||
struct ofono_modem *ofono_radio_settings_get_modem(
|
||||
struct ofono_radio_settings *rs)
|
||||
{
|
||||
return __ofono_atom_get_modem(rs->atom);
|
||||
}
|
||||
|
||||
@@ -2504,16 +2504,9 @@ void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
|
||||
sim_inserted_update(sim);
|
||||
call_state_watches(sim);
|
||||
|
||||
if (inserted)
|
||||
if (inserted) {
|
||||
sim_initialize(sim);
|
||||
else {
|
||||
/*
|
||||
* Reset type to trigger property change signal after sim is
|
||||
* removed and inserted.
|
||||
* Can't reset in sim_free_main_state because it's called also
|
||||
* when sim state changes to OFONO_SIM_STATE_LOCKED_OUT
|
||||
* (PUK lock) if user fails to change PIN.
|
||||
*/
|
||||
} else {
|
||||
sim->pin_type = OFONO_SIM_PASSWORD_NONE;
|
||||
|
||||
sim_free_state(sim);
|
||||
@@ -2802,6 +2795,7 @@ static void sim_pin_query_cb(const struct ofono_error *error,
|
||||
g_strfreev(locked_pins);
|
||||
}
|
||||
}
|
||||
|
||||
ofono_dbus_signal_property_changed(conn, path,
|
||||
OFONO_SIM_MANAGER_INTERFACE,
|
||||
"PinRequired", DBUS_TYPE_STRING,
|
||||
|
||||
@@ -1195,6 +1195,7 @@ static void dispatch_app_datagram(struct ofono_sms *sms,
|
||||
ofono_sms_datagram_notify_cb_t notify;
|
||||
struct sms_handler *h;
|
||||
GSList *l;
|
||||
gboolean dispatched = FALSE;
|
||||
|
||||
ts = sms_scts_to_time(scts, &remote);
|
||||
localtime_r(&ts, &local);
|
||||
@@ -1206,9 +1207,15 @@ static void dispatch_app_datagram(struct ofono_sms *sms,
|
||||
if (!port_equal(dst, h->dst) || !port_equal(src, h->src))
|
||||
continue;
|
||||
|
||||
dispatched = TRUE;
|
||||
|
||||
notify(sender, &remote, &local, dst, src, buf, len,
|
||||
h->item.notify_data);
|
||||
}
|
||||
|
||||
if (!dispatched)
|
||||
ofono_info("Datagram with ports [%d,%d] not delivered",
|
||||
dst, src);
|
||||
}
|
||||
|
||||
static void dispatch_text_message(struct ofono_sms *sms,
|
||||
|
||||
@@ -1946,9 +1946,6 @@ static gboolean extract_app_port_common(struct sms_udh_iter *iter, int *dst,
|
||||
if (((addr_hdr[0] << 8) | addr_hdr[1]) > 49151)
|
||||
break;
|
||||
|
||||
if (((addr_hdr[2] << 8) | addr_hdr[3]) > 49151)
|
||||
break;
|
||||
|
||||
dstport = (addr_hdr[0] << 8) | addr_hdr[1];
|
||||
srcport = (addr_hdr[2] << 8) | addr_hdr[3];
|
||||
is_addr_8bit = FALSE;
|
||||
|
||||
@@ -1534,6 +1534,9 @@ static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
|
||||
if (g_slist_length(vc->call_list) >= MAX_VOICE_CALLS)
|
||||
return -EPERM;
|
||||
|
||||
if (valid_ussd_string(number, vc->call_list != NULL))
|
||||
return -EINVAL;
|
||||
|
||||
if (!valid_long_phone_number_format(number))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -2777,16 +2780,25 @@ static void emulator_hfp_unregister(struct ofono_atom *atom)
|
||||
struct ofono_voicecall *vc = __ofono_atom_get_data(atom);
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(atom);
|
||||
|
||||
struct emulator_status data;
|
||||
data.vc = vc;
|
||||
|
||||
data.status = OFONO_EMULATOR_CALL_INACTIVE;
|
||||
__ofono_modem_foreach_registered_atom(modem,
|
||||
OFONO_ATOM_TYPE_EMULATOR_HFP,
|
||||
emulator_call_status_cb, 0);
|
||||
emulator_call_status_cb, &data);
|
||||
|
||||
data.status = OFONO_EMULATOR_CALLSETUP_INACTIVE;
|
||||
__ofono_modem_foreach_registered_atom(modem,
|
||||
OFONO_ATOM_TYPE_EMULATOR_HFP,
|
||||
emulator_callsetup_status_cb,
|
||||
0);
|
||||
&data);
|
||||
|
||||
data.status = OFONO_EMULATOR_CALLHELD_NONE;
|
||||
__ofono_modem_foreach_registered_atom(modem,
|
||||
OFONO_ATOM_TYPE_EMULATOR_HFP,
|
||||
emulator_callheld_status_cb, 0);
|
||||
emulator_callheld_status_cb,
|
||||
&data);
|
||||
|
||||
__ofono_modem_foreach_registered_atom(modem,
|
||||
OFONO_ATOM_TYPE_EMULATOR_HFP,
|
||||
|
||||
20
ofono/test/reset-contexts
Executable file
20
ofono/test/reset-contexts
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import dbus
|
||||
import sys
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
path = sys.argv[1]
|
||||
else:
|
||||
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
|
||||
'org.ofono.Manager')
|
||||
modems = manager.GetModems()
|
||||
path = modems[0][0]
|
||||
|
||||
print("Resetting contexts for SIM on modem %s..." % path)
|
||||
cm = dbus.Interface(bus.get_object('org.ofono', path),
|
||||
'org.ofono.ConnectionManager')
|
||||
|
||||
cm.ResetContexts()
|
||||
@@ -10,6 +10,7 @@ Source0: http://www.kernel.org/pub/linux/network/ofono/ofono-%{version}.tar.x
|
||||
Requires: dbus
|
||||
Requires: systemd
|
||||
Requires: ofono-configs
|
||||
Requires: libgrilio >= 1.0.6
|
||||
Requires(preun): systemd
|
||||
Requires(post): systemd
|
||||
Requires(postun): systemd
|
||||
@@ -20,7 +21,7 @@ BuildRequires: pkgconfig(bluez) >= 4.85
|
||||
BuildRequires: pkgconfig(mobile-broadband-provider-info)
|
||||
BuildRequires: pkgconfig(libwspcodec) >= 2.0
|
||||
BuildRequires: pkgconfig(libglibutil)
|
||||
BuildRequires: pkgconfig(libgrilio)
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.6
|
||||
BuildRequires: libtool
|
||||
BuildRequires: automake
|
||||
BuildRequires: autoconf
|
||||
|
||||
20
test/reset-contexts
Executable file
20
test/reset-contexts
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import dbus
|
||||
import sys
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
path = sys.argv[1]
|
||||
else:
|
||||
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
|
||||
'org.ofono.Manager')
|
||||
modems = manager.GetModems()
|
||||
path = modems[0][0]
|
||||
|
||||
print("Resetting contexts for SIM on modem %s..." % path)
|
||||
cm = dbus.Interface(bus.get_object('org.ofono', path),
|
||||
'org.ofono.ConnectionManager')
|
||||
|
||||
cm.ResetContexts()
|
||||
2
upstream
2
upstream
Submodule upstream updated: 649ee6bf67...8929d131a3
Reference in New Issue
Block a user